Node.js 可调用的 C++ 模块:鼠标中键点击事件监听
本文将介绍如何编写一个 Node.js 可调用的 C++ 模块,该模块可以在 Electron 环境下运行,并监听 PC 端鼠标中键按下的事件。该模块将兼容 Linux、Windows 和 macOS 系统,并通过 Node.js 注册事件来回调 JavaScript 代码。
模块功能
该 C++ 模块将提供以下功能:
- 监听鼠标中键按下事件: 兼容 Linux、Windows 和 macOS 系统。
- 注册事件回调函数: 通过 Node.js 的
addMiddleMouseClickListener函数注册。 - 移除事件回调函数: 通过 Node.js 的
removeMiddleMouseClickListener函数移除。 - 允许多次注册: 当鼠标中键按下时,会一次调用所有注册的回调函数。
- 未注册时不响应: 如果没有注册任何回调函数,则不会响应鼠标中键按下事件。
模块代码
#include <node.h>
#include <v8.h>
#include <stdio.h>
#include <stdlib.h>
#if defined(WIN32)
#include <windows.h>
#include <winuser.h>
#elif defined(__linux__)
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#elif defined(__APPLE__)
#include <ApplicationServices/ApplicationServices.h>
#endif
using namespace v8;
Persistent<Function> middleMouseClickListener;
#if defined(WIN32)
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode >= 0 && wParam == WM_MBUTTONDOWN) {
Local<Function>::New(Isolate::GetCurrent(), middleMouseClickListener)->Call(Null(Isolate::GetCurrent()), 0, {});
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
HHOOK mouseHook = NULL;
#elif defined(__linux__)
Display *display;
Window rootWindow;
XEvent event;
#elif defined(__APPLE__)
CGEventRef event;
#endif
void AddMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
if (args.Length() != 1 || !args[0]->IsFunction()) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, 'Invalid argument')));
return;
}
Local<Function> callback = Local<Function>::Cast(args[0]);
middleMouseClickListener.Reset(isolate, callback);
#if defined(WIN32)
if (mouseHook == NULL) {
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProc, NULL, 0);
if (mouseHook == NULL) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, 'Failed to set Windows hook')));
}
}
#elif defined(__linux__)
if (display == NULL) {
display = XOpenDisplay(NULL);
if (display == NULL) {
isolate->ThrowException(Exception::TypeError(String::NewFromUtf8(isolate, 'Failed to open X11 display')));
return;
}
rootWindow = XDefaultRootWindow(display);
XSelectInput(display, rootWindow, ButtonPressMask);
}
#elif defined(__APPLE__)
// no initialization needed
#endif
}
void RemoveMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
middleMouseClickListener.Reset();
}
void Init(Handle<Object> exports) {
NODE_SET_METHOD(exports, 'addMiddleMouseClickListener', AddMiddleMouseClickListener);
NODE_SET_METHOD(exports, 'removeMiddleMouseClickListener', RemoveMiddleMouseClickListener);
}
#if defined(WIN32)
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) {
return TRUE;
}
#endif
NODE_MODULE(middle_mouse_click, Init)
编译 C++ 模块
- 安装
node-gyp:
npm install -g node-gyp
- 在命令行中进入 C++ 文件所在的目录,运行以下命令来编译 C++ 模块:
node-gyp configure
node-gyp build
编译成功后,会生成一个名为 build/Release/middle_mouse_click.node 的文件,这就是我们的 C++ 模块。
测试模块
创建一个 JavaScript 脚本来测试这个模块,命名为 test.js,代码如下:
const { addMiddleMouseClickListener, removeMiddleMouseClickListener } = require('./build/Release/middle_mouse_click.node');
function middleMouseClickHandler() {
console.log('Middle mouse button clicked');
}
addMiddleMouseClickListener(middleMouseClickHandler);
setTimeout(() => {
removeMiddleMouseClickListener(middleMouseClickHandler);
}, 10000);
最后,在命令行中运行以下命令来运行这个脚本:
node test.js
注意事项
- 在 C++ 代码中监听事件时,不要使用阻塞的方式,以避免影响 Node.js 的运行。
- 使用
node-gyp编译 C++ 模块时,需要确保你的系统环境配置正确,并且安装了必要的依赖库。 - 当你在 Electron 环境下使用这个模块时,你需要将
build/Release/middle_mouse_click.node文件打包到你的 Electron 应用中。
示例代码
以上示例代码展示了如何使用这个 C++ 模块监听鼠标中键按下的事件。你可以根据自己的需求对代码进行修改和扩展。
原文地址: https://www.cveoy.top/t/topic/oky4 著作权归作者所有。请勿转载和采集!