[PATCH 2/6] Cygwin: pty: Add workaround for handling of backspace when pcon enabled

Takashi Yano takashi.yano@nifty.ne.jp
Tue Mar 17 12:23:06 GMT 2026


In Windows 11, pseudo console has a weird behaviour that the Ctrl-H
is translated into Ctrl-Backspace (not Backspace). Similary, Backspace
(0x7f) is translated into Ctrl-H. Due to this behaviour, inrec_eq()
in cons_master_thread() fails to compare backspace/Ctrl-H events in
the input record sequence. This patch is a workaround for that issue
which pushes the Ctrl-H or Backspace as a ConsoleInput event instead
of sending char code to pseudo console.

Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
Reviewed-by:
---
 winsup/cygwin/fhandler/pty.cc | 64 +++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc
index 371e67103..bde88ab0e 100644
--- a/winsup/cygwin/fhandler/pty.cc
+++ b/winsup/cygwin/fhandler/pty.cc
@@ -2290,9 +2290,73 @@ fhandler_pty_master::write (const void *ptr, size_t len)
 	    }
 	}
 
+      /* In Windows 11, pseudo console has a weird behaviour that
+	 Ctrl-H is translated into Ctrl-Backspace (not Backspace).
+	 Similary, backspace (0x7f) is translated into Ctrl-H. The
+	 following code is a workaround for that issue. */
+      char *bs_pos1 = (char *) memchr (buf, '\010' /* ^H */, nlen);
+      char *bs_pos2 = (char *) memchr (buf, '\177' /* BS */, nlen);
+      HANDLE h_pcon_in = get_ttyp ()->h_pcon_in;
+      DWORD resume_pid = 0;
+      if ((bs_pos1 || bs_pos2)
+	  && !nat_pipe_owner_self (get_ttyp ()->nat_pipe_owner_pid))
+	{
+	  HANDLE pcon_owner = OpenProcess (PROCESS_DUP_HANDLE, FALSE,
+					   get_ttyp ()->nat_pipe_owner_pid);
+	  DuplicateHandle (pcon_owner, h_pcon_in,
+			   GetCurrentProcess (), &h_pcon_in,
+			   0, FALSE, DUPLICATE_SAME_ACCESS);
+	  CloseHandle(pcon_owner);
+	  resume_pid =
+	    attach_console_temporarily (get_ttyp()->nat_pipe_owner_pid);
+	}
+
       DWORD n;
+      while (bs_pos1)
+	{
+	  if (bs_pos1 - buf > 0)
+	    WriteFile (to_slave_nat, buf, bs_pos1 - buf, &n, NULL);
+	  INPUT_RECORD r;
+	  r.EventType = KEY_EVENT;
+	  r.Event.KeyEvent.bKeyDown = 1;
+	  r.Event.KeyEvent.wRepeatCount = 0;
+	  r.Event.KeyEvent.wVirtualKeyCode = 0;
+	  r.Event.KeyEvent.wVirtualScanCode = 0;
+	  r.Event.KeyEvent.uChar.AsciiChar = '\010'; /* ^H */
+	  r.Event.KeyEvent.dwControlKeyState = LEFT_CTRL_PRESSED;
+	  WriteConsoleInput(h_pcon_in, &r, 1, &n);
+	  r.Event.KeyEvent.bKeyDown = 0;
+	  WriteConsoleInput(h_pcon_in, &r, 1, &n);
+	  nlen -= bs_pos1 - buf + 1;
+	  buf = bs_pos1 + 1;
+	  bs_pos1 = (char *) memchr (buf, '\010' /* ^H */, nlen);
+	}
+      while (bs_pos2)
+	{
+	  if (bs_pos2 - buf > 0)
+	    WriteFile (to_slave_nat, buf, bs_pos2 - buf, &n, NULL);
+	  INPUT_RECORD r;
+	  r.EventType = KEY_EVENT;
+	  r.Event.KeyEvent.bKeyDown = 1;
+	  r.Event.KeyEvent.wRepeatCount = 0;
+	  r.Event.KeyEvent.wVirtualKeyCode = 0;
+	  r.Event.KeyEvent.wVirtualScanCode = 0;
+	  r.Event.KeyEvent.uChar.AsciiChar = '\177'; /* BS */
+	  r.Event.KeyEvent.dwControlKeyState = 0;
+	  WriteConsoleInput(h_pcon_in, &r, 1, &n);
+	  r.Event.KeyEvent.bKeyDown = 0;
+	  WriteConsoleInput(h_pcon_in, &r, 1, &n);
+	  nlen -= bs_pos2 - buf + 1;
+	  buf = bs_pos2 + 1;
+	  bs_pos2 = (char *) memchr (buf, '\177' /* BS */, nlen);
+	}
       if (nlen)
 	WriteFile (to_slave_nat, buf, nlen, &n, NULL);
+
+      if (resume_pid)
+	resume_from_temporarily_attach (resume_pid);
+      if (h_pcon_in)
+	CloseHandle(h_pcon_in);
       ReleaseMutex (input_mutex);
 
       return orig_len;
-- 
2.51.0



More information about the Cygwin-patches mailing list