From f8574e0be89e7b523e64f656c93814d6948b2a33 Mon Sep 17 00:00:00 2001 From: onefang Date: Mon, 16 Mar 2020 14:49:09 +1000 Subject: Revert "The new sledjchisl binary, to replace the management scripts and web stuff." This reverts commit 34c5ee4c2a489a506e93d5b303fbc80b263747f0. --- src/handlekeys.c | 445 ------------------------------------------------------- 1 file changed, 445 deletions(-) delete mode 100644 src/handlekeys.c (limited to 'src/handlekeys.c') diff --git a/src/handlekeys.c b/src/handlekeys.c deleted file mode 100644 index 8bae529..0000000 --- a/src/handlekeys.c +++ /dev/null @@ -1,445 +0,0 @@ -/* handlekeys.c - Generic terminal input handler. - * - * Copyright 2012 David Seikel - */ - -// I use camelCaseNames internally, instead of underscore_names as is preferred -// in the rest of toybox. A small limit of 80 characters per source line infers -// shorter names should be used. CamelCaseNames are shorter. Externally visible -// stuff is underscore_names as usual. Plus, I'm used to camelCaseNames, my -// fingers twitch that way. - -#include "toys.h" -#include "handlekeys.h" - -struct key -{ - char *code; - char *name; -}; - -// This table includes some variations I have found on some terminals. -// http://rtfm.etla.org/xterm/ctlseq.html has a useful guide. -// TODO - Don't think I got all the linux console or xterm variations. -// TODO - Add more shift variations, plus Ctrl & Alt variations when needed. -// TODO - tmux messes with the shift function keys somehow. -// TODO - Add other miscelany that does not use an escape sequence. - -// This is sorted by type, though there is some overlap. -// Human typing speeds wont need fast searching speeds on this small table. -// So simple wins out over speed, and sorting by terminal type wins -// the simple test. -static struct key keys[] = -{ - // Control characters. - // Commented out coz it's the C string terminator, and may confuse things. - //{"\x00", "^@"}, // NUL - {"\x01", "^A"}, // SOH Apparently sometimes sent as Home. - {"\x02", "^B"}, // STX - {"\x03", "^C"}, // ETX SIGINT Emacs and vi. - {"\x04", "^D"}, // EOT EOF Emacs, joe, and nano. - {"\x05", "^E"}, // ENQ Apparently sometimes sent as End - {"\x06", "^F"}, // ACK - {"\x07", "^G"}, // BEL - {"\x08", "Del"}, // BS Delete key, usually. - {"\x09", "Tab"}, // HT - {"\x0A", "Enter"}, // LF Roxterm translates Ctrl-M to this. - {"\x0B", "^K"}, // VT - {"\x0C", "^L"}, // FF - {"\x0D", "Return"}, // CR Other Enter/Return key, usually. - {"\x0E", "^N"}, // SO - {"\x0F", "^O"}, // SI DISCARD - {"\x10", "^P"}, // DLE - {"\x11", "^Q"}, // DC1 SIGCONT Vi. - {"\x12", "^R"}, // DC2 - {"\x13", "^S"}, // DC3 SIGSTOP can't be caught. Emacs and vi. - {"\x14", "^T"}, // DC4 SIGINFO STATUS - {"\x15", "^U"}, // NAK KILL character - {"\x16", "^V"}, // SYN LNEXT - {"\x17", "^W"}, // ETB WERASE - {"\x18", "^X"}, // CAN KILL character - {"\x19", "^Y"}, // EM DSUSP SIGTSTP - {"\x1A", "^Z"}, // SUB SIGTSTP - // Commented out coz it's the ANSI start byte in the below multibyte keys. - // Handled in the code with a timeout. - //{"\x1B", "Esc"}, // ESC Esc key. - {"\x1C", "^\\"}, // FS SIGQUIT - {"\x1D", "^]"}, // GS - {"\x1E", "^^"}, // RS - {"\x1F", "^_"}, // US - {"\x7F", "BS"}, // Backspace key, usually. Ctrl-? perhaps? - // Commented out for the same reason Esc is. - //{"\x9B", "CSI"}, // CSI The eight bit encoding of "Esc [". - - // "Usual" xterm CSI sequences, with ";1" omitted for no modifiers. - // Even though we have a proper CSI parser, - // these should still be in this table. Coz we would need a table anyway - // in the CSI parser, so might as well keep them with the others. - // Also, less code, no need to have a separate scanner for that other table. - {"\x9B\x31~", "Home"}, // Duplicate, think I've seen this somewhere. - {"\x9B\x32~", "Ins"}, - {"\x9B\x33~", "Del"}, - {"\x9B\x34~", "End"}, // Duplicate, think I've seen this somewhere. - {"\x9B\x35~", "PgUp"}, - {"\x9B\x36~", "PgDn"}, - {"\x9B\x37~", "Home"}, - {"\x9B\x38~", "End"}, - {"\x9B\x31\x31~", "F1"}, - {"\x9B\x31\x32~", "F2"}, - {"\x9B\x31\x33~", "F3"}, - {"\x9B\x31\x34~", "F4"}, - {"\x9B\x31\x35~", "F5"}, - {"\x9B\x31\x37~", "F6"}, - {"\x9B\x31\x38~", "F7"}, - {"\x9B\x31\x39~", "F8"}, - {"\x9B\x32\x30~", "F9"}, - {"\x9B\x32\x31~", "F10"}, - {"\x9B\x32\x33~", "F11"}, - {"\x9B\x32\x34~", "F12"}, - - // As above, ";2" means shift modifier. - {"\x9B\x31;2~", "Shift Home"}, - {"\x9B\x32;2~", "Shift Ins"}, - {"\x9B\x33;2~", "Shift Del"}, - {"\x9B\x34;2~", "Shift End"}, - {"\x9B\x35;2~", "Shift PgUp"}, - {"\x9B\x36;2~", "Shift PgDn"}, - {"\x9B\x37;2~", "Shift Home"}, - {"\x9B\x38;2~", "Shift End"}, - {"\x9B\x31\x31;2~", "Shift F1"}, - {"\x9B\x31\x32;2~", "Shift F2"}, - {"\x9B\x31\x33;2~", "Shift F3"}, - {"\x9B\x31\x34;2~", "Shift F4"}, - {"\x9B\x31\x35;2~", "Shift F5"}, - {"\x9B\x31\x37;2~", "Shift F6"}, - {"\x9B\x31\x38;2~", "Shift F7"}, - {"\x9B\x31\x39;2~", "Shift F8"}, - {"\x9B\x32\x30;2~", "Shift F9"}, - {"\x9B\x32\x31;2~", "Shift F10"}, - {"\x9B\x32\x33;2~", "Shift F11"}, - {"\x9B\x32\x34;2~", "Shift F12"}, - - // "Normal" Some terminals are special, and it seems they only have - // four function keys. - {"\x9B\x41", "Up"}, - {"\x9B\x42", "Down"}, - {"\x9B\x43", "Right"}, - {"\x9B\x44", "Left"}, - {"\x9B\x46", "End"}, - {"\x9BH", "Home"}, - {"\x9BP", "F1"}, - {"\x9BQ", "F2"}, - {"\x9BR", "F3"}, - {"\x9BS", "F4"}, - {"\x9B\x31;2P", "Shift F1"}, - {"\x9B\x31;2Q", "Shift F2"}, - {"\x9B\x31;2R", "Shift F3"}, - {"\x9B\x31;2S", "Shift F4"}, - - // "Application" Esc O is known as SS3 - {"\x1BOA", "Up"}, - {"\x1BOB", "Down"}, - {"\x1BOC", "Right"}, - {"\x1BOD", "Left"}, - {"\x1BOF", "End"}, - {"\x1BOH", "Home"}, - {"\x1BOn", "Del"}, - {"\x1BOp", "Ins"}, - {"\x1BOq", "End"}, - {"\x1BOw", "Home"}, - {"\x1BOP", "F1"}, - {"\x1BOQ", "F2"}, - {"\x1BOR", "F3"}, - {"\x1BOS", "F4"}, - {"\x1BOT", "F5"}, - // These two conflict with the above four function key variations. - {"\x9BR", "F6"}, - {"\x9BS", "F7"}, - {"\x9BT", "F8"}, - {"\x9BU", "F9"}, - {"\x9BV", "F10"}, - {"\x9BW", "F11"}, - {"\x9BX", "F12"}, - - // Can't remember, but saw them somewhere. - {"\x1BO1;2P", "Shift F1"}, - {"\x1BO1;2Q", "Shift F2"}, - {"\x1BO1;2R", "Shift F3"}, - {"\x1BO1;2S", "Shift F4"}, -}; - -static volatile sig_atomic_t sigWinch; -static int stillRunning; - -static void handleSIGWINCH(int signalNumber) -{ - sigWinch = 1; -} - -void handle_keys(long extra, int (*handle_event)(long extra, struct keyevent *event)) -{ - struct keyevent event; - fd_set selectFds; - struct timespec timeOut; - struct sigaction sigAction, oldSigAction; - sigset_t signalMask; - char buffer[20], sequence[20]; - int buffIndex = 0, pendingEsc = 0; - - buffer[0] = 0; - sequence[0] = 0; - - // Terminals send the SIGWINCH signal when they resize. - memset(&sigAction, 0, sizeof(sigAction)); - sigAction.sa_handler = handleSIGWINCH; - sigAction.sa_flags = SA_RESTART; // Useless if we are using poll. - if (sigaction(SIGWINCH, &sigAction, &oldSigAction)) - perror_exit("can't set signal handler for SIGWINCH"); - sigemptyset(&signalMask); - sigaddset(&signalMask, SIGWINCH); - - // TODO - OS buffered keys might be a problem, but we can't do the - // usual timestamp filter for now. - - stillRunning = 1; - while (stillRunning) - { - int j, p, csi = 0; - - // Apparently it's more portable to reset these each time. - FD_ZERO(&selectFds); - FD_SET(0, &selectFds); - timeOut.tv_sec = 0; timeOut.tv_nsec = 100000000; // One tenth of a second. - - // We got a "terminal size changed" signal, ask the terminal - // how big it is now. - if (sigWinch) - { - // Send - save cursor position, down 999, right 999, - // request cursor position, restore cursor position. - fputs("\x1B[s\x1B[999C\x1B[999B\x1B[6n\x1B[u", stdout); - fflush(stdout); - sigWinch = 0; - } - - // TODO - Should only ask for a time out after we get an Escape, or - // the user requested time ticks. - // I wanted to use poll, but that would mean using ppoll, which is - // Linux only, and involves defining swear words to get it. - p = pselect(0 + 1, &selectFds, NULL, NULL, &timeOut, &signalMask); - if (0 > p) - { - if (EINTR == errno) - continue; - perror_exit("poll"); - } - else if (0 == p) // A timeout, trigger a time event. - { - if (pendingEsc) - { - // After a short delay to check, this is a real Escape key, - // not part of an escape sequence, so deal with it. - strcat(sequence, "Esc"); - buffer[0] = buffIndex = 0; - } - // TODO - Call some sort of timer tick callback. This wont be - // a precise timed event, but don't think we need one. - } - else if ((0 < p) && FD_ISSET(0, &selectFds)) - { - j = xread(0, &buffer[buffIndex], sizeof(buffer) - (buffIndex + 1)); - if (j == 0) // End of file. - stillRunning = 0; - else - { - buffIndex += j; - buffer[buffIndex] = 0; - - // Send raw keystrokes, mostly for things like showkey. - event.type = HK_RAW; - event.sequence = buffer; - event.isTranslated = 0; - handle_event(extra, &event); - - if (sizeof(buffer) < (buffIndex + 1)) // Ran out of buffer. - { - buffer[buffIndex] = 0; - fprintf(stderr, "Full buffer - %s -> %s\n", buffer, sequence); - for (j = 0; buffer[j]; j++) - fprintf(stderr, "(%x) %c, ", (int) buffer[j], buffer[j]); - fflush(stderr); - buffer[0] = buffIndex = 0; - } - } - } - - // Check for lone Esc first, wait a bit longer if it is. - pendingEsc = ((0 == buffer[1]) && ('\x1B' == buffer[0])); - if (pendingEsc) continue; - - // Check if it's a CSI before we check for the known key sequences. - // C29B is the UTF8 encoding of CSI. - // In all cases we reduce CSI to 9B to keep the keys table shorter. - if ((('\x1B' == buffer[0]) && ('[' == buffer[1])) - || (('\xC2' == buffer[0]) && ('\x9B' == buffer[1]))) - { - buffer[0] = '\x9B'; - for (j = 1; buffer[j]; j++) - buffer[j] = buffer[j + 1]; - buffIndex--; - } - csi = ('\x9B' == buffer[0]); - - // Check for known key sequences. - // For a real timeout checked Esc, buffer is now empty, so this for loop - // wont find it anyway. While it's true we could avoid it by checking, - // the user already had to wait for a time out, and this loop wont take THAT long. - for (j = 0; j < ARRAY_LEN(keys); j++) - { - if (strcmp(keys[j].code, buffer) == 0) - { - strcat(sequence, keys[j].name); - buffer[0] = buffIndex = 0; - csi = 0; - break; - } - } - - // Find out if it's a CSI sequence that's not in the known key sequences. - if (csi) - { - /* ECMA-048 section 5.2 defines this, and is unreadable. - * So I'll include some notes here that tries to simplify that. - * - * The CSI format is - CSI [private] n1 ; n2 [extra] final - * Each of those parts, except for the initial CSI bytes, is an ordinary - * ASCII character. - * - * The optional [private] part is one of these characters "<=>?". - * If the first byte is one of these, then this is a private command, if - * it's one of the other n1 ones, it's not private. - * - * Next is a semi colon separated list of parameters (n1, n2, etc), which - * can be any characters from this set "01234567890:;<=>?". What the non - * digit ones mean is up to the command. Parameters can be left out, but - * their defaults are command dependant. - * - * Next is an optional [extra] part from this set of characters - * "!#$%&'()*+,-./", which includes double quotes. Can be many of these, - * likely isn't. - * - * Finally is the "final" from this set of characters "@[\]^_`{|}~", plus - * upper and lower case letters. It's private if it's one of these - * "pqrstuvwxyz{|}~". Though the "private" ~ is used for key codes. - * - * A full CSI command is the private, extra, and final parts. - * - * Any C0 controls, DEL (0x7f), or higher characters are undefined. - * TODO - So abort the current CSI and start from scratch on one of those. - */ - - if ('M' == buffer[1]) - { - // We have a mouse report, which is CSI M ..., where the rest is - // binary encoded, more or less. Not fitting into the CSI format. - // To make things worse, can't tell how long this will be. - // So leave it up to the caller to tell us if they used it. - event.type = HK_MOUSE; - event.sequence = buffer; - event.isTranslated = 0; - if (handle_event(extra, &event)) - { - buffer[0] = buffIndex = 0; - sequence[0] = 0; - } - } - else - { - char *t, csFinal[8]; - int csIndex = 1, csParams[8]; - - csFinal[0] = 0; - p = 0; - - // Unspecified params default to a value that is command dependant. - // However, they will never be negative, so we can use -1 to flag - // a default value. - for (j = 0; j < ARRAY_LEN(csParams); j++) - csParams[j] = -1; - - // Check for the private bit. - if (index("<=>?", buffer[1])) - { - csFinal[0] = buffer[1]; - csFinal[1] = 0; - csIndex++; - } - - // Decode parameters. - j = csIndex; - do - { - // So we know when we get to the end of parameter space. - t = index("01234567890:;<=>?", buffer[j + 1]); - // See if we passed a paremeter. - if ((';' == buffer[j]) || (!t)) - { - // Only stomp on the ; if it's really the ;. - if (t) - buffer[j] = 0; - // Empty parameters are default parameters, so only deal with - // non defaults. - if (';' != buffer[csIndex] || (!t)) - { - // TODO - Might be ":" in the number somewhere, but we are not - // expecting any in anything we do. - csParams[p] = atoi(&buffer[csIndex]); - } - p++; - csIndex = j + 1; - } - j++; - } - while (t); - - // Check if we got the final byte, and send it to the callback. - strcat(csFinal, &buffer[csIndex]); - t = csFinal + strlen(csFinal) - 1; - if (('\x40' <= (*t)) && ((*t) <= '\x7e')) - { - event.type = HK_CSI; - event.sequence = csFinal; - event.isTranslated = 1; - event.count = p; - event.params = csParams; - handle_event(extra, &event); - buffer[0] = buffIndex = 0; - sequence[0] = 0; - } - } - } - - // Pass the result to the callback. - if (sequence[0] || buffer[0]) - { - char b[strlen(sequence) + strlen(buffer) + 1]; - - sprintf(b, "%s%s", sequence, buffer); - event.type = HK_KEYS; - event.sequence = b; - event.isTranslated = (0 != sequence[0]); - if (handle_event(extra, &event)) - { - buffer[0] = buffIndex = 0; - sequence[0] = 0; - } - } - } - - sigaction(SIGWINCH, &oldSigAction, NULL); -} - -void handle_keys_quit() -{ - stillRunning = 0; -} -- cgit v1.1