ClipCursor成功,但实际上什么也没做

Pur*_*ebe 5 winapi

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

我已经检查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);
Run Code Online (Sandbox Code Playgroud)

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

Ray*_*hen 5

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


Pur*_*ebe 3

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

无论如何,修复方法是执行低级鼠标挂钩并从那里调用 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;
}
Run Code Online (Sandbox Code Playgroud)