diff options
author | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
---|---|---|
committer | Eduardo Chappa <echappa@gmx.com> | 2013-02-03 00:59:38 -0700 |
commit | 094ca96844842928810f14844413109fc6cdd890 (patch) | |
tree | e60efbb980f38ba9308ccb4fb2b77b87bbc115f3 /pico/osdep/getkey.c | |
download | alpine-094ca96844842928810f14844413109fc6cdd890.tar.xz |
Initial Alpine Version
Diffstat (limited to 'pico/osdep/getkey.c')
-rw-r--r-- | pico/osdep/getkey.c | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/pico/osdep/getkey.c b/pico/osdep/getkey.c new file mode 100644 index 00000000..b55dd092 --- /dev/null +++ b/pico/osdep/getkey.c @@ -0,0 +1,565 @@ +#if !defined(lint) && !defined(DOS) +static char rcsid[] = "$Id: getkey.c 769 2007-10-24 00:15:40Z hubert@u.washington.edu $"; +#endif + +/* + * ======================================================================== + * Copyright 2006-2007 University of Washington + * Copyright 2013 Eduardo Chappa + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * ======================================================================== + */ + +#include <system.h> +#include <general.h> + +#include "../estruct.h" +#include "../mode.h" +#include "../pico.h" +#include "../edef.h" +#include "../efunc.h" +#include "../keydefs.h" + +#include "tty.h" +#include "getkey.h" +#include "read.h" +#include "mouse.h" + +#ifdef _WINDOWS +#include "mswin.h" +static int MapMSKEYtoPK(int c); +#endif /* _WINDOWS */ + + +/* internal declarations */ +static int timeo = 0; + +/* these next two are declared in pith/conf.h */ +int +set_input_timeout(int t) +{ + int oldtimeo = timeo; + + timeo = t; + return(oldtimeo); +} + +int +get_input_timeout(void) +{ + return(timeo); +} + + +#ifndef _WINDOWS + + +/* internal prototypes */ +void bail(void); +int ReadyForKey(int); + + + +void +bail(void) +{ + sleep(30); /* see if os receives SIGHUP */ + kill(getpid(), SIGHUP); /* eof or bad error */ +} + + +#if TYPEAH +/* + * typahead - Check to see if any characters are already in the + * keyboard buffer + */ +int +typahead(void) +{ + int x; /* holds # of pending chars */ + + return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x); +} +#endif /* TYPEAH */ + + + +/* + * ReadyForKey - return true if there's no timeout or we're told input + * is available... + */ +int +ReadyForKey(int timeout) +{ + switch(input_ready(timeout)){ + case READY_TO_READ: + return(1); + break; + + case NO_OP_COMMAND: + case NO_OP_IDLE: + case READ_INTR: + return(0); + + case BAIL_OUT: + case PANIC_NOW: + emlwrite("\007Problem reading from keyboard!", NULL); + kill(getpid(), SIGHUP); /* Bomb out (saving our work)! */ + /* no return */ + } + + /* can't happen */ + return(0); +} + + + +/* + * GetKey - Read in a key. + * Do the standard keyboard preprocessing. Convert the keys to the internal + * character set. Resolves escape sequences and returns no-op if global + * timeout value exceeded. + */ +UCS +GetKey(void) +{ + UCS ch, status, cc; + + if(!ReadyForKey(FUDGE-5)) + return(NODATA); + + switch(status = kbseq(simple_ttgetc, NULL, bail, input_cs, &ch)){ + case 0: /* regular character */ + break; + + case KEY_DOUBLE_ESC: + /* + * Special hack to get around comm devices eating control characters. + */ + if(!ReadyForKey(5)) + return(BADESC); /* user typed ESC ESC, then stopped */ + else + switch(status = kbseq(simple_ttgetc, NULL, bail, input_cs, &ch)){ + case KEY_UP : + case KEY_DOWN : + case KEY_RIGHT : + case KEY_LEFT : + case KEY_PGUP : + case KEY_PGDN : + case KEY_HOME : + case KEY_END : + case KEY_DEL : + case F1 : + case F2 : + case F3 : + case F4 : + case F5 : + case F6 : + case F7 : + case F8 : + case F9 : + case F10 : + case F11 : + case F12 : + return(CTRL | status); + break; + + case 0: /* regular character */ + break; + + default: /* punt the whole thing */ + (*term.t_beep)(); + return(BADESC); + break; + } + + ch &= 0x7f; + if(isdigit((unsigned char)ch)){ + int n = 0, i = ch - '0'; + + if(i < 0 || i > 2) + return(BADESC); /* bogus literal char value */ + + while(n++ < 2){ + if(!ReadyForKey(5) + || (!isdigit((unsigned char) (ch = + (*term.t_getchar)(NODATA, NULL, bail))) + || (n == 1 && i == 2 && ch > '5') + || (n == 2 && i == 25 && ch > '5'))){ + return(BADESC); + } + + i = (i * 10) + (ch - '0'); + } + + ch = i; + } + else{ + if(islower((unsigned char)ch)) /* canonicalize if alpha */ + ch = toupper((unsigned char)ch); + + return((isalpha((unsigned char)ch) || ch == '@' + || (ch >= '[' && ch <= '_')) + ? (CTRL | ch) : ((ch == ' ') ? (CTRL | '@') : ch)); + } + + break; + +#ifdef MOUSE + case KEY_XTERM_MOUSE: + { + /* + * Special hack to get mouse events from an xterm. + * Get the details, then pass it past the keymenu event + * handler, and then to the installed handler if there + * is one... + */ + static int down = 0; + int x, y, button; + unsigned long cmd; + + button = (*term.t_getchar)(NODATA, NULL, bail) & 0x03; + + x = (*term.t_getchar)(NODATA, NULL, bail) - '!'; + y = (*term.t_getchar)(NODATA, NULL, bail) - '!'; + + if(button == 0){ + down = 1; + if(checkmouse(&cmd, 1, x, y)) + return((UCS) cmd); + } + else if(down && button == 3){ + down = 0; + if(checkmouse(&cmd, 0, x, y)) + return((UCS) cmd); + } + + return(NODATA); + } + + break; +#endif /* MOUSE */ + + case KEY_UP : + case KEY_DOWN : + case KEY_RIGHT : + case KEY_LEFT : + case KEY_PGUP : + case KEY_PGDN : + case KEY_HOME : + case KEY_END : + case KEY_DEL : + case F1 : + case F2 : + case F3 : + case F4 : + case F5 : + case F6 : + case F7 : + case F8 : + case F9 : + case F10 : + case F11 : + case F12 : + return(status); + + case CTRL_KEY_UP : + return(CTRL | KEY_UP); + case CTRL_KEY_DOWN : + return(CTRL | KEY_DOWN); + case CTRL_KEY_RIGHT : + return(CTRL | KEY_RIGHT); + case CTRL_KEY_LEFT : + return(CTRL | KEY_LEFT); + + case KEY_SWALLOW_Z: + status = BADESC; + case KEY_SWAL_UP: + case KEY_SWAL_DOWN: + case KEY_SWAL_LEFT: + case KEY_SWAL_RIGHT: + do + if(!ReadyForKey(2)){ + status = BADESC; + break; + } + while(!strchr("~qz", (*term.t_getchar)(NODATA, NULL, bail))); + + return((status == BADESC) + ? status + : status - (KEY_SWAL_UP - KEY_UP)); + break; + + case KEY_KERMIT: + do{ + cc = ch; + if(!ReadyForKey(2)) + return(BADESC); + else + ch = (*term.t_getchar)(NODATA, NULL, bail) & 0x7f; + }while(cc != '\033' && ch != '\\'); + + ch = NODATA; + break; + + case BADESC: + (*term.t_beep)(); + return(status); + + default: /* punt the whole thing */ + (*term.t_beep)(); + break; + } + + if (ch >= 0x00 && ch <= 0x1F) /* C0 control -> C- */ + ch = CTRL | (ch+'@'); + + return(ch); +} + + +/* + * kbseq - looks at an escape sequence coming from the keyboard and + * compares it to a trie of known keyboard escape sequences, and + * returns the function bound to the escape sequence. + * + * Args: getcfunc -- Function to get a single character from stdin, + * called with the next two arguments to this + * function as its arguments. + * recorder -- If non-NULL, function used to record keystroke. + * bail_handler -- Function used to bail out on read error. + * c -- Pointer to returned character. + * + * Returns: BADESC + * The escaped function. + * 0 if a regular char with char stuffed in location c. + */ +UCS +kbseq(int (*getcfunc)(int (*recorder)(int ), void (*bail_handler)(void )), + int (*recorder)(int), + void (*bail_handler)(void), + void *data, + UCS *ch) +{ + unsigned char c; + int first = 1; + KBESC_T *current; + + current = kbesc; + if(current == NULL) /* bag it */ + return(BADESC); + + while(1){ + c = (*getcfunc)(recorder, bail_handler); + + while(current->value != c){ + if(current->left == NULL){ /* NO MATCH */ + if(first){ + unsigned long octets_so_far, remaining_octets; + unsigned char *inputp; + UCS ucs; + unsigned char inputbuf[20]; + + /* + * Regular character. + * Read enough bytes to make up a character and convert it to UCS-4. + */ + memset(inputbuf, 0, sizeof(inputbuf)); + inputbuf[0] = c; + octets_so_far = 1; + for(;;){ + remaining_octets = octets_so_far; + inputp = inputbuf; + ucs = mbtow(data, &inputp, &remaining_octets); + switch(ucs){ + case CCONV_BADCHAR: + /* + * Not really a BADESC but that ought to + * be sufficient. We can add another type if + * we need to. + */ + return(BADESC); + + case CCONV_NEEDMORE: + if(octets_so_far >= sizeof(inputbuf)) + return(BADESC); + + c = (*getcfunc)(recorder, bail_handler); + inputbuf[octets_so_far++] = c; + break; + + default: + /* got a good UCS-4 character */ + *ch = ucs; + return(0); + } + } + + /* NOTREACHED */ + return(0); + } + else + return(BADESC); + } + current = current->left; + } + + if(current->down == NULL) /* match!!!*/ + return(current->func); + else + current = current->down; + + first = 0; + } +} + + +#define newnode() (KBESC_T *)malloc(sizeof(KBESC_T)) + +/* + * kpinsert - insert a keystroke escape sequence into the global search + * structure. + */ +void +kpinsert(char *kstr, int kval, int termcap_wins) +{ + register char *buf; + register KBESC_T *temp; + register KBESC_T *trail; + + if(kstr == NULL) + return; + + /* + * Don't allow escape sequences that don't start with ESC unless + * termcap_wins. This is to protect against mistakes in termcap files. + */ + if(!termcap_wins && *kstr != '\033') + return; + + temp = trail = kbesc; + buf = kstr; + + for(;;){ + if(temp == NULL){ + temp = newnode(); + temp->value = *buf; + temp->func = 0; + temp->left = NULL; + temp->down = NULL; + if(kbesc == NULL) + kbesc = temp; + else + trail->down = temp; + } + else{ /* first entry */ + while((temp != NULL) && (temp->value != *buf)){ + trail = temp; + temp = temp->left; + } + + if(temp == NULL){ /* add new val */ + temp = newnode(); + temp->value = *buf; + temp->func = 0; + temp->left = NULL; + temp->down = NULL; + trail->left = temp; + } + } + + if(*(++buf) == '\0') + break; + else{ + /* + * Ignore attempt to overwrite shorter existing escape sequence. + * That means that sequences with higher priority should be + * set up first, so if we want termcap sequences to override + * hardwired sequences, put the kpinsert calls for the + * termcap sequences first. (That's what you get if you define + * TERMCAP_WINS.) + */ + if(temp->func != 0) + return; + + trail = temp; + temp = temp->down; + } + } + + /* + * Ignore attempt to overwrite longer sequences we are a prefix + * of (down != NULL) and exact same sequence (func != 0). + */ + if(temp != NULL && temp->down == NULL && temp->func == 0) + temp->func = kval; +} + + + +/* + * kbdestroy() - kills the key pad function key search tree + * and frees all lines associated with it + * + * Should be called with arg kbesc, the top of the tree. + */ +void +kbdestroy(KBESC_T *kb) +{ + if(kb){ + kbdestroy(kb->left); + kbdestroy(kb->down); + free((char *)kb); + kb = NULL; + } +} + +#else /* _WINDOWS */ + +/* + * Read in a key. + * Do the standard keyboard preprocessing. Convert the keys to the internal + * character set. Resolves escape sequences and returns no-op if global + * timeout value exceeded. + */ +UCS +GetKey(void) +{ + UCS ch = 0; + long timein; + + + ch = NODATA; + timein = time(0L); + + /* + * Main character processing loop. + */ + while(!mswin_charavail()) { + +#ifdef MOUSE + /* Check Mouse. If we get a mouse event, convert to char + * event and return that. */ + if (checkmouse (&ch,0,0,0)) { + curwp->w_flag |= WFHARD; + return (ch); + } +#endif /* MOUSE */ + + + /* Check Timeout. */ + if(time(0L) >= timein+(FUDGE-10)) + return(NODATA); + } + + + return (mswin_getc_fast()); +} + +#endif /* _WINDOWS */ |