diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-25 23:23:32 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2008-10-25 23:23:32 +0000 |
| commit | 39b0135c59555203a568bd9fb4fc4126dbdde992 (patch) | |
| tree | d35a9c52aa9afb10c9816cb2d7bf2ce2d154b0eb | |
| parent | 0112ff5203e1bbc37425b87a71326aa0a85ec283 (diff) | |
| download | busybox-w32-39b0135c59555203a568bd9fb4fc4126dbdde992.tar.gz busybox-w32-39b0135c59555203a568bd9fb4fc4126dbdde992.tar.bz2 busybox-w32-39b0135c59555203a568bd9fb4fc4126dbdde992.zip | |
libbb: add forgotten file from previous commit :(
| -rw-r--r-- | libbb/read_key.c | 146 |
1 files changed, 146 insertions, 0 deletions
diff --git a/libbb/read_key.c b/libbb/read_key.c new file mode 100644 index 000000000..598bd94f5 --- /dev/null +++ b/libbb/read_key.c | |||
| @@ -0,0 +1,146 @@ | |||
| 1 | /* vi: set sw=4 ts=4: */ | ||
| 2 | /* | ||
| 3 | * Utility routines. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2008 Denys Vlasenko | ||
| 6 | * | ||
| 7 | * Licensed under GPL version 2, see file LICENSE in this tarball for details. | ||
| 8 | */ | ||
| 9 | #include "libbb.h" | ||
| 10 | |||
| 11 | int FAST_FUNC read_key(int fd, smalluint *nbuffered, char *buffer) | ||
| 12 | { | ||
| 13 | struct pollfd pfd; | ||
| 14 | const char *seq; | ||
| 15 | int n; | ||
| 16 | int c; | ||
| 17 | |||
| 18 | /* Known escape sequences for cursor and function keys */ | ||
| 19 | static const char esccmds[] ALIGN1 = { | ||
| 20 | 'O','A' |0x80,KEYCODE_UP , | ||
| 21 | 'O','B' |0x80,KEYCODE_DOWN , | ||
| 22 | 'O','C' |0x80,KEYCODE_RIGHT , | ||
| 23 | 'O','D' |0x80,KEYCODE_LEFT , | ||
| 24 | 'O','H' |0x80,KEYCODE_HOME , | ||
| 25 | 'O','F' |0x80,KEYCODE_END , | ||
| 26 | #if 0 | ||
| 27 | 'O','P' |0x80,KEYCODE_FUN1 , | ||
| 28 | 'O','Q' |0x80,KEYCODE_FUN2 , | ||
| 29 | 'O','R' |0x80,KEYCODE_FUN3 , | ||
| 30 | 'O','S' |0x80,KEYCODE_FUN4 , | ||
| 31 | #endif | ||
| 32 | '[','A' |0x80,KEYCODE_UP , | ||
| 33 | '[','B' |0x80,KEYCODE_DOWN , | ||
| 34 | '[','C' |0x80,KEYCODE_RIGHT , | ||
| 35 | '[','D' |0x80,KEYCODE_LEFT , | ||
| 36 | '[','H' |0x80,KEYCODE_HOME , | ||
| 37 | '[','F' |0x80,KEYCODE_END , | ||
| 38 | '[','1','~' |0x80,KEYCODE_HOME , | ||
| 39 | '[','2','~' |0x80,KEYCODE_INSERT , | ||
| 40 | '[','3','~' |0x80,KEYCODE_DELETE , | ||
| 41 | '[','4','~' |0x80,KEYCODE_END , | ||
| 42 | '[','5','~' |0x80,KEYCODE_PAGEUP , | ||
| 43 | '[','6','~' |0x80,KEYCODE_PAGEDOWN, | ||
| 44 | #if 0 | ||
| 45 | '[','1','1','~'|0x80,KEYCODE_FUN1 , | ||
| 46 | '[','1','2','~'|0x80,KEYCODE_FUN2 , | ||
| 47 | '[','1','3','~'|0x80,KEYCODE_FUN3 , | ||
| 48 | '[','1','4','~'|0x80,KEYCODE_FUN4 , | ||
| 49 | '[','1','5','~'|0x80,KEYCODE_FUN5 , | ||
| 50 | '[','1','7','~'|0x80,KEYCODE_FUN6 , | ||
| 51 | '[','1','8','~'|0x80,KEYCODE_FUN7 , | ||
| 52 | '[','1','9','~'|0x80,KEYCODE_FUN8 , | ||
| 53 | '[','2','0','~'|0x80,KEYCODE_FUN9 , | ||
| 54 | '[','2','1','~'|0x80,KEYCODE_FUN10 , | ||
| 55 | '[','2','3','~'|0x80,KEYCODE_FUN11 , | ||
| 56 | '[','2','4','~'|0x80,KEYCODE_FUN12 , | ||
| 57 | #endif | ||
| 58 | 0 | ||
| 59 | }; | ||
| 60 | |||
| 61 | n = *nbuffered; | ||
| 62 | if (n == 0) { | ||
| 63 | /* If no data, block waiting for input. If we read more | ||
| 64 | * than the minimal ESC sequence size, the "n=0" below | ||
| 65 | * would instead have to figure out how much to keep, | ||
| 66 | * resulting in larger code. */ | ||
| 67 | n = safe_read(fd, buffer, 3); | ||
| 68 | if (n <= 0) | ||
| 69 | return -1; | ||
| 70 | } | ||
| 71 | |||
| 72 | /* Grab character to return from buffer */ | ||
| 73 | c = (unsigned char)buffer[0]; | ||
| 74 | n--; | ||
| 75 | if (n) | ||
| 76 | memmove(buffer, buffer + 1, n); | ||
| 77 | |||
| 78 | /* Only ESC starts ESC sequences */ | ||
| 79 | if (c != 27) | ||
| 80 | goto ret; | ||
| 81 | |||
| 82 | /* Loop through known ESC sequences */ | ||
| 83 | pfd.fd = fd; | ||
| 84 | pfd.events = POLLIN; | ||
| 85 | seq = esccmds; | ||
| 86 | while (*seq != '\0') { | ||
| 87 | /* n - position in sequence we did not read yet */ | ||
| 88 | int i = 0; /* position in sequence to compare */ | ||
| 89 | |||
| 90 | /* Loop through chars in this sequence */ | ||
| 91 | while (1) { | ||
| 92 | /* So far escape sequence matched up to [i-1] */ | ||
| 93 | if (n <= i) { | ||
| 94 | /* Need more chars, read another one if it wouldn't block. | ||
| 95 | * Note that escape sequences come in as a unit, | ||
| 96 | * so if we block for long it's not really an escape sequence. | ||
| 97 | * Timeout is needed to reconnect escape sequences | ||
| 98 | * split up by transmission over a serial console. */ | ||
| 99 | if (safe_poll(&pfd, 1, 50) == 0) { | ||
| 100 | /* No more data! | ||
| 101 | * Array is sorted from shortest to longest, | ||
| 102 | * we can't match anything later in array, | ||
| 103 | * break out of both loops. */ | ||
| 104 | goto ret; | ||
| 105 | } | ||
| 106 | errno = 0; | ||
| 107 | if (safe_read(fd, buffer + n, 1) <= 0) { | ||
| 108 | /* If EAGAIN, then fd is O_NONBLOCK and poll lied: | ||
| 109 | * in fact, there is no data. */ | ||
| 110 | if (errno != EAGAIN) | ||
| 111 | c = -1; /* otherwise it's EOF/error */ | ||
| 112 | goto ret; | ||
| 113 | } | ||
| 114 | n++; | ||
| 115 | } | ||
| 116 | if (buffer[i] != (seq[i] & 0x7f)) { | ||
| 117 | /* This seq doesn't match, go to next */ | ||
| 118 | seq += i; | ||
| 119 | /* Forward to last char */ | ||
| 120 | while (!(*seq & 0x80)) | ||
| 121 | seq++; | ||
| 122 | /* Skip it and the keycode which follows */ | ||
| 123 | seq += 2; | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | if (seq[i] & 0x80) { | ||
| 127 | /* Entire seq matched */ | ||
| 128 | c = (signed char)seq[i+1]; | ||
| 129 | n = 0; | ||
| 130 | /* n -= i; memmove(...); | ||
| 131 | * would be more correct, | ||
| 132 | * but we never read ahead that much, | ||
| 133 | * and n == i here. */ | ||
| 134 | goto ret; | ||
| 135 | } | ||
| 136 | i++; | ||
| 137 | } | ||
| 138 | } | ||
| 139 | /* We did not find matching sequence, it was a bare ESC. | ||
| 140 | * We possibly read and stored more input in buffer[] | ||
| 141 | * by now. */ | ||
| 142 | |||
| 143 | ret: | ||
| 144 | *nbuffered = n; | ||
| 145 | return c; | ||
| 146 | } | ||
