[PATCH v5 1/3] Cygwin: pty: Use OpenConsole.exe if available

Takashi Yano takashi.yano@nifty.ne.jp
Wed Mar 25 12:41:09 GMT 2026


Hi Johannes,

Thanks for reviewing!

On Mon, 16 Mar 2026 10:55:29 +0100 (CET)
Johannes Schindelin wrote:
> Hi Takashi,
> 
> On Thu, 12 Mar 2026, Takashi Yano wrote:
> 
> > This patch replaces legacy conhost.exe with OpenConsole.exe if
> > it is available. This enables various new features such as mouse
> > support in pseudo console and bug fixes. The legacy conhost has
> > problems, e.g. character attributes are mangled or ignored, and
> > terminal reports are not passed through. This patch resolve the
> > issue by loading /usr/bin/OpenColnsole.exe instead of conhost.exe
> 
> I know that Corinna cares about typos in commit messages, so I'd like to
> point out that "OpenColnsole" has an extra "l" in it.
> 
> > if it is available.
> 
> My biggest issue with this patch: There is no opt-out mechanism: No
> CYGWIN=disable_openconsole or MSYS=disable_openconsole flag. If
> /usr/bin/OpenConsole.exe exists and is buggy, or this here patch, the user
> is stuck.

Thnaks. I'll add CYGWIN=use_lagacy_pcon option.

> My second-biggest issue: The commit message leaves too many legitimate
> questions unanswered. It says "various new features such as mouse support"
> and "terminal reports are not passed through" without specifics, without

To be honest, aside from the few points I mentioned here, I’m not aware
of any other improvements in OpenConsole.exe.
I tested only mouse support and attached text from Thomas.
These improvements seems already applied to conhost.exe in
latest Windows 11.

Any idea > Thomas?

> linking to any bug report, and without explaining why reimplementing
> `CreatePseudoConsole()` using undocumented NT kernel APIs
> (`\Device\ConDrv\Server`) is necessary (vs. just passing the
> `OpenConsole.exe` path to the standard `CreatePseudoConsole()` somehow).
> The message also doesn't address the maintenance burden of vendoring
> Windows Terminal code.

I expect the APIs will not be changed so often, because the same code
works even for old conhost.exe.

> Another concern I have, which is however very easily addressed, is that
> this patch does two things for the price of one. It would be better to
> separate the CSIc handling from the `OpenConsole.exe` integration. This
> would make it possible to fast-track one without the other, and make
> reviews of future iterations much easier.

I'll separate the CSIc matter.

> > +extern "C" WINBASEAPI HRESULT WINAPI
> 
> This should probably not be exported from cygwin1.dll, it is for
> internal use only.
> 
> > +CreatePseudoConsole_new (COORD size, HANDLE h_input, HANDLE h_output,
> > +			 DWORD flags, HPCON *hpcon)

Thanks. Fixed.

> > +{
> > +
> > +  HANDLE h_con_server, h_con_reference;
> > +  NTSTATUS status;
> > +  BOOL res;
> > +  HANDLE h_read_pipe, h_write_pipe;
> > +  BOOL inherit_cursor;
> > +  path_conv conhost ("/usr/bin/OpenConsole.exe");
> 
> Is it really a good idea to hard-code that path? That would not only
> preclude an `OpenConsole.exe` that is in the `PATH` to be used, it also
> suggests that you plan on building a Cygwin version of that executable
> (because that location should only contain native Cygwin applications and
> DLLs).

I imagine we would have openconsole cygwin package which install
OpenConsole.exe into /usr/bin/.

> > +  InitializeProcThreadAttributeList (NULL, 1, 0, &list_size);
> 
> This requires a corresponding `DeleteProcThreadAttributeList()` call.

This call is for retrieving list_size. Nothing is allocated with this call.
 
> > +  hpcon_internal->hWritePipe = h_write_pipe;
> > +  hpcon_internal->hConDrvReference = h_con_reference;
> > +  hpcon_internal->hConHostProcess = pi.hProcess;
> > +  *hpcon = (HPCON) hpcon_internal;
> > +
> > +  HeapFree (GetProcessHeap(), 0, attr_list);
> > +  CloseHandle (h_con_server);
> > +  CloseHandle (pi.hThread);
> 
> I see `h_read_pipe` being closed in the failure mode, but not in the
> success one.
> 
> `h_write_pipe` is stored in `*h_pcon`, so it becomes the caller's
> responsibility. And `h_con_server`/`pi.hThread` are closed properly, but I
> don't see where `h_read_pipe` is handled properly.

Indeed. My fault. Fixed.

> > -  if (get_ttyp ()->pcon_start)
> > +  int pcon_start_mode =
> > +    get_ttyp ()->pcon_start ? 1 : (get_ttyp ()->pcon_start_csi_c ? 2 : 0);
> > +  if (pcon_start_mode)
> 
> Does this need to be made thread-safe in case `write()` is called
> simultaneously on two separate processor cores?

Yeah! Thanks for pointing this out. This is not a bug only of
OpenConsole.exe implementation, but also regacy psseudo console.
I'll submit an indivisual patch.

> > @@ -2693,6 +2865,7 @@ workarounds_for_pseudo_console_output (char *outbuf, DWORD rlen)
> >    int arg = 0;
> >    bool saw_greater_than_sign = false;
> >    bool saw_question_mark = false;
> > +  static bool in_pcon_start = false;
> >    for (DWORD i=0; i<rlen; i++)
> >      if (state == 0 && outbuf[i] == '\033')
> >        {
> > @@ -2774,8 +2947,21 @@ workarounds_for_pseudo_console_output (char *outbuf, DWORD rlen)
> >  	    start_at = i;
> >  	    state = 1;
> >  	  }
> > +	else if (arg == 6 && outbuf[i] == 'n' && ttyp->pcon_start)
> > +	  {
> > +	    in_pcon_start = true;
> 
> Should this variable be reset in error paths below? This might be
> _particularly_ nasty to debug because `in_pcon_start` is `static` and will
> therefore persist indefinitely.

Do you mean in the else block:
    else
      { /* Never reached */
        is_csi = false;
        is_osc = false;
        saw_greater_than_sign = false;
        saw_question_mark = false;
        arg = 0;
        state = 0;
      }
?

Maybe. Added.

-- 
Takashi Yano <takashi.yano@nifty.ne.jp>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: xtextattr1
Type: application/octet-stream
Size: 390 bytes
Desc: not available
URL: <https://cygwin.com/pipermail/cygwin-patches/attachments/20260325/26fffcc1/attachment.obj>


More information about the Cygwin-patches mailing list