Don't set key KEYC_NONE on xterm_keys_find match()

When calling xterm_keys_find(); if we get a complete match, don't set
the key to unknown before calling the action to complete the binding;
otherwise non-prefixed bindings will not work.

From Thomas Adam
pull/1/head
Nicholas Marriott 2013-03-21 18:45:38 +00:00
parent 3d24c75d0f
commit d4785fe798
1 changed files with 64 additions and 84 deletions

View File

@ -353,17 +353,19 @@ tty_keys_build(struct tty *tty)
tdkr = &tty_default_raw_keys[i]; tdkr = &tty_default_raw_keys[i];
s = tdkr->string; s = tdkr->string;
if (s[0] == '\033' && s[1] != '\0') if (*s != '\0')
tty_keys_add(tty, s + 1, tdkr->key); tty_keys_add(tty, s, tdkr->key);
} }
for (i = 0; i < nitems(tty_default_code_keys); i++) { for (i = 0; i < nitems(tty_default_code_keys); i++) {
tdkc = &tty_default_code_keys[i]; tdkc = &tty_default_code_keys[i];
s = tty_term_string(tty->term, tdkc->code); s = tty_term_string(tty->term, tdkc->code);
if (s[0] == '\033' || s[1] == '\0') if (*s != '\0')
tty_keys_add(tty, s + 1, tdkc->key); tty_keys_add(tty, s, tdkc->key);
} }
tty_keys_add(tty, "abc", 'x');
} }
/* Free the entire key tree. */ /* Free the entire key tree. */
@ -439,34 +441,18 @@ tty_keys_next(struct tty *tty)
cc_t bspace; cc_t bspace;
int key, delay; int key, delay;
/* Get key buffer. */
buf = EVBUFFER_DATA(tty->event->input); buf = EVBUFFER_DATA(tty->event->input);
len = EVBUFFER_LENGTH(tty->event->input); len = EVBUFFER_LENGTH(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);
/* If a normal key, return it. */
if (*buf != '\033') {
key = (u_char) *buf;
evbuffer_drain(tty->event->input, 1);
/*
* Check for backspace key using termios VERASE - the terminfo
* kbs entry is extremely unreliable, so cannot be safely
* used. termios should have a better idea.
*/
bspace = tty->tio.c_cc[VERASE];
if (bspace != _POSIX_VDISABLE && key == bspace)
key = KEYC_BSPACE;
goto handle_key;
}
/* Is this device attributes response? */ /* Is this device attributes response? */
switch (tty_keys_device(tty, buf, len, &size)) { switch (tty_keys_device(tty, buf, len, &size)) {
case 0: /* yes */ case 0: /* yes */
evbuffer_drain(tty->event->input, size);
key = KEYC_NONE; key = KEYC_NONE;
goto handle_key; goto complete_key;
case -1: /* no, or not valid */ case -1: /* no, or not valid */
break; break;
case 1: /* partial */ case 1: /* partial */
@ -476,9 +462,8 @@ tty_keys_next(struct tty *tty)
/* 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)) {
case 0: /* yes */ case 0: /* yes */
evbuffer_drain(tty->event->input, size);
key = KEYC_MOUSE; key = KEYC_MOUSE;
goto handle_key; goto complete_key;
case -1: /* no, or not valid */ case -1: /* no, or not valid */
break; break;
case 1: /* partial */ case 1: /* partial */
@ -488,8 +473,7 @@ tty_keys_next(struct tty *tty)
/* Try to parse a key with an xterm-style modifier. */ /* Try to parse a key with an xterm-style modifier. */
switch (xterm_keys_find(buf, len, &size, &key)) { switch (xterm_keys_find(buf, len, &size, &key)) {
case 0: /* found */ case 0: /* found */
evbuffer_drain(tty->event->input, size); goto complete_key;
goto handle_key;
case -1: /* not found */ case -1: /* not found */
break; break;
case 1: case 1:
@ -497,93 +481,90 @@ tty_keys_next(struct tty *tty)
} }
/* Look for matching key string and return if found. */ /* Look for matching key string and return if found. */
tk = tty_keys_find(tty, buf + 1, len - 1, &size); tk = tty_keys_find(tty, buf, len, &size);
if (tk != NULL) { if (tk != NULL) {
if (tk->next != NULL)
goto partial_key;
key = tk->key; key = tk->key;
goto found_key; goto complete_key;
} }
/* Skip the escape. */ /* Is this a meta key? */
buf++; if (len >= 2 && buf[0] == '\033') {
len--; if (buf[1] != '\033') {
key = buf[1] | KEYC_ESCAPE;
size = 2;
goto complete_key;
}
/* Is there a normal key following? */
if (len != 0 && *buf != '\033') {
key = *buf | KEYC_ESCAPE;
evbuffer_drain(tty->event->input, 2);
goto handle_key;
}
/* Or a key string? */
if (len > 1) {
tk = tty_keys_find(tty, buf + 1, len - 1, &size); tk = tty_keys_find(tty, buf + 1, len - 1, &size);
if (tk != NULL) { if (tk != NULL) {
key = tk->key | KEYC_ESCAPE;
size++; /* include escape */ size++; /* include escape */
goto found_key; if (tk->next != NULL)
goto partial_key;
key = tk->key;
if (key != KEYC_NONE)
key |= KEYC_ESCAPE;
goto complete_key;
} }
} }
/* Escape and then nothing useful - fall through. */ first_key:
/* No key found, take first. */
key = (u_char) *buf;
size = 1;
/*
* Check for backspace key using termios VERASE - the terminfo
* kbs entry is extremely unreliable, so cannot be safely
* used. termios should have a better idea.
*/
bspace = tty->tio.c_cc[VERASE];
if (bspace != _POSIX_VDISABLE && key == bspace)
key = KEYC_BSPACE;
goto complete_key;
partial_key: partial_key:
/* log_debug("partial key %.*s", (int) len, buf);
* Escape but no key string. If have already seen an escape and the
* timer has expired, give up waiting and send the escape. /* If timer is going, check for expiration. */
*/ if (tty->flags & TTY_TIMER) {
if ((tty->flags & TTY_ESCAPE) && if (evtimer_initialized(&tty->key_timer) &&
evtimer_initialized(&tty->key_timer) && !evtimer_pending(&tty->key_timer, NULL))
!evtimer_pending(&tty->key_timer, NULL)) { goto first_key;
evbuffer_drain(tty->event->input, 1); return (0);
key = '\033';
goto handle_key;
} }
/* Fall through to start the timer. */ /* Get the time period. */
start_timer:
/* If already waiting for timer, do nothing. */
if (evtimer_initialized(&tty->key_timer) &&
evtimer_pending(&tty->key_timer, NULL))
return (0);
/* Start the timer and wait for expiry or more data. */
delay = options_get_number(&global_options, "escape-time"); delay = options_get_number(&global_options, "escape-time");
tv.tv_sec = delay / 1000; tv.tv_sec = delay / 1000;
tv.tv_usec = (delay % 1000) * 1000L; tv.tv_usec = (delay % 1000) * 1000L;
/* Start the timer. */
if (event_initialized(&tty->key_timer)) if (event_initialized(&tty->key_timer))
evtimer_del(&tty->key_timer); evtimer_del(&tty->key_timer);
evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_set(&tty->key_timer, tty_keys_callback, tty);
evtimer_add(&tty->key_timer, &tv); evtimer_add(&tty->key_timer, &tv);
tty->flags |= TTY_ESCAPE; tty->flags |= TTY_TIMER;
return (0); return (0);
found_key: complete_key:
if (tk->next != NULL) { log_debug("complete key %.*s %#x", (int) size, buf, key);
/* Partial key. Start the timer if not already expired. */
if (!(tty->flags & TTY_ESCAPE))
goto start_timer;
/* Otherwise, if no key, send the escape alone. */ /* Remove data from buffer. */
if (tk->key == KEYC_NONE) evbuffer_drain(tty->event->input, size);
goto partial_key;
/* Or fall through to send the partial key found. */ /* Remove key timer. */
}
evbuffer_drain(tty->event->input, size + 1);
goto handle_key;
handle_key:
if (event_initialized(&tty->key_timer)) if (event_initialized(&tty->key_timer))
evtimer_del(&tty->key_timer); evtimer_del(&tty->key_timer);
tty->flags &= ~TTY_TIMER;
/* Fire the key. */
if (key != KEYC_NONE) if (key != KEYC_NONE)
server_client_handle_key(tty->client, key); server_client_handle_key(tty->client, key);
tty->flags &= ~TTY_ESCAPE;
return (1); return (1);
} }
@ -594,11 +575,10 @@ tty_keys_callback(unused int fd, unused short events, void *data)
{ {
struct tty *tty = data; struct tty *tty = data;
if (!(tty->flags & TTY_ESCAPE)) if (tty->flags & TTY_TIMER) {
return; while (tty_keys_next(tty))
;
while (tty_keys_next(tty)) }
;
} }
/* /*