How to use Console API to detect if app is running in classic Windows Console? #11919

Closed
opened 2026-01-31 03:01:02 +00:00 by claunia · 10 comments
Owner

Originally created by @DaRosenberg on GitHub (Dec 30, 2020).

Wasn't sure which repo and/or issue template to use, feel free to point me in the right direction.

We are building a fairly elaborate cross-platform CLI on .NET 5.0. We expect equal usage shares on macOS, Linux and Windows. The app makes extensive use of VT sequences and Unicode output for formatting and interactivity purposes.

In macOS, Linux and Windows Terminal, things are great. In classic Windows Console, not so great. ;) These days, honestly, mostly because the default font on Windows Console is Consolas which has very limited Unicode support. Other aspects of Windows Console seem to have largely caught up.

We are currently relying on OS detection to downgrade our experience on Windows, because we are not in a position to force users to install Windows Terminal, and even if they did, we have some scenarios where the default console would be used even if the user had Windows Terminal installed.

This of course means that also users running our CLI in Windows Terminal are getting the "impaired" experience for no good reason - our downgrade heuristics are much too blunt.

Which leads me to my question: is there any way (either using VT sequences or the Console API) that we could detect whether the app is connected to Windows Console? If we have to do some funky P/Invoke stuff on Windows to achieve this, than that's a fair trade-off for us.

It's also not super important that it's future-proof - i.e. if we can rely, for now, on some part of Console API that is known to currently behave differently in Windows Console than in Windows Terminal, we'd be willing to keep an eye on this regularly in case Windows Terminal closes such compatibility gaps over time.

Thanks in advance!

Originally created by @DaRosenberg on GitHub (Dec 30, 2020). Wasn't sure which repo and/or issue template to use, feel free to point me in the right direction. We are building a fairly elaborate cross-platform CLI on .NET 5.0. We expect equal usage shares on macOS, Linux and Windows. The app makes extensive use of VT sequences and Unicode output for formatting and interactivity purposes. In macOS, Linux and Windows Terminal, things are great. In classic Windows Console, not so great. ;) These days, honestly, mostly because the default font on Windows Console is Consolas which has very limited Unicode support. Other aspects of Windows Console seem to have largely caught up. We are currently relying on OS detection to downgrade our experience on Windows, because we are not in a position to force users to install Windows Terminal, and even if they did, we have some scenarios where the default console would be used even if the user had Windows Terminal installed. This of course means that also users running our CLI in Windows Terminal are getting the "impaired" experience for no good reason - our downgrade heuristics are much too blunt. Which leads me to my question: is there any way (either using VT sequences or the Console API) that we could detect whether the app is connected to Windows Console? If we have to do some funky P/Invoke stuff on Windows to achieve this, than that's a fair trade-off for us. It's also not super important that it's future-proof - i.e. if we can rely, for now, on some part of Console API that is known to currently behave differently in Windows Console than in Windows Terminal, we'd be willing to keep an eye on this regularly in case Windows Terminal closes such compatibility gaps over time. Thanks in advance!
claunia added the Issue-QuestionNeeds-Tag-FixResolution-Answered labels 2026-01-31 03:01:02 +00:00
Author
Owner

@DaRosenberg commented on GitHub (Dec 30, 2020):

This sounds like a pretty promising candidate: https://github.com/microsoft/terminal/issues/6395

@DaRosenberg commented on GitHub (Dec 30, 2020): This sounds like a pretty promising candidate: https://github.com/microsoft/terminal/issues/6395
Author
Owner

@zadjii-msft commented on GitHub (Jan 4, 2021):

So I'd maybe not rely on doing this. Using the console font size to try and detect if you're in the Terminal is sure to net you a bunch of false positives, and isn't an API contract by any means.

For a while, part of the goal with the Terminal was to help flesh out a new renderer that we could use for the vintage console as well. By using the Terminal's renderer in the vintage console, then there wouldn't be a difference between how the two render unicode characters anymore. So long-term, you hopefully shouldn't have to do this at all. Unfortunately, that work is sitting lower on the backlog, so we'd need some extra business justification to bump the priority.

I think technically, there's the WT_SESSION variable we're setting when commandline apps are run in the Terminal. That's certainly a better heuristic than the font size.

