C++:如何捕捉鼠标点击发生的任何地方

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10817860/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 14:30:02  来源:igfitidea点击:

c++: How to catch mouse clicks wherever they happen

c++winapimouse

提问by GSta

I am stuck with an application I am writing where I need to monitor for mouse clicks.

我被我正在编写的应用程序困住了,我需要监视鼠标点击。

The clicks may happen anywhere on the screen and not inside the app window, and for each click I must pass a message (perform an action or something).

点击可能发生在屏幕上的任何地方,而不是在应用程序窗口内,每次点击我都必须传递一条消息(执行一个动作或某事)。

I looked around and read some suggestions like using

我环顾四周并阅读了一些建议,例如使用

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

but I was unsuccessful.

但我没有成功。

Does anyone have an idea on how to implement what I need?

有没有人知道如何实现我需要的东西?

采纳答案by Eugene Mayevski 'Callback

You need to set a mouse hook as described in MSDN.

您需要按照MSDN 中的说明设置鼠标挂钩。

Note that in your case the hook would need to be global. This means that you need to implement a handler function in a DLL, which will be loaded into all processes in the system which receive mouse message. Such DLL will communicate with your main application using some interprocess communication (IPC) mechanism like shared memory or via Windows messages posted(not sent) from the DLL to the main application.

请注意,在您的情况下,钩子需要是全局的。这意味着您需要在 DLL 中实现一个处理函数,该函数将被加载到系统中所有接收鼠标消息的进程中。此类 DLL 将使用某些进程间通信 (IPC) 机制(如共享内存)或通过从 DLL发布(未发送)到主应用程序的Windows 消息与您的主应用程序进行通信。

You can use the source code from this CodeProject articleas a guide.

您可以使用此 CodeProject 文章中的源代码作为指南。

Update: as per Chris' correction, I should note that above applies to "regular" mouse hook which is synchronous. Low-level hook doesn't need to be located in the DLL, but it has certain limitations which are described in the corresponding MSDN article.

更新:根据克里斯的更正,我应该注意到以上适用于同步的“常规”鼠标钩子。低级钩子不需要位于 DLL 中,但它有一些限制,在相应的 MSDN 文章中有所描述。

回答by Enrique Wood

well I don't really know if you solved your problem. I hope so. But I was in the same trouble today and searching I found a way really easy to do it.

好吧,我真的不知道你是否解决了你的问题。但愿如此。但是今天我遇到了同样的麻烦,我在搜索中找到了一种非常容易做到的方法。

So here you are:

所以你在这里:

int keyPressed(int key){
    return (GetAsyncKeyState(key) & 0x8000 != 0);
}

int main(){
    while(1){
        if(keyPressed(VK_LBUTTON)){
            printf("%s\n","Click izquierdo");
        }
        if(keyPressed(VK_RBUTTON)){
            printf("%s\n","Click Derecho");
        }
    }
    return 0;
}

the key of this solution is the function GetAsyncKeyState(key), where key anyone of the codes that appears here https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx

这个解决方案的关键是函数 GetAsyncKeyState(key),这里出现的任何代码都是关键https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx

回答by Aurus

You could use SetWindowsHookEx

你可以用 SetWindowsHookEx

Here's a small sample:

这是一个小示例:

#define _WIN32_WINNT 0x0500
#include <windows.h>

HHOOK MouseHook;

LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam){

        PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);
        POINT p;


        if(wParam == WM_RBUTTONDOWN)
        { 
          // right button clicked 
          GetCursorPos(&p);
        }

}

void StayAlive(){
        while(_getch() != 27) { }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nShowCmd){
        FreeConsole();

        MouseHook = SetWindowsHookEx(WH_MOUSE_LL,MouseHookProc,hInstance,0);
        StayAlive();

        UnhookWindowsHookEx(MouseHook);
        return 0;
}

回答by Aurus

LRESULT CALLBACK WndProc(...), as it name suggests is a (specific) window (message) processor where you can analyze and respond to messages on the queue that were deferred by the system to your custom definition of the callback for further processing.

LRESULT CALLBACK WndProc(...),顾名思义,它是一个(特定的)窗口(消息)处理器,您可以在其中分析和响应队列中被系统推迟到您自定义的回调定义以进行进一步处理的消息。

Since you want to detect and act on mouse clicks anywhere on the screen, as chris suggested in the comments, one way is to hook yourself into the system by calling SetWindowsHookEx() which is quite verbose in its very definition - it allows you to track stuff happening on the system and relay that information back to your application.

由于您想检测屏幕上任意位置的鼠标点击并采取行动,正如克里斯在评论中建议的那样,一种方法是通过调用 SetWindowsHookEx() 将自己连接到系统中,它的定义非常冗长 - 它允许您跟踪系统上发生的事情并将该信息传递回您的应用程序。

This is the syntax which you need to employ in order to get yourself

这是您需要使用的语法才能让自己

HHOOK WINAPI SetWindowsHookEx(
  __in  int idHook,
  __in  HOOKPROC lpfn,
  __in  HINSTANCE hMod,
  __in  DWORD dwThreadId
);

It takes in a specific hook id, which are basically little #defines which tell the function what kind of messages you wish to receive from all over the system, you pass it a callback just like the WndProc, but this time it's meant to process the incoming messages regarding across the system. hMod simply refers to the handle to the application or the DLL in which the just mentioned proc function callback is located in. The last one relates to threads currently running on the system, setting this to 0 or NULL retrieves messages for all existing threads.

它接受一个特定的钩子 id,它基本上是一个小 #defines,它告诉函数你希望从整个系统接收什么样的消息,你像 WndProc 一样向它传递一个回调,但这次它是为了处理关于整个系统的传入消息。hMod 只是指应用程序或刚刚提到的 proc 函数回调所在的 DLL 的句柄。最后一个与当前在系统上运行的线程有关,将此设置为 0 或 NULL 检索所有现有线程的消息。

Important:

重要

Do note that Aurus' example call to the SetWindowsHookEx is process-specific which a fancy word relating it to an actual application, instead of a DLL which can be appended to multiple processes across the system ( a global one ) and return information to your application. It would be prudent to take the time and effort to investigate Eugene's recommended method instead of this forceful approach useful only for experiments. It's a bit "harder", but the reward is worthwhile.

请注意,Aurus 对 SetWindowsHookEx 的示例调用是特定于进程的,这是一个将它与实际应用程序相关联的花哨词,而不是一个可以附加到系统中多个进程(全局进程)并将信息返回到应用程序的 DLL . 谨慎的做法是花时间和精力研究尤金推荐的方法,而不是这种仅对实验有用的有力方法。这有点“难”,但回报是值得的。

Less work is not always better or preferable.

更少的工作并不总是更好或更可取。