Node.js 可调用的 C++ 模块:鼠标中间按钮监听
Node.js 可调用的 C++ 模块:鼠标中间按钮监听
这是一个跨平台的 C++ 模块,用于监听鼠标中间按钮事件,并在 Electron 环境中通过 Node.js 注册回调函数来处理事件。
功能
- 兼容 Windows、Linux 和 macOS 系统。
- 通过
addMiddleMouseClickListener函数注册回调函数,在鼠标中间按钮按下时调用。 - 通过
removeMiddleMouseClickListener函数移除某个注册的回调函数。 - 允许多次注册
addMiddleMouseClickListener,当鼠标中间按钮按下时,所有注册的回调函数都会被调用。 - 如果没有注册回调函数,则不会响应鼠标中间按钮按下事件。
代码示例
C++ 模块文件 (middleMouseClickListener.cpp)
#include <node.h>
#include <v8.h>
#include <iostream>
#include <thread>
#ifdef _WIN32
#include <windows.h>
#elif __linux__
#include <X11/Xlib.h>
#include <X11/extensions/XInput2.h>
#elif __APPLE__
#include <ApplicationServices/ApplicationServices.h>
#endif
using namespace v8;
// 定义回调函数类型
typedef std::function<void()> MiddleMouseClickCallback;
// 中间按钮监听类
class MiddleMouseClickListener {
public:
// 添加回调函数
void addListener(const MiddleMouseClickCallback& callback) {
callbacks.push_back(callback);
}
// 移除某个回调函数
void removeListener(const MiddleMouseClickCallback& callback) {
callbacks.erase(std::remove(callbacks.begin(), callbacks.end(), callback), callbacks.end());
}
// 监听中间按钮事件
void listen() {
#ifdef _WIN32
// Windows下使用系统API获取鼠标信息
while (true) {
if ((GetAsyncKeyState(VK_MBUTTON) & 0x8000) != 0) {
// 中间按钮按下
for (auto callback : callbacks) {
callback();
}
}
Sleep(10);
}
#elif __linux__
// Linux下使用X11扩展库获取鼠标信息
Display* display = XOpenDisplay(NULL);
int xi_opcode, event, error;
if (XQueryExtension(display, "XInputExtension", &xi_opcode, &event, &error)) {
int major = 2, minor = 0;
if (XIQueryVersion(display, &major, &minor) == Success) {
int device_count;
XIDeviceInfo* devices = XIQueryDevice(display, XIAllDevices, &device_count);
if (devices != NULL) {
// 查找鼠标设备
for (int i = 0; i < device_count; i++) {
if (devices[i].use == XIMasterPointer) {
XIDeviceInfo* device = &devices[i];
XEventClass event_class;
// 注册中间按钮事件
if (XIQueryPointer(display, device->deviceid, DefaultRootWindow(display), &event_class, &event, &error) == Success) {
XIEventMask event_mask;
unsigned char mask[(XI_LASTEVENT + 7)/8];
memset(mask, 0, sizeof(mask));
XISetMask(mask, XI_ButtonPress);
XISetMask(mask, XI_ButtonRelease);
event_mask.deviceid = device->deviceid;
event_mask.mask_len = sizeof(mask);
event_mask.mask = mask;
XISelectEvents(display, DefaultRootWindow(display), &event_mask, 1);
while (true) {
XEvent event;
XGenericEventCookie* cookie = (XGenericEventCookie*)&event.xcookie;
XNextEvent(display, &event);
if (cookie->type == GenericEvent && cookie->extension == xi_opcode) {
XIDeviceEvent* xi_event = (XIDeviceEvent*)cookie->data;
if (xi_event->evtype == XI_ButtonPress && xi_event->detail == 2) {
// 中间按钮按下
for (auto callback : callbacks) {
callback();
}
}
}
}
}
}
}
XIFreeDeviceInfo(devices);
}
}
}
XCloseDisplay(display);
#elif __APPLE__
// Mac下使用系统API获取鼠标信息
CGEventMask mask = CGEventMaskBit(kCGEventOtherMouseDown);
CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionListenOnly, mask, NULL);
CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
while (true) {
CFRunLoopRun();
}
#endif
}
private:
std::vector<MiddleMouseClickCallback> callbacks;
};
// 中间按钮监听器实例
MiddleMouseClickListener listener;
// 初始化中间按钮监听模块
void initModule(Local<Object> exports) {
// 添加addMiddleMouseClickListener函数
exports->Set(String::NewFromUtf8(Isolate::GetCurrent(), "addMiddleMouseClickListener"), FunctionTemplate::New(Isolate::GetCurrent(), [](const FunctionCallbackInfo<Value>& args) {
if (args.Length() > 0 && args[0]->IsFunction()) {
// 注册回调函数
Local<Function> callback = Local<Function>::Cast(args[0]);
listener.addListener([callback]() {
callback->Call(Null(Isolate::GetCurrent()), 0, nullptr);
});
}
args.GetReturnValue().Set(Undefined(Isolate::GetCurrent()));
})->GetFunction());
// 添加removeMiddleMouseClickListener函数
exports->Set(String::NewFromUtf8(Isolate::GetCurrent(), "removeMiddleMouseClickListener"), FunctionTemplate::New(Isolate::GetCurrent(), [](const FunctionCallbackInfo<Value>& args) {
if (args.Length() > 0 && args[0]->IsFunction()) {
// 移除回调函数
Local<Function> callback = Local<Function>::Cast(args[0]);
listener.removeListener([callback]() {
callback->Call(Null(Isolate::GetCurrent()), 0, nullptr);
});
}
args.GetReturnValue().Set(Undefined(Isolate::GetCurrent()));
})->GetFunction());
// 启动中间按钮监听线程
std::thread([&listener]() {
listener.listen();
}).detach();
}
// 导出中间按钮监听模块
NODE_MODULE(middleMouseClickListener, initModule)
Demo 文件 (main.js)
const middleMouseClickListener = require('./middleMouseClickListener');
// 添加回调函数
middleMouseClickListener.addMiddleMouseClickListener(() => {
console.log('中间按钮按下');
});
// 移除回调函数
let callback = () => {
console.log('这个回调函数会被移除');
};
middleMouseClickListener.addMiddleMouseClickListener(callback);
middleMouseClickListener.removeMiddleMouseClickListener(callback);
注意事项
- 在 C++ 代码中监听事件时,不要使用阻塞方式,否则会影响 Electron 的运行。
- 该代码仅供参考,实际应用中可能需要根据具体情况进行调整。
使用方法
- 将
middleMouseClickListener.cpp文件编译成 Node.js 模块。 - 在 Electron 应用中使用
require函数加载该模块。 - 使用
addMiddleMouseClickListener函数注册回调函数。 - 使用
removeMiddleMouseClickListener函数移除回调函数。
总结
该模块提供了一个方便的方式,在 Electron 应用中监听鼠标中间按钮事件,并通过 Node.js 回调函数处理事件。它可以用于各种场景,例如在图片编辑器中实现缩放功能、在网页浏览器中实现滚轮滚动功能等。
原文地址: https://www.cveoy.top/t/topic/olDG 著作权归作者所有。请勿转载和采集!