2
votes

I need to hide mouse cursor immediately after application start. I am using ShowCursor(FALSE) for this. But often after ShowCursor(FALSE) the cursor remains on the screen until mouse move. I and other people reproduced this on different PCs with Windows from XP to 10. In order to reproduce this, just launch the application from Windows Explorer by double clicking the executable and ABSOLUTELY DON'T move the mouse while double clicking and after that. If the application is launched in any other way, the cursor is hidden, as expected. It seems that cursor, when it stays on the screen, belongs to Windows Explorer, sometimes in addition to cursor on the screen remains Explorer tooltip.

Code that does not always work:

#include <Windows.h>

LRESULT __stdcall WndProcFull(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg==WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pszCmdLine, int iCmdShow)
{
    MSG msg;
    HWND hWnd;
    PCWSTR pszFullName=L"FullWindow";
    WNDCLASSEX wc={sizeof (WNDCLASSEX), 0, WndProcFull, 0, 0, hInstance, 0, LoadCursor(0, IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), 0, pszFullName, 0};
    RegisterClassEx(&wc);
    hWnd=CreateWindow(pszFullName, L"HideCursor", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, 0, 0, 0, 0, 0, 0, hInstance, 0);
    UpdateWindow(hWnd);
    ShowCursor(FALSE);
    while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);
    return 0;
}

The source code is compiled in any VS.

The only thing that currently helps is to set the timer and, after timer interval expires, programmatically move mouse cursor, then it hides. But I would prefer to find more suitable and stable solution.

Code with workaround:

#include <Windows.h>

#define HIDECURSOR_TIMER_ID 1

LRESULT __stdcall WndProcFull(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_TIMER:
        POINT pt;
        GetCursorPos(&pt);
        SetCursorPos(pt.x+1, pt.y);
        KillTimer(hWnd, HIDECURSOR_TIMER_ID);
        return 0;
    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pszCmdLine, int iCmdShow)
{
    MSG msg;
    HWND hWnd;
    PCWSTR pszFullName=L"FullWindow";
    WNDCLASSEX wc={sizeof (WNDCLASSEX), 0, WndProcFull, 0, 0, hInstance, 0, LoadCursor(0, IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), 0, pszFullName, 0};
    RegisterClassEx(&wc);
    hWnd=CreateWindow(pszFullName, L"HideCursor", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, 0, 0, 0, 0, 0, 0, hInstance, 0);
    UpdateWindow(hWnd);
    ShowCursor(FALSE);
    SetTimer(hWnd, HIDECURSOR_TIMER_ID, 200, 0);
    while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);
    return 0;
}

200 ms is the minimum timeout value at which the cursor stable disappears.

2
Works just fine when I try it without the timer hack. Do what works. - Hans Passant
Probably you slightly moved the mouse while double clicking the executable? Two other people also were able to reproduce this on other computers when they stopped moving the mouse. - Mogod
Obvious questions: Why do you register a window class, that has a non-null cursor? Why aren't you handling WM_SETCURSOR? - IInspectable
Because in the original application I often need to show the cursor again in this window. With null cursor situation is the same, I tried it already. - Mogod
What about the second question? If you want to manipulate the cursor it would appear natural to handle WM_SETCURSOR. - IInspectable

2 Answers

2
votes

When the CreateWindow function returns, the window is still not displayed on screen. You should call the ShowCursor function in early window creation time immediately after it has been realized. IMHO the best place is when processing the WM_CREATE message. Code would become:

#include <Windows.h>

LRESULT __stdcall WndProcFull(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    if (uMsg==WM_DESTROY)
    {
        PostQuitMessage(0);
        return 0;
    }
    else if (uMsg == WM_CREATE) {
        ShowCursor(FALSE);
    }
    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pszCmdLine, int iCmdShow)
{
    MSG msg;
    HWND hWnd;
    PCWSTR pszFullName=L"FullWindow";
    WNDCLASSEX wc={sizeof (WNDCLASSEX), 0, WndProcFull, 0, 0, hInstance, 0, LoadCursor(0, IDC_ARROW), (HBRUSH)GetStockObject(BLACK_BRUSH), 0, pszFullName, 0};
    RegisterClassEx(&wc);
    hWnd=CreateWindow(pszFullName, L"HideCursor", WS_POPUP | WS_MAXIMIZE | WS_VISIBLE, 0, 0, 0, 0, 0, 0, hInstance, 0);
    UpdateWindow(hWnd);
    //ShowCursor(FALSE);
    while (GetMessage(&msg, 0, 0, 0)) DispatchMessage(&msg);
    return 0;
}

That way you really hide the cursor as soon as the window has been created and realized.

1
votes

According the documentation:

If bShow is TRUE, the display count is incremented by one. If bShow is FALSE, the display count is decremented by one.

So to hide the cursor, you want something like this:

while(ShowCursor(FALSE) >= 0);