diff options
| author | David Walter Seikel | 2014-04-15 18:38:18 +1000 |
|---|---|---|
| committer | David Walter Seikel | 2014-04-15 18:38:18 +1000 |
| commit | bbaa3db47599ba25949277e7075fa61ccc1c5a3c (patch) | |
| tree | 63ec62f775c4e68de5a100388b6a3bfcd3a50c56 | |
| parent | Add a showkey toy. Not standard, I'll see if there's an actual standard later. (diff) | |
| download | boxes-bbaa3db47599ba25949277e7075fa61ccc1c5a3c.zip boxes-bbaa3db47599ba25949277e7075fa61ccc1c5a3c.tar.gz boxes-bbaa3db47599ba25949277e7075fa61ccc1c5a3c.tar.bz2 boxes-bbaa3db47599ba25949277e7075fa61ccc1c5a3c.tar.xz | |
Change from using a bunch of callbacks to using one, with a structure and type.
| -rw-r--r-- | boxes.c | 94 | ||||
| -rw-r--r-- | dumbsh.c | 119 | ||||
| -rw-r--r-- | handlekeys.c | 37 | ||||
| -rw-r--r-- | handlekeys.h | 65 | ||||
| -rw-r--r-- | showkey.c | 91 |
5 files changed, 240 insertions, 166 deletions
| @@ -1651,59 +1651,69 @@ struct CSI CSIcommands[] = | |||
| 1651 | {"R", termSize} // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize. | 1651 | {"R", termSize} // Parameters are cursor line and column. Note this may be sent at other times, not just during terminal resize. |
| 1652 | }; | 1652 | }; |
| 1653 | 1653 | ||
| 1654 | // Callback for incoming CSI commands from the terminal. | ||
| 1655 | static void handleCSI(long extra, char *command, int *params, int count) | ||
| 1656 | { | ||
| 1657 | int j; | ||
| 1658 | 1654 | ||
| 1659 | for (j = 0; j < (sizeof(CSIcommands) / sizeof(*CSIcommands)); j++) | 1655 | // Callback for incoming sequences from the terminal. |
| 1656 | static int handleEvent(long extra, struct keyevent *event) | ||
| 1657 | { | ||
| 1658 | switch (event->type) | ||
| 1660 | { | 1659 | { |
| 1661 | if (strcmp(CSIcommands[j].code, command) == 0) | 1660 | case HK_CSI : |
| 1662 | { | 1661 | { |
| 1663 | CSIcommands[j].func(extra, params, count); | 1662 | int j; |
| 1663 | |||
| 1664 | for (j = 0; j < ARRAY_LEN(CSIcommands); j++) | ||
| 1665 | { | ||
| 1666 | if (strcmp(CSIcommands[j].code, event->sequence) == 0) | ||
| 1667 | { | ||
| 1668 | CSIcommands[j].func(extra, event->params, event->count); | ||
| 1669 | break; | ||
| 1670 | } | ||
| 1671 | } | ||
| 1664 | break; | 1672 | break; |
| 1665 | } | 1673 | } |
| 1666 | } | ||
| 1667 | } | ||
| 1668 | 1674 | ||
| 1669 | // Callback for incoming key sequences from the user. | 1675 | case HK_KEYS : |
| 1670 | static int handleKeySequence(long extra, char *sequence, int isTranslated) | 1676 | { |
| 1671 | { | 1677 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. |
| 1672 | struct _view *view = (struct _view *) extra; // Though we pretty much stomp on this straight away. | 1678 | struct keyCommand *commands = currentBox->view->content->context->modes[currentBox->view->mode].keys; |
| 1673 | struct keyCommand *commands = currentBox->view->content->context->modes[currentBox->view->mode].keys; | 1679 | int j, l = strlen(event->sequence); |
| 1674 | int j, l = strlen(sequence); | ||
| 1675 | 1680 | ||
| 1676 | // Coz things might change out from under us, find the current view. | 1681 | // Coz things might change out from under us, find the current view. |
| 1677 | if (commandMode) view = commandLine; | 1682 | if (commandMode) view = commandLine; |
| 1678 | else view = currentBox->view; | 1683 | else view = currentBox->view; |
| 1679 | 1684 | ||
| 1680 | // Search for a key sequence bound to a command. | 1685 | // Search for a key sequence bound to a command. |
| 1681 | for (j = 0; commands[j].key; j++) | 1686 | for (j = 0; commands[j].key; j++) |
| 1682 | { | ||
| 1683 | if (strncmp(commands[j].key, sequence, l) == 0) | ||
| 1684 | { | ||
| 1685 | // If it's a partial match, keep accumulating them. | ||
| 1686 | if (strlen(commands[j].key) != l) | ||
| 1687 | return 0; | ||
| 1688 | else | ||
| 1689 | { | 1687 | { |
| 1690 | doCommand(view, commands[j].command); | 1688 | if (strncmp(commands[j].key, event->sequence, l) == 0) |
| 1691 | return 1; | 1689 | { |
| 1690 | // If it's a partial match, keep accumulating them. | ||
| 1691 | if (strlen(commands[j].key) != l) | ||
| 1692 | return 0; | ||
| 1693 | else | ||
| 1694 | { | ||
| 1695 | doCommand(view, commands[j].command); | ||
| 1696 | return 1; | ||
| 1697 | } | ||
| 1698 | } | ||
| 1692 | } | 1699 | } |
| 1700 | |||
| 1701 | // See if it's ordinary keys. | ||
| 1702 | // NOTE - with vi style ordinary keys can be commands, | ||
| 1703 | // but they would be found by the command check above first. | ||
| 1704 | if (!event->isTranslated) | ||
| 1705 | { | ||
| 1706 | // TODO - Should check for tabs to, and insert them. | ||
| 1707 | // Though better off having a function for that? | ||
| 1708 | mooshStrings(view->line, event->sequence, view->iX, 0, !overWriteMode); | ||
| 1709 | view->oW = formatLine(view, view->line->line, &(view->output)); | ||
| 1710 | moveCursorRelative(view, strlen(event->sequence), 0, 0, 0); | ||
| 1711 | updateLine(view); | ||
| 1712 | } | ||
| 1713 | break; | ||
| 1693 | } | 1714 | } |
| 1694 | } | ||
| 1695 | 1715 | ||
| 1696 | // See if it's ordinary keys. | 1716 | default : break; |
| 1697 | // NOTE - with vi style ordinary keys can be commands, | ||
| 1698 | // but they would be found by the command check above first. | ||
| 1699 | if (!isTranslated) | ||
| 1700 | { | ||
| 1701 | // TODO - Should check for tabs to, and insert them. | ||
| 1702 | // Though better off having a function for that? | ||
| 1703 | mooshStrings(view->line, sequence, view->iX, 0, !overWriteMode); | ||
| 1704 | view->oW = formatLine(view, view->line->line, &(view->output)); | ||
| 1705 | moveCursorRelative(view, strlen(sequence), 0, 0, 0); | ||
| 1706 | updateLine(view); | ||
| 1707 | } | 1717 | } |
| 1708 | 1718 | ||
| 1709 | // Tell handle_keys to drop it, coz we dealt with it, or it's not one of ours. | 1719 | // Tell handle_keys to drop it, coz we dealt with it, or it's not one of ours. |
| @@ -2481,7 +2491,7 @@ void boxes_main(void) | |||
| 2481 | updateLine(currentBox->view); | 2491 | updateLine(currentBox->view); |
| 2482 | 2492 | ||
| 2483 | // Run the main loop. | 2493 | // Run the main loop. |
| 2484 | handle_keys((long) currentBox->view, handleKeySequence, handleCSI); | 2494 | handle_keys((long) currentBox->view, handleEvent); |
| 2485 | 2495 | ||
| 2486 | // TODO - Should remember to turn off mouse reporting when we leave. | 2496 | // TODO - Should remember to turn off mouse reporting when we leave. |
| 2487 | 2497 | ||
| @@ -48,34 +48,6 @@ static void updateLine() | |||
| 48 | fflush(stdout); | 48 | fflush(stdout); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | // Callback for incoming CSI commands from the terminal. | ||
| 52 | static void handleCSI(long extra, char *command, int *params, int count) | ||
| 53 | { | ||
| 54 | // Is it a cursor location report? | ||
| 55 | if (strcmp("R", command) == 0) | ||
| 56 | { | ||
| 57 | // Parameters are cursor line and column. | ||
| 58 | // NOTE - This may be sent at other times, not just during terminal resize. | ||
| 59 | // We are assuming here that it's a resize. | ||
| 60 | // The defaults are 1, which get ignored by the heuristic below. | ||
| 61 | int r = params[0], c = params[1]; | ||
| 62 | |||
| 63 | // Check it's not an F3 key variation, coz some of them use | ||
| 64 | // the same CSI function command. | ||
| 65 | // This is a heuristic, we are checking against an unusable terminal size. | ||
| 66 | if ((2 == count) && (8 < r) && (8 < c)) | ||
| 67 | { | ||
| 68 | TT.h = r; | ||
| 69 | TT.w = c; | ||
| 70 | updateLine(); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | // NOTE - The CSI differs from the sequence callback | ||
| 74 | // in not having to return anything. CSI sequences include a | ||
| 75 | // definite terminating byte, so no need for this callback | ||
| 76 | // to tell handle_keys to keep accumulating. | ||
| 77 | } | ||
| 78 | |||
| 79 | // The various commands. | 51 | // The various commands. |
| 80 | static void deleteChar() | 52 | static void deleteChar() |
| 81 | { | 53 | { |
| @@ -184,43 +156,76 @@ static struct keyCommand simpleEmacsKeys[] = | |||
| 184 | {"^P", prevHistory} | 156 | {"^P", prevHistory} |
| 185 | }; | 157 | }; |
| 186 | 158 | ||
| 187 | // Callback for incoming key sequences from the user. | 159 | // Callback for incoming sequences from the terminal. |
| 188 | static int handleKeySequence(long extra, char *sequence, int isTranslated) | 160 | static int handleEvent(long extra, struct keyevent *event) |
| 189 | { | 161 | { |
| 190 | int j, l = strlen(sequence); | 162 | switch (event->type) |
| 191 | |||
| 192 | // Search for a key sequence bound to a command. | ||
| 193 | for (j = 0; j < (sizeof(simpleEmacsKeys) / sizeof(*simpleEmacsKeys)); j++) | ||
| 194 | { | 163 | { |
| 195 | if (strncmp(simpleEmacsKeys[j].key, sequence, l) == 0) | 164 | case HK_KEYS : |
| 196 | { | 165 | { |
| 197 | // If it's a partial match, keep accumulating them. | 166 | int j, l = strlen(event->sequence); |
| 198 | if (strlen(simpleEmacsKeys[j].key) != l) | 167 | |
| 199 | return 0; | 168 | // Search for a key sequence bound to a command. |
| 200 | else | 169 | for (j = 0; j < ARRAY_LEN(simpleEmacsKeys); j++) |
| 201 | { | 170 | { |
| 202 | if (simpleEmacsKeys[j].handler) simpleEmacsKeys[j].handler(); | 171 | if (strncmp(simpleEmacsKeys[j].key, event->sequence, l) == 0) |
| 203 | return 1; | 172 | { |
| 173 | // If it's a partial match, keep accumulating them. | ||
| 174 | if (strlen(simpleEmacsKeys[j].key) != l) | ||
| 175 | return 0; | ||
| 176 | else | ||
| 177 | { | ||
| 178 | if (simpleEmacsKeys[j].handler) simpleEmacsKeys[j].handler(); | ||
| 179 | return 1; | ||
| 180 | } | ||
| 181 | } | ||
| 204 | } | 182 | } |
| 183 | |||
| 184 | // See if it's ordinary keys. | ||
| 185 | // NOTE - with vi style ordinary keys can be commands, | ||
| 186 | // but they would be found by the command check above first. | ||
| 187 | if (!event->isTranslated) | ||
| 188 | { | ||
| 189 | if (TT.x < sizeof(toybuf)) | ||
| 190 | { | ||
| 191 | int j, l = strlen(event->sequence); | ||
| 192 | |||
| 193 | for (j = strlen(toybuf); j >= TT.x; j--) | ||
| 194 | toybuf[j + l] = toybuf[j]; | ||
| 195 | for (j = 0; j < l; j++) | ||
| 196 | toybuf[TT.x + j] = event->sequence[j]; | ||
| 197 | TT.x += l; | ||
| 198 | updateLine(); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | break; | ||
| 205 | } | 202 | } |
| 206 | } | ||
| 207 | 203 | ||
| 208 | // See if it's ordinary keys. | 204 | case HK_CSI : |
| 209 | // NOTE - with vi style ordinary keys can be commands, | ||
| 210 | // but they would be found by the command check above first. | ||
| 211 | if (!isTranslated) | ||
| 212 | { | ||
| 213 | if (TT.x < sizeof(toybuf)) | ||
| 214 | { | 205 | { |
| 215 | int j, l = strlen(sequence); | 206 | // Is it a cursor location report? |
| 216 | 207 | if (strcmp("R", event->sequence) == 0) | |
| 217 | for (j = strlen(toybuf); j >= TT.x; j--) | 208 | { |
| 218 | toybuf[j + l] = toybuf[j]; | 209 | // Parameters are cursor line and column. |
| 219 | for (j = 0; j < l; j++) | 210 | // NOTE - This may be sent at other times, not just during terminal resize. |
| 220 | toybuf[TT.x + j] = sequence[j]; | 211 | // We are assuming here that it's a resize. |
| 221 | TT.x += l; | 212 | // The defaults are 1, which get ignored by the heuristic below. |
| 222 | updateLine(); | 213 | int r = event->params[0], c = event->params[1]; |
| 214 | |||
| 215 | // Check it's not an F3 key variation, coz some of them use | ||
| 216 | // the same CSI function command. | ||
| 217 | // This is a heuristic, we are checking against an unusable terminal size. | ||
| 218 | if ((2 == event->count) && (8 < r) && (8 < c)) | ||
| 219 | { | ||
| 220 | TT.h = r; | ||
| 221 | TT.w = c; | ||
| 222 | updateLine(); | ||
| 223 | } | ||
| 224 | break; | ||
| 225 | } | ||
| 223 | } | 226 | } |
| 227 | |||
| 228 | default : break; | ||
| 224 | } | 229 | } |
| 225 | 230 | ||
| 226 | // Tell handle_keys to drop it, coz we dealt with it, or it's not one of ours. | 231 | // Tell handle_keys to drop it, coz we dealt with it, or it's not one of ours. |
| @@ -269,7 +274,7 @@ void dumbsh_main(void) | |||
| 269 | 274 | ||
| 270 | // Let's rock! | 275 | // Let's rock! |
| 271 | updateLine(); | 276 | updateLine(); |
| 272 | handle_keys(0, handleKeySequence, handleCSI); | 277 | handle_keys(0, handleEvent); |
| 273 | 278 | ||
| 274 | // Clean up. | 279 | // Clean up. |
| 275 | tcsetattr(0, TCSANOW, &oldTermIo); | 280 | tcsetattr(0, TCSANOW, &oldTermIo); |
diff --git a/handlekeys.c b/handlekeys.c index df18088..7501dbd 100644 --- a/handlekeys.c +++ b/handlekeys.c | |||
| @@ -176,10 +176,9 @@ static void handleSIGWINCH(int signalNumber) | |||
| 176 | sigWinch = 1; | 176 | sigWinch = 1; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | void handle_keys(long extra, | 179 | void handle_keys(long extra, int (*handle_event)(long extra, struct keyevent *event)) |
| 180 | int (*handle_sequence)(long extra, char *sequence, int isTranslated), | ||
| 181 | void (*handle_CSI)(long extra, char *command, int *params, int count)) | ||
| 182 | { | 180 | { |
| 181 | struct keyevent event; | ||
| 183 | fd_set selectFds; | 182 | fd_set selectFds; |
| 184 | struct timespec timeOut; | 183 | struct timespec timeOut; |
| 185 | struct sigaction sigAction, oldSigAction; | 184 | struct sigaction sigAction, oldSigAction; |
| @@ -261,6 +260,12 @@ void handle_keys(long extra, | |||
| 261 | else | 260 | else |
| 262 | { | 261 | { |
| 263 | buffIndex += j; | 262 | buffIndex += j; |
| 263 | // Send raw keystrokes, mostly for things like showkey. | ||
| 264 | event.type = HK_RAW; | ||
| 265 | event.sequence = buffer; | ||
| 266 | event.isTranslated = 0; | ||
| 267 | handle_event(extra, &event); | ||
| 268 | |||
| 264 | if (sizeof(buffer) < (buffIndex + 1)) // Ran out of buffer. | 269 | if (sizeof(buffer) < (buffIndex + 1)) // Ran out of buffer. |
| 265 | { | 270 | { |
| 266 | fprintf(stderr, "Full buffer - %s -> %s\n", buffer, sequence); | 271 | fprintf(stderr, "Full buffer - %s -> %s\n", buffer, sequence); |
| @@ -331,9 +336,18 @@ void handle_keys(long extra, | |||
| 331 | 336 | ||
| 332 | if ('M' == buffer[1]) | 337 | if ('M' == buffer[1]) |
| 333 | { | 338 | { |
| 334 | // TODO - We have a mouse report, which is CSI M ..., where the rest is | 339 | // We have a mouse report, which is CSI M ..., where the rest is |
| 335 | // binary encoded, more or less. Not fitting into the CSI format. | 340 | // binary encoded, more or less. Not fitting into the CSI format. |
| 336 | // To make things worse, can't tell how long this will be. | 341 | // To make things worse, can't tell how long this will be. |
| 342 | // So leave it up to the caller to tell us if they used it. | ||
| 343 | event.type = HK_MOUSE; | ||
| 344 | event.sequence = buffer; | ||
| 345 | event.isTranslated = 0; | ||
| 346 | if (handle_event(extra, &event)) | ||
| 347 | { | ||
| 348 | buffer[0] = buffIndex = 0; | ||
| 349 | sequence[0] = 0; | ||
| 350 | } | ||
| 337 | } | 351 | } |
| 338 | else | 352 | else |
| 339 | { | 353 | { |
| @@ -389,8 +403,12 @@ void handle_keys(long extra, | |||
| 389 | t = csFinal + strlen(csFinal) - 1; | 403 | t = csFinal + strlen(csFinal) - 1; |
| 390 | if (('\x40' <= (*t)) && ((*t) <= '\x7e')) | 404 | if (('\x40' <= (*t)) && ((*t) <= '\x7e')) |
| 391 | { | 405 | { |
| 392 | if (handle_CSI) | 406 | event.type = HK_CSI; |
| 393 | handle_CSI(extra, csFinal, csParams, p); | 407 | event.sequence = csFinal; |
| 408 | event.isTranslated = 1; | ||
| 409 | event.count = p; | ||
| 410 | event.params = csParams; | ||
| 411 | handle_event(extra, &event); | ||
| 394 | buffer[0] = buffIndex = 0; | 412 | buffer[0] = buffIndex = 0; |
| 395 | sequence[0] = 0; | 413 | sequence[0] = 0; |
| 396 | } | 414 | } |
| @@ -398,12 +416,15 @@ void handle_keys(long extra, | |||
| 398 | } | 416 | } |
| 399 | 417 | ||
| 400 | // Pass the result to the callback. | 418 | // Pass the result to the callback. |
| 401 | if ((handle_sequence) && (sequence[0] || buffer[0])) | 419 | if (sequence[0] || buffer[0]) |
| 402 | { | 420 | { |
| 403 | char b[strlen(sequence) + strlen(buffer) + 1]; | 421 | char b[strlen(sequence) + strlen(buffer) + 1]; |
| 404 | 422 | ||
| 405 | sprintf(b, "%s%s", sequence, buffer); | 423 | sprintf(b, "%s%s", sequence, buffer); |
| 406 | if (handle_sequence(extra, b, (0 != sequence[0]))) | 424 | event.type = HK_KEYS; |
| 425 | event.sequence = b; | ||
| 426 | event.isTranslated = (0 != sequence[0]); | ||
| 427 | if (handle_event(extra, &event)) | ||
| 407 | { | 428 | { |
| 408 | buffer[0] = buffIndex = 0; | 429 | buffer[0] = buffIndex = 0; |
| 409 | sequence[0] = 0; | 430 | sequence[0] = 0; |
diff --git a/handlekeys.h b/handlekeys.h index 9678131..868183f 100644 --- a/handlekeys.h +++ b/handlekeys.h | |||
| @@ -3,6 +3,21 @@ | |||
| 3 | * Copyright 2012 David Seikel <won_fang@yahoo.com.au> | 3 | * Copyright 2012 David Seikel <won_fang@yahoo.com.au> |
| 4 | */ | 4 | */ |
| 5 | 5 | ||
| 6 | enum keyeventtype{ | ||
| 7 | HK_CSI, | ||
| 8 | HK_KEYS, | ||
| 9 | HK_MOUSE, | ||
| 10 | HK_RAW | ||
| 11 | }; | ||
| 12 | |||
| 13 | struct keyevent { | ||
| 14 | enum keyeventtype type; // The type of this event. | ||
| 15 | char *sequence; // Either a translated sequence, or raw bytes. | ||
| 16 | int isTranslated; // Whether or not sequence is translated. | ||
| 17 | int count; // Number of entries in params. | ||
| 18 | int *params; // For CSI events, the decoded parameters. | ||
| 19 | }; | ||
| 20 | |||
| 6 | /* An input loop that handles keystrokes and terminal CSI commands. | 21 | /* An input loop that handles keystrokes and terminal CSI commands. |
| 7 | * | 22 | * |
| 8 | * Reads stdin, trying to translate raw keystrokes into something more readable. | 23 | * Reads stdin, trying to translate raw keystrokes into something more readable. |
| @@ -17,42 +32,44 @@ | |||
| 17 | * | 32 | * |
| 18 | * handle_keys also sets up a SIGWINCH handler to catch terminal resizes, | 33 | * handle_keys also sets up a SIGWINCH handler to catch terminal resizes, |
| 19 | * and sends a request to the terminal to report it's current size when it gets | 34 | * and sends a request to the terminal to report it's current size when it gets |
| 20 | * a SIGWINCH. This is the main reason for handle_CSI, as those reports are | 35 | * a SIGWINCH. This is the main reason for HK_CSI, as those reports are |
| 21 | * sent as CSI. It's still up to the user code to recognise and deal with the | 36 | * sent as CSI. It's still up to the user code to recognise and deal with the |
| 22 | * terminal resize response, but at least it's nicely decoded for you. | 37 | * terminal resize response, but at least it's nicely decoded for you. |
| 23 | * | 38 | * |
| 24 | * Arguments - | 39 | * Arguments - |
| 25 | * extra - arbitrary data that gets passed back to the callbacks. | 40 | * extra - arbitrary data that gets passed back to the callbacks. |
| 26 | * handle_sequence - a callback to handle keystroke sequences. | 41 | * handle_event - a callback to handle sequences. |
| 27 | * handle_CSI - a callback to handle terminal CSI commands. | 42 | * |
| 43 | * handle_event is called when a complete sequence has been accumulated. It is | ||
| 44 | * passed a keyevent structure. The type member of that structure determines | ||
| 45 | * what sort of event this is. What's in the rest of the keyevent depends on | ||
| 46 | * the type - | ||
| 28 | * | 47 | * |
| 29 | * handle_sequence is called when a complete keystroke sequence has been | 48 | * HK_CSI |
| 30 | * accumulated. The sequence argument holds the accumulated keystrokes. | 49 | * sequence is the fully decoded CSI command, including the private and intermediate characters. |
| 31 | * The translated argument flags if any have been translated, otherwise you | 50 | * isTranslated is 1, since the CSI command has been translated. |
| 32 | * can assume it's all ordinary characters. | 51 | * count is the count of translated CSI parameters. |
| 52 | * params is an array of translateted CSI parameters. | ||
| 53 | * Empty parameters are set to -1, coz -1 parameters are not legal, | ||
| 54 | * and empty ones should default to something that is command dependant. | ||
| 33 | * | 55 | * |
| 34 | * handle_keys should return 1 if the sequence has been dealt with, or ignored. | 56 | * HK_KEYS |
| 35 | * It should return 0, if handle_keys should keep adding more | 57 | * sequence the keystrokes as ASCII, either translated or not. |
| 58 | * isTranslated if 0, then sequence is ordinary keys, otherwise | ||
| 59 | * sequence is the names of keys, from the keys[] array. | ||
| 60 | * count and params are not used. | ||
| 61 | * | ||
| 62 | * For HK_KEYS handle_event should return 1 if the sequence has been dealt with, | ||
| 63 | * or ignored. It should return 0, if handle_keys should keep adding more | ||
| 36 | * translated keystroke sequences on the end, and try again later. | 64 | * translated keystroke sequences on the end, and try again later. |
| 37 | * 0 should really only be used if it's a partial match, and we need more | 65 | * 0 should really only be used if it's a partial match, and we need more |
| 38 | * keys in the sequence to make a full match. | 66 | * keys in the sequence to make a full match. |
| 39 | * | 67 | * |
| 40 | * handle_CSI is called when a complete terminal CSI command has been | 68 | * HK_MOUSE |
| 41 | * detected. The command argument is the full CSI command code, including | 69 | * sequence is the raw bytes of the mouse report. The rest are not used. |
| 42 | * private and intermediate characters. The params argument is the decoded | 70 | * |
| 43 | * parameters from the command. The count argument is the number of decoded | ||
| 44 | * parameters. Empty parameters are set to -1, coz -1 parameters are not legal, | ||
| 45 | * and empty ones should default to something that is command dependant. | ||
| 46 | * | ||
| 47 | * NOTE - handle_CSI differs from handle_sequence in not having to | ||
| 48 | * return anything. CSI sequences include a definite terminating byte, | ||
| 49 | * so no need for this callback to tell handle_keys to keep accumulating. | ||
| 50 | * Some applications use a series of keystrokes for things, so they | ||
| 51 | * get accumulated until fully recognised by the user code. | ||
| 52 | */ | 71 | */ |
| 53 | void handle_keys(long extra, | 72 | void handle_keys(long extra, int (*handle_event)(long extra, struct keyevent *event)); |
| 54 | int (*handle_sequence)(long extra, char *sequence, int isTranslated), | ||
| 55 | void (*handle_CSI)(long extra, char *command, int *params, int count)); | ||
| 56 | 73 | ||
| 57 | 74 | ||
| 58 | /* Call this when you want handle_keys to return. */ | 75 | /* Call this when you want handle_keys to return. */ |
| @@ -34,24 +34,6 @@ GLOBALS( | |||
| 34 | #define TT this.showkey | 34 | #define TT this.showkey |
| 35 | 35 | ||
| 36 | 36 | ||
| 37 | // Callback for incoming CSI commands from the terminal. | ||
| 38 | static void handleCSI(long extra, char *command, int *params, int count) | ||
| 39 | { | ||
| 40 | int i; | ||
| 41 | |||
| 42 | // Is it a cursor location report? | ||
| 43 | if (strcmp("R", command) == 0) | ||
| 44 | { | ||
| 45 | printf("CSI cursor position - line %d, column %d\r\n", params[0], params[1]); | ||
| 46 | return; | ||
| 47 | } | ||
| 48 | |||
| 49 | printf("CSI command %s - ", command); | ||
| 50 | for (i = 0; i < count; i++) | ||
| 51 | printf("%d ", params[i]); | ||
| 52 | printf("\r\n"); | ||
| 53 | } | ||
| 54 | |||
| 55 | static void quit() | 37 | static void quit() |
| 56 | { | 38 | { |
| 57 | printf("Quitting.\r\n"); | 39 | printf("Quitting.\r\n"); |
| @@ -64,31 +46,70 @@ static struct keyCommand simpleKeys[] = | |||
| 64 | {"^C", quit} | 46 | {"^C", quit} |
| 65 | }; | 47 | }; |
| 66 | 48 | ||
| 67 | // Callback for incoming key sequences from the user. | 49 | // Callback for incoming sequences from the terminal. |
| 68 | static int handleKeySequence(long extra, char *sequence, int isTranslated) | 50 | static int handleEvent(long extra, struct keyevent *event) |
| 69 | { | 51 | { |
| 70 | int j, l = strlen(sequence); | 52 | int i; |
| 71 | |||
| 72 | if (isTranslated) | ||
| 73 | printf("TRANSLATED - "); | ||
| 74 | else | ||
| 75 | printf("KEY - "); | ||
| 76 | printf("%s\r\n", sequence); | ||
| 77 | 53 | ||
| 78 | // Search for a key sequence bound to a command. | 54 | switch (event->type) |
| 79 | for (j = 0; j < (sizeof(simpleKeys) / sizeof(*simpleKeys)); j++) | ||
| 80 | { | 55 | { |
| 81 | if (strncmp(simpleKeys[j].key, sequence, l) == 0) | 56 | case HK_RAW : |
| 57 | { | ||
| 58 | printf("RAW "); | ||
| 59 | for (i = 0; event->sequence[i]; i++) | ||
| 60 | { | ||
| 61 | printf("(%x) ", (int) event->sequence[i]); | ||
| 62 | if (32 > event->sequence[i]) | ||
| 63 | printf("^%c, ", (int) event->sequence[i] + 'A' - 1); | ||
| 64 | else | ||
| 65 | printf("%c, ", (int) event->sequence[i]); | ||
| 66 | } | ||
| 67 | printf("-> "); | ||
| 68 | break; | ||
| 69 | } | ||
| 70 | |||
| 71 | case HK_KEYS : | ||
| 82 | { | 72 | { |
| 83 | // If it's a partial match, keep accumulating them. | 73 | int l = strlen(event->sequence); |
| 84 | if (strlen(simpleKeys[j].key) != l) | 74 | |
| 85 | return 0; | 75 | if (event->isTranslated) |
| 76 | printf("TRANSLATED - "); | ||
| 86 | else | 77 | else |
| 78 | printf("KEY - "); | ||
| 79 | printf("%s\r\n", event->sequence); | ||
| 80 | |||
| 81 | // Search for a key sequence bound to a command. | ||
| 82 | for (i = 0; i < ARRAY_LEN(simpleKeys); i++) | ||
| 83 | { | ||
| 84 | if (strncmp(simpleKeys[i].key, event->sequence, l) == 0) | ||
| 85 | { | ||
| 86 | // If it's a partial match, keep accumulating them. | ||
| 87 | if (strlen(simpleKeys[i].key) != l) | ||
| 88 | return 0; | ||
| 89 | else | ||
| 90 | if (simpleKeys[i].handler) simpleKeys[i].handler(); | ||
| 91 | } | ||
| 92 | } | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | |||
| 96 | case HK_CSI : | ||
| 97 | { | ||
| 98 | // Is it a cursor location report? | ||
| 99 | if (strcmp("R", event->sequence) == 0) | ||
| 87 | { | 100 | { |
| 88 | if (simpleKeys[j].handler) simpleKeys[j].handler(); | 101 | printf("CSI cursor position - line %d, column %d\r\n", event->params[0], event->params[1]); |
| 89 | return 1; | 102 | return 1; |
| 90 | } | 103 | } |
| 104 | |||
| 105 | printf("CSI command %s - ", event->sequence); | ||
| 106 | for (i = 0; i < event->count; i++) | ||
| 107 | printf("%d ", event->params[i]); | ||
| 108 | printf("\r\n"); | ||
| 109 | break; | ||
| 91 | } | 110 | } |
| 111 | |||
| 112 | default : break; | ||
| 92 | } | 113 | } |
| 93 | 114 | ||
| 94 | return 1; | 115 | return 1; |
| @@ -117,7 +138,7 @@ void showkey_main(void) | |||
| 117 | termIo.c_cc[VMIN]=1; | 138 | termIo.c_cc[VMIN]=1; |
| 118 | tcsetattr(0, TCSANOW, &termIo); | 139 | tcsetattr(0, TCSANOW, &termIo); |
| 119 | 140 | ||
| 120 | handle_keys(0, handleKeySequence, handleCSI); | 141 | handle_keys(0, handleEvent); |
| 121 | 142 | ||
| 122 | tcsetattr(0, TCSANOW, &oldTermIo); | 143 | tcsetattr(0, TCSANOW, &oldTermIo); |
| 123 | puts(""); | 144 | puts(""); |
