mirror of https://github.com/MidnightCommander/mc
Merge branch '2988_ignore_unknown_esc_sequences'
* 2988_ignore_unknown_esc_sequences: When we see an unknown sequence, it is not enough to drop already received part - there can be more of it coming over e.g. a serial line. This change prevents misinterpreting an unknown ESC sequence's tail as a garbage input. To reproduce, run "sleep 3" and hold down Down_Arrow key until sleep runs. With debugging log enabled, the following can be seen: Ticket #2988: When an unknown key is pressed, it is interpreted as garbage.
This commit is contained in:
commit
1df77c409e
153
lib/tty/key.c
153
lib/tty/key.c
|
@ -2,7 +2,7 @@
|
|||
Keyboard support routines.
|
||||
|
||||
Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
2005, 2006, 2007, 2009, 2010, 2011
|
||||
2005, 2006, 2007, 2009, 2010, 2011, 2013
|
||||
The Free Software Foundation, Inc.
|
||||
|
||||
Written by:
|
||||
|
@ -10,6 +10,8 @@
|
|||
Janne Kukonlehto, 1994, 1995
|
||||
Jakub Jelinek, 1995
|
||||
Norbert Warmuth, 1997
|
||||
Denys Vlasenko <vda.linux@googlemail.com>, 2013
|
||||
Slava Zanko <slavazanko@gmail.com>, 2013
|
||||
|
||||
This file is part of the Midnight Commander.
|
||||
|
||||
|
@ -1129,14 +1131,14 @@ correct_key_code (int code)
|
|||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
||||
static int
|
||||
xgetch_second (void)
|
||||
getch_with_timeout (unsigned int delay_us)
|
||||
{
|
||||
fd_set Read_FD_Set;
|
||||
int c;
|
||||
struct timeval time_out;
|
||||
|
||||
time_out.tv_sec = old_esc_mode_timeout / 1000000;
|
||||
time_out.tv_usec = old_esc_mode_timeout % 1000000;
|
||||
time_out.tv_sec = delay_us / 1000000u;
|
||||
time_out.tv_usec = delay_us % 1000000u;
|
||||
tty_nodelay (TRUE);
|
||||
FD_ZERO (&Read_FD_Set);
|
||||
FD_SET (input_fd, &Read_FD_Set);
|
||||
|
@ -1745,14 +1747,31 @@ get_key_code (int no_delay)
|
|||
if (pending_keys != NULL)
|
||||
{
|
||||
int d;
|
||||
gboolean bad_seq;
|
||||
|
||||
d = *pending_keys++;
|
||||
while (d == ESC_CHAR && *pending_keys != '\0')
|
||||
while (d == ESC_CHAR)
|
||||
d = ALT (*pending_keys++);
|
||||
|
||||
if (*pending_keys == '\0')
|
||||
bad_seq = (*pending_keys != ESC_CHAR && *pending_keys != 0);
|
||||
if (*pending_keys == '\0' || bad_seq)
|
||||
pending_keys = seq_append = NULL;
|
||||
|
||||
if (bad_seq)
|
||||
{
|
||||
/* This is an unknown ESC sequence.
|
||||
* To prevent interpreting its tail as a random garbage,
|
||||
* eat and discard all buffered and quickly following chars.
|
||||
* Small, but non-zero timeout is needed to reconnect
|
||||
* escape sequence split up by e.g. a serial line.
|
||||
*/
|
||||
int paranoia = 20;
|
||||
|
||||
while (getch_with_timeout (old_esc_mode_timeout) >= 0 && --paranoia != 0)
|
||||
;
|
||||
goto nodelay_try_again;
|
||||
}
|
||||
|
||||
if (d > 127 && d < 256 && use_8th_bit_as_meta)
|
||||
d = ALT (d & 0x7f);
|
||||
|
||||
|
@ -1828,49 +1847,12 @@ get_key_code (int no_delay)
|
|||
this = keys->child;
|
||||
}
|
||||
}
|
||||
|
||||
while (this != NULL)
|
||||
{
|
||||
if (c == this->ch)
|
||||
{
|
||||
if (this->child)
|
||||
{
|
||||
if (!push_char (c))
|
||||
{
|
||||
pending_keys = seq_buffer;
|
||||
goto pend_send;
|
||||
}
|
||||
parent = this;
|
||||
this = this->child;
|
||||
if (parent->action == MCKEY_ESCAPE && old_esc_mode)
|
||||
{
|
||||
if (no_delay)
|
||||
{
|
||||
GET_TIME (esctime);
|
||||
if (this == NULL)
|
||||
{
|
||||
/* Shouldn't happen */
|
||||
fputs ("Internal error\n", stderr);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
goto nodelay_try_again;
|
||||
}
|
||||
esctime.tv_sec = -1;
|
||||
c = xgetch_second ();
|
||||
if (c == -1)
|
||||
{
|
||||
pending_keys = seq_append = NULL;
|
||||
this = NULL;
|
||||
return ESC_CHAR;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (no_delay)
|
||||
goto nodelay_try_again;
|
||||
c = tty_lowlevel_getch ();
|
||||
}
|
||||
}
|
||||
else
|
||||
if (this->child == NULL)
|
||||
{
|
||||
/* We got a complete match, return and reset search */
|
||||
int code;
|
||||
|
@ -1880,36 +1862,67 @@ get_key_code (int no_delay)
|
|||
this = NULL;
|
||||
return correct_key_code (code);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this->next != NULL)
|
||||
this = this->next;
|
||||
else
|
||||
/* No match yet, but it may be a prefix for a valid seq */
|
||||
if (!push_char (c))
|
||||
{
|
||||
if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
|
||||
{
|
||||
/* Convert escape-digits to F-keys */
|
||||
if (g_ascii_isdigit (c))
|
||||
c = KEY_F (c - '0');
|
||||
else if (c == ' ')
|
||||
c = ESC_CHAR;
|
||||
else
|
||||
c = ALT (c);
|
||||
|
||||
pending_keys = seq_append = NULL;
|
||||
this = NULL;
|
||||
return correct_key_code (c);
|
||||
}
|
||||
/* Did not find a match or {c} was changed in the if above,
|
||||
so we have to return everything we had skipped
|
||||
*/
|
||||
push_char (c);
|
||||
pending_keys = seq_buffer;
|
||||
goto pend_send;
|
||||
}
|
||||
parent = this;
|
||||
this = this->child;
|
||||
if (parent->action == MCKEY_ESCAPE && old_esc_mode)
|
||||
{
|
||||
if (no_delay)
|
||||
{
|
||||
GET_TIME (esctime);
|
||||
goto nodelay_try_again;
|
||||
}
|
||||
esctime.tv_sec = -1;
|
||||
c = getch_with_timeout (old_esc_mode_timeout);
|
||||
if (c == -1)
|
||||
{
|
||||
pending_keys = seq_append = NULL;
|
||||
this = NULL;
|
||||
return ESC_CHAR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (no_delay)
|
||||
goto nodelay_try_again;
|
||||
c = tty_lowlevel_getch ();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* c != this->ch. Try other keys with this prefix */
|
||||
if (this->next != NULL)
|
||||
{
|
||||
this = this->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* No match found. Is it one of our ESC <key> specials? */
|
||||
if ((parent != NULL) && (parent->action == MCKEY_ESCAPE))
|
||||
{
|
||||
/* Convert escape-digits to F-keys */
|
||||
if (g_ascii_isdigit (c))
|
||||
c = KEY_F (c - '0');
|
||||
else if (c == ' ')
|
||||
c = ESC_CHAR;
|
||||
else
|
||||
c = ALT (c);
|
||||
|
||||
pending_keys = seq_append = NULL;
|
||||
this = NULL;
|
||||
return correct_key_code (c);
|
||||
}
|
||||
|
||||
/* Unknown sequence. Maybe a prefix of a longer one. Save it. */
|
||||
push_char (c);
|
||||
pending_keys = seq_buffer;
|
||||
goto pend_send;
|
||||
|
||||
} /* while (this != NULL) */
|
||||
|
||||
this = NULL;
|
||||
return correct_key_code (c);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue