FillConsole on the final cell in a line moves the internal cursor #6403

Open
opened 2026-01-31 00:37:42 +00:00 by claunia · 0 comments
Owner

Originally created by @malxau on GitHub (Feb 13, 2020).

Environment

Windows build number: 10.0.18363.657
Windows Terminal version (if applicable):  0.8.10261.0

Steps to reproduce

Here's a repro program. I've tried to make this as simple as I can, but the way the visual cursor location is not the same as the reported cursor location makes this strangely confusing:

#include <windows.h>
#include <stdio.h>

int main(int argc, char * argv[])
{
    CONSOLE_SCREEN_BUFFER_INFO StartScreenInfo;
    CONSOLE_SCREEN_BUFFER_INFO PostFillScreenInfo;
    CONSOLE_SCREEN_BUFFER_INFO PostWriteScreenInfo;
    HANDLE ConHandle;
    DWORD NumberWritten;

    ConHandle = GetStdHandle(STD_OUTPUT_HANDLE);
    GetConsoleScreenBufferInfo(ConHandle, &StartScreenInfo);

    // Set the console mode to some consistent value.
    SetConsoleMode(ConHandle, ENABLE_PROCESSED_OUTPUT);

    // Move the cursor to the rightmost cell in the line, and sleep to show
    // that as far as the user is concerned, that's where it is.  If this is
    // any cell except the rightmost one, the following test case will behave
    // correctly.
    StartScreenInfo.dwCursorPosition.X = StartScreenInfo.dwSize.X - 1;
    SetConsoleCursorPosition(ConHandle, StartScreenInfo.dwCursorPosition);
    Sleep(3000);

    // Fill the final cell.  This API should not move the cursor.  In conhost,
    // the cursor does not appear to move, but in WT, it visually moves.
    // Sleep for a bit to show that the cursor location displayed to the user
    // has changed.
    FillConsoleOutputCharacter(ConHandle, 'X', 1, StartScreenInfo.dwCursorPosition, &NumberWritten);
    Sleep(3000);

    // Check the location of the cursor according to the API.  This shows that
    // the cursor has not moved.
    GetConsoleScreenBufferInfo(ConHandle, &PostFillScreenInfo);

    // Write to the current cursor location.  This shows that the visual
    // display is right and the API is wrong - the cursor has moved.  In
    // conhost, this Y should overwrite the previous X.  In WT, the Y goes
    // off into the ether.
    WriteConsole(ConHandle, "Y", 1, &NumberWritten, NULL);
    GetConsoleScreenBufferInfo(ConHandle, &PostWriteScreenInfo);

    // According to the API, the cursor was in the same place the whole time.
    printf("\nCursor before fill at %i,%i; after fill at %i,%i; after write at %i,%i\n",
           StartScreenInfo.dwCursorPosition.X,
           StartScreenInfo.dwCursorPosition.Y,
           PostFillScreenInfo.dwCursorPosition.X,
           PostFillScreenInfo.dwCursorPosition.Y,
           PostWriteScreenInfo.dwCursorPosition.X,
           PostWriteScreenInfo.dwCursorPosition.Y);

    return 0;
}

Expected behavior

With the attached repro program, the cursor should move to the right of the line; X should be displayed, and the cursor should not move; Y should overwrite X; and the program should complete that indicates each of the three cursor locations are identical. Note that changing the dwCursorPositionValue to be anything except the rightmost character will generate this behavior.

Actual behavior

With WT, the repro displays X, but the visual cursor moves even though the reported cursor location does not. The next character written is presumably written to the visual cursor location, meaning that it is not displayed. The reported cursor locations suggest the cursor has not moved, which is clearly not what is happening internally.

Originally created by @malxau on GitHub (Feb 13, 2020). <!-- 🚨🚨🚨🚨🚨🚨🚨🚨🚨🚨 I ACKNOWLEDGE THE FOLLOWING BEFORE PROCEEDING: 1. If I delete this entire template and go my own path, the core team may close my issue without further explanation or engagement. 2. If I list multiple bugs/concerns in this one issue, the core team may close my issue without further explanation or engagement. 3. If I write an issue that has many duplicates, the core team may close my issue without further explanation or engagement (and without necessarily spending time to find the exact duplicate ID number). 4. If I leave the title incomplete when filing the issue, the core team may close my issue without further explanation or engagement. 5. If I file something completely blank in the body, the core team may close my issue without further explanation or engagement. All good? Then proceed! --> <!-- This bug tracker is monitored by Windows Terminal development team and other technical folks. **Important: When reporting BSODs or security issues, DO NOT attach memory dumps, logs, or traces to Github issues**. Instead, send dumps/traces to secure@microsoft.com, referencing this GitHub issue. If this is an application crash, please also provide a Feedback Hub submission link so we can find your diagnostic data on the backend. Use the category "Apps > Windows Terminal (Preview)" and choose "Share My Feedback" after submission to get the link. Please use this form and describe your issue, concisely but precisely, with as much detail as possible. --> # Environment ``` Windows build number: 10.0.18363.657 Windows Terminal version (if applicable): 0.8.10261.0 ``` # Steps to reproduce Here's a repro program. I've tried to make this as simple as I can, but the way the visual cursor location is not the same as the reported cursor location makes this strangely confusing: ``` #include <windows.h> #include <stdio.h> int main(int argc, char * argv[]) { CONSOLE_SCREEN_BUFFER_INFO StartScreenInfo; CONSOLE_SCREEN_BUFFER_INFO PostFillScreenInfo; CONSOLE_SCREEN_BUFFER_INFO PostWriteScreenInfo; HANDLE ConHandle; DWORD NumberWritten; ConHandle = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(ConHandle, &StartScreenInfo); // Set the console mode to some consistent value. SetConsoleMode(ConHandle, ENABLE_PROCESSED_OUTPUT); // Move the cursor to the rightmost cell in the line, and sleep to show // that as far as the user is concerned, that's where it is. If this is // any cell except the rightmost one, the following test case will behave // correctly. StartScreenInfo.dwCursorPosition.X = StartScreenInfo.dwSize.X - 1; SetConsoleCursorPosition(ConHandle, StartScreenInfo.dwCursorPosition); Sleep(3000); // Fill the final cell. This API should not move the cursor. In conhost, // the cursor does not appear to move, but in WT, it visually moves. // Sleep for a bit to show that the cursor location displayed to the user // has changed. FillConsoleOutputCharacter(ConHandle, 'X', 1, StartScreenInfo.dwCursorPosition, &NumberWritten); Sleep(3000); // Check the location of the cursor according to the API. This shows that // the cursor has not moved. GetConsoleScreenBufferInfo(ConHandle, &PostFillScreenInfo); // Write to the current cursor location. This shows that the visual // display is right and the API is wrong - the cursor has moved. In // conhost, this Y should overwrite the previous X. In WT, the Y goes // off into the ether. WriteConsole(ConHandle, "Y", 1, &NumberWritten, NULL); GetConsoleScreenBufferInfo(ConHandle, &PostWriteScreenInfo); // According to the API, the cursor was in the same place the whole time. printf("\nCursor before fill at %i,%i; after fill at %i,%i; after write at %i,%i\n", StartScreenInfo.dwCursorPosition.X, StartScreenInfo.dwCursorPosition.Y, PostFillScreenInfo.dwCursorPosition.X, PostFillScreenInfo.dwCursorPosition.Y, PostWriteScreenInfo.dwCursorPosition.X, PostWriteScreenInfo.dwCursorPosition.Y); return 0; } ``` # Expected behavior With the attached repro program, the cursor should move to the right of the line; X should be displayed, and the cursor should not move; Y should overwrite X; and the program should complete that indicates each of the three cursor locations are identical. Note that changing the dwCursorPositionValue to be anything except the rightmost character will generate this behavior. # Actual behavior With WT, the repro displays X, but the visual cursor moves even though the reported cursor location does not. The next character written is presumably written to the visual cursor location, meaning that it is not displayed. The reported cursor locations suggest the cursor has not moved, which is clearly not what is happening internally.
claunia added the Needs-TriageNeeds-Tag-FixNeeds-Attention labels 2026-01-31 00:37:42 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#6403