version 1.85, 2016/03/02 15:36:03 |
version 1.86, 2016/04/26 22:19:22 |
|
|
* into a ternary tree. |
* into a ternary tree. |
*/ |
*/ |
|
|
void tty_keys_add1(struct tty_key **, const char *, key_code); |
static void tty_keys_add1(struct tty_key **, const char *, key_code); |
void tty_keys_add(struct tty *, const char *, key_code); |
static void tty_keys_add(struct tty *, const char *, key_code); |
void tty_keys_free1(struct tty_key *); |
static void tty_keys_free1(struct tty_key *); |
struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t, |
static struct tty_key *tty_keys_find1(struct tty_key *, const char *, size_t, |
size_t *); |
size_t *); |
struct tty_key *tty_keys_find(struct tty *, const char *, size_t, size_t *); |
static struct tty_key *tty_keys_find(struct tty *, const char *, size_t, |
void tty_keys_callback(int, short, void *); |
size_t *); |
int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); |
static int tty_keys_next1(struct tty *, const char *, size_t, key_code *, |
|
size_t *); |
|
static void tty_keys_callback(int, short, void *); |
|
static int tty_keys_mouse(struct tty *, const char *, size_t, size_t *); |
|
|
/* Default raw keys. */ |
/* Default raw keys. */ |
struct tty_default_key_raw { |
struct tty_default_key_raw { |
|
|
}; |
}; |
|
|
/* Add key to tree. */ |
/* Add key to tree. */ |
void |
static void |
tty_keys_add(struct tty *tty, const char *s, key_code key) |
tty_keys_add(struct tty *tty, const char *s, key_code key) |
{ |
{ |
struct tty_key *tk; |
struct tty_key *tk; |
|
|
} |
} |
|
|
/* Add next node to the tree. */ |
/* Add next node to the tree. */ |
void |
static void |
tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) |
tty_keys_add1(struct tty_key **tkp, const char *s, key_code key) |
{ |
{ |
struct tty_key *tk; |
struct tty_key *tk; |
|
|
} |
} |
|
|
/* Free a single key. */ |
/* Free a single key. */ |
void |
static void |
tty_keys_free1(struct tty_key *tk) |
tty_keys_free1(struct tty_key *tk) |
{ |
{ |
if (tk->next != NULL) |
if (tk->next != NULL) |
|
|
} |
} |
|
|
/* Lookup a key in the tree. */ |
/* Lookup a key in the tree. */ |
struct tty_key * |
static struct tty_key * |
tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) |
tty_keys_find(struct tty *tty, const char *buf, size_t len, size_t *size) |
{ |
{ |
*size = 0; |
*size = 0; |
|
|
} |
} |
|
|
/* Find the next node. */ |
/* Find the next node. */ |
struct tty_key * |
static struct tty_key * |
tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) |
tty_keys_find1(struct tty_key *tk, const char *buf, size_t len, size_t *size) |
{ |
{ |
/* If the node is NULL, this is the end of the tree. No match. */ |
/* If the node is NULL, this is the end of the tree. No match. */ |
|
|
return (tty_keys_find1(tk, buf, len, size)); |
return (tty_keys_find1(tk, buf, len, size)); |
} |
} |
|
|
|
/* Look up part of the next key. */ |
|
static int |
|
tty_keys_next1(struct tty *tty, const char *buf, size_t len, key_code *key, |
|
size_t *size) |
|
{ |
|
struct tty_key *tk, *tk1; |
|
struct utf8_data ud; |
|
enum utf8_state more; |
|
u_int i; |
|
wchar_t wc; |
|
|
|
log_debug("next key is %zu (%.*s)", len, (int)len, buf); |
|
|
|
/* Empty buffer is a partial key. */ |
|
if (len == 0) |
|
return (1); |
|
|
|
/* Is this a known key? */ |
|
tk = tty_keys_find(tty, buf, len, size); |
|
if (tk != NULL) { |
|
tk1 = tk; |
|
do |
|
log_debug("keys in list: %#llx", tk->key); |
|
while ((tk1 = tk1->next) != NULL); |
|
*key = tk->key; |
|
return (tk->next != NULL); |
|
} |
|
|
|
/* Is this valid UTF-8? */ |
|
more = utf8_open(&ud, (u_char)*buf); |
|
if (more == UTF8_MORE) { |
|
*size = ud.size; |
|
if (len < ud.size) |
|
return (1); |
|
for (i = 1; i < ud.size; i++) |
|
more = utf8_append(&ud, (u_char)buf[i]); |
|
if (more != UTF8_DONE) |
|
return (0); |
|
|
|
if (utf8_combine(&ud, &wc) != UTF8_DONE) |
|
return (0); |
|
*key = wc; |
|
|
|
log_debug("UTF-8 key %.*s %#llx", (int)ud.size, buf, *key); |
|
return (0); |
|
} |
|
|
|
return (-1); |
|
} |
|
|
/* |
/* |
* Process at least one key in the buffer and invoke tty->key_callback. Return |
* Process at least one key in the buffer and invoke tty->key_callback. Return |
* 0 if there are no further keys, or 1 if there could be more in the buffer. |
* 0 if there are no further keys, or 1 if there could be more in the buffer. |
|
|
key_code |
key_code |
tty_keys_next(struct tty *tty) |
tty_keys_next(struct tty *tty) |
{ |
{ |
struct tty_key *tk; |
struct timeval tv; |
struct timeval tv; |
const char *buf; |
const char *buf; |
size_t len, size; |
size_t len, size; |
cc_t bspace; |
cc_t bspace; |
int delay, expired = 0; |
int delay, expired = 0; |
key_code key; |
key_code key; |
|
struct utf8_data ud; |
|
enum utf8_state more; |
|
u_int i; |
|
wchar_t wc; |
|
|
|
/* Get key buffer. */ |
/* Get key buffer. */ |
buf = EVBUFFER_DATA(tty->event->input); |
buf = EVBUFFER_DATA(tty->event->input); |
|
|
|
|
if (len == 0) |
if (len == 0) |
return (0); |
return (0); |
log_debug("keys are %zu (%.*s)", len, (int) len, buf); |
log_debug("keys are %zu (%.*s)", len, (int)len, buf); |
|
|
/* Is this a mouse key press? */ |
/* Is this a mouse key press? */ |
switch (tty_keys_mouse(tty, buf, len, &size)) { |
switch (tty_keys_mouse(tty, buf, len, &size)) { |
|
|
goto partial_key; |
goto partial_key; |
} |
} |
|
|
/* Look for matching key string and return if found. */ |
first_key: |
tk = tty_keys_find(tty, buf, len, &size); |
/* If escape is at the start, try without it. */ |
if (tk != NULL) { |
if (*buf == '\033') { |
if (tk->next != NULL) |
switch (tty_keys_next1 (tty, buf + 1, len - 1, &key, &size)) { |
|
case 0: /* found */ |
|
if (key != KEYC_UNKNOWN) |
|
key |= KEYC_ESCAPE; |
|
size++; /* include escape */ |
|
goto complete_key; |
|
case -1: /* not found */ |
|
break; |
|
case 1: |
|
if (expired) |
|
goto complete_key; |
goto partial_key; |
goto partial_key; |
key = tk->key; |
} |
|
} |
|
|
|
/* Try with the escape. */ |
|
switch (tty_keys_next1 (tty, buf, len, &key, &size)) { |
|
case 0: /* found */ |
goto complete_key; |
goto complete_key; |
|
case -1: /* not found */ |
|
break; |
|
case 1: |
|
if (expired) |
|
goto complete_key; |
|
goto partial_key; |
} |
} |
|
|
/* Try to parse a key with an xterm-style modifier. */ |
/* Is this an an xterm(1) key? */ |
switch (xterm_keys_find(buf, len, &size, &key)) { |
switch (xterm_keys_find(buf, len, &size, &key)) { |
case 0: /* found */ |
case 0: /* found */ |
goto complete_key; |
goto complete_key; |
case -1: /* not found */ |
case -1: /* not found */ |
break; |
break; |
case 1: |
case 1: |
|
if (expired) |
|
break; |
goto partial_key; |
goto partial_key; |
} |
} |
|
|
first_key: |
/* |
/* Is this a meta key? */ |
* If this starts with escape and is at least two keys, it must be |
if (len >= 2 && buf[0] == '\033') { |
* complete even if the timer has not expired, because otherwise |
if (buf[1] != '\033') { |
* tty_keys_next1 would have found a partial key. If just an escape |
key = buf[1] | KEYC_ESCAPE; |
* alone, it needs to wait for the timer first. |
|
*/ |
|
if (*buf == '\033') { |
|
if (len >= 2) { |
|
key = (u_char)buf[1] | KEYC_ESCAPE; |
size = 2; |
size = 2; |
goto complete_key; |
goto complete_key; |
} |
} |
|
if (!expired) |
tk = tty_keys_find(tty, buf + 1, len - 1, &size); |
|
if (tk != NULL && (!expired || tk->next == NULL)) { |
|
size++; /* include escape */ |
|
if (tk->next != NULL) |
|
goto partial_key; |
|
key = tk->key; |
|
if (key != KEYC_UNKNOWN) |
|
key |= KEYC_ESCAPE; |
|
goto complete_key; |
|
} |
|
} |
|
|
|
/* Is this valid UTF-8? */ |
|
if ((more = utf8_open(&ud, (u_char)*buf) == UTF8_MORE)) { |
|
size = ud.size; |
|
if (len < size) { |
|
if (expired) |
|
goto discard_key; |
|
goto partial_key; |
goto partial_key; |
} |
|
for (i = 1; i < size; i++) |
|
more = utf8_append(&ud, (u_char)buf[i]); |
|
if (more != UTF8_DONE) |
|
goto discard_key; |
|
|
|
if (utf8_combine(&ud, &wc) != UTF8_DONE) |
|
goto discard_key; |
|
key = wc; |
|
|
|
log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key); |
|
goto complete_key; |
|
} |
} |
|
|
/* No key found, take first. */ |
/* No longer key found, use the first character. */ |
key = (u_char)*buf; |
key = (u_char)*buf; |
size = 1; |
size = 1; |
|
|
|
|
goto complete_key; |
goto complete_key; |
|
|
partial_key: |
partial_key: |
log_debug("partial key %.*s", (int) len, buf); |
log_debug("partial key %.*s", (int)len, buf); |
|
|
/* If timer is going, check for expiration. */ |
/* If timer is going, check for expiration. */ |
if (tty->flags & TTY_TIMER) { |
if (tty->flags & TTY_TIMER) { |
|
|
} |
} |
|
|
/* Key timer callback. */ |
/* Key timer callback. */ |
void |
static void |
tty_keys_callback(__unused int fd, __unused short events, void *data) |
tty_keys_callback(__unused int fd, __unused short events, void *data) |
{ |
{ |
struct tty *tty = data; |
struct tty *tty = data; |
|
|
* Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial |
* Handle mouse key input. Returns 0 for success, -1 for failure, 1 for partial |
* (probably a mouse sequence but need more data). |
* (probably a mouse sequence but need more data). |
*/ |
*/ |
int |
static int |
tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) |
tty_keys_mouse(struct tty *tty, const char *buf, size_t len, size_t *size) |
{ |
{ |
struct mouse_event *m = &tty->mouse; |
struct mouse_event *m = &tty->mouse; |