Terminal doesn't respond to WM_VSCROLL #9580

Closed
opened 2026-01-31 01:58:15 +00:00 by claunia · 5 comments
Owner

Originally created by @AnFunctionArray on GitHub (Jul 12, 2020).

Environment

Platform ServicePack Version VersionString


Win32NT 10.0.20152.0 Microsoft Windows NT 10.0.20152.0

Windows Terminal Preview 1.1.1812.0

Steps to reproduce

Send a WM_VSCROLL message to GetConsoleWindow() (C language example here):

SendMessage(GetConsoleWindow(), WM_VSCROLL, SB_TOP, 0);

Expected behavior

Scroll to top.

Actual behavior

I've looked at the code here - it seems this functionality isn't implemented. I can only assume it can be done with a one linear as scrolling seems to be working otherwise. And there is a function that receives this message - only it's with an empty body.

Originally created by @AnFunctionArray on GitHub (Jul 12, 2020). # Environment Platform ServicePack Version VersionString -------- ----------- ------- ------------- Win32NT 10.0.20152.0 Microsoft Windows NT 10.0.20152.0 Windows Terminal Preview 1.1.1812.0 # Steps to reproduce Send a WM_VSCROLL message to `GetConsoleWindow()` (C language example here): `SendMessage(GetConsoleWindow(), WM_VSCROLL, SB_TOP, 0);` # Expected behavior Scroll to top. # Actual behavior I've looked at the code here - it seems this functionality isn't implemented. I can only assume it can be done with a one linear as scrolling seems to be working otherwise. And there is a function that receives this message - only it's with an empty body.
Author
Owner

@zadjii-msft commented on GitHub (Jul 13, 2020):

Why are you doing this? There is certainly a better way of controlling the buffer output, rather than using window messages.

For the record, the Terminal (and any terminal emulators using conpty) will only return a dummy value from GetConsoleWindow(). It's generally regarded that that was a silly API, and modern app developers shouldn't be using that.

@zadjii-msft commented on GitHub (Jul 13, 2020): Why are you doing this? There is certainly a better way of controlling the buffer output, rather than using window messages. For the record, the Terminal (and any terminal emulators using conpty) will only return a dummy value from `GetConsoleWindow()`. It's generally regarded that that was a silly API, and modern app developers shouldn't be using that.
Author
Owner

@AnFunctionArray commented on GitHub (Jul 13, 2020):

Why are you doing this? There is certainly a better way of controlling the buffer output, rather than using window messages.

For the record, the Terminal (and any terminal emulators using conpty) will only return a dummy value from GetConsoleWindow(). It's generally regarded that that was a silly API, and modern app developers shouldn't be using that.

I don't mind being a modern developer - what do I use here - I just want to programmatically scroll the console to the top.

@AnFunctionArray commented on GitHub (Jul 13, 2020): > Why are you doing this? There is certainly a better way of controlling the buffer output, rather than using window messages. > > For the record, the Terminal (and any terminal emulators using conpty) will only return a dummy value from `GetConsoleWindow()`. It's generally regarded that that was a silly API, and modern app developers shouldn't be using that. I don't mind being a modern developer - what do I use here - I just want to programmatically scroll the console to the top.
Author
Owner

@AnFunctionArray commented on GitHub (Jul 16, 2020):

Nvm - I've found a way to get ahold of the actual cascadia hosting window handle using the following code:

#include  <stdio.h>
#include <Windows.h>
#include <stdbool.h>
#include <tlhelp32.h>

static HWND hActualConsoleWindow;

BOOL CALLBACK enumwindows(HWND hwnd, LPARAM lParam)
{
    printf("%x\n", hwnd);
    CHAR chBuffer[1024];
    GetClassName(hwnd, chBuffer, sizeof chBuffer);
    printf("%s\n", chBuffer);
    if (!stricmp(chBuffer, "CASCADIA_HOSTING_WINDOW_CLASS"))
        hActualConsoleWindow = hwnd;
}
main()
{
    DWORD dwProcessIdConsole;
    GetWindowThreadProcessId(GetConsoleWindow(), &dwProcessIdConsole);

    THREADENTRY32 threadinfo = { .dwSize = sizeof threadinfo };

    PROCESSENTRY32 procinfo = { .dwSize = sizeof procinfo };

    printf("%x\n", dwProcessIdConsole);

    HANDLE hThreads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessIdConsole);

    HANDLE hProcesses = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, dwProcessIdConsole);

    if (Process32First(hProcesses, &procinfo)) do
        if (procinfo.th32ProcessID == dwProcessIdConsole && (dwProcessIdConsole = procinfo.th32ParentProcessID, true))
            break;
    while (Process32Next(hProcesses, &procinfo));

    printf("%x\n", hThreads);

    if (Thread32First(hThreads, &threadinfo)) do 
        if(GetProcessIdOfThread(OpenThread(THREAD_QUERY_LIMITED_INFORMATION, 0, threadinfo.th32ThreadID)) == dwProcessIdConsole)
            printf("%x\n", threadinfo.th32ThreadID), EnumThreadWindows(threadinfo.th32ThreadID, enumwindows, 0);
    while (Thread32Next(hThreads, &threadinfo) && !hActualConsoleWindow);

    printf("%x\n", hActualConsoleWindow);

    RECT r;
    GetClientRect(hActualConsoleWindow, &r);

    //scroll up
    SendMessage(hActualConsoleWindow, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA * 2), MAKELPARAM(r.right / 2, r.bottom / 2));

    Sleep(-1);

    return;
}
@AnFunctionArray commented on GitHub (Jul 16, 2020): Nvm - I've found a way to get ahold of the actual cascadia hosting window handle using the following code: ``` #include <stdio.h> #include <Windows.h> #include <stdbool.h> #include <tlhelp32.h> static HWND hActualConsoleWindow; BOOL CALLBACK enumwindows(HWND hwnd, LPARAM lParam) { printf("%x\n", hwnd); CHAR chBuffer[1024]; GetClassName(hwnd, chBuffer, sizeof chBuffer); printf("%s\n", chBuffer); if (!stricmp(chBuffer, "CASCADIA_HOSTING_WINDOW_CLASS")) hActualConsoleWindow = hwnd; } main() { DWORD dwProcessIdConsole; GetWindowThreadProcessId(GetConsoleWindow(), &dwProcessIdConsole); THREADENTRY32 threadinfo = { .dwSize = sizeof threadinfo }; PROCESSENTRY32 procinfo = { .dwSize = sizeof procinfo }; printf("%x\n", dwProcessIdConsole); HANDLE hThreads = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, dwProcessIdConsole); HANDLE hProcesses = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, dwProcessIdConsole); if (Process32First(hProcesses, &procinfo)) do if (procinfo.th32ProcessID == dwProcessIdConsole && (dwProcessIdConsole = procinfo.th32ParentProcessID, true)) break; while (Process32Next(hProcesses, &procinfo)); printf("%x\n", hThreads); if (Thread32First(hThreads, &threadinfo)) do if(GetProcessIdOfThread(OpenThread(THREAD_QUERY_LIMITED_INFORMATION, 0, threadinfo.th32ThreadID)) == dwProcessIdConsole) printf("%x\n", threadinfo.th32ThreadID), EnumThreadWindows(threadinfo.th32ThreadID, enumwindows, 0); while (Thread32Next(hThreads, &threadinfo) && !hActualConsoleWindow); printf("%x\n", hActualConsoleWindow); RECT r; GetClientRect(hActualConsoleWindow, &r); //scroll up SendMessage(hActualConsoleWindow, WM_MOUSEWHEEL, MAKEWPARAM(0, WHEEL_DELTA * 2), MAKELPARAM(r.right / 2, r.bottom / 2)); Sleep(-1); return; } ```
Author
Owner

@zadjii-msft commented on GitHub (Jul 16, 2020):

For the record, I'm offering no guarantees that this will continue working. Our windowing should be considered an implementation detail, it's not really something that we're exposing to application developers.

Part of the trick here is that the Terminal is a terminal, not a console. On other platforms, commandline applications can only control the bottom viewport of the buffer. Everything above that, the "history" (or "scrollback") is immutable, and an implementation detail of the Terminal. So client applications can't tell the Terminal "scroll up to this point in your history".

The Windows Terminal is trying to be more like a terminal than a console, so you'd probably have a similarly hard time doing that in the Windows Terminal (as you would on other platforms). Could you elaborate more on why you're trying to scroll the history up to the top? Maybe there's a better way of achieving what you're looking for than manually scrolling the buffer contents.

@zadjii-msft commented on GitHub (Jul 16, 2020): For the record, I'm offering no guarantees that this will continue working. Our windowing should be considered an implementation detail, it's not _really_ something that we're exposing to application developers. Part of the trick here is that the Terminal is a _terminal_, not a _console_. On other platforms, commandline applications can only control the bottom viewport of the buffer. Everything above that, the "history" (or "scrollback") is _immutable_, and an implementation detail of the Terminal. So client applications can't tell the Terminal "scroll up to this point in your history". The Windows Terminal is trying to be more like a _terminal_ than a _console_, so you'd probably have a similarly hard time doing that in the Windows Terminal (as you would on other platforms). Could you elaborate more on why you're trying to scroll the history up to the top? Maybe there's a better way of achieving what you're looking for than manually scrolling the buffer contents.
Author
Owner

@AnFunctionArray commented on GitHub (Jul 16, 2020):

@zadjii-msft Look at.

@AnFunctionArray commented on GitHub (Jul 16, 2020): @zadjii-msft Look [at](https://github.com/microsoft/terminal/issues/6935).
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/terminal#9580