5

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

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

// 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),但是这段代码肯定会在它应该运行的时候运行。光标只是没有被剪裁,我无法理解为什么。

4

2 回答 2

6

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

于 2012-08-20T15:28:31.477 回答
4

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

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

// 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;
}
于 2012-08-19T14:26:37.943 回答