/* * 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. */ int tty_keys_next(struct tty *tty) { struct tty_key *tk; struct timeval tv; const char *buf; size_t len, size; cc_t bspace; int key, delay; buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (0); 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? */ switch (tty_keys_device(tty, buf, len, &size)) { case 0: /* yes */ evbuffer_drain(tty->event->input, size); key = KEYC_NONE; goto handle_key; case -1: /* no, or not valid */ break; case 1: /* partial */ goto partial_key; } /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ evbuffer_drain(tty->event->input, size); key = KEYC_MOUSE; goto handle_key; case -1: /* no, or not valid */ break; case 1: /* partial */ goto partial_key; } /* Try to parse a key with an xterm-style modifier. */ switch (xterm_keys_find(buf, len, &size, &key)) { case 0: /* found */ evbuffer_drain(tty->event->input, size); goto handle_key; case -1: /* not found */ break; case 1: goto partial_key; } /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { key = tk->key; goto found_key; } /* Skip the escape. */ buf++; len--; /* 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); if (tk != NULL) { key = tk->key | KEYC_ESCAPE; size++; /* include escape */ goto found_key; } } /* Escape and then nothing useful - fall through. */ partial_key: /* * Escape but no key string. If have already seen an escape and the * timer has expired, give up waiting and send the escape. */ if ((tty->flags & TTY_ESCAPE) && !evtimer_pending(&tty->key_timer, NULL)) { evbuffer_drain(tty->event->input, 1); key = '\033'; goto handle_key; } /* Fall through to start the timer. */ start_timer: /* If already waiting for timer, do nothing. */ if (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"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); tty->flags |= TTY_ESCAPE; return (0); found_key: if (tk->next != NULL) { /* 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. */ if (tk->key == KEYC_NONE) goto partial_key; /* Or fall through to send the partial key found. */ } evbuffer_drain(tty->event->input, size + 1); goto handle_key; handle_key: if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); if (key != KEYC_NONE) server_client_handle_key(tty->client, key); tty->flags &= ~TTY_ESCAPE; return (1); }
/* * 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. */ int tty_keys_next(struct tty *tty) { struct tty_key *tk; struct timeval tv; const char *buf; size_t len, size; cc_t bspace; int key, delay; /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (0); log_debug("keys are %zu (%.*s)", len, (int) len, buf); /* Is this device attributes response? */ switch (tty_keys_device(tty, buf, len, &size)) { case 0: /* yes */ key = KEYC_NONE; goto complete_key; case -1: /* no, or not valid */ break; case 1: /* partial */ goto partial_key; } /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ key = KEYC_MOUSE; goto complete_key; case -1: /* no, or not valid */ break; case 1: /* partial */ goto partial_key; } /* Try to parse a key with an xterm-style modifier. */ switch (xterm_keys_find(buf, len, &size, &key)) { case 0: /* found */ goto complete_key; case -1: /* not found */ break; case 1: goto partial_key; } /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, buf, len, &size); if (tk != NULL) { if (tk->next != NULL) goto partial_key; key = tk->key; goto complete_key; } /* Is this a meta key? */ if (len >= 2 && buf[0] == '\033') { if (buf[1] != '\033') { key = buf[1] | KEYC_ESCAPE; size = 2; goto complete_key; } tk = tty_keys_find(tty, buf + 1, len - 1, &size); if (tk != NULL) { size++; /* include escape */ if (tk->next != NULL) goto partial_key; key = tk->key; if (key != KEYC_NONE) key |= KEYC_ESCAPE; goto complete_key; } } 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: log_debug("partial key %.*s", (int) len, buf); /* If timer is going, check for expiration. */ if (tty->flags & TTY_TIMER) { if (evtimer_initialized(&tty->key_timer) && !evtimer_pending(&tty->key_timer, NULL)) goto first_key; return (0); } /* Get the time period. */ delay = options_get_number(&global_options, "escape-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; /* Start the timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); tty->flags |= TTY_TIMER; return (0); complete_key: log_debug("complete key %.*s %#x", (int) size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); /* Remove key timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); tty->flags &= ~TTY_TIMER; /* Fire the key. */ if (key != KEYC_NONE) server_client_handle_key(tty->client, key); return (1); }
/* * 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. */ key_code tty_keys_next(struct tty *tty) { struct tty_key *tk; struct timeval tv; const char *buf; size_t len, size; cc_t bspace; int delay, expired = 0; key_code key; struct utf8_data ud; enum utf8_state more; u_int i; /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (0); log_debug("keys are %zu (%.*s)", len, (int) len, buf); /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ key = KEYC_MOUSE; goto complete_key; case -1: /* no, or not valid */ break; case -2: /* yes, but we don't care. */ key = KEYC_MOUSE; goto discard_key; case 1: /* partial */ goto partial_key; } /* Look for matching key string and return if found. */ tk = tty_keys_find(tty, buf, len, &size); if (tk != NULL) { if (tk->next != NULL) goto partial_key; key = tk->key; goto complete_key; } /* Try to parse a key with an xterm-style modifier. */ switch (xterm_keys_find(buf, len, &size, &key)) { case 0: /* found */ goto complete_key; case -1: /* not found */ break; case 1: goto partial_key; } first_key: /* Is this a meta key? */ if (len >= 2 && buf[0] == '\033') { if (buf[1] != '\033') { key = buf[1] | KEYC_ESCAPE; size = 2; goto complete_key; } 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_NONE) 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; } for (i = 1; i < size; i++) more = utf8_append(&ud, (u_char)buf[i]); if (more != UTF8_DONE) goto discard_key; key = utf8_combine(&ud); log_debug("UTF-8 key %.*s %#llx", (int)size, buf, key); goto complete_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: log_debug("partial key %.*s", (int) len, buf); /* If timer is going, check for expiration. */ if (tty->flags & TTY_TIMER) { if (evtimer_initialized(&tty->key_timer) && !evtimer_pending(&tty->key_timer, NULL)) { expired = 1; goto first_key; } return (0); } /* Get the time period. */ delay = options_get_number(global_options, "escape-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; /* Start the timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); tty->flags |= TTY_TIMER; return (0); complete_key: log_debug("complete key %.*s %#llx", (int)size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); /* Remove key timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); tty->flags &= ~TTY_TIMER; /* Check for focus events. */ if (key == KEYC_FOCUS_OUT) { tty->client->flags &= ~CLIENT_FOCUSED; return (1); } else if (key == KEYC_FOCUS_IN) { tty->client->flags |= CLIENT_FOCUSED; return (1); } /* Fire the key. */ if (key != KEYC_NONE) server_client_handle_key(tty->client, key); return (1); discard_key: log_debug("discard key %.*s %#llx", (int)size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); return (1); }
/* * 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. */ key_code tty_keys_next(struct tty *tty) { struct timeval tv; const char *buf; size_t len, size; cc_t bspace; int delay, expired = 0, n; key_code key; /* Get key buffer. */ buf = EVBUFFER_DATA(tty->event->input); len = EVBUFFER_LENGTH(tty->event->input); if (len == 0) return (0); log_debug("keys are %zu (%.*s)", len, (int)len, buf); /* Is this a mouse key press? */ switch (tty_keys_mouse(tty, buf, len, &size)) { case 0: /* yes */ key = KEYC_MOUSE; goto complete_key; case -1: /* no, or not valid */ break; case -2: /* yes, but we don't care. */ key = KEYC_MOUSE; goto discard_key; case 1: /* partial */ goto partial_key; } first_key: /* Handle keys starting with escape. */ if (*buf == '\033') { /* Look for a key without the escape. */ n = tty_keys_next1(tty, buf + 1, len - 1, &key, &size, expired); if (n == 0) { /* found */ key |= KEYC_ESCAPE; size++; goto complete_key; } if (n == 1) /* partial */ goto partial_key; } /* Try to lookup key. */ n = tty_keys_next1(tty, buf, len, &key, &size, expired); if (n == 0) /* found */ goto complete_key; if (n == 1) goto partial_key; /* Is this an an xterm(1) key? */ n = xterm_keys_find(buf, len, &size, &key); if (n == 0) goto complete_key; if (n == 1 && !expired) goto partial_key; /* * At this point, we know the key is not partial (with or without * escape). So pass it through even if the timer has not expired. */ if (*buf == '\033' && len >= 2) { key = (u_char)buf[1] | KEYC_ESCAPE; size = 2; } else { key = (u_char)buf[0]; size = 1; } goto complete_key; partial_key: log_debug("partial key %.*s", (int)len, buf); /* If timer is going, check for expiration. */ if (tty->flags & TTY_TIMER) { if (evtimer_initialized(&tty->key_timer) && !evtimer_pending(&tty->key_timer, NULL)) { expired = 1; goto first_key; } return (0); } /* Get the time period. */ delay = options_get_number(global_options, "escape-time"); tv.tv_sec = delay / 1000; tv.tv_usec = (delay % 1000) * 1000L; /* Start the timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); evtimer_set(&tty->key_timer, tty_keys_callback, tty); evtimer_add(&tty->key_timer, &tv); tty->flags |= TTY_TIMER; return (0); complete_key: log_debug("complete key %.*s %#llx", (int)size, buf, key); /* * 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 & KEYC_MASK_KEY) == bspace) key = (key & KEYC_MASK_MOD) | KEYC_BSPACE; /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); /* Remove key timer. */ if (event_initialized(&tty->key_timer)) evtimer_del(&tty->key_timer); tty->flags &= ~TTY_TIMER; /* Check for focus events. */ if (key == KEYC_FOCUS_OUT) { tty->client->flags &= ~CLIENT_FOCUSED; return (1); } else if (key == KEYC_FOCUS_IN) { tty->client->flags |= CLIENT_FOCUSED; return (1); } /* Fire the key. */ if (key != KEYC_UNKNOWN) server_client_handle_key(tty->client, key); return (1); discard_key: log_debug("discard key %.*s %#llx", (int)size, buf, key); /* Remove data from buffer. */ evbuffer_drain(tty->event->input, size); return (1); }