Understanding Windows Console Host Settings

Welcome to the first of several posts that describe some of the inner workings of the Windows Console.

This post was written by Craig Loewen (our awesome 2017 summer intern), and Paul Campbell (SDE on Windows Console, Cmd, & Bash on Windows).

Settings in the Windows Console Host can be a bit tricky to understand. This is mostly because the settings system evolved over the course of decades. Settings are persisted to/from a variety of locations depending on how the Windows Console Host was invoked.


The hierarchy of loaded settings

Where a Console's settings are loaded-from and/or persisted-to is decided upon based upon the following hierarchy:

  1. Hardcoded settings in conhostv2.dll
  2. User's configured Console defaults, stored as values in 'HKCU\Console'
  3. Per-Console-application registry settings, stored as sub-keys of 'HKCU\Console\<sub-key>' using one of two sub-key names:
    • Console application path (replacing '\' with '_')
    • Console title
  4. Windows shortcut (.lnk) files

When Console applications are launched, the Windows Console Host determines which settings to use by loading the Console details, and overlaying settings from the hierarchy in order. Each setting will take on the value of whatever is loaded last, and so values in a Windows shortcut (#4) will override values set in the user's configured defaults (#2).

This hierarchy explains why each Console window has a 'Defaults' option and a 'Properties' option inside of its title bar menu:

When modifying 'Defaults', changes are written to the User's configured defaults, stored as values in 'HKCU\Console', (#2 in the hierarchy above).

When modifying 'Properties', changes will be persisted to either the per-Console-application settings in the registry, or to the Windows shortcut file:

  • If the application was launched directly (e.g. via the Windows run dialog), changes will be persisted in the per-application storage location mentioned above (#3 in the hierarchy).
  • If the application was launched via a Windows shortcut file, changes will be persisted directly into the .lnk file (the fourth item in the hierarchy). For Console applications with a shortcut, you can also right-click on the shortcut file itself and choose 'Properties' to access the settings dialog.

When Console applications are launched, the Windows Console Host determines which settings to use by overlaying settings from the hierarchy in order, starting with the hardcoded defaults. This means that a Windows Console shortcut with settings information inside of it will override the application storage and default settings.

Note that the registry settings are "sparse", meaning that if a setting isn't present, then whatever value that is already in use remains unchanged. This allows users to have some settings shared amongst all Console applications and other settings be specific.

Shortcut files, however, store each setting regardless of whether it was a default setting or not. Settings are stored in shortcuts as opaque blobs of data.

Here's a full list of every setting for the Windows Console, including a quick description on what it does.

Setting Name Type Description
FontSize Coordinate (REG_DWORD) Size of font in pixels
FontFamily REG_DWORD GDI Font family
ScreenBufferSize Coordinate (REG_DWORD) Size of the screen buffer in WxH characters
CursorSize REG_DWORD Cursor height as percentage of a single character
WindowSize Coordinate (REG_DWORD) Initial size of the window in WxH characters
WindowPosition Coordinate (REG_DWORD) Initial position of the window in WxH pixels (if not set, use auto-positioning)
WindowAlpha REG_DWORD Opacity of the window (valid range: 0x4D-0xFF)
ScreenColors REG_DWORD Default foreground and background colors
PopupColors REG_DWORD FG and BG colors used when displaying a popup window (e.g. when F2 is pressed in CMD.exe)
QuickEdit REG_DWORD Whether QuickEdit is on by default or not
FaceName REG_SZ Name of font to use (or "__DefaultTTFont__", which defaults to whichever font is deemed most appropriate for your codepage)
FontWeight REG_DWORD GDI font weight
InsertMode REG_DWORD Whether Insert mode is on by default or not
HistoryBufferSize REG_DWORD Number of history entries to retain
NumberOfHistoryBuffers REG_DWORD Number of history buffers to retain
HistoryNoDup REG_DWORD Whether to retain duplicate history entries or not
ColorTable%% REG_DWORD For each of the 16 colors in the palette, the RGB value of the color to use
ExtendedEditKey REG_DWORD Whether to allow the use of extended edit keys or not
WordDelimiters REG_SZ A list of characters that are considered as delimiting words (e.g. `' .-/\=|,()[]{}'`)
TrimLeadingZeros REG_DWORD Whether to remove zeroes from the beginning of a selected string on copy (e.g. `00000001` becomes `1`)
EnableColorSelection REG_DWORD Whether to allow selection colorization or not
ScrollScale REG_DWORD How many lines to scroll when using `SHIFT|Scroll Wheel`
CodePage REG_DWORD The default codepage to use
ForceV2 REG_DWORD Whether to use the improved version of the Windows Console Host
LineSelection* REG_DWORD Whether to use wrapped text selection
FilterOnPaste* REG_DWORD Whether to replace characters on paste (e.g. Word "smart quotes" are replaced with regular quotes)
LineWrap REG_DWORD Whether to have the Windows Console Host break long lines into multiple rows
CtrlKeyShortcutsDisabled REG_DWORD Disables new control key shortcuts
AllowAltF4Close REG_DWORD Allows the user to disable the Alt-F4 hotkey
VirtualTerminalLevel REG_DWORD The level of VT support provided by the Windows Console Host

*Only applies to the improved version of the Windows Console Host

Known Issues

As with most complex things, there are a few gotcha's to be aware of:

Settings get reset on OS upgrade

Whenever you upgrade to a new version of Windows, system-owned shortcuts and/or Start Menu items' settings are reset to defaults. This means that if you customize default fonts, colors, etc., when you upgrade to a new OS build, your settings will be reset to Windows defaults.

While there are several ways in which you can set things back to your own defaults after each upgrade, most of them involve updating the registry (which should always be done with care), and most don't handle updating shortcuts/links at all.

We're working on a tool to make handling Console settings easier and more manageable. We'll announce this tool here, so be sure to visit this blog regularly to be among the first to use this tool when it is released.

Comments (11)

  1. Is there documentation on what the valid values for VirtualTerminalLevel are, the max level each version of Windows supports, and what VT sequences are actually supported at each level?

    1. No, but one can assume that any Windows version prior to Anniversary Update had minimal VT support, whereas Anniversary Update and later have pretty comprehensive VT support.

  2. JC Ruiz says:

    How is this related to the PowerShell Console Host ?

    1. There is but on ConHost for all of Windows. Cmd, PowerShell, Bash, etc. all use the same Console.

  3. Refael says:

    What about https://github.com/PowerShell/PowerShell/issues/4266 – ConHost uses it’s palette to remap ANSI colors (spesificly ANSI Colors 33 and 35 are remapped by the default Powershell shortcut)
    That’s not cricket.

    1. That’s an issue with PowerShell – please work with the team on that GH issue to drive to resolution.

      FWIW though; we’re in a state of transition: Now that the Windows Console supports most VT/ANSI sequences, there will be fewer reasons to not be able to emit VT on OS versions that support it. There will, however, be a very long tail of legacy apps that will never be updated to support VT, and which will expect the Console to look and behave as it has for the last 30 years.

      1. Len Chisholm says:

        However, making window scrolling by mouse wheel the exclusive domain of conhost rather than the application will surely break console apps which implement their own scrolling with the wheel messages.

        1. If you’re writing a Windows command-line app, you can first SetConsoleMode() to ENABLE_MOUSE_INPUT, and then call ReadConsoleInput() and will receive INPUT_RECORDs indicating MOUSE_EVENT_RECORDs indicating MOUSE_WHEELED events. See this as an example: https://docs.microsoft.com/en-us/windows/console/reading-input-buffer-events.

          Linux command-line apps, on the other hand, expect to receive VT sequences indicating mouse events: https://linux.die.net/man/4/console_codes. In Creators Update, we added the ability for Windows Console to emit the necessary VT sequences so that apps and tools like Midnight Commander can receive and handle mouse move, click & scroll events.

          1. Len Chisholm says:

            Well, that’s what we are doing, but (as many others on the Net have said) we no longer get ANY of the MOUSE_WHEELED messages via ReadConsoleInput() once we’re not in Legacy Console mode. I have verified that today, I get messages in the log in legacy mode, and nothing in new console mode,
            We do resize the screen so the window and buffer are both 80*25, but that doesn’t help.

  4. eryk sun says:

    Setting CodePage in the “HKCU\Console” key has been broken forever. With a debugger attached to conhost.exe, I see that it initially loads the default value in the SetUpConsole function, but then it gets reset back to the OEM codepage in the function that attempts to load settings from a shortcut (i.e. ::GetSettingsFromLink). If there’s an “HKCU\Console\” subkey, it subsequently loads the CodePage setting from there. So currently the only way to set the codepage is via the per-title settings — either the default application title (e.g. “%SystemRoot%_System32_cmd.exe”) or a custom title set in STARTUPINFO (e.g. set the title via CMD’s `start` command). I’d like to be able to set the overall default CodePage to 65001 (UTF-8) – at least when UTF-8 finally works right for console input. That’s a separate issue and off-topic for this blog posting, but I’ll rant a bit about some other console annoyances in case I have someone’s ear.

    The console should fully support UTF-8. Its file-like nature makes it an exception to the legacy status of codepages in the Windows API. Requiring UTF-16 via ReadConsoleW and WriteConsoleW is a needless pain for cross-platform code that uses UTF-8 for I/O. Nowadays UTF-8 does work partially in the console. The update in Windows 8 to replace the old LPC connection with the new ConDrv device and kernel File objects solved a bug in which WriteFile would return the number of UTF-16 codes written instead the number of UTF-8 bytes written. So setting the output codepage to UTF-8 works well enough. (It would be better if the console used a small carry-over buffer between writes, for when a buffered stream splits a UTF-8 sequence across multiple writes.) However, reading non-ASCII UTF-8 input via ReadFile or ReadConsoleA is still broken. In the debugger, I can see that, in Windows 10, the console’s TranslateUnicodeToOem function now encodes 1 character at a time in a loop, but it still uses the old assumption of 1 byte per character. This ends up encoding non-ASCII characters as NUL bytes (e.g. input L”aβc” is read as “a\x00c”), or two NULs for a surrogate pair. It’s a bit better than in previous versions, which encoded in one pass with a single WideCharToMultiByte call. That would fail on the server side but return ‘success’ to the client, with 0 characters read; this looks like EOF when using ReadFile. Still, while it’s an improvement, substituting NUL characters is not a solution. It should encode to a 4-byte scratch buffer and also check for a surrogate pair. Iteratively encode and copy to the target buffer until it’s full. It may not have space at the end for a complete character, in which case the console can return 1-3 fewer bytes read than requested.

    Also, the switch to ConDrv in Windows 8 broke documented behavior of ReadFile. When a console read is interrupted by Ctrl+C, the last error is supposed to be ERROR_OPERATION_ABORTED, which is required in order to reliably distinguish Ctrl+C from EOF (i.e. ReadFile returns 0 bytes read if a line starts with Ctrl+Z). That’s still the case for ReadConsole, even though it was never documented. On the other hand, ReadFile with console input no longer shares a common implementation with ReadConsoleA. Instead it calls NtReadFile and uses the generic translation of the NTSTATUS return value. Weirdly, when interrupted by Ctrl+C, the console returns STATUS_ALERTED (0x00000101), a success code for a waiting thread that was alerted via NtAlertThread, etc. The correct code is STATUS_CANCELLED (0xC0000120). If it were up to me, I’d fix the status code in the console, rather than hacking an exception into ReadFile.

    Also, along the lines of canceled I/O, since the console now uses real kernel I/O instead of LPC, a console read can end up being canceled by CancelSynchronousIo. That cancels the operation on the client side, but the console itself will remain in a cooked read that’s simply thrown away after the user presses enter. I see there’s a ConsoleIoThread function that’s dedicated for communicating with ConDrv via DeviceIoControl. Hopefully there’s a way for it to detect the canceled operation and signal the input thread to cancel its cooked read, without needlessly requiring the user to press enter.

    1. While I appreciate your passion and enthusiasm, long wandering comments posted on a vaguely related blog post are not a good use of your or our time.

      If you would like to ask for or suggest new features, please upvote/add them here: https://aka.ms/winbashuv
      If you would like to report specific issues, please do so here: https://github.com/microsoft/console


Skip to main content