Hi Takashi, On Thu, 18 Dec 2025, Takashi Yano wrote:
> In Windows 11, the command "rlwrap cmd" outputs garbaged screen. > This is because rlwrap treats text between NLs as a line, while > pseudo console sometimes omits NL before "CSIm;nH". This issue > does not happen in Windows 10. This patch fixes the issue by > adding CR NL before "CSIm:nH" into the output from the pseudo > console if the OS is Windows 11. > > Reviewed-by: Corinna Vinschen <[email protected]> > Signed-off-by: Takashi Yano <[email protected]> > --- > winsup/cygwin/fhandler/pty.cc | 44 +++++++++++++++++++++++++++ > winsup/cygwin/local_includes/wincap.h | 2 ++ > winsup/cygwin/wincap.cc | 11 +++++++ > 3 files changed, 57 insertions(+) > > diff --git a/winsup/cygwin/fhandler/pty.cc b/winsup/cygwin/fhandler/pty.cc > index 3b0b4f073..7acedc165 100644 > --- a/winsup/cygwin/fhandler/pty.cc > +++ b/winsup/cygwin/fhandler/pty.cc > @@ -2775,6 +2775,50 @@ fhandler_pty_master::pty_master_fwd_thread (const > master_fwd_thread_param_t *p) > else > state = 0; > > + /* Workaround for rlwrap in Win11. rlwrap treats text between > + NLs as a line, however, pseudo console in Win11 somtimes > + omits NL before "CSIm;nH". This does not happen in Win10. */ > + if (wincap.has_pcon_omit_nl_before_cursor_move ()) > + { > + state = 0; The pattern of the first two `for()` loops in this function is to reset both `state` and `start_at` (even if the `/* Remove OSC Ps ; ? BEL/ST */` loop seems not to reset either, which might be a bug). Should `start_at` be re-set to 0 here, too? > + for (DWORD i = 0; i < rlen; i++) > + if (state == 0 && outbuf[i] == '\033') > + { > + start_at = i; > + state++; > + continue; > + } > + else if (state == 1 && outbuf[i] == '[') > + { > + state++; > + continue; > + } > + else if (state == 2 > + && (isdigit (outbuf[i]) || outbuf[i] == ';')) > + continue; > + else if (state == 2 && outbuf[i] == 'H') > + { > + /* Add omitted CR NL before "CSIm;nH". However, when the > + cusor is on the bottom-most line, adding NL might cause > + unexpected scrolling. To avoid this, add "CSI H" before > + CR NL. */ > + const char *ins = "\033[H\r\n"; > + const int ins_len = strlen (ins); > + if (rlen + ins_len <= NT_MAX_PATH) How can we avoid this problem when running out of buffer space? Ciao, Johannes > + { > + memmove (&outbuf[start_at + ins_len], > + &outbuf[start_at], rlen - start_at); > + memcpy (&outbuf[start_at], ins, ins_len); > + rlen += ins_len; > + i += ins_len; > + } > + state = 0; > + continue; > + } > + else > + state = 0; > + } > + > if (p->ttyp->term_code_page != CP_UTF8) > { > size_t nlen = NT_MAX_PATH; > diff --git a/winsup/cygwin/local_includes/wincap.h > b/winsup/cygwin/local_includes/wincap.h > index 2416eee1d..0496d807e 100644 > --- a/winsup/cygwin/local_includes/wincap.h > +++ b/winsup/cygwin/local_includes/wincap.h > @@ -34,6 +34,7 @@ struct wincaps > unsigned has_con_broken_tabs : 1; > unsigned has_user_shstk : 1; > unsigned has_alloc_console_with_options : 1; > + unsigned has_pcon_omit_nl_before_cursor_move : 1; > }; > }; > > @@ -92,6 +93,7 @@ public: > bool IMPLEMENT (has_con_broken_tabs) > bool IMPLEMENT (has_user_shstk) > bool IMPLEMENT (has_alloc_console_with_options) > + bool IMPLEMENT (has_pcon_omit_nl_before_cursor_move) > > void disable_case_sensitive_dirs () > { > diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc > index 91caefe9b..f94b9f60b 100644 > --- a/winsup/cygwin/wincap.cc > +++ b/winsup/cygwin/wincap.cc > @@ -33,6 +33,7 @@ static const wincaps wincap_8_1 = { > has_con_broken_tabs:false, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -56,6 +57,7 @@ static const wincaps wincap_10_1507 = { > has_con_broken_tabs:false, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -79,6 +81,7 @@ static const wincaps wincap_10_1607 = { > has_con_broken_tabs:false, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -102,6 +105,7 @@ static const wincaps wincap_10_1703 = { > has_con_broken_tabs:true, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -125,6 +129,7 @@ static const wincaps wincap_10_1709 = { > has_con_broken_tabs:true, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -148,6 +153,7 @@ static const wincaps wincap_10_1803 = { > has_con_broken_tabs:true, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -171,6 +177,7 @@ static const wincaps wincap_10_1809 = { > has_con_broken_tabs:true, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -194,6 +201,7 @@ static const wincaps wincap_10_1903 = { > has_con_broken_tabs:true, > has_user_shstk:false, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -217,6 +225,7 @@ static const wincaps wincap_10_2004 = { > has_con_broken_tabs:true, > has_user_shstk:true, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:false, > }, > }; > > @@ -240,6 +249,7 @@ static const wincaps wincap_11 = { > has_con_broken_tabs:false, > has_user_shstk:true, > has_alloc_console_with_options:false, > + has_pcon_omit_nl_before_cursor_move:true, > }, > }; > > @@ -263,6 +273,7 @@ static const wincaps wincap_11_24h2 = { > has_con_broken_tabs:false, > has_user_shstk:true, > has_alloc_console_with_options:true, > + has_pcon_omit_nl_before_cursor_move:true, > }, > }; > > -- > 2.51.0 > >
