Blame src/wkeys.c

Packit 15a96c
/*
Packit 15a96c
 * wkeys.c	Read a keypress from the standard input. If it is an escape
Packit 15a96c
 *		code, return a special value.
Packit 15a96c
 *
Packit 15a96c
 *		WARNING: possibly the most ugly code in this package!
Packit 15a96c
 *
Packit 15a96c
 *		This file is part of the minicom communications package,
Packit 15a96c
 *		Copyright 1991-1995 Miquel van Smoorenburg.
Packit 15a96c
 *
Packit 15a96c
 *		This program is free software; you can redistribute it and/or
Packit 15a96c
 *		modify it under the terms of the GNU General Public License
Packit 15a96c
 *		as published by the Free Software Foundation; either version
Packit 15a96c
 *		2 of the License, or (at your option) any later version.
Packit 15a96c
 *
Packit 15a96c
 *  You should have received a copy of the GNU General Public License along
Packit 15a96c
 *  with this program; if not, write to the Free Software Foundation, Inc.,
Packit 15a96c
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Packit 15a96c
 */
Packit 15a96c
#ifdef HAVE_CONFIG_H
Packit 15a96c
#include <config.h>
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
#include <strings.h>
Packit 15a96c
Packit 15a96c
#include "port.h"
Packit 15a96c
#include "minicom.h"
Packit 15a96c
#include "intl.h"
Packit 15a96c
Packit 15a96c
#if KEY_KLUDGE && defined(linux)
Packit 15a96c
#  include <sys/kd.h>
Packit 15a96c
#  include <sys/ioctl.h>
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
/* If enabled, this will cause minicom to treat ESC [ A and
Packit 15a96c
 * ESC O A the same (stupid VT100 two mode keyboards).
Packit 15a96c
 */
Packit 15a96c
#define VT_KLUDGE 0
Packit 15a96c
Packit 15a96c
static struct key _keys[NUM_KEYS];
Packit 15a96c
static int keys_in_buf;
Packit 15a96c
Packit 15a96c
static char erasechar;
Packit 15a96c
static int gotalrm;
Packit 15a96c
int pendingkeys = 0;
Packit 15a96c
int io_pending = 0;
Packit 15a96c
Packit 15a96c
#ifndef NCURSES_CONST
Packit 15a96c
#define NCURSES_CONST
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
static NCURSES_CONST char *func_key[] = {
Packit 15a96c
  "", "k1", "k2", "k3", "k4", "k5", "k6", "k7", "k8", "k9", "k0",
Packit 15a96c
  "kh", "kP", "ku", "kl", "kr", "kd", "kH", "kN", "kI", "kD",
Packit 15a96c
  "F1", "F2", NULL };
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
/*
Packit 15a96c
 * A VERY DIRTY HACK FOLLOWS:
Packit 15a96c
 * This routine figures out if the tty we're using is a serial
Packit 15a96c
 * device OR an IBM PC console. If we're using a console, we can
Packit 15a96c
 * easily reckognize single escape-keys since escape sequences
Packit 15a96c
 * always return > 1 characters from a read()
Packit 15a96c
 */
