[PATCH v7 3/3] Cygwin: console: Fix master thread for OpenConsole.exe

Takashi Yano takashi.yano@nifty.ne.jp
Tue Apr 7 12:26:30 GMT 2026


If the console is originating from a pseudo console, current master
thread code does not work as expected if ENABLE_VIRTUAL_TERMINAL_INPUT
flag is set, particularly when OpenConsole.exe is used. This is because
the pseudo console does not preserve all the key event as is.
All bKeyDown == 0 events will be omitted from the input record written
by WriteConsoleInput() and events regarding pressing shift/control/alt
keys will be dropped as well.

This patch adds strip_inrec() function to remove all the key events
of bKeyDown == 0 or UnicodeChar == 0 before comparing/writing input
record. This function is called only when the console is originating
from a pseudo console and ENABLE_VIRTUAL_TERMINAL_INPUT flag is set.

Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
---
 winsup/cygwin/fhandler/console.cc | 42 +++++++++++++++++++++++++++++++
 1 file changed, 42 insertions(+)

diff --git a/winsup/cygwin/fhandler/console.cc b/winsup/cygwin/fhandler/console.cc
index 39c4f6ff0..3da3a80db 100644
--- a/winsup/cygwin/fhandler/console.cc
+++ b/winsup/cygwin/fhandler/console.cc
@@ -305,6 +305,23 @@ cons_master_thread (VOID *arg)
   return 0;
 }
 
+static inline DWORD
+strip_inrec (INPUT_RECORD *r, DWORD n)
+{
+  /* Pseudo console with OpenConsole.exe removes the events
+     whose bKeyDown is 0 as well as ones whose charcode is 0. */
+  DWORD j = 0;
+  for (DWORD i = 0; i < n; i++)
+    {
+      if (r[i].EventType != KEY_EVENT)
+	r[j++] = r[i];
+      else if (r[i].Event.KeyEvent.bKeyDown
+	       && r[i].Event.KeyEvent.uChar.UnicodeChar)
+	r[j++] = r[i];
+    }
+  return j;
+}
+
 /* Compare two INPUT_RECORD sequences */
 static inline bool
 inrec_eq (const INPUT_RECORD *a, const INPUT_RECORD *b, DWORD n)
@@ -417,6 +434,8 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
   while (con.owner == GetCurrentProcessId ())
     {
       DWORD total_read, n, i;
+      DWORD mode;
+      bool need_strip = false;
 
       if (con.disable_master_thread)
 	{
@@ -472,6 +491,23 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
 	{
 	case WAIT_OBJECT_0:
 	  acquire_attach_mutex (mutex_timeout);
+	  /* When ENABLE_VIRTUAL_TERMINAL_INPUT is set, the key events
+	     are not preserved as is. Particularly, when OpenConsole.exe
+	     is used, the following key events are simlified so much.
+	     Writing the events:
+	         press shift key -> press 'A' key ->
+	         release 'A' key -> release shift key
+	     results in only one key event whth:
+	         uChar.UnicodeChar = 0x41,
+		 wVirtualKeyCode = 0,
+		 wVirtualScanCode = 0,
+		 dwControlKeyState = 0,
+		 bKeyDown = 1
+	     Therefore, we need fixup the input record by calling
+	     strip_inrec() if the ENABLE_VIRTUAL_TERMINAL_INPUT flag is
+	     set, so that the input records are compared as expected. */
+	  GetConsoleMode (p->input_handle, &mode);
+	  need_strip = inside_pcon && (mode & ENABLE_VIRTUAL_TERMINAL_INPUT);
 	  total_read = 0;
 	  while (cygwait (p->input_handle, (DWORD) 0) == WAIT_OBJECT_0
 		 && total_read < inrec_size)
@@ -483,6 +519,8 @@ fhandler_console::cons_master_thread (handle_set_t *p, tty *ttyp)
 	      total_read += len;
 	    }
 	  release_attach_mutex ();
+	  if (need_strip)
+	    total_read = strip_inrec (input_rec, total_read);
 	  break;
 	case WAIT_TIMEOUT:
 	  con.num_processed = 0;
@@ -607,6 +645,8 @@ remove_record:
 	      acquire_attach_mutex (mutex_timeout);
 	      PeekConsoleInputW (p->input_handle, input_tmp, inrec_size, &n);
 	      release_attach_mutex ();
+	      if (need_strip)
+		n = strip_inrec (input_tmp, n);
 	      if (n < min (total_read, inrec_size))
 		break; /* Someone has read input without acquiring
 			  input_mutex. ConEmu cygwin-connector? */
@@ -625,6 +665,8 @@ remove_record:
 		  n += len;
 		}
 	      release_attach_mutex ();
+	      if (need_strip)
+		n = strip_inrec (input_tmp, n);
 	      bool fixed = false;
 	      for (DWORD ofs = n - total_read; ofs > 0; ofs--)
 		{
-- 
2.51.0



More information about the Cygwin-patches mailing list