mirror of
https://github.com/MidnightCommander/mc
synced 2024-12-22 20:36:50 +03:00
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.
|
Keyboard support routines.
|
||||||
|
|
||||||
Copyright (C) 1994, 1995, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
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.
|
The Free Software Foundation, Inc.
|
||||||
|
|
||||||
Written by:
|
Written by:
|
||||||
@ -10,6 +10,8 @@
|
|||||||
Janne Kukonlehto, 1994, 1995
|
Janne Kukonlehto, 1994, 1995
|
||||||
Jakub Jelinek, 1995
|
Jakub Jelinek, 1995
|
||||||
Norbert Warmuth, 1997
|
Norbert Warmuth, 1997
|
||||||
|
Denys Vlasenko <vda.linux@googlemail.com>, 2013
|
||||||
|
Slava Zanko <slavazanko@gmail.com>, 2013
|
||||||
|
|
||||||
This file is part of the Midnight Commander.
|
This file is part of the Midnight Commander.
|
||||||
|
|
||||||
@ -1129,14 +1131,14 @@ correct_key_code (int code)
|
|||||||
/* --------------------------------------------------------------------------------------------- */
|
/* --------------------------------------------------------------------------------------------- */
|
||||||
|
|
||||||
static int
|
static int
|
||||||
xgetch_second (void)
|
getch_with_timeout (unsigned int delay_us)
|
||||||
{
|
{
|
||||||
fd_set Read_FD_Set;
|
fd_set Read_FD_Set;
|
||||||
int c;
|
int c;
|
||||||
struct timeval time_out;
|
struct timeval time_out;
|
||||||
|
|
||||||
time_out.tv_sec = old_esc_mode_timeout / 1000000;
|
time_out.tv_sec = delay_us / 1000000u;
|
||||||
time_out.tv_usec = old_esc_mode_timeout % 1000000;
|
time_out.tv_usec = delay_us % 1000000u;
|
||||||
tty_nodelay (TRUE);
|
tty_nodelay (TRUE);
|
||||||
FD_ZERO (&Read_FD_Set);
|
FD_ZERO (&Read_FD_Set);
|
||||||
FD_SET (input_fd, &Read_FD_Set);
|
FD_SET (input_fd, &Read_FD_Set);
|
||||||
@ -1745,14 +1747,31 @@ get_key_code (int no_delay)
|
|||||||
if (pending_keys != NULL)
|
if (pending_keys != NULL)
|
||||||
{
|
{
|
||||||
int d;
|
int d;
|
||||||
|
gboolean bad_seq;
|
||||||
|
|
||||||
d = *pending_keys++;
|
d = *pending_keys++;
|
||||||
while (d == ESC_CHAR && *pending_keys != '\0')
|
while (d == ESC_CHAR)
|
||||||
d = ALT (*pending_keys++);
|
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;
|
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)
|
if (d > 127 && d < 256 && use_8th_bit_as_meta)
|
||||||
d = ALT (d & 0x7f);
|
d = ALT (d & 0x7f);
|
||||||
|
|
||||||
@ -1828,49 +1847,12 @@ get_key_code (int no_delay)
|
|||||||
this = keys->child;
|
this = keys->child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (this != NULL)
|
while (this != NULL)
|
||||||
{
|
{
|
||||||
if (c == this->ch)
|
if (c == this->ch)
|
||||||
{
|
{
|
||||||
if (this->child)
|
if (this->child == NULL)
|
||||||
{
|
|
||||||
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
|
|
||||||
{
|
{
|
||||||
/* We got a complete match, return and reset search */
|
/* We got a complete match, return and reset search */
|
||||||
int code;
|
int code;
|
||||||
@ -1880,36 +1862,67 @@ get_key_code (int no_delay)
|
|||||||
this = NULL;
|
this = NULL;
|
||||||
return correct_key_code (code);
|
return correct_key_code (code);
|
||||||
}
|
}
|
||||||
}
|
/* No match yet, but it may be a prefix for a valid seq */
|
||||||
else
|
if (!push_char (c))
|
||||||
{
|
|
||||||
if (this->next != NULL)
|
|
||||||
this = this->next;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
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;
|
pending_keys = seq_buffer;
|
||||||
goto pend_send;
|
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;
|
this = NULL;
|
||||||
return correct_key_code (c);
|
return correct_key_code (c);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user