@zadjii-msft commented on GitHub (Jan 4, 2021): So I'd maybe not rely on doing this. Using the console font size to try and detect if you're in the Terminal is sure to net you a bunch of false positives, and isn't an API contract by any means. For a while, part of the goal with the Terminal was to help flesh out a new renderer that we could use for the vintage console as well. By using the Terminal's renderer in the vintage console, then there wouldn't be a difference between how the two render unicode characters anymore. So long-term, you hopefully shouldn't have to do this at all. Unfortunately, that work is sitting lower on the backlog, so we'd need some extra business justification to bump the priority. I think technically, there's the `WT_SESSION` variable we're setting when commandline apps are run in the Terminal. That's certainly a better heuristic than the font size.
Author
Owner

@DaRosenberg commented on GitHub (Jan 4, 2021):

@zadjii-msft WT_SESSION is exactly what I was looking for, thank you. I didn't even think to check environment variables. :) Obviously this is both safer and simpler to implement. 👍

To clarify though, the idea was not to rely on a specific font size, but rather rely on the fact that, in Terminal, the font size is always returned as 0. Not sure how that could have yielded any false positives/negatives?

Do you think there's anything to do from a documentation standpoint here, i.e. is this env var document and/or should it be? Otherwise I'll close out this issue.

@DaRosenberg commented on GitHub (Jan 4, 2021): @zadjii-msft `WT_SESSION` is exactly what I was looking for, thank you. I didn't even think to check environment variables. :) Obviously this is both safer and simpler to implement. 👍 To clarify though, the idea was not to rely on a specific font size, but rather rely on the fact that, in Terminal, the font size is always returned as 0. Not sure how that could have yielded any false positives/negatives? Do you think there's anything to do from a documentation standpoint here, i.e. is this env var document and/or should it be? Otherwise I'll close out this issue.
Author
Owner

@DHowett commented on GitHub (Jan 4, 2021):

... could have yielded false ... negatives

In the fullness of time, "running in Terminal" should be undetectable. There's a lot of things that influence how applications are going to work, going forward, and not one of them should be whether it's running in the new modern experience or the more vintage one.

The SSH server on Windows uses the same API as Windows Terminal to host a console session. It has no font -- it's an SSH server -- and so it will return the same result (0,16) today¹. That will make you think you're running in Terminal.

Conversely, WT_SESSION is only local. If you're connected to a windows machine over SSH, the remote end will absolutely not have WT_SESSION set... even if you're running in Terminal.

My honest answer is: don't detect it. Let applications look broken in the vintage console host until such time as users either move to Terminal or move to a version of windows where the inbox console host either (1) supports awesome new rendering or (2) can delegate to an updated version that is shipped outside of the Windows release cycle. Any--any!--heuristic you use today will be broken tomorrow.

It's also not super important that it's future-proof...

Thanks for saying this part. 😄 I know you've got the best intentions, but y'know... we get reports from people running Vim for Windows 5.0. Five! It came out in 1998! They report bugs, and all we can do is say "please user something made in this century." (Or fix the bug, but that's for better folks than I 😉)

I'll counter, though, with: why be past-proof?

¹ This is not a guarantee. I keep a list of the ways in which the PTY hosting API differs in detectable application behavior so that I can fix them.

@DHowett commented on GitHub (Jan 4, 2021): > ... could have yielded false ... negatives In the fullness of time, "running in Terminal" should be undetectable. There's a lot of things that influence how applications are going to work, going forward, and not one of them should be whether it's running in the new modern experience or the more vintage one. The SSH server on Windows uses the same API as Windows Terminal to host a console session. It has no font -- it's an SSH server -- and so it will return the same result (0,16) today¹. That will make you think you're running in Terminal. Conversely, `WT_SESSION` is only local. If you're connected to a windows machine over SSH, the remote end will absolutely _not_ have `WT_SESSION` set... even if you're running in Terminal. My honest answer is: don't detect it. Let applications look broken in the vintage console host until such time as users either move to Terminal or move to a version of windows where the inbox console host either (1) supports awesome new rendering or (2) can delegate to an updated version that is shipped outside of the Windows release cycle. Any--**any!**--heuristic you use today will be broken tomorrow. > It's also not super important that it's future-proof... Thanks for saying this part. :smile: I know you've got the best intentions, but y'know... we get reports from people running Vim for Windows 5.0. Five! It came out in 1998! They report bugs, and all we can do is say "please user something made in this century." (Or fix the bug, but that's for better folks than I 😉) I'll counter, though, with: why be _past-proof_? ¹ This is not a guarantee. I keep a list of the ways in which the PTY hosting API differs in detectable application behavior _so that I can fix them_.
Author
Owner

@DaRosenberg commented on GitHub (Jan 4, 2021):

@DHowett thanks for chiming in.

In general I agree with you that we should all be a tad more liberal in allowing the old to be broken so that we may encourage adoption of the new. But since users do not currently even have a way to make Terminal the default console, it's not really an option. Users will not think Console is broken - they will think our CLI is broken, because other CLIs do adapt.

Good points on SSH server and font size. That would indeed be a false negative. Your thoughts on the remote scenarios in general are also much appreciated, however given our app and target scenarios WT_SESSION makes a lot of sense for us so we're going with it.

I'll counter, though, with: why be past-proof?

Wish we didn't have to. But like I said, making Terminal the default is simply not implemented yet. Console is going to be far more common than Terminal for the users/machines we are targeting, for a while. And it's just not acceptable for us to give our customers a broken experience just to promote/encourage Terminal adoption. 😉

@DaRosenberg commented on GitHub (Jan 4, 2021): @DHowett thanks for chiming in. In general I agree with you that we should all be a tad more liberal in allowing the old to be broken so that we may encourage adoption of the new. But since users do not currently even have a way to make Terminal the default console, it's not really an option. Users will not think Console is broken - they will think our CLI is broken, because other CLIs do adapt. Good points on SSH server and font size. That would indeed be a false negative. Your thoughts on the remote scenarios in general are also much appreciated, however given our app and target scenarios `WT_SESSION` makes a lot of sense for us so we're going with it. > I'll counter, though, with: why be past-proof? Wish we didn't have to. But like I said, making Terminal the default is simply not implemented yet. Console is going to be far more common than Terminal for the users/machines we are targeting, for a while. And it's just not acceptable for us to give our customers a broken experience just to promote/encourage Terminal adoption. 😉
Author
Owner

@DHowett commented on GitHub (Jan 4, 2021):

Fair enough! No promises that we don't rework WT_SESSION without notice, but... for 2021-01-04 let's call it answered.

@DHowett commented on GitHub (Jan 4, 2021): Fair enough! No promises that we don't rework WT_SESSION without notice, but... for 2021-01-04 let's call it answered.
Author
Owner

@edvilme commented on GitHub (Dec 16, 2022):

I know I am a little late to the discussion and this question has been marked as answered, but is there an equivalent of WT_SESSION for the legacy conhost?
That is, how can I detect if the program is NOT running on conhost (aka, Windows Terminal, inside VS or VSCode, or any other tool)?

@edvilme commented on GitHub (Dec 16, 2022): I know I am a little late to the discussion and this question has been marked as answered, but is there an equivalent of `WT_SESSION` for the legacy conhost? That is, how can I detect if the program is NOT running on conhost (aka, Windows Terminal, inside VS or VSCode, or any other tool)?
Author
Owner

@KalleOlaviNiemitalo commented on GitHub (Dec 16, 2022):

how can I detect if the program is NOT running on conhost

Perhaps it can be done with GetConsoleWindow + GetWindowThreadProcessId + OpenProcess + QueryFullProcessImageNameW. I didn't try. Why would you want to know that, though?

@KalleOlaviNiemitalo commented on GitHub (Dec 16, 2022): > how can I detect if the program is NOT running on conhost Perhaps it can be done with [GetConsoleWindow](https://learn.microsoft.com/windows/console/getconsolewindow) + [GetWindowThreadProcessId](https://learn.microsoft.com/windows/win32/api/winuser/nf-winuser-getwindowthreadprocessid) + [OpenProcess](https://learn.microsoft.com/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess) + [QueryFullProcessImageNameW](https://learn.microsoft.com/windows/win32/api/winbase/nf-winbase-queryfullprocessimagenamew). I didn't try. Why would you want to know that, though?
Author
Owner

@edvilme commented on GitHub (Dec 16, 2022):

Same reason as OP. But figured other terminal emulators other than Windows Terminal might support it.

@edvilme commented on GitHub (Dec 16, 2022): Same reason as OP. But figured other terminal emulators other than Windows Terminal might support it.
Author
Owner

@DHowett commented on GitHub (Jan 9, 2023):

conhost is gaining support for these things at roughly the same rate as Windows Terminal; they are in fact built from the same code. Any detection you do today will produce an incorrect result tomorrow (for suitably broad definitions of "today" and "tomorrow")!

@DHowett commented on GitHub (Jan 9, 2023): conhost is gaining support for these things at roughly the same rate as Windows Terminal; they are in fact built from the same code. Any detection you do today will produce an incorrect result tomorrow (for suitably broad definitions of "today" and "tomorrow")!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#11919