【问题标题】:How can I set cursor position from mouse hook in Windows?如何在 Windows 中从鼠标挂钩设置光标位置?
【发布时间】:2013-01-04 13:23:32
【问题描述】:

我正在尝试创建一个小应用程序,该应用程序将检测鼠标光标何时移动到屏幕边缘并将其移动到另一边缘,以创建连续的桌面效果,如果这有意义的话。

下面是其他人的一些代码(鼠标钩子部分),我通过添加 SetCursorPos 来将鼠标移动到固定位置。当我运行它时,SetCursorPos 返回 true,我认为这意味着调用成功,但鼠标没有移动。我在某个地方读到了一些关于更高版本 Windows 版本中的安全约束的内容,以防止这样的事情,这是有道理的,但来源不清楚这是多么真实。有谁知道为什么这不起作用?

谢谢,代码如下:

#define _WIN32_WINNT 0x0400
#pragma comment( lib, "user32.lib" )

#include <windows.h>
#include <stdio.h>

HHOOK hMouseHook;

__declspec(dllexport) LRESULT CALLBACK KeyboardEvent (int nCode, WPARAM wParam, LPARAM lParam)
{
    MOUSEHOOKSTRUCT * pMouseStruct = (MOUSEHOOKSTRUCT *)lParam;
    if (pMouseStruct != NULL)
    {
        if (pMouseStruct->pt.x < -1900)
        {
            BOOL r = SetCursorPos(
                500,
                500
            );

            printf("Trigger %d.  Response %d", pMouseStruct->pt.x, r);
        }
    }

    return CallNextHookEx(hMouseHook, nCode, wParam, lParam);
}

void MessageLoop()
{
    MSG message;
    while (GetMessage(&message,NULL,0,0)) {
        TranslateMessage( &message );
        DispatchMessage( &message );
    }
}

DWORD WINAPI MyMouseLogger(LPVOID lpParm)
{
    HINSTANCE hInstance = GetModuleHandle(NULL);
    if (!hInstance) hInstance = LoadLibrary((LPCSTR) lpParm); 
    if (!hInstance) return 1;

    hMouseHook = SetWindowsHookEx (  
        WH_MOUSE_LL,
        (HOOKPROC) KeyboardEvent,  
        hInstance,                 
        NULL                       
        );
    MessageLoop();
    UnhookWindowsHookEx(hMouseHook);
    return 0;
}

int main(int argc, char** argv)
{
    HANDLE hThread;
    DWORD dwThread;

    hThread = CreateThread(NULL,NULL,(LPTHREAD_START_ROUTINE)
        MyMouseLogger, (LPVOID) argv[0], NULL, &dwThread);
    if (hThread)
        return WaitForSingleObject(hThread,INFINITE);
    else return 1;
}

【问题讨论】:

  • 您的 printfs 是否有任何输出?
  • 另外,您可能想尝试比 -1900 更大的东西来进行测试。
  • @drescherjm 这是-1900,因为那是我左手显示器左侧大约 20 个像素。我的 printf 吐出以下“触发器 -1917。响应 1”等。我认为“响应 1”表示调用没有失败,但鼠标没有移动。这可能与单独的线程有关吗?如果我在程序开始时(挂钩之前)直接调用 SetCursorPos,则调用成功。
  • 您的 KeyboardEvent 函数不是 100% 正确的。当 nCode
  • 许多事情在异步执行时开始起作用。我会尝试将用户定义的消息从 KeyboardEvent 发布到主应用程序线程,并在那里执行 SetCursorPos。

标签: c++ windows winapi mouse-hook


【解决方案1】:

这似乎是在您的钩子过程中调用 SetCursorPos 时出现的问题。我想这在 Vista/Windows 7 中是明确禁止的,但我找不到任何文档来确认这一点。我稍微修改了您的代码以在它想要移动光标时发布一条线程消息,并在您的消息过程中执行实际的 SetCursorPos 。完成后就可以正常使用了。

在你的钩子程序中:

if (pMouseStruct->pt.x < -1900)
    {
        PostThreadMessage( GetCurrentThreadId(), WM_USER, 0, 0 );
        printf("Trigger %d.  Response %d", pMouseStruct->pt.x, r);
    }

在您的消息循环中:

while (GetMessage(&message,NULL,0,0)) {
    if( message.hwnd == NULL ) {
        if( message.message == WM_USER ) {
            SetWindowPos( 500, 500 );
        }
     } else {
         TranslateMessage( &message );
         DispatchMessage( &message );
     }
}

(请注意,这只是一个演示,并非实际修复。)

话虽如此,您的代码存在许多严重的问题。我认为这里不适合全部介绍,但我建议您将其发布到https://codereview.stackexchange.com/

【讨论】:

  • 谢谢彼得,试过了,它奏效了。我知道代码很糟糕,它是一个糟糕的原型,我想稍后可能会制作,但无法弄清楚 SetCursorPos 不起作用。再次感谢史蒂夫。 PS不知道codereview,肯定有用!
【解决方案2】:

看来您需要翻译坐标。 根据文档,您需要调用 ClientToScreenScreenToClient 来翻译这一点。我不知道哪个 Window 是参考。您需要将该窗口句柄作为点(作为输出参数)作为参数传递。然后将更改后的点与SetCursorPos一起使用

检查example

如果你想要屏幕你需要做GetDC(NULL)并将返回的句柄传递给ClientToScreen

【讨论】:

  • 抱歉,我不确定我是否理解。您指的是哪些文档?为什么我需要一个窗口?我只是希望这是一个监控全局鼠标位置的简单应用程序。事件方法正确接收屏幕坐标中的鼠标位置。 SetCursorPos 需要屏幕坐标。为什么我需要翻译?
猜你喜欢
  • 1970-01-01
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多