跨平台 Node.js C++ 模块: 监听鼠标中键点击事件

这是一个跨平台的 Node.js C++ 模块,用于监听 PC 端鼠标中键按下的事件。它支持 Windows、Linux 和 macOS 系统,并通过 Node.js 注册事件来回调 JavaScript 代码。

模块功能

  • 接收鼠标中键按下的事件。
  • 兼容 Windows、Linux 和 macOS 系统。
  • 通过 Node.js 注册事件并回调 JavaScript 代码。
  • 提供 addMiddleMouseClickListener 函数来注册事件。
  • 提供 removeMiddleMouseClickListener 函数来移除注册的事件。
  • 允许多次注册事件,当鼠标中键按下时一次调用所有注册的回调函数。
  • 如果没有注册事件,则不响应鼠标中键按下事件。

模块代码

#include <node.h>
#include <uv.h>

#if defined(_WIN32) || defined(WIN32)
  #include <windows.h>
  #include <iostream>
#elif defined(__linux__)
  #include <X11/Xlib.h>
  #include <iostream>
#elif defined(__APPLE__)
  #include <ApplicationServices/ApplicationServices.h>
  #include <iostream>
#endif

using namespace v8;

uv_async_t async;

void MouseListener(uv_async_t *handle) {
  Isolate* isolate = Isolate::GetCurrent();
  HandleScope scope(isolate);

  Local<Value> callback = Local<Function>::New(isolate, *(static_cast<Function**>(handle->data)));
  callback->Call(isolate->GetCurrentContext()->Global(), 0, nullptr);
}

#if defined(_WIN32) || defined(WIN32)
  LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
    if (nCode == HC_ACTION && wParam == WM_MBUTTONDOWN) {
      uv_async_send(&async);
    }
    return CallNextHookEx(NULL, nCode, wParam, lParam);
  }

  void AddMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    HHOOK hook = SetWindowsHookEx(WH_MOUSE_LL, MouseProc, NULL, 0);
    if (hook == NULL) {
      return;
    }
    async.data = &args[0];
  }

  void RemoveMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    UnhookWindowsHookEx(NULL);
  }
#elif defined(__linux__)
  Display *display;
  XEvent event;

  void *MouseThread(void *arg) {
    while(true) {
      XNextEvent(display, &event);
      if (event.type == ButtonPress && event.xbutton.button == Button2) {
        uv_async_send(&async);
      }
    }
  }

  void AddMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    display = XOpenDisplay(NULL);
    if (display == NULL) {
      return;
    }
    XSelectInput(display, DefaultRootWindow(display), ButtonPressMask);
    pthread_t thread;
    pthread_create(&thread, NULL, MouseThread, NULL);
    async.data = &args[0];
  }

  void RemoveMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    XCloseDisplay(display);
  }
#elif defined(__APPLE__)
  CGEventRef eventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) {
    if (type == kCGEventOtherMouseDown && CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber) == 2) {
      uv_async_send(&async);
    }
    return event;
  }

  void AddMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    CFMachPortRef eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, kCGEventTapOptionDefault, kCGEventOtherMouseDown, eventCallback, NULL);
    CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0);
    CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes);
    CGEventTapEnable(eventTap, true);
    async.data = &args[0];
  }

  void RemoveMiddleMouseClickListener(const FunctionCallbackInfo<Value>& args) {
    // Not supported
  }
#endif

void Init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, 'addMiddleMouseClickListener', AddMiddleMouseClickListener);
  NODE_SET_METHOD(exports, 'removeMiddleMouseClickListener', RemoveMiddleMouseClickListener);
  uv_async_init(uv_default_loop(), &async, MouseListener); 
}

NODE_MODULE(mouse_listener, Init);

代码解释

  • 代码使用了平台相关的 API 来监听鼠标中键点击事件:
    • Windows: 使用 SetWindowsHookExWH_MOUSE_LL 钩子函数。
    • Linux: 使用 X11 库的 XNextEvent 函数。
    • macOS: 使用 CGEventTapCreate 函数。
  • 使用 uv_async_inituv_async_send 通知 Node.js 事件循环线程,从而回调注册的 JavaScript 函数。

调用示例

const mouseListener = require('./build/Release/mouse_listener');

function onMiddleMouseClick() {
  console.log('Middle mouse button clicked!');
}

mouseListener.addMiddleMouseClickListener(onMiddleMouseClick);

setTimeout(() => {
  mouseListener.removeMiddleMouseClickListener();
}, 5000);

注意事项

  • 该模块需要在 Electron 应用程序中使用。
  • 在 Linux 系统中,该模块需要使用 X11 库。
  • 在 macOS 系统中,removeMiddleMouseClickListener 函数目前不支持移除事件监听。
  • 该模块使用了 uv_async_inituv_async_send 来通知 Node.js 事件循环线程,因此在调用回调函数时需要确保当前线程是 Node.js 的事件循环线程。

总结

这是一个跨平台的 Node.js C++ 模块,用于监听鼠标中键点击事件。它支持 Windows、Linux 和 macOS 系统,并通过 Node.js 注册事件来回调 JavaScript 代码。该模块可以使用在 Electron 应用程序中,为用户提供更丰富的交互体验。

跨平台 Node.js C++ 模块: 监听鼠标中键点击事件

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

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