Node.js 可调用的 C++ 模块:跨平台鼠标中键点击事件监听
Node.js 可调用的 C++ 模块:跨平台鼠标中键点击事件监听
该模块用于在 Electron 环境下监听 PC 端鼠标中键按下事件,并通过 Node.js 注册事件回调 JavaScript 代码。它支持 Linux、Windows 和 macOS 三个平台,并允许用户多次注册事件回调,并在鼠标中键按下时一次调用所有注册的回调函数。
模块功能
- 跨平台支持: 支持 Linux、Windows 和 macOS 系统。
- 事件注册: 通过
addMiddleMouseClickListener函数注册鼠标中键点击事件回调。 - 事件移除: 通过
removeMiddleMouseClickListener函数移除已注册的事件回调。 - 多回调函数支持: 允许多次注册事件回调,并在鼠标中键按下时依次调用所有注册的回调函数。
代码实现
以下是一个简单的实现示例:
#include <nan.h>
#include <iostream>
#ifdef __linux__
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#elif _WIN32
#include <Windows.h>
#else
// macOS
#include <ApplicationServices/ApplicationServices.h>
#endif
using namespace Nan;
using namespace std;
namespace {
#ifdef __linux__
Display* dpy;
#elif _WIN32
HHOOK mouseHook;
#else
// macOS
CFMachPortRef eventTap;
#endif
Persistent<Array> callbacks;
// 回调函数类型
typedef void(*Callback)(int);
// 回调函数列表
vector<Callback> callbackList;
// 添加回调函数
NAN_METHOD(AddMiddleMouseClickListener) {
Callback callback = [](int button) {
// 调用 JavaScript 回调函数
CallbacksHolder(callbacks).Call({
New<String>('middleMouseClick').ToLocalChecked(),
New<Number>(button)
});
};
callbackList.push_back(callback);
info.GetReturnValue().Set(New<Number>(callbackList.size() - 1));
}
// 移除回调函数
NAN_METHOD(RemoveMiddleMouseClickListener) {
int index = To<int>(info[0]).FromJust();
if (index >= 0 && index < callbackList.size()) {
callbackList.erase(callbackList.begin() + index);
}
}
#ifdef __linux__
// Linux 平台下的事件监听函数
void handleEvent(XEvent* evt) {
if (evt->type == ButtonPress && evt->xbutton.button == Button2) {
int count = callbackList.size();
for (int i = 0; i < count; i++) {
callbackList[i](Button2);
}
}
}
// 线程函数,用于监听事件
void threadFunc() {
XEvent evt;
while (true) {
XNextEvent(dpy, &evt);
handleEvent(&evt);
}
}
#elif _WIN32
// Windows 平台下的事件监听函数
LRESULT CALLBACK mouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
if (nCode == HC_ACTION && wParam == WM_MBUTTONDOWN) {
int count = callbackList.size();
for (int i = 0; i < count; i++) {
callbackList[i](VK_MBUTTON);
}
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// 线程函数,用于安装鼠标钩子
void threadFunc() {
mouseHook = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, NULL, 0);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(mouseHook);
}
#else
// macOS 平台下的事件监听函数
CGEventRef eventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* userInfo) {
if (type == kCGEventOtherMouseDown && CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) == kCGMouseButtonCenter) {
int count = callbackList.size();
for (int i = 0; i < count; i++) {
callbackList[i](kCGMouseButtonCenter);
}
}
return event;
}
// 线程函数,用于监听事件
void threadFunc() {
CFRunLoopSourceRef runLoopSource;
eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventOtherMouseDown, eventTapCallback, NULL);
if (!eventTap) {
cerr << "Failed to create event tap." << endl;
return;
}
runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
if (!runLoopSource) {
cerr << "Failed to create run loop source." << endl;
CFRelease(eventTap);
return;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
CGEventTapEnable(eventTap, true);
CFRunLoopRun();
CGEventTapEnable(eventTap, false);
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
CFRelease(runLoopSource);
CFRelease(eventTap);
}
#endif
// 初始化函数
NAN_MODULE_INIT(init) {
callbacks.Reset(New<Array>());
Set(target, New<String>('addMiddleMouseClickListener').ToLocalChecked(), GetFunction(New<FunctionTemplate>(AddMiddleMouseClickListener)).ToLocalChecked());
Set(target, New<String>('removeMiddleMouseClickListener').ToLocalChecked(), GetFunction(New<FunctionTemplate>(RemoveMiddleMouseClickListener)).ToLocalChecked());
#ifdef __linux__
dpy = XOpenDisplay(NULL);
if (dpy) {
thread t(threadFunc);
t.detach();
}
#elif _WIN32
thread t(threadFunc);
t.detach();
#else
// macOS
thread t(threadFunc);
t.detach();
#endif
}
}
NODE_MODULE(mouse, init)
JavaScript 调用示例
const { ipcRenderer } = require('electron');
const mouse = require('./build/Release/mouse.node');
// 注册回调函数
let id = mouse.addMiddleMouseClickListener((button) => {
console.log('middle mouse button clicked:', button);
ipcRenderer.send('middleMouseClick', button);
});
// 移除回调函数
setTimeout(() => {
mouse.removeMiddleMouseClickListener(id);
}, 5000);
在这个示例中,我们使用 ipcRenderer 模块与主进程进行通信,并将鼠标中键按下的事件发送给主进程。在 5 秒后,我们移除这个回调函数。
注意
- 模块代码需要根据平台进行编译。
- 确保 Electron 环境已经配置好。
- 监听事件时不要使用阻塞方式,以免影响程序性能。
总结
该模块提供了一种简单易用的方法来在 Electron 环境下监听鼠标中键点击事件,并通过 Node.js 接口进行回调,方便开发者进行跨平台的鼠标事件处理。
原文地址: https://www.cveoy.top/t/topic/ooeS 著作权归作者所有。请勿转载和采集!