Node.js 可调用 C++ 模块:监听鼠标中间按钮事件
Node.js 可调用 C++ 模块:监听鼠标中间按钮事件
本模块实现了一个可被 Node.js 调用的 C++ 模块,用于监听鼠标中间按钮的点击事件。该模块支持 Windows、Linux 和 macOS 平台,并提供 addMiddleMouseClickListener 和 removeMiddleMouseClickListener 函数用于注册和移除事件监听。
功能概述:
- 在 Electron 环境下运行。
- 接收 PC 端鼠标中间按钮按下的事件。
- 兼容 Linux、Windows 和 macOS 系统。
- 通过 Node.js 注册事件来回调 JavaScript 代码。
- 支持多次注册事件,当鼠标中间按钮按下时一次调用所有回调函数。
- 如果没有注册事件,则不响应鼠标中间按钮点击事件。
使用方法:
-
注册事件监听:
const middleMouseClick = require('./build/Release/middleMouseClick.node'); function callback() { console.log('Middle mouse button clicked.'); } middleMouseClick.addMiddleMouseClickListener(callback); -
移除事件监听:
setTimeout(() => { middleMouseClick.removeMiddleMouseClickListener(callback); }, 5000);
C++ 模块代码 (middleMouseClick.cpp):
#include <node.h>
#include <nan.h>
#include <iostream>
#include <thread>
#include <chrono>
#if defined(_WIN32) || defined(WIN32)
#include <Windows.h>
#define SLEEP_MS(x) Sleep(x)
#define MOUSEEVENTF_MIDDLEDOWN 0x0020
#define MOUSEEVENTF_MIDDLEUP 0x0040
#elif defined(__linux__)
#include <X11/Xlib.h>
#define SLEEP_MS(x) std::this_thread::sleep_for(std::chrono::milliseconds(x))
#elif defined(__APPLE__)
#include <ApplicationServices/ApplicationServices.h>
#define SLEEP_MS(x) std::this_thread::sleep_for(std::chrono::milliseconds(x))
#endif
using namespace Nan;
using namespace v8;
// 定义回调函数类型
typedef void (*MiddleMouseClickCallback)();
// 定义全局变量存储回调函数
static std::vector<MiddleMouseClickCallback> middleMouseClickCallbacks;
// 定义监听线程函数
void listenMiddleMouseClick() {
while (true) {
SLEEP_MS(100);
#if defined(_WIN32) || defined(WIN32)
if (GetAsyncKeyState(VK_MBUTTON) & 0x8000) {
for (auto callback : middleMouseClickCallbacks) {
callback();
}
}
#elif defined(__linux__)
Display *display = XOpenDisplay(NULL);
if (display == NULL) {
std::cerr << 'Failed to open X display.' << std::endl;
continue;
}
Window root = DefaultRootWindow(display);
XEvent event;
while (XPending(display) > 0) {
XNextEvent(display, &event);
if (event.type == ButtonPress && event.xbutton.button == Button2) {
for (auto callback : middleMouseClickCallbacks) {
callback();
}
}
}
XCloseDisplay(display);
#elif defined(__APPLE__)
CGEventRef event = CGEventCreate(NULL);
if (event == NULL) {
std::cerr << 'Failed to create CGEvent.' << std::endl;
continue;
}
CGEventFlags flags = CGEventGetFlags(event);
CFRelease(event);
if ((flags & kCGEventFlagMaskNonCoalesced) == kCGEventFlagMaskNonCoalesced) {
for (auto callback : middleMouseClickCallbacks) {
callback();
}
}
#endif
}
}
// 定义addMiddleMouseClickListener函数
NAN_METHOD(addMiddleMouseClickListener) {
// 获取回调函数参数
if (info.Length() < 1 || !info[0]->IsFunction()) {
return ThrowTypeError('Argument 1 must be a function.');
}
Local<Function> callback = info[0].As<Function>();
// 将回调函数存入全局变量
MiddleMouseClickCallback c_callback = []() {
Nan::HandleScope scope;
callback->Call(Nan::GetCurrentContext()->Global(), 0, NULL);
};
middleMouseClickCallbacks.push_back(c_callback);
// 如果是第一个回调函数,启动监听线程
if (middleMouseClickCallbacks.size() == 1) {
std::thread(listenMiddleMouseClick).detach();
}
}
// 定义removeMiddleMouseClickListener函数
NAN_METHOD(removeMiddleMouseClickListener) {
// 获取回调函数参数
if (info.Length() < 1 || !info[0]->IsFunction()) {
return ThrowTypeError('Argument 1 must be a function.');
}
Local<Function> callback = info[0].As<Function>();
// 从全局变量中移除回调函数
MiddleMouseClickCallback c_callback = []() {
Nan::HandleScope scope;
callback->Call(Nan::GetCurrentContext()->Global(), 0, NULL);
};
for (auto it = middleMouseClickCallbacks.begin(); it != middleMouseClickCallbacks.end(); ++it) {
if (*it == c_callback) {
middleMouseClickCallbacks.erase(it);
break;
}
}
}
// 定义模块初始化函数
NAN_MODULE_INIT(init) {
// 注册addMiddleMouseClickListener函数
Nan::Set(target, New<String>('addMiddleMouseClickListener').ToLocalChecked(),
GetFunction(New<FunctionTemplate>(addMiddleMouseClickListener)).ToLocalChecked());
// 注册removeMiddleMouseClickListener函数
Nan::Set(target, New<String>('removeMiddleMouseClickListener').ToLocalChecked(),
GetFunction(New<FunctionTemplate>(removeMiddleMouseClickListener)).ToLocalChecked());
}
// 导出模块
NODE_MODULE(middleMouseClick, init)
demo 代码 (index.js):
const middleMouseClick = require('./build/Release/middleMouseClick.node');
function callback() {
console.log('Middle mouse button clicked.');
}
middleMouseClick.addMiddleMouseClickListener(callback);
setTimeout(() => {
middleMouseClick.removeMiddleMouseClickListener(callback);
}, 5000);
注意:
- 监听事件时使用非阻塞方式,避免影响程序运行。
- 确保在编译 C++ 模块时包含必要的头文件和库文件。
- 在 Electron 中使用该模块,需要将 C++ 模块编译成 Node.js 可执行文件。
- 该模块仅用于监听鼠标中间按钮点击事件,不涉及其他鼠标事件。
使用示例:
在 Electron 应用程序中使用该模块,可以实现以下功能:
- 在鼠标中间按钮点击时打开一个新窗口或执行其他操作。
- 在特定时间段内监听鼠标中间按钮点击,并在点击时触发特定事件。
- 根据鼠标中间按钮点击的次数执行不同的操作。
更多功能:
可以扩展该模块以支持其他鼠标事件,例如鼠标左键点击、鼠标右键点击、鼠标移动等。还可以添加其他功能,例如设置监听时间间隔、过滤特定类型的事件等。
原文地址: https://www.cveoy.top/t/topic/ok4b 著作权归作者所有。请勿转载和采集!