ClipCursor 成功,但实际上什么也没做 [英] ClipCursor succeeds, but effectively does nothing

查看:34
本文介绍了ClipCursor 成功,但实际上什么也没做的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm writing a very simple program to clip the mouse to a specified window. It runs from the system tray without a visible window. Because there will be multiple instances of the same window, it uses EnumWindows() to iterate through every top-level window and compare their hwnd with GetForegroundWindow(). When true, it runs the standard ClipCursor() code. ClipCursor() returns TRUE, and, I've asserted that the RECT set by GetClipCursor() is the exact same as the RECT passed to ClipCursor(). Yet, the cursor is free to move anywhere on the screen.

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

I've checked that the values in the RECT are the exact values of the window, I've compiled the program in release mode and ran it with admin rights, still nothing. The code below is exactly what runs after we've found the HWND of the GetForegroundWindow():

// 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() 的),但是这段代码肯定会在它应该运行的时候运行.光标没有被剪掉,我不明白为什么.

I've removed a lot of the checks because they were getting annoying (I was using MessageBox()'s), but this code is certainly running when it's supposed to. The cursor just isn't getting clipped, and I can't fathom why.

推荐答案

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

Well, it only took me a few days to find out that despite the shared nature of the Cursor resource, if a process is clipping a cursor in certain circumstances that I don't fully know of yet (maybe the process has to be the foreground application? or something like that... I'm not so sure.) then the OS automatically releases the cursor back to full clipping mode (or whatever you'd call it).

无论如何,修复是做一个低级鼠标钩子并从那里调用剪辑光标.这是一些概念代码的快速证明(经过测试并有效,但我删除了不相关的内容,例如创建窗口或设置系统托盘等):

Anyway, the fix is to do a low level mouse hook and call the clipcursor from there. Here's some quick proof of concept code (tested and works, although I removed the irrelevant stuff like creating a window or setting up the systray etc):

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

这篇关于ClipCursor 成功,但实际上什么也没做的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