Exemple #1
0
/* 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, int expired)
{
	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) (expired=%d)", len, (int)len, buf,
	    expired);

	/* Is this a known key? */
	tk = tty_keys_find(tty, buf, len, size);
	if (tk != NULL && tk->key != KEYC_UNKNOWN) {
		tk1 = tk;
		do
			log_debug("keys in list: %#llx", tk1->key);
		while ((tk1 = tk1->next) != NULL);
		if (tk->next != NULL && !expired)
			return (1);
		*key = tk->key;
		return (0);
	}

	/* Is this valid UTF-8? */
	more = utf8_open(&ud, (u_char)*buf);
	if (more == UTF8_MORE) {
		*size = ud.size;
		if (len < ud.size) {
			if (!expired)
				return (1);
			return (-1);
		}
		for (i = 1; i < ud.size; i++)
			more = utf8_append(&ud, (u_char)buf[i]);
		if (more != UTF8_DONE)
			return (-1);

		if (utf8_combine(&ud, &wc) != UTF8_DONE)
			return (-1);
		*key = wc;

		log_debug("UTF-8 key %.*s %#llx", (int)ud.size, buf, *key);
		return (0);
	}

	return (-1);
}
Exemple #2
0
void
tty_keys_add(struct tty *tty, const char *s, int key)
{
	struct tty_key	*tk;
	size_t		 size;
	const char     	*keystr;

	keystr = key_string_lookup_key(key);
	if ((tk = tty_keys_find(tty, s, strlen(s), &size)) == NULL) {
		log_debug("new key %s: 0x%x (%s)", s, key, keystr);
		tty_keys_add1(&tty->key_tree, s, key);
	} else {
		log_debug("replacing key %s: 0x%x (%s)", s, key, keystr);
		tk->key = key;
	}
}
Exemple #3
0
/*
 * 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);
}
Exemple #4
0
/*
 * 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);
}
Exemple #5
0
/*
 * 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);
}