TYPE resets console tab settings

May 20, 2008
Syracuse, NY, USA
Windows 10's enhanced console allows setting the tab stops. I've suggested that TCC v25 give us some interface to this mechanism and I've been experimenting with it myself. I find that many things will cause the console's tabs to revert to the default every 8 spaces ... running any console EXE in the same console ... even running notepad (by name only, but not with START). The most surprising one (because it's internal) is TYPE. See below how the tabs are set to 4 spaces and how they're reset to 8 spaces when I type the file. The file contains "a<tab>b<tab>c ...".

Rex, can you shed some light on why the tab settings change in this and other circumstances. FWIW, I'm setting the tabs using a handle obtained with CreateFile(L"CONOUT$"). I'm using WriteConsole() with ANSI escape sequences to do it and subsequently closing the handle.
Last edited:
If you have ANSI enabled, TYPE will be calling SetConsoleMode.
Does it change any settings? Is it expected to clobber tabs set with ANSI? What about notepad? Does issuing "notepad" at the prompt trigger a call to SetConsoleMode ... and (again) is that expected to clobber the tab settings?
Does it change any settings? Is it expected to clobber tabs set with ANSI? What about notepad? Does issuing "notepad" at the prompt trigger a call to SetConsoleMode ... and (again) is that expected to clobber the tab settings?

TYPE does a GetConsoleMode to save the original settings, then calls SetConsoleMode to restore them after it's done. There is no flag for ANSI tabs.

Executing Notepad will not trigger a call to SetConsoleMode.

As to all the rest of your questions -- I have no idea. Talk to Microsoft; it's their undocumented feature.
The escape sequences are documented in Console Virtual Terminal Sequences - Windows Console

That document also has sketchy info on enabling/disabling VT processing with SetConsoleMode().

When, from the plugin function that set the tabs, I use CreateProcess() to run notepad, the tabs settings are not clobbered.

As far as I can tell, SetConsoleMode is called on every keystroke and with every issuance of the prompt. Issuing the command "notepad" causes a few additional calls to SetConsoleMode (with a different value (0x3 vs. 0xe7) for mode). Disabling/re-enabling VT processing may well clobber the tab settings.
Well, issuing "notepad" clobbers the tab settings. I don't know enough about it to say more now. After 30 years with tabs every 8 characters, I'm eager to see what's possible. Maybe TCC will wind up helping.
TCC does not remove the ENABLE_VIRTUAL_TERMINAL_PROCESSING flag. It sets it at startup if you are running Windows 10 & have selected ANSI.
Do you think it could NOT do that in pipe and transient instances? In those cases, it's already running in a console with ENABLE_VIRTUAL_TERMINAL_PROCESSING. Transient instances clobber the tab settings (even though I set them to every 4th column in TCSTART.BTM).

Maybe for child pipe processes. It would be a bad idea for transient instances.
More on this, mostly just FYI and FWIW.

I read about the DWORD value HKCU\Console\VirtualTerminalLevel. When it exists and equals 1, ENABLE_VIRTUAL_TERMINAL_PROCESSING is the default (tested it with my own EXE). But even with VirtualTerminalLevel = 1, ENABLE_VIRTUAL_TERMINAL_PROCESSING is off at InitializePlugin time. So I figure TCC is turning it off earlier, possibly inadvertantly (and back on later). That may be what's clobbering the tab settings.
ENABLE_VIRTUAL_TERMINAL_PROCESSING is always disabled when a new console session starts.

That doesn't seem to be true. Using this code in a test app.

INT wmain(INT argc, WCHAR **argv)
    DWORD dwMode;
    GetConsoleMode(hConOut, &dwMode);
    wprintf(L"Mode: 0x%lX\n", dwMode);
    return 0;

and starting the test app with a double-click in explorer I get:

0x3 when HKCU\Console\VirtualTerminalLevel=0, and
0x7 when HKCU\Console\VirtualTerminalLevel=1.

Since ENABLE_VIRTUAL_TERMINAL_PROCESSING = 0x4, I reckon the registry setting really does control the default startup mode.

I have HKCU\Console\VirtualTerminalLevel=1. And I have this code in InitializePlugin (to set tabs at 1, 5, 9 ...).

Starting TCC from explorer I get garbage.


If the plugin first does

    GetConsoleMode(con.h, &dwMode);
    SetConsoleMode(con.h, dwMode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);

I get tabs at 1, 5, 9, ... as desired.

That's why I figure TCC has turned off ENABLE_VIRTUAL_TERMINAL_PROCESSING before InitializePlugin.
This code was supposed to be in my last post as text but the forum wouldn't accept it. So I'm trying again.

    if ( g.bInteractive )
        INT iTabWidth = 4;                                // or maybe something from INI file
        WCHAR szSequence[16];

        emit(L"\x1b[?25l\x1b[s\x1b[3g");                // cursor: off, save its position; clear all tabs


        for ( INT i = 1; i <= con.csbi.dwSize.X; i += iTabWidth )
            wsprintf(szSequence, L"\x1b[%dG\x1bH", i);    // cursor to column i and set a tabstop

        emit(L"\x1b[u\x1b[?25h");                        // restore cursor pos and turn it back on

Similar threads