Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DISCUSSION: Is my app running in Terminal? #7434

Open
Tracked by #12000
vefatica opened this issue Aug 27, 2020 · 43 comments
Open
Tracked by #12000

DISCUSSION: Is my app running in Terminal? #7434

vefatica opened this issue Aug 27, 2020 · 43 comments
Labels
Issue-Question For questions or discussion Needs-Tag-Fix Doesn't match tag requirements
Milestone

Comments

@vefatica
Copy link

I've been using

!((BOOL) SendMessage(GetConsoleWindow(), WM_GETICON, 0, 0))

Other ideas? Thanks. - Vince

@ghost ghost added Needs-Triage It's a new issue that the core contributor team needs to triage at the next triage meeting Needs-Tag-Fix Doesn't match tag requirements labels Aug 27, 2020
@zadjii-msft
Copy link
Member

Could you clarify? What exactly are you trying to do?

@zadjii-msft zadjii-msft added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Aug 27, 2020
@DHowett
Copy link
Member

DHowett commented Aug 27, 2020

Looks like somebody is trying to set the icon by literally telling the window manager to replace it. Hm.

@vefatica
Copy link
Author

I'm trying to find out if my app is running in Windows Terminal. I don't care about the icon. If I'm in a console, that evaluates to FALSE; in Terminal to TRUE.

@ghost ghost added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 27, 2020
@DHowett
Copy link
Member

DHowett commented Aug 27, 2020

If you have a reason to detect if you are running inside terminal, we should probably have the discussion as to why you want to detect that.

Any behavior you believe to be Terminal-specific is not, I promise you, and your application will do the wrong thing.

@zadjii-msft zadjii-msft added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Attention The core contributors need to come back around and look at this ASAP. labels Aug 27, 2020
@vefatica
Copy link
Author

Didn't you (a while back) give me a list of Win32 API console functions that wouldn't work as expected in Terminal. I suppose much behavior IS Terminal-specific and I don't want my app doing the wrong thing.

@ghost ghost added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 27, 2020
@zadjii-msft
Copy link
Member

Ah, those functions you should avoid calling in general, not just "in the Windows Terminal". Those are functions that'll work less well in any ConPTY session. This includes the Windows Terminal, ssh sessions, and other terminal emulators as well, like VsCode, hyper, mintty, etc. In those other applications, you might not be able to detect that you're running in the Windows Terminal, but those APIs would still behave weirdly.

Very specifically, GetConsoleWindow is one of those APIs 😉

@zadjii-msft zadjii-msft added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Attention The core contributors need to come back around and look at this ASAP. labels Aug 27, 2020
@vefatica
Copy link
Author

I wish I saw the bigger picture. I don't even know what ConPTY is. For me Windows Terminal is the only alternative to conhost. I don't know how to re-phrase my question.

@ghost ghost added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 27, 2020
@zadjii-msft
Copy link
Member

Don't worry about it, let me help however I can.

In short: The rest of the terminal world (*nix) uses streams of characters to have client applications interact with the Terminal. On windows however, client apps use the Console API to interact with the "terminal" (conhost.exe).

The Console API however is terrible and full of poorly documented, poorly supported APIs. Plus, it only works on Windows, so it's hard for commandline client apps to target both Windows and *nix OSes.

Enter ConPTY - Conpty is a magic layer that translates all the console API calls to streams of characters, so that they could be used by any terminal emulator. This means that terminal no longer needs to understand the ins and outs of the console API - conpty will do that bit for them.

Conpty is what powers the Terminal - fundamentally, the Terminal could be hooked up to a linux commandline client app, and work just fine, via a stream of characters.

This is a very broad overview, but should help explain the situation.

@vefatica
Copy link
Author

Thanks. For me, Terminal is just a way to run command interpreters in Windows. It has features that the Windows console lacks.

My preferred command interpreter is "TCC" (grandson of "4DOS", still from JP Software). I write plugins (DLLs) to extend its capabilities. Having used the console APIs for a long time I'm pretty comfortable with them. Many things don't work in Terminal (and never will) and I'd like one of my plugins (dedicated to console-related things) to decline being loaded if TCC is running in Terminal. Hence, my question.

