/* Replacement console read/write routines that allow for key remappings */ /* * console input/output routines. * written by Eric R. Smith and placed in the public domain */ /* * BUGS: assumes all input is coming from the same place; * this bug shows up only when keys are remapped, though. */ #include #include #include #include #include #include #include #include #include #define STRDUP(x,y) if (x) free(x); x = strdup(y); #define S_SHIFT 0x03 #define S_CNTRL 0x04 #define S_ALT 0x08 extern int _console_dev; /* in main.c */ int __check_signals = 0; /* arrays to hold keyboard strings */ static char *kb_unshft[N_KEYCODES], *kb_shft[N_KEYCODES], *kb_alt[N_KEYCODES]; static char *_str = NULL; void console_set_key(keycode, regular, shifted, alted) int keycode; char *regular, *shifted, *alted; { if (keycode < 1 || keycode >= N_KEYCODES) return; if (regular) { if (!*regular) regular = 0; STRDUP(kb_unshft[keycode],regular); } if (shifted) { if (!*shifted) shifted = 0; /* shifted function keys are a bit screwy */ if (keycode >= F_1 && keycode <= F_10) { STRDUP(kb_shft[keycode - F_1 + 0x54],shifted); } else { STRDUP(kb_shft[keycode],shifted); } } if (alted) { if (!*alted) alted = 0; STRDUP(kb_alt[keycode],alted); } } #define KBUFSIZ 80 #define NUMDEV 3 /* 0 == prn:, 1 == aux:, 2 == con: */ typedef struct _buffer { short head, tail; long buffer[KBUFSIZ]; } k_buf; static k_buf in_buf[NUMDEV]; #define IN_BUF(dev) (&in_buf[(dev) > 2 ? _console_dev : (dev)]) /* * what handle means:: 0-2: BIOS handle, 3: stdout, 4: stderr */ static short LOOKUP(handle) short handle; { switch(handle) { case -3: case -2: case -1: case 0: return handle + 3; case 2: return 4; case 1: if (isatty(0)) return 3; if (isatty(2)) return 4; /* else fall through */ default: return _console_dev; } } /* * raw i/o routines */ static long raw_in(dev) int dev; { if (dev < 3) return Bconin(dev); else if (dev == 3) return Crawcin(); else return Cauxin(); } #if 0 static void raw_out(dev, c) int dev, c; { if (dev < 3) Bconout(dev, c); else if (dev == 3) Crawio(c); else Cauxout(c); } #endif static long raw_instat(dev) int dev; { if (dev < 3) return Bconstat(dev); else if (dev == 3) return Cconis(); else return Cauxis(); } /* * somewhat less raw i/o routines. The main difference is that these ones * will check for pending input before doing output, to see if a signal * needs to be raised. This is only done if __check_signals is non-zero; * signal() should set __check_signals when the user attempts to catch * SIGINT or SIGQUIT. We don't do this checking all the time because * the user may be typing ahead input for another program (e.g. if this * is a little utility of some sort) and we shouldn't steal keystrokes * unless necessary. */ unsigned int console_read_byte(handle) int handle; { k_buf *p; short i, j, dev; unsigned scan, key, shft; long r; dev = LOOKUP(handle); if (_str) { if (*_str) return *(unsigned char *)_str++; else _str = 0; } p = IN_BUF(dev); if ( p->head != (i = p->tail)) { j = p->tail + 1; if (j >= KBUFSIZ) j = 0; p->tail = j; r = p->buffer[i]; } else r = raw_in(dev); scan = (r & 0x00ff0000) >> 16; key = r & 0x00ff; if (scan > 0 && scan < N_KEYCODES) { shft = Kbshift(-1); if (shft & S_ALT) _str = kb_alt[scan]; else if (shft & S_SHIFT) _str = kb_shft[scan]; else if (!(shft & S_CNTRL)) _str = kb_unshft[scan]; if (_str) return *(unsigned char *)_str++; } return key; } int console_input_status(handle) int handle; { short dev; k_buf *p; if (_str && *_str) return 1; dev = LOOKUP(handle); p = IN_BUF(dev); return (p->head != p->tail) || raw_instat(dev); } void console_write_byte(handle, n) int handle; int n; { long c; short i, j, waiting = 0; unsigned char ch; k_buf *p; short dev; dev = LOOKUP(handle); p = IN_BUF(dev); while (__check_signals && (raw_instat(dev) || waiting)) { c = raw_in(dev); if (!(__ttymode & RAW)) { ch = c & 0xff; if (ch == ('S'-'@')) { waiting = 1; } else if (ch == ('Q'-'@')) { waiting = 0; } else if (ch == __tchars[TC_INTRC]) { p->head = p->tail; raise(SIGINT); } else if (ch == __tchars[TC_QUITC]) { p->head = p->tail; raise(SIGQUIT); } else if (!waiting) { i = p->head; j = i + 1; if (j >= KBUFSIZ) j = 0; if (j != p->tail) { p->buffer[i] = c; p->head = j; } } } } #if 0 raw_out(dev, n); #endif ch = n; (void)Fwrite(handle, 1L, &ch); } void flush_key_buff(fd) int fd; { long c; short i, j, waiting = 0; unsigned char ch; k_buf *p; short dev; short handle; handle = fd; dev = LOOKUP(handle); p = IN_BUF(dev); while (raw_instat(dev) || waiting) { c = raw_in(dev); if (!(__ttymode & RAW)) { ch = c & 0xff; if (ch == ('S'-'@')) { waiting = 1; } else if (ch == ('Q'-'@')) { waiting = 0; } else if (ch == __tchars[TC_INTRC]) { p->head = p->tail; raise(SIGINT); } else if (ch == __tchars[TC_QUITC]) { p->head = p->tail; raise(SIGQUIT); } else if (!waiting) { i = p->head; j = i + 1; if (j >= KBUFSIZ) j = 0; if (j != p->tail) { p->buffer[i] = c; p->head = j; } } } } }