【问题标题】:Impossible to hide mouse cursor using ShowCursor(FALSE) immediately after application start应用程序启动后无法立即使用 ShowCursor(FALSE) 隐藏鼠标光标
【发布时间】:2015-10-25 14:20:12
【问题描述】:

我需要在应用程序启动后立即隐藏鼠标光标。我为此使用 ShowCursor(FALSE)。但通常在 ShowCursor(FALSE) 之后,光标会一直停留在屏幕上,直到鼠标移动。我和其他人在 Windows 从 XP 到 10 的不同 PC 上重现了这个。为了重现这个,只需通过双击可执行文件从 Windows 资源管理器启动应用程序,然后绝对不要在双击和之后移动鼠标。如果应用程序以任何其他方式启动,则光标会按预期隐藏。似乎光标停留在屏幕上时属于Windows资源管理器,有时除了屏幕上的光标之外仍然是资源管理器工具提示。

并非总是有效的代码:

#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;
}

源代码在任何VS中编译。

目前唯一有用的是设置计时器,并且在计时器间隔到期后,以编程方式移动鼠标光标,然后隐藏。但我更愿意找到更合适、更稳定的解决方案。

带有解决方法的代码:

#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 毫秒是光标稳定消失的最小超时值。

【问题讨论】:

  • 当我在没有计时器黑客的情况下尝试它时工作得很好。做有效的事。
  • 可能您在双击可执行文件时稍微移动了鼠标?当另外两个人停止移动鼠标时,他们也能够在其他计算机上重现这一点。
  • 显而易见的问题:为什么要注册一个具有非空光标的窗口类?你为什么不处理WM_SETCURSOR
  • 因为在原来的应用程序中我经常需要在这个窗口中再次显示光标。用空游标的情况也是一样的,我已经试过了。
  • 第二个问题呢?如果您想操作光标,处理WM_SETCURSOR 似乎很自然。

标签: c++ winapi


【解决方案1】:

CreateWindow 函数返回时,窗口仍然没有显示在屏幕上。您应该在窗口创建的早期调用ShowCursor 函数,在它实现后立即调用它。恕我直言,最好的地方是在处理WM_CREATE 消息时。代码将变为:

#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;
}

这样一来,一旦创建并实现了窗口,您就真正隐藏了光标。

【讨论】:

  • 在 WM_CREATE 和 WM_SHOWWINDOW 处理程序中尝试过 ShowCursor(FALSE),也无济于事。由于某种原因,我无法在没有 150-200 毫秒延迟的情况下以编程方式隐藏此光标。
  • WM_CREATE 被发送到窗口过程之前 CreateWindow[Ex] 返回。
【解决方案2】:

根据the documentation

如果 bShow 为 TRUE,则显示计数加一。如果 bShow 为 FALSE,则显示计数减一。

所以要隐藏光标,你需要这样的东西:

while(ShowCursor(FALSE) >= 0);

【讨论】:

  • 已经试过了,没用。光标保持在屏幕上直到鼠标移动,即使是负数显示计数器。我认为这个光标属于 Explorer,而不是我的应用程序。
  • 我会按照@IInspectable 的建议处理WM_SETCURSOR。也许你别无选择。
猜你喜欢
  • 1970-01-01
  • 2017-06-07
  • 2021-10-19
  • 1970-01-01
  • 1970-01-01
  • 2014-10-18
  • 2011-05-24
  • 2018-06-04
  • 1970-01-01
相关资源
最近更新 更多