The SendMessage was just a gimmick. I used WM_GETICON because I saw it sent to (Terminal's version of) GetConsoleWindow().

And FWIW, WindowsTerminal.exe crashed on me a few times after being spied on with Spy++. That is not reliably reproducible.

@zadjii-msft
Copy link
Member

Many things don't work in Terminal (and never will)

What kinds of things are you doing specifically? I'd love to hear more about your use case

@zadjii-msft zadjii-msft added Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something and removed Needs-Attention The core contributors need to come back around and look at this ASAP. labels Aug 27, 2020
@vefatica
Copy link
Author

Hmmm! I could go on for a long time. The plugin interface allows the plugin to export COMMANDs, internal _VARIABLES, variable @functions, and the address of a keystroke-handling function. In all, I have more than 300 items that do quite a variety of things. Here are a very few examples.

CONSIZE - set any of screen buffer size, console window size (characters), and console window position (absolute, relative, and nine canonical centered positions)

CONIMAGE/CONRESTORE - save/restore the console sceeen buffer (text and attributes),

SETICON - set the console's icon (to any from a DLL or EXE)

v:> echo %@iCons[c:\windows\system32\shell32.dll]
329

v:> echo %@keytime[hkcu\environment]
2020-08-23,12:40:21.1293486

v:> echo %@up[v]
7 days 1 hour 34 minutes 17 seconds

v:> echo %@up[d]
7.06666

v:> echo %_ruler
....+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8....+....9....+....0....+....1....+....2....+...

My keyhandler's most useful function is bound to Ctrl-Del. Leaving the current prompt fixed, it erases the text above, one line at a time, while scrolling the text further-above down (to just above the command line). There is no viewport/history distinction as in Terminal so I can go right up to the top of the console screen buffer. This is very useful if I'd like to execute a sequence of commands (say to be copied and pasted into a post). If I botch one I can erase it and its output and try again. Ctrl-Shift-Del does the same 1 page at a time.

I already have a rudimentary 4WT.DLL plugin which implements Ctrl-Del = delete upwards (as best it can ... pretty easy with VT control sequences).

@ghost ghost added Needs-Attention The core contributors need to come back around and look at this ASAP. and removed Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something labels Aug 27, 2020
@vefatica
Copy link
Author

I might have gotten carried away there. If you only wanted to hear about things that are or might be problematic in Terminal ...

v:> help _curchar
character at mouse cursor (decimal)

I don't know if I can do that if running in Terminal. Does GetCurrentConsoleFontEx() work? I might also need Terminal's padding?????

@jdebp
Copy link

jdebp commented Aug 29, 2020

M. Fatica: http://jdebp.uk./FGA/capture-console-win32.html may help a little bit with the concepts and architecture.

Other people: See https://jpsoft.com/forums/threads/detect-windows-terminal.10484/ for some more context.

@Diablo-D3
Copy link

Shouldn't the question be answered as, simply, check if $TERM is set, and if you don't want to handle the particularities of terminals, pretend all terminals comply to the modern standard of "emulate xterm-256color", and emit the proper sequences?

@chrisant996
Copy link

chrisant996 commented Aug 9, 2022

@Diablo-D3 no, and I'll try to share more details:

  1. Neither $TERM on *nix nor %TERM% on Windows indicate anything about the font, the cursor API quirks, or rendering capabilities (e.g. emoji substitutions, CJK width adjustments, etc).
  2. %TERM% doesn't address the %WT_SESSION% inheritance problem at all.
  3. Clink is a Windows program, and generally speaking %TERM% has no meaning for Windows programs (though it can have meaning for *nix programs ported to Windows). And so it's generally not set at all.
  4. Environment variables are inherited, and so %WT_SESSION% and %TERM% can be inherited when a console mode program running inside one terminal program spawns a new console window that gets hosted by a different terminal program -- thus causing malfunctions.

I don't believe that users should have to do a bunch of arcane configuration before programs can work reasonably (on Windows %TERM% qualifies as "arcane" because it's not a concept Windows users are really exposed to on Windows).

More importantly, I don't want to handle all the support requests when Windows users attempt to use a Windows console program like Clink and right out of the box it doesn't work at all, simply because the Windows users are using Windows and thus don't have %TERM% set. 😉

@Diablo-D3
Copy link

  1. It is not the job of a program running in a terminal to know if the terminal supports any of those. Any program that wishes to support that either should argue for an OSC extension, or should have this as configurable behavior and rely on the user to know what they're doing.

  2. $WT_SESSION seems like something that third party programs shouldn't use to infer behavior. If I run clink via ssh, using Microsoft's official openssh server binary, $WT_SESSION will not be set.

  3. Having $TERM unset tells you that you're on an extremely plain terminal, and since you only target Windows, its clearly the old conhost.

  4. Your situation only makes sense if I've explicitly invoked a console program in a way that it spawns a new conhost. If I did that, I would consider it user error, as I expect all child processes that are also console programs to run in the same console.

You're right in that Windows users are unfamiliar with $TERM. Microsoft chose not to implement this 30+ years ago, and Microsoft customers have been paying for that oversight ever since. However, terminal programs in general are "arcane"; the average user on any OS (even Linux, nowadays) are going to be unfamiliar with terminals.

@DHowett
Copy link
Member

DHowett commented Aug 10, 2022

its clearly the old conhost.

Which, on Windows 10+, supports a whole host of control sequences... which muddies the water significantly.

@chrisant996
Copy link

chrisant996 commented Aug 10, 2022

  1. It is not the job of a program running in a terminal to know if the terminal supports any of those. Any program that wishes to support that either should argue for an OSC extension, or should have this as configurable behavior and rely on the user to know what they're doing.

Almost. But Clink uses IAT hooking to extend CMD.exe. And Clink includes a built in terminal emulator for when it's running in a host that lacks support for escape sequences. And some terminal GUI hosts such as ZConsole just pass escape sequences to the underlying console. Clink needs to know a little about the environment in which it's running. %TERM% plainly does not achieve that, because it's not present.

  1. $WT_SESSION seems like something that third party programs shouldn't use to infer behavior. If I run clink via ssh, using Microsoft's official openssh server binary, $WT_SESSION will not be set.

It is the only way for a program to infer whether it is running inside Microsoft Terminal. Clink needs a reliable way to detect that. %TERM% plainly does not achieve that.

  1. Having $TERM unset tells you that you're on an extremely plain terminal, and since you only target Windows, its clearly the old conhost.

No. How did you reach that conclusion?

  • %TERM% is unset when running in Windows Terminal.
  • Clink targets all of old conhost, new conhost, Windows Terminal, ConEmu, Cmder, ZConsole, HyperTerm and so on.
  1. Your situation only makes sense if I've explicitly invoked a console program in a way that it spawns a new conhost. If I did that, I would consider it user error, as I expect all child processes that are also console programs to run in the same console.

It is not "user error" to start Windows Terminal, then start a GUI app from WT, then start a console program from the GUI app. That is a perfectly reasonable thing for a user to do, and it indeed happens.

You're right in that Windows users are unfamiliar with $TERM. Microsoft chose not to implement this 30+ years ago, and Microsoft customers have been paying for that oversight ever since. However, terminal programs in general are "arcane"; the average user on any OS (even Linux, nowadays) are going to be unfamiliar with terminals.

My point is that Clink wants to provide a seamless experience for users, and that there is no way to do so. It seems you believe that programs should not do that, and that users should not use shells without both configuring the shell and configuring the terminal in advance. I can respect that viewpoint, but I cannot require my program's users to do all that. Especially when there is no documentation or system in place for that on Windows.

@chrisant996
Copy link

I expect all child processes that are also console programs to run in the same console.

The expectation is mistaken:

  • Start Windows Terminal, with a CMD.exe tab.
  • Run start cmd.

On Windows, there are many ways for a console program to run in a new console window. There are APIs for controlling that, the start command controls that, and when a console then GUI then console the second console is separate because GUIs are not attached to any console.

@vefatica
Copy link
Author

vefatica commented Dec 5, 2022

With specific regard to a shell wanting to know where the Windows Terminal user interface is ...

I revisit this every now and then. I'm using the process ID of GetConsoleWindow() and a Toolhelp32Snapshot to find the parent process of OpenConsole.exe. Then I use EnumWindows() to find a CASCADIA_HOSTING_WINDOW_CLASS window belonging to that parent. It works, at least to my satisfaction, but it's a bit cumbersome.

Could you make the handle of the CASCADIA_HOSTING_WINDOW_CLASS window more readily available? One thought is to put it in the value of the WT_SESSION environment variable (along with the GUID which is (AFAICT) useless to the shell.

    `WT_SESSION=69f813f0-06ef-49d5-a64a-95359e0305c8, 0x303C0`

A shell might be looking for the existence of that variable anyway. If it's value had more useful information in it, that would be great.

Am I wrong about the GUID? Is it of any value to the shell (or to anyone)?

@german-one
Copy link
Contributor

Stop worrying about it. It's pretty obvious that there will be no support from the Terminal folks on this issue.
I think your initial "get icon" approach is a good point to start having fun 😄 And based on that, I had some fun recently:
https://github.com/german-one/termproc
Now it already rings in my ears "I whouldn't if I was you ...", "Don't rely on ...". Also "But SSH ..." when people were asking about locally running applications etc.
Yes, of course those work-arounds make things worse. What else but the worst can ever be expected if we don't get an easier way? 🤣

@adithya-s-sekhar
Copy link

What's with the whole stackoverflow attitude of "you're not supposed to do that"? Setting custom window sizes, screen buffers have been a thing on cmd since the dark ages. For an OS that touts itself so much on backward compatibility that it goes out of its way to keep even the rarest of things working the same way, this is such a stupid thing to do.

Let us have a way to detect if the script is running in Windows Terminal, we're not asking you to add features from conhost.

@german-one
Copy link
Contributor

I archived my old termproc repo and created a new one to reflect the new process model of Windows Terminal v. 1.18 and its feature to move tabs between windows.

The new code can be found in my termwnd repo for those who are interested in.

@mataha
Copy link

mataha commented Jul 11, 2023

I have a similar conundrum - not being able to detect whether ANSI sequences are supported (for, among other things, colored output and line movement) which boils down to checking if I'm running inside conhost.exe; I can't even send CSI 0 c as there won't be a response - the code will wait forever.

Use-case
@setlocal EnableExtensions & if "%DEBUG%"=="" echo off

call :query_state response "0c" c
if defined response (
    set /p="%response:*[=^[[%"
    (echo()
) <nul

exit /b 0

:query_state (out response: string, query: string, terminator: char, device: string = "con")
    setlocal DisableDelayedExpansion

    if not "%~4"=="" (
        set "device=%~4"
    ) else (
        set "device=con"
    )

    for /f "delims=" %%c in (
        '""%SystemRoot%\system32\forfiles.exe"
            /p "%~dp0." /m "%~nx0" /c ""%ComSpec%" /d /q /c @echo(0x1B[""'
    ) do (
        set "CSI=%%c"
    )

    set /a "index=0"
    set "response="

    :query_state_unpack
        set "character="

        set /p="%CSI%%~2" <nul >"%device%"

        for /l %%_ in (1, 1, %index%) do (pause) <"%device%" >nul

        for /f "skip=1 tokens=1 delims=* eol=" %%c in (
            '""%SystemRoot%\system32\replace.exe" ? . /w /u <"%device%""'
        ) do (
            set "character=%%c"
        )

        set /a "index+=1"
        set "response=%response%%character%"

        if defined character if not "%character%"=="%3" (
            goto :query_state_unpack
        )

    endlocal & set "%~1=%response%" & goto :EOF

To help with that I've cooked the following algorithm; no idea whether it's suitable for all scenarios, but I'd be happy to receive any feedback:

  1. For each child conhost.exe of the examined process (cmd.exe or whatever):
    • if it doesn't have any children - bingo
  2. Go up a process
    • if we can't - it's not conhost.exe
    • if it's conhost.exe - bingo
    • else go to step 1

@chrisant996
Copy link

I have a similar conundrum - not being able to detect whether ANSI sequences are supported (for, among other things, colored output and line movement) which boils down to checking if I'm running inside conhost.exe

@mataha It sounds like you're checking whether there's a conhost.exe that can be identified as either the parent or child of the current cmd.exe, and concluding that means escape sequences are supported.

A few examples where the approach doesn't work (there are more):

  • Inaccurate on older versions of Windows where conhost.exe didn't support escape sequences.
  • Accuracy may be affected by the ConsoleV2 regkey.
  • Accuracy can depend on what terminal program is being used to host the window. Some terminal programs hook the OS console output APIs and intercept them. Usually that's to add support for escape sequences, but there's no guarantee about which escape sequences will be supported, if any.
  • Inaccurate when VS Code or other programs host the cmd.exe in an integrated terminal window. In that case conhost.exe is a sibling process.
  • Etc. This is not a complete list; it's just meant to demonstrate that there are cases where the approach does not yield an accurate answer as to whether escape sequences are supported.

Looking for conhost.exe has a low enough correlation to escape sequence support that I wouldn't recommend to pursue trying to expand on it. I'd recommend to find a different approach entirely.

With that said, if you like the results it achieves in the scenarios that your code runs in, then that's probably what's important for your own purposes. It doesn't generalize well, though.

@chrisant996
Copy link

chrisant996 commented Jul 15, 2023

For Clink (which hooks into cmd.exe and runs within the cmd.exe process itself) the following is what I'm currently exploring/refining for determining whether cmd.exe is running in Windows Terminal.

The intent, of course, is to stop looking at %WT_SESSION% at all since it's too unreliable (and prone to both false positives and false negatives).

It's running in Windows Terminal if any of the following are true:

  • If the parent process is WindowsTerminal.exe.
    • Technically that isn't 100% reliable since something else could choose the name "WindowsTerminal.exe" without being the "real" one.
  • If an OpenConsole.exe child process exists.
    • Technically that isn't 100% reliable since something else could explicitly use Windows Terminal's OpenConsole.exe, and something else could choose the name "OpenConsole.exe" without being the "real" one.
  • If a conhost.exe child process has OpenConsoleProxy.dll loaded.
    • Technically this isn't 100% reliable since something else could name itself "conhost.exe" or "OpenConsoleProxy.dll" without being the "real" ones.

(Edited to clarify about OpenConsole.exe.)

@lhecker
Copy link
Member

lhecker commented Jul 17, 2023

To be honest, I haven't followed the discussion from the beginning so please ignore me if I misunderstood this, but isn't the correct question to ask (if anything) "Am I running under ConPTY?" and not really about Windows Terminal at all? After all, the issues mentioned here aren't really specific to Windows Terminal, but rather for anyone using ConPTY right?

As such, couldn't you do this?

wchar_t buffer[32];
const auto length = GetClassNameW(GetConsoleWindow(), &buffer[0], 32);
const auto isConhost = length == 18 && memcmp(&buffer[0], L"ConsoleWindowClass", 36) == 0;

With ConPTY the buffer will instead contain PseudoConsoleWindow.

I would not test for PseudoConsoleWindow however. While neither class name is technically part of a public API, ConsoleWindowClass is way older and much more specific. It would also still work if a 3rd class name was ever introduced. Or if we made GetConsoleWindow return nullptr with ConPTY, etc.

@chrisant996
Copy link

To be honest, I haven't followed the discussion from the beginning so please ignore me if I misunderstood this, but isn't the correct question to ask (if anything) "Am I running under ConPTY?" and not really about Windows Terminal at all? After all, the issues mentioned here aren't really specific to Windows Terminal, but rather for anyone using ConPTY right?

Both questions are valid, depending on what the code is trying to determine (or why).

For example, if code wants to know whether Windows Terminal shell integration support is present, that's a Windows Terminal feature, not ConPty.

@chrisant996
Copy link

@lhecker Here are a few more examples why a console mode program may need to know specifically which terminal program is hosting them. While ConPty manages the screen buffer, individual terminal programs are responsible for rendering the screen, and they render it differently. Those differences can be crucial for console mode apps that are trying to align things or right-justify things or measure things.

"What exactly would you light up only for windows terminal users and not Visual Studio or VS Code users?"

  • The new Windows Terminal shell integration.
  • Which uses different escape sequences than the VS Code shell integration.
  • Windows Terminal renders color emoji codepoints differently than the legacy conhost window or than ConEmu. The widths can be different, for example. Each terminal renders things differently, and apps have to manually find ways to compensate for hidden differences.
  • Mouse input and Quick Edit mode work differently in Windows Terminal.
  • Show/hide the flashing cursor works differently Windows Terminal; using the console APIs accidentally changes the shape of the cursor as a side effect. An app has to conditionally choose between using console APIs or using escape codes like ESC [ ? 25 h depending on the capabilities of the terminal hosting them.

Quick example of color emoji rendering differences

Legacy console:
image

ConEmu:
image

Windows Terminal:
image

@vefatica
Copy link
Author

What's a shell to do if its conpty is not attached to a terminal (ssh, for example)? Since starting this thread, I have worked out most of my difficulties. If you monkey around enough with GetConsoleWindow, GetClassName, GetWindowThreadProcessId, CreateToolhelp32Snapshot (for parent PIDs), and EnumWindows, you can figure out if your in WT (and get WT's PID and a handle to its CASCADIA_HOSTING_WINDOW_CLASS window if you want them). That's all I wanted.

You could probably, and similarly, figure out if you're in any terminal emulator, and which one. But what's a shell to do ... hard-code for differences among terminal emulators? That's not for me.

@chrisant996
Copy link

chrisant996 commented Jul 17, 2023

But what's a shell to do ... hard-code for differences among terminal emulators? That's not for me.

A shell could require the user (and/or the terminal itself) to tell the shell about the terminal emulator it's running in. Like $term and terminfo in Linux. Windows has no equivalent (and certainly no standard), which leads console mode apps on Windows to try to deduce things themselves, which leads to a wide range of malfunction scenarios in different combinations of terminals and apps.

I don't know how (or if) terminfo/ncurses describe color emoji capabilities in Linux terminals.

@vefatica
Copy link
Author

I don't know how terminfo works. Who writes it? Who reads it? And who implements what's in it?

@chrisant996
Copy link

I don't know how terminfo works. Who writes it? Who reads it? And who implements what's in it?

A good place to start reading to understand the terminfo stuff is the link I shared on the previous reply.

@tig
Copy link

tig commented Oct 26, 2023

Terminal.Gui maintainer here.

We feel we need this. We can't move to Virtual Terminal Sequences any time soon (esp given the perf issues). In the meantime, the conhost and WT behave so differently (as have been noted above). We've gone back and forth between testing for WT_SESSION and trying to detect "If the parent process is WindowsTerminal.exe". It's just yucky and frustrating.

@a-usr
Copy link

a-usr commented Mar 18, 2024

I have a similar conundrum - not being able to detect whether ANSI sequences are supported (for, among other things, colored output and line movement)

@mataha You do realize that on WIndows 10+ conhost does support ANSI seqences? You just have to enable them.

Here is a function written in python that does just that:

import ctypes
import ctypes.wintypes
from time import sleep

# Windows API constants
INVALID_HANDLE_VALUE = -1

GENERIC_READ = 2147483648
GENERIC_WRITE = 1073741824

FILE_SHARE_READ = 1
FILE_SHARE_WRITE = 2

OPEN_EXISTING = 3

ENABLE_VT_PROCESSING = 4

# own constant for better code
FUNCTION_FAILED = 0

def enable_vt_processing():
    kernel32 = ctypes.windll.kernel32

    # get stdout handle
    conout = ctypes.wintypes.LPCWSTR("CONOUT$\0")
    stdoutH = kernel32.CreateFileW(conout, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, ctypes.c_void_p(), OPEN_EXISTING, 0,ctypes.c_void_p())
    if stdoutH == INVALID_HANDLE_VALUE:
        raise ctypes.WinError(kernel32.GetLastError())

    # get current mode 
    mode = ctypes.wintypes.DWORD()
    if kernel32.GetConsoleMode(stdoutH, ctypes.byref(mode)) == FUNCTION_FAILED:
        raise ctypes.WinError(kernel32.GetLastError())

    # set mode if needed
    if mode.value & ENABLE_VT_PROCESSING == 0:
        if kernel32.SetConsoleMode(stdoutH, mode.value | ENABLE_VT_PROCESSING) == FUNCTION_FAILED:
            raise ctypes.WinError(kernel32.GetLastError())

And here are the links to the documentation for the Windows API functions used:

CreateFileW

GetConsoleMode
SetConsoleMode

GetLastError

The reason I use CreateFileW on CONOUT$ instead of GetStdHandle is described here

@NRJank
Copy link

NRJank commented Apr 12, 2024

The GNU Octave is a cross platform project built to use the default OS terminal. Currently we would love to be able to identify if that is the new Windows Terminal. There is some incompatibility between conhost and the new Windows Terminal that is causing strange artifacts and program crashes for users of the new Windows Terminal that became very apparent when win11 made it the default. Octave is primarily developed on linux and crossbuilt for windows users, and we have few windows developers working that part of the program.

For now we wanted to create a script to try to identify if Octave was started in the Windows Terminal to prompt the user to switch, but so far have just settled on checking if the the registry key was set for having Windows Console Host be system default, and prompt the Windows users to switch the system default to that if it's not. Yes, it is a rather poor workaround. but it's effective. Until we have the developer resources to better troubleshoot the conhost / windows terminal incompatibility (or finish developing a separate, cross-platform compatible terminal widget to bundle with Octave), that change solves the problem for the users. But it does come with some false positives for the prompt because it gets set off when the windows setting is "let windows decide" even if that wouldn't use the new terminal, causing some other user confusion. So, it would at least be cleaner if at startup we could positively identify the Windows terminal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Issue-Question For questions or discussion Needs-Tag-Fix Doesn't match tag requirements
Projects
None yet
Development

No branches or pull requests