ConPTY does not move cursor to new line when writing to inactive screen buffer #23874

Open
opened 2026-01-31 08:54:53 +00:00 by claunia · 3 comments
Owner

Originally created by @trexxet on GitHub (Dec 14, 2025).

Windows Terminal version

1.23.12811.0

Windows build number

10.0.19045.0

Other Software

No response

Steps to reproduce

I'm trying to measure the size that a text (which may contain tabs, newlines etc.) would take in a console without printing it. For this purpose, I created a console screen buffer that does not become active (so let's call it "virtual screen buffer"). The idea is simple: sync virtual buffer settings and cursor position with a "real" screen buffer; write text to it; get new cursor position.

The code (compiled with gcc 15.1.0, MinGW64 / MSYS2):

    hOut = CreateConsoleScreenBuffer (GENERIC_WRITE | GENERIC_READ, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    if (hOut == INVALID_HANDLE_VALUE) [[unlikely]]
        throw std::runtime_error ("Can't create hOut for VHandle");

    ... // sync CSBI srWindow, dwSize and dwCursorPosition

    COORD curPosSave = csbi(hOut).dwCursorPosition;

    DWORD written;
    if (!WriteConsole (hOut, s.c_str(), s.length(), &written, NULL)) [[unlikely]]
        throw std::runtime_error (std::format ("Can't WriteConsole for hOut {}", hOut));
    Debug::print (std::format ("WriteConsole hOut {} written {}\n", hOut, written));
    // Debug::print writes to file not to mess with console

    COORD curPos = csbi(hOut).dwCursorPosition;
    Debug::print (std::format ("hOut {} cursor [{} {}] -> [{} {}]\n", hOut, curPosSave.X, curPosSave.Y, curPos.X, curPos.Y));

I've tested this code with:

  • cmd.exe (conhost)
  • powershell (conhost)
  • powershell (windows terminal, conpty)
  • bash (mintty mingw64, conpty)
  • bash (mintty mingw64 --pcon off) - fails on GetConsoleMode()
  • bash (VS Code terminal, conpty)

As I want the program to work with older Windows versions, I'm not using virtual terminal sequences.

Expected Behavior

No response

Actual Behavior

For all test cases, WriteConsole() did not fail and wrote the correct value to written.

For each shell/console, I tested writing a "test string" and "test string\n" (as I'm building with mingw, I don't need to care about '\r').

Shell/console Without \n With \n
cmd.exe (conhost) ✔️[0 130] -> [11 130] ✔️[0 127] -> [0 128]
powershell (conhost) ✔️[0 51] -> [11 51] ✔️[0 7] -> [0 8]
powershell (windows terminal, conpty) ✔️[0 29] -> [11 29] [0 29] -> [0 29]
bash (mintty, conpty) ✔️[0 26] -> [11 26] [0 26] -> [0 26]
bash (VS Code terminal, conpty) ✔️[0 13] -> [11 13] [0 13] -> [0 13]

If the text is long enough to cause line wrap, ConPTY does not move the cursor in Y axis as well, while conhost does.

Originally created by @trexxet on GitHub (Dec 14, 2025). ### Windows Terminal version 1.23.12811.0 ### Windows build number 10.0.19045.0 ### Other Software _No response_ ### Steps to reproduce I'm trying to measure the size that a text (which may contain tabs, newlines etc.) would take in a console without printing it. For this purpose, I created a console screen buffer that does not become active (so let's call it "virtual screen buffer"). The idea is simple: sync virtual buffer settings and cursor position with a "real" screen buffer; write text to it; get new cursor position. The code (compiled with gcc 15.1.0, MinGW64 / MSYS2): ```c++ hOut = CreateConsoleScreenBuffer (GENERIC_WRITE | GENERIC_READ, 0, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); if (hOut == INVALID_HANDLE_VALUE) [[unlikely]] throw std::runtime_error ("Can't create hOut for VHandle"); ... // sync CSBI srWindow, dwSize and dwCursorPosition COORD curPosSave = csbi(hOut).dwCursorPosition; DWORD written; if (!WriteConsole (hOut, s.c_str(), s.length(), &written, NULL)) [[unlikely]] throw std::runtime_error (std::format ("Can't WriteConsole for hOut {}", hOut)); Debug::print (std::format ("WriteConsole hOut {} written {}\n", hOut, written)); // Debug::print writes to file not to mess with console COORD curPos = csbi(hOut).dwCursorPosition; Debug::print (std::format ("hOut {} cursor [{} {}] -> [{} {}]\n", hOut, curPosSave.X, curPosSave.Y, curPos.X, curPos.Y)); ``` I've tested this code with: * cmd.exe (conhost) * powershell (conhost) * powershell (windows terminal, conpty) * bash (mintty mingw64, conpty) * bash (mintty mingw64 --pcon off) - fails on `GetConsoleMode()` * bash (VS Code terminal, conpty) As I want the program to work with older Windows versions, I'm not using virtual terminal sequences. ### Expected Behavior _No response_ ### Actual Behavior For all test cases, `WriteConsole()` did not fail and wrote the correct value to `written`. For each shell/console, I tested writing a `"test string"` and `"test string\n"` (as I'm building with mingw, I don't need to care about `'\r'`). |Shell/console|Without \n|With \n| |---------------|------------|-------| |cmd.exe (conhost)|✔️[0 130] -> [11 130]|✔️[0 127] -> [0 128]| |powershell (conhost)|✔️[0 51] -> [11 51]|✔️[0 7] -> [0 8]| |powershell (windows terminal, conpty)|✔️[0 29] -> [11 29]|❌[0 29] -> [0 29]| |bash (mintty, conpty)|✔️[0 26] -> [11 26]|❌[0 26] -> [0 26]| |bash (VS Code terminal, conpty)|✔️[0 13] -> [11 13]|❌[0 13] -> [0 13]| If the text is long enough to cause line wrap, ConPTY does not move the cursor in Y axis as well, while conhost does.
claunia added the Issue-BugPriority-3Area-ServerProduct-Conpty labels 2026-01-31 08:54:53 +00:00
Author
Owner

@lhecker commented on GitHub (Dec 14, 2025):

Could you please turn your example snippet into a complete (standalone) repro? Just the C/C++ code would be enough. I'd like to compile and test it.

@lhecker commented on GitHub (Dec 14, 2025): Could you please turn your example snippet into a complete (standalone) repro? Just the C/C++ code would be enough. I'd like to compile and test it.
Author
Owner

@trexxet commented on GitHub (Dec 14, 2025):

@lhecker Sure, here it is https://github.com/trexxet/test-conpty-cursor

@trexxet commented on GitHub (Dec 14, 2025): @lhecker Sure, here it is https://github.com/trexxet/test-conpty-cursor
Author
Owner

@trexxet commented on GitHub (Dec 14, 2025):

Some further observations:

  1. Other control characters ('\t', '\b') work fine
  2. Regardless of '\n', writing a text long enough to cause line wrap does not move the cursor to a new line in ConPTY, but works fine in conhost.
@trexxet commented on GitHub (Dec 14, 2025): Some further observations: 1) Other control characters ('\t', '\b') work fine 2) Regardless of '\n', writing a text long enough to cause line wrap does not move the cursor to a new line in ConPTY, but works fine in conhost.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#23874