Cygwin: console: Fix read() in non-canonical mode.

- In non-canonical mode, cygwin console returned only one character
  even if several keys are typed before read() called. This patch
  fixes this behaviour.
This commit is contained in:
Takashi Yano 2019-09-14 04:34:39 +09:00 committed by Ken Brown
parent 3355a6d4b9
commit fca4cda7a4

View File

@ -499,21 +499,31 @@ fhandler_console::process_input_message (void)
termios *ti = &(get_ttyp ()->ti); termios *ti = &(get_ttyp ()->ti);
DWORD nread; /* Per MSDN, max size of buffer required is below 64K. */
INPUT_RECORD input_rec; #define INREC_SIZE (65536 / sizeof (INPUT_RECORD))
const char *toadd = NULL;
if (!ReadConsoleInputW (get_handle (), &input_rec, 1, &nread)) fhandler_console::input_states stat = input_processing;
DWORD total_read, i;
INPUT_RECORD input_rec[INREC_SIZE];
if (!PeekConsoleInputW (get_handle (), input_rec, INREC_SIZE, &total_read))
{ {
termios_printf ("ReadConsoleInput failed, %E"); termios_printf ("PeekConsoleInput failed, %E");
return input_error; return input_error;
} }
const WCHAR &unicode_char = input_rec.Event.KeyEvent.uChar.UnicodeChar; for (i = 0; i < total_read; i ++)
const DWORD &ctrl_key_state = input_rec.Event.KeyEvent.dwControlKeyState; {
DWORD nread = 1;
const char *toadd = NULL;
const WCHAR &unicode_char =
input_rec[i].Event.KeyEvent.uChar.UnicodeChar;
const DWORD &ctrl_key_state =
input_rec[i].Event.KeyEvent.dwControlKeyState;
/* check the event that occurred */ /* check the event that occurred */
switch (input_rec.EventType) switch (input_rec[i].EventType)
{ {
case KEY_EVENT: case KEY_EVENT:
@ -521,39 +531,39 @@ fhandler_console::process_input_message (void)
#ifdef DEBUGGING #ifdef DEBUGGING
/* allow manual switching to/from raw mode via ctrl-alt-scrolllock */ /* allow manual switching to/from raw mode via ctrl-alt-scrolllock */
if (input_rec.Event.KeyEvent.bKeyDown if (input_rec[i].Event.KeyEvent.bKeyDown
&& input_rec.Event.KeyEvent.wVirtualKeyCode == VK_SCROLL && input_rec[i].Event.KeyEvent.wVirtualKeyCode == VK_SCROLL
&& (ctrl_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) && (ctrl_key_state & (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED))
== (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED)) == (LEFT_ALT_PRESSED | LEFT_CTRL_PRESSED))
{ {
set_raw_win32_keyboard_mode (!con.raw_win32_keyboard_mode); set_raw_win32_keyboard_mode (!con.raw_win32_keyboard_mode);
return input_processing; continue;
} }
#endif #endif
if (con.raw_win32_keyboard_mode) if (con.raw_win32_keyboard_mode)
{ {
__small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK", __small_sprintf (tmp, "\033{%u;%u;%u;%u;%u;%luK",
input_rec.Event.KeyEvent.bKeyDown, input_rec[i].Event.KeyEvent.bKeyDown,
input_rec.Event.KeyEvent.wRepeatCount, input_rec[i].Event.KeyEvent.wRepeatCount,
input_rec.Event.KeyEvent.wVirtualKeyCode, input_rec[i].Event.KeyEvent.wVirtualKeyCode,
input_rec.Event.KeyEvent.wVirtualScanCode, input_rec[i].Event.KeyEvent.wVirtualScanCode,
input_rec.Event.KeyEvent.uChar.UnicodeChar, input_rec[i].Event.KeyEvent.uChar.UnicodeChar,
input_rec.Event.KeyEvent.dwControlKeyState); input_rec[i].Event.KeyEvent.dwControlKeyState);
toadd = tmp; toadd = tmp;
nread = strlen (toadd); nread = strlen (toadd);
break; break;
} }
/* Ignore key up events, except for Alt+Numpad events. */ /* Ignore key up events, except for Alt+Numpad events. */
if (!input_rec.Event.KeyEvent.bKeyDown && if (!input_rec[i].Event.KeyEvent.bKeyDown &&
!is_alt_numpad_event (&input_rec)) !is_alt_numpad_event (&input_rec[i]))
return input_processing; continue;
/* Ignore Alt+Numpad keys. They are eventually handled below after /* Ignore Alt+Numpad keys. They are eventually handled below after
releasing the Alt key. */ releasing the Alt key. */
if (input_rec.Event.KeyEvent.bKeyDown if (input_rec[i].Event.KeyEvent.bKeyDown
&& is_alt_numpad_key (&input_rec)) && is_alt_numpad_key (&input_rec[i]))
return input_processing; continue;
if (ctrl_key_state & SHIFT_PRESSED) if (ctrl_key_state & SHIFT_PRESSED)
con.nModifiers |= 1; con.nModifiers |= 1;
@ -565,7 +575,7 @@ fhandler_console::process_input_message (void)
con.nModifiers |= 8; con.nModifiers |= 8;
/* Allow Backspace to emit ^? and escape sequences. */ /* Allow Backspace to emit ^? and escape sequences. */
if (input_rec.Event.KeyEvent.wVirtualKeyCode == VK_BACK) if (input_rec[i].Event.KeyEvent.wVirtualKeyCode == VK_BACK)
{ {
char c = con.backspace_keycode; char c = con.backspace_keycode;
nread = 0; nread = 0;
@ -581,20 +591,21 @@ fhandler_console::process_input_message (void)
toadd = tmp; toadd = tmp;
} }
/* Allow Ctrl-Space to emit ^@ */ /* Allow Ctrl-Space to emit ^@ */
else if (input_rec.Event.KeyEvent.wVirtualKeyCode else if (input_rec[i].Event.KeyEvent.wVirtualKeyCode
== (wincap.has_con_24bit_colors () ? '2' : VK_SPACE) == (wincap.has_con_24bit_colors () ? '2' : VK_SPACE)
&& (ctrl_key_state & CTRL_PRESSED) && (ctrl_key_state & CTRL_PRESSED)
&& !(ctrl_key_state & ALT_PRESSED)) && !(ctrl_key_state & ALT_PRESSED))
toadd = ""; toadd = "";
else if (unicode_char == 0 else if (unicode_char == 0
/* arrow/function keys */ /* arrow/function keys */
|| (input_rec.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY)) || (input_rec[i].Event.KeyEvent.dwControlKeyState
& ENHANCED_KEY))
{ {
toadd = get_nonascii_key (input_rec, tmp); toadd = get_nonascii_key (input_rec[i], tmp);
if (!toadd) if (!toadd)
{ {
con.nModifiers = 0; con.nModifiers = 0;
return input_processing; continue;
} }
nread = strlen (toadd); nread = strlen (toadd);
} }
@ -643,7 +654,7 @@ fhandler_console::process_input_message (void)
case MOUSE_EVENT: case MOUSE_EVENT:
send_winch_maybe (); send_winch_maybe ();
{ {
MOUSE_EVENT_RECORD& mouse_event = input_rec.Event.MouseEvent; MOUSE_EVENT_RECORD& mouse_event = input_rec[i].Event.MouseEvent;
/* As a unique guard for mouse report generation, /* As a unique guard for mouse report generation,
call mouse_aware() which is common with select(), so the result call mouse_aware() which is common with select(), so the result
of select() and the actual read() will be consistent on the of select() and the actual read() will be consistent on the
@ -816,7 +827,7 @@ fhandler_console::process_input_message (void)
case FOCUS_EVENT: case FOCUS_EVENT:
if (con.use_focus) if (con.use_focus)
{ {
if (input_rec.Event.FocusEvent.bSetFocus) if (input_rec[i].Event.FocusEvent.bSetFocus)
__small_sprintf (tmp, "\033[I"); __small_sprintf (tmp, "\033[I");
else else
__small_sprintf (tmp, "\033[O"); __small_sprintf (tmp, "\033[O");
@ -828,10 +839,13 @@ fhandler_console::process_input_message (void)
case WINDOW_BUFFER_SIZE_EVENT: case WINDOW_BUFFER_SIZE_EVENT:
if (send_winch_maybe ()) if (send_winch_maybe ())
return input_winch; {
stat = input_winch;
goto out;
}
/* fall through */ /* fall through */
default: default:
return input_processing; continue;
} }
if (toadd) if (toadd)
@ -839,14 +853,24 @@ fhandler_console::process_input_message (void)
ssize_t ret; ssize_t ret;
line_edit_status res = line_edit (toadd, nread, *ti, &ret); line_edit_status res = line_edit (toadd, nread, *ti, &ret);
if (res == line_edit_signalled) if (res == line_edit_signalled)
return input_signalled; {
stat = input_signalled;
goto out;
}
else if (res == line_edit_input_done) else if (res == line_edit_input_done)
{ {
input_ready = true; input_ready = true;
return input_ok; stat = input_ok;
if (ti->c_lflag & ICANON)
goto out;
} }
} }
return input_processing; }
out:
/* Discard processed recored. */
DWORD dummy;
ReadConsoleInputW (get_handle (), input_rec, min (total_read, i+1), &dummy);
return stat;
} }
void void