【问题标题】:ClipCursor succeeds, but effectively does nothingClipCursor 成功,但实际上什么也没做
【发布时间】:2021-09-14 09:05:17
【问题描述】:

我正在编写一个非常简单的程序来将鼠标剪辑到指定的窗口。它从系统托盘运行,没有可见窗口。因为同一个窗口会有多个实例,所以它使用EnumWindows() 遍历每个顶级窗口并将它们的hwnd 与GetForegroundWindow() 进行比较。如果为真,它会运行标准的ClipCursor() 代码。 ClipCursor() 返回TRUE,并且我断言GetClipCursor() 设置的RECT 与传递给ClipCursor()RECT 完全相同。然而,光标可以在屏幕上任意移动。

我已经检查了RECT 中的值是窗口的确切值,我已经在发布模式下编译了程序并以管理员权限运行它,仍然没有。下面的代码正是我们找到GetForegroundWindow()HWND 之后运行的代码:

// Get the window client area.
GetClientRect(hwnd, &rc);

// Convert the client area to screen coordinates.
POINT pt = { rc.left, rc.top };
POINT pt2 = { rc.right, rc.bottom };
ClientToScreen(hwnd, &pt);
ClientToScreen(hwnd, &pt2);
SetRect(&rc, pt.x, pt.y, pt2.x, pt2.y);

clipped = true;
ClipCursor(&rc);

RECT rect;
GetClipCursor(&rect);

assert(rect.bottom == rc.bottom);
assert(rect.left == rc.left);
assert(rect.right == rc.right);
assert(rect.top == rc.top);

我已经删除了很多检查,因为它们变得烦人(我使用的是MessageBox()'s),但是这段代码肯定会在它应该运行的时候运行。光标没有被剪断,我无法理解为什么。

【问题讨论】:

  • 您正在剪辑的窗口是否在同一进程中?我不确定,但如果您不能在其他进程中剪辑光标,我不会感到惊讶。
  • 光标是共享资源,因此任何进程都可以对其进行剪辑(您不是将其剪辑到进程,而是屏幕上的一个矩形。)

标签: winapi


【解决方案1】:

由于光标是共享资源,因此任何其他调用ClipCursor 取消光标剪辑的人都会覆盖您剪辑它的尝试。并且很多操作会自动松开光标(例如任何焦点变化)。背景窗口更改光标剪辑被认为是一种糟糕的形式。

【讨论】:

    【解决方案2】:

    好吧,我只花了几天时间就发现,尽管光标资源具有共享性质,但如果一个进程在某些我还不完全了解的情况下剪切光标(也许该进程必须是前台应用程序?或类似的东西......我不太确定。)然后操作系统会自动将光标释放回完全剪切模式(或任何你称之为的)。

    无论如何,解决方法是做一个低级鼠标钩子并从那里调用剪辑光标。这是一些概念代码的快速证明(经过测试并且可以工作,尽管我删除了不相关的东西,例如创建窗口或设置系统托盘等):

    // Some variables we'll use
    bool clipped = false;   // Do we need to clip the mouse?
    RECT rc;                // The clip rect
    HHOOK hMouseHook;       // Low level mouse hook
    
    // Low level mouse hook callback function
    __declspec(dllexport) LRESULT CALLBACK MouseEvent(int nCode, WPARAM wParam, LPARAM lParam)
    {
        // This part should be rewritten to make it not be a CPU-hog
        // But works as a proof of concept
        if ( clipped )
            ClipCursor(&rc);
    
        return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
    }
    
    int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
    {
        // .... Blah blah blah ....
    
        // Low level mouse hook
        hMouseHook = SetWindowsHookEx(WH_MOUSE_LL, (HOOKPROC)MouseEvent, hInstance, 0);
    
        // Only included to show that you set the hook before this,
        // And unhook after this.
        while(GetMessage(&msg, NULL, 0, 0) > 0)
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    
        // Unhook the mouse
        UnhookWindowsHookEx(hMouseHook);
    
        return msg.wParam;
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-26
      • 1970-01-01
      • 2011-08-07
      • 2013-06-02
      • 2020-11-21
      • 2015-02-26
      • 2017-06-29
      • 2013-06-13
      相关资源
      最近更新 更多