When the cursor position report ("CSI m;n R") is transferred from
cyg-pipe to nat-pipe, it is undesirably converted into Fn3 key by
pseudo console. This patch adds a workaround to prevent this
unintended conversion for cursor position report by enabling
ENABLE_VIRTUAL_TERMINAL_INPUT flag temporarily.Addresses: https://cygwin.com/pipermail/cygwin/2026-June/259776.html Reported-by: Koichi Murase <[email protected]> Signed-off-by: Takashi Yano <[email protected]> Reviewed-by: --- winsup/cygwin/fhandler/pty.cc | 53 +++++++++++++++++++++++++++++- winsup/cygwin/local_includes/tty.h | 1 + 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc index e60e30230..e0fc67ae1 100644 --- a/winsup/cygwin/fhandler/pty.cc +++ b/winsup/cygwin/fhandler/pty.cc @@ -2445,7 +2445,6 @@ fhandler_pty_master::write (const void *ptr, size_t len) ixput = 0; state = 0; wp_tid = 0; - get_ttyp ()->req_xfer_input = false; if (!get_ttyp ()->pcon_start && !get_ttyp ()->pcon_start_csi_c) break; } @@ -2460,6 +2459,20 @@ fhandler_pty_master::write (const void *ptr, size_t len) && pp && pp->pgid == get_ttyp ()->getpgid () && get_ttyp ()->pty_input_state_eq (tty::to_cyg)) { + if (!get_ttyp ()->req_xfer_input) + { + HANDLE pcon_handle_ready_event = + get_ttyp ()->pcon_handle_ready_event; + get_handle_from_process (get_ttyp ()->nat_pipe_owner_pid, + pcon_handle_ready_event); + if (pcon_handle_ready_event) + { + cygwait (pcon_handle_ready_event, INFINITE); + ResetEvent (pcon_handle_ready_event); + CloseHandle (pcon_handle_ready_event); + } + } + /* This accept_input() call is needed in order to transfer input which is not accepted yet to non-cygwin pipe. */ WaitForSingleObject (input_mutex, mutex_timeout); @@ -2473,6 +2486,7 @@ fhandler_pty_master::write (const void *ptr, size_t len) release_attach_mutex (); ReleaseMutex (input_mutex); } + get_ttyp ()->req_xfer_input = false; get_ttyp ()->pcon_start_pid = 0; } if (len == 0) @@ -3767,6 +3781,8 @@ fhandler_pty_slave::setup_pseudoconsole () si.StartupInfo.hStdOutput = NULL; si.StartupInfo.hStdError = NULL; + get_ttyp ()->pcon_handle_ready_event = + CreateEvent (&sec_none_nih, TRUE, FALSE, NULL); get_ttyp ()->pcon_activated = true; get_ttyp ()->pcon_start = true; get_ttyp ()->pcon_start_pid = myself->pid; @@ -3853,6 +3869,7 @@ skip_create: /* Discard the pseudo console handler container here. Reconstruct it temporary when it is needed. */ HeapFree (GetProcessHeap (), 0, hp); + SetEvent (get_ttyp ()->pcon_handle_ready_event); } acquire_attach_mutex (mutex_timeout); @@ -4060,6 +4077,11 @@ fhandler_pty_slave::close_pseudoconsole (tty *ttyp, DWORD force_switch_to) ttyp->pcon_start = false; ttyp->pcon_start_pid = 0; } + if (ttyp->pcon_handle_ready_event) + { + CloseHandle (ttyp->pcon_handle_ready_event); + ttyp->pcon_handle_ready_event = NULL; + } } else { /* Just detach from the pseudo console if I am not owner. */ @@ -4308,6 +4330,26 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp, UINT cp_from = 0, cp_to = 0; + HANDLE h_pcon_in = NULL; + DWORD con_mode = 0; + if (ttyp->pcon_activated && dir == tty::to_nat) + { + /* Escape sequences such as the cursor position report ("CSI m;n R") + are undesirably converted into an Fn3 key by pseudo console. + To privent this unintended conversion, temporarily enable + ENABLE_VIRTUAL_TERMINAL_INPUT flag. */ + h_pcon_in = + get_handle_from_process (ttyp->nat_pipe_owner_pid, ttyp->h_pcon_in); + if (h_pcon_in) + { + DWORD target_pid = ttyp->nat_pipe_owner_pid; + DWORD resume_pid = attach_console_temporarily (target_pid); + GetConsoleMode (h_pcon_in, &con_mode); + SetConsoleMode (h_pcon_in, con_mode | ENABLE_VIRTUAL_TERMINAL_INPUT); + resume_from_temporarily_attach (resume_pid); + } + } + if (dir == tty::to_nat) { cp_from = ttyp->term_code_page; @@ -4422,6 +4464,15 @@ fhandler_pty_slave::transfer_input (tty::xfer_dir dir, HANDLE from, tty *ttyp, } CloseHandle (to); + if (h_pcon_in) + { + DWORD target_pid = ttyp->nat_pipe_owner_pid; + DWORD resume_pid = attach_console_temporarily (target_pid); + SetConsoleMode (h_pcon_in, con_mode); + resume_from_temporarily_attach (resume_pid); + CloseHandle (h_pcon_in); + } + ttyp->pty_input_state = dir; /* Fix input_available_event which indicates availability in cyg pipe. */ if (dir == tty::to_nat) /* all data is transfered to nat pipe, diff --git a/winsup/cygwin/local_includes/tty.h b/winsup/cygwin/local_includes/tty.h index 4fbebd820..0adad03e6 100644 --- a/winsup/cygwin/local_includes/tty.h +++ b/winsup/cygwin/local_includes/tty.h @@ -125,6 +125,7 @@ private: bool pcon_start_csi_c; bool switch_to_nat_pipe; DWORD nat_pipe_owner_pid; + HANDLE pcon_handle_ready_event; UINT term_code_page; ULONGLONG fwd_last_time; bool fwd_not_empty; -- 2.51.0