Packit 15a96c
static int isconsole;
Packit 15a96c
Packit 15a96c
static int testconsole(void)
Packit 15a96c
{
Packit 15a96c
  /* For Linux it's easy to see if this is a VC. */
Packit 15a96c
  int info;
Packit 15a96c
Packit 15a96c
  return ioctl(0, KDGETLED, &info) == 0;
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Function to read chunks of data from fd 0 all at once
Packit 15a96c
 */
Packit 15a96c
Packit 15a96c
static int cread(char *c)
Packit 15a96c
{
Packit 15a96c
  static char buf[32];
Packit 15a96c
  static int idx = 0;
Packit 15a96c
  static int lastread = 0;
Packit 15a96c
Packit 15a96c
  if (idx > 0 && idx < lastread) {
Packit 15a96c
    *c = buf[idx++];
Packit 15a96c
    keys_in_buf--;
Packit 15a96c
    if (keys_in_buf == 0 && pendingkeys == 0)
Packit 15a96c
      io_pending = 0;
Packit 15a96c
    return lastread;
Packit 15a96c
  }
Packit 15a96c
  idx = 0;
Packit 15a96c
  do {
Packit 15a96c
    lastread = read(0, buf, 32);
Packit 15a96c
    keys_in_buf = lastread - 1;
Packit 15a96c
  } while (lastread < 0 && errno == EINTR);
Packit 15a96c
Packit 15a96c
  *c = buf[0];
Packit 15a96c
  if (lastread > 1) {
Packit 15a96c
    idx = 1;
Packit 15a96c
    io_pending++;
Packit 15a96c
  }
Packit 15a96c
  return lastread;
Packit 15a96c
}
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
static void _initkeys(void)
Packit 15a96c
{
Packit 15a96c
  int i;
Packit 15a96c
  static char *cbuf, *tbuf;
Packit 15a96c
  char *term;
Packit 15a96c
Packit 15a96c
  if (_tptr == NULL) {
Packit 15a96c
    if ((tbuf = (char *)malloc(512)) == NULL ||
Packit 15a96c
        (cbuf = (char *)malloc(2048)) == NULL) {
Packit 15a96c
      fprintf(stderr, _("Out of memory.\n"));
Packit 15a96c
      exit(1);
Packit 15a96c
    }
Packit 15a96c
    term = getenv("TERM");
Packit 15a96c
    switch (tgetent(cbuf, term)) {
Packit 15a96c
      case 0:
Packit 15a96c
        fprintf(stderr, _("No termcap entry.\n"));
Packit 15a96c
        exit(1);
Packit 15a96c
      case -1:
Packit 15a96c
        fprintf(stderr, _("No /etc/termcap present!\n"));
Packit 15a96c
        exit(1);
Packit 15a96c
      default:
Packit 15a96c
        break;
Packit 15a96c
    }
Packit 15a96c
    _tptr = tbuf;
Packit 15a96c
  }
Packit 15a96c
  /* Initialize codes for special keys */
Packit 15a96c
  for (i = 0; func_key[i]; i++) {
Packit 15a96c
    if ((_keys[i].cap = tgetstr(func_key[i], &_tptr)) == NULL)
Packit 15a96c
      _keys[i].cap = "";
Packit 15a96c
    _keys[i].len = strlen(_keys[i].cap);
Packit 15a96c
  }
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
  isconsole = testconsole();
Packit 15a96c
#endif
Packit 15a96c
}
Packit 15a96c
Packit 15a96c
/*
Packit 15a96c
 * Read a character from the keyboard.
Packit 15a96c
 * Handle special characters too!
Packit 15a96c
 */
Packit 15a96c
int wxgetch(void)
Packit 15a96c
{
Packit 15a96c
  int f, g;
Packit 15a96c
  int match = 1;
Packit 15a96c
  int len;
Packit 15a96c
  char c;
Packit 15a96c
  static unsigned char mem[8];
Packit 15a96c
  static int leftmem = 0;
Packit 15a96c
  static int init = 0;
Packit 15a96c
  int nfound = 0;
Packit 15a96c
  int start_match;
Packit 15a96c
#if VT_KLUDGE
Packit 15a96c
  char temp[8];
Packit 15a96c
#endif
Packit 15a96c
  struct timeval timeout;
Packit 15a96c
  fd_set readfds;
Packit 15a96c
Packit 15a96c
  if (init == 0) {
Packit 15a96c
    _initkeys();
Packit 15a96c
    init++;
Packit 15a96c
    erasechar = setcbreak(3);
Packit 15a96c
  }
Packit 15a96c
Packit 15a96c
  /* Some sequence still in memory ? */
Packit 15a96c
  if (leftmem > 0) {
Packit 15a96c
    leftmem--;
Packit 15a96c
    if (leftmem == 0)
Packit 15a96c
      pendingkeys = 0;
Packit 15a96c
    if (pendingkeys == 0 && keys_in_buf == 0)
Packit 15a96c
      io_pending = 0;
Packit 15a96c
    return mem[leftmem];
Packit 15a96c
  }
Packit 15a96c
  gotalrm = 0;
Packit 15a96c
  pendingkeys = 0;
Packit 15a96c
Packit 15a96c
  for (len = 1; len < 8 && match; len++) {
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
    if (len > 1 && keys_in_buf == 0)
Packit 15a96c
#else
Packit 15a96c
    if (len > 1)
Packit 15a96c
#endif
Packit 15a96c
    {
Packit 15a96c
      timeout.tv_sec = 0;
Packit 15a96c
      timeout.tv_usec = 400000; /* 400 ms */
Packit 15a96c
      FD_ZERO(&readfds);
Packit 15a96c
      FD_SET(0, &readfds);
Packit 15a96c
      if (!(nfound = select(1, &readfds, NULL, NULL, &timeout)))
Packit 15a96c
        break;
Packit 15a96c
    }
Packit 15a96c
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
    while ((nfound = cread(&c)) < 0 && (errno == EINTR && !gotalrm))
Packit 15a96c
      ;
Packit 15a96c
#else
Packit 15a96c
    while ((nfound = read(0, &c, 1)) < 0 && (errno == EINTR && !gotalrm))
Packit 15a96c
      ;
Packit 15a96c
#endif
Packit 15a96c
Packit 15a96c
    if (nfound < 1)
Packit 15a96c
      return EOF;
Packit 15a96c
Packit 15a96c
    if (len == 1) {
Packit 15a96c
      /* Enter and erase have precedence over anything else */
Packit 15a96c
      if (c == '\n')
Packit 15a96c
        return c;
Packit 15a96c
      if (c == erasechar)
Packit 15a96c
        return K_ERA;
Packit 15a96c
    }
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
    /* Return single characters immideately */
Packit 15a96c
    if (isconsole && nfound == 1 && len == 1)
Packit 15a96c
      return c;
Packit 15a96c
Packit 15a96c
    /* Another hack - detect the Meta Key. */
Packit 15a96c
    if (isconsole && nfound == 2 && len == 1 && c == 27 && escape == 27) {
Packit 15a96c
      cread(&c);
Packit 15a96c
      return c + K_META;
Packit 15a96c
    }
Packit 15a96c
#endif
Packit 15a96c
    mem[len - 1] = c;
Packit 15a96c
    match = 0;
Packit 15a96c
#if VT_KLUDGE
Packit 15a96c
    /* Oh boy. Stupid vt100 2 mode keyboard. */
Packit 15a96c
    strncpy(temp, mem, len);
Packit 15a96c
    if (len > 1 && temp[0] == 27) {
Packit 15a96c
      if (temp[1] == '[')
Packit 15a96c
        temp[1] = 'O';
Packit 15a96c
      else if (temp[1] == 'O')
Packit 15a96c
        temp[1] = '[';
Packit 15a96c
    }
Packit 15a96c
    /* We now have an alternate string to check. */
Packit 15a96c
#endif
Packit 15a96c
    start_match = 0;
Packit 15a96c
    for (f = 0; f < NUM_KEYS; f++) {
Packit 15a96c
#if VT_KLUDGE
Packit 15a96c
      if (_keys[f].len >= len &&
Packit 15a96c
          (strncmp(_keys[f].cap, (char *)mem,  len) == 0 ||
Packit 15a96c
           strncmp(_keys[f].cap, (char *)temp, len) == 0))
Packit 15a96c
#else
Packit 15a96c
        if (_keys[f].len >= len &&
Packit 15a96c
            strncmp(_keys[f].cap, (char *)mem, len) == 0)
Packit 15a96c
#endif
Packit 15a96c
        {
Packit 15a96c
          match++;
Packit 15a96c
          if (_keys[f].len == len) {
Packit 15a96c
            return f + KEY_OFFS;
Packit 15a96c
          }
Packit 15a96c
        }
Packit 15a96c
      /* Does it match on first two chars? */
Packit 15a96c
      if (_keys[f].len > 1 && len == 2 &&
Packit 15a96c
          strncmp(_keys[f].cap, (char *)mem, 2) == 0)
Packit 15a96c
        start_match++;
Packit 15a96c
    }
Packit 15a96c
#if KEY_KLUDGE
Packit 15a96c
    if (!isconsole)
Packit 15a96c
#endif
Packit 15a96c
#ifndef _MINIX /* Minix doesn't have ESC-c meta mode */
Packit 15a96c
      /* See if this _might_ be a meta-key. */
Packit 15a96c
      if (escape == 27 && !start_match && len == 2 && mem[0] == 27)
Packit 15a96c
        return c + K_META;
Packit 15a96c
#endif
Packit 15a96c
  }
Packit 15a96c
  /* No match. in len we have the number of characters + 1 */
Packit 15a96c
  len--; /* for convenience */
Packit 15a96c
  if (len == 1)
Packit 15a96c
    return mem[0];
Packit 15a96c
  /* Remember there are more keys waiting in the buffer */
Packit 15a96c
  pendingkeys++;
Packit 15a96c
  io_pending++;
Packit 15a96c
Packit 15a96c
  /* Reverse the "mem" array */
Packit 15a96c
  for (f = 0; f < len / 2; f++) {
Packit 15a96c
    g = mem[f];
Packit 15a96c
    mem[f] = mem[len - f - 1];
Packit 15a96c
    mem[len - f - 1] = g;
Packit 15a96c
  }
Packit 15a96c
  leftmem = len - 1;
Packit 15a96c
  return mem[leftmem];
Packit 15a96c
}