Node.js 可调用 C++ 模块:监听鼠标中间按钮事件

本模块实现了一个可被 Node.js 调用的 C++ 模块,用于监听鼠标中间按钮的点击事件。该模块支持 Windows、Linux 和 macOS 平台,并提供 addMiddleMouseClickListenerremoveMiddleMouseClickListener 函数用于注册和移除事件监听。

功能概述:

  • 在 Electron 环境下运行。
  • 接收 PC 端鼠标中间按钮按下的事件。
  • 兼容 Linux、Windows 和 macOS 系统。
  • 通过 Node.js 注册事件来回调 JavaScript 代码。
  • 支持多次注册事件,当鼠标中间按钮按下时一次调用所有回调函数。
  • 如果没有注册事件,则不响应鼠标中间按钮点击事件。

使用方法:

  1. 注册事件监听:

    const middleMouseClick = require('./build/Release/middleMouseClick.node');
    
    function callback() {
        console.log('Middle mouse button clicked.');
    }
    
    middleMouseClick.addMiddleMouseClickListener(callback);
    
  2. 移除事件监听:

    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 应用程序中使用该模块,可以实现以下功能:

  • 在鼠标中间按钮点击时打开一个新窗口或执行其他操作。
  • 在特定时间段内监听鼠标中间按钮点击,并在点击时触发特定事件。
  • 根据鼠标中间按钮点击的次数执行不同的操作。

更多功能:

可以扩展该模块以支持其他鼠标事件,例如鼠标左键点击、鼠标右键点击、鼠标移动等。还可以添加其他功能,例如设置监听时间间隔、过滤特定类型的事件等。

Node.js 可调用 C++ 模块:监听鼠标中间按钮事件

原文地址: https://www.cveoy.top/t/topic/ok4b 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录