使用node-nan在node.js模块中设置WindowsHookEx

SetWindowsHookEx in a node.js module using node-nan

本文关键字:设置 WindowsHookEx 模块 js node-nan node 使用      更新时间:2023-10-16

我正在尝试创建一个Electron node.js应用程序,该应用程序可以使用全局键绑定执行某些功能。不幸的是,Electron中的全局键绑定API在游戏中不起作用,所以我需要创建一个本地节点模块来侦听这些低级别的键事件。

因此,我使用node-gyp与visualstudio2015和nan一起编译该项目,以提供node与c++之间的通信。我已经设法使项目的两个方面分别工作(低级密钥绑定和node.js<-->nan通信),但我很难将它们结合起来。我也承认我对c++的经验很少(我还没有写过一个c++程序)。

#include "node_modules/nan/nan.h"
using namespace std;
using namespace Nan;
HHOOK _hook;
KBDLLHOOKSTRUCT kbdStruct;
class KeyboardEventWorker : public AsyncProgressWorker {
 public:
  KeyboardEventWorker(Callback *callback, Callback *progress)
    : AsyncProgressWorker(callback), progress(progress) {}
  ~KeyboardEventWorker() {}
  
  LRESULT CALLBACK HookCallback(int nCode,WPARAM wParam,LPARAM lParam) {  
    executionProgress->Send(reinterpret_cast<const char*>(nCode), sizeof(nCode));
    return CallNextHookEx(_hook, nCode, wParam, lParam);
  }
  
  void Execute (const AsyncProgressWorker::ExecutionProgress& progress) {
    executionProgress = &progress; //PROBLEM #1
        _hook = SetWindowsHookEx(13, HookCallback, NULL, 0); //PROBLEM #2
    
    SleepEx(INFINITE, true);
  }

  void HandleProgressCallback(const char *data, size_t size) {
    HandleScope scope;
    
    v8::Local<v8::Value> argv[] = {
        New<v8::Integer>(*reinterpret_cast<int*>(const_cast<char*>(data)))
    };
    progress->Call(1, argv);
  }
  
  private:
    Callback *progress;
    AsyncProgressWorker::ExecutionProgress *executionProgress;
};
NAN_METHOD(DoProgress) {
  Callback *progress = new Callback(info[0].As<v8::Function>());
  Callback *callback = new Callback(info[1].As<v8::Function>());
  AsyncQueueWorker(new KeyboardEventWorker(callback, progress));
}
NAN_MODULE_INIT(Init) {
  Set(target
    , New<v8::String>("init").ToLocalChecked()
    , New<v8::FunctionTemplate>(DoProgress)->GetFunction());
}
NODE_MODULE(asyncprogressworker, Init)

问题#1:为了能够将消息发送回node.js,我需要复制AsyncProgressWorker::ExecutionProgress的指针,并使其对整个类可用,这样当HookCallback触发时,它就可以向node.js发送消息。

编译器不喜欢这个

\binding.cc(21):错误C2440:"=":无法从"const"转换Nan::AsyncProgressWorker::ExecutionProgress*'到'Nan::AsyncProgressWorker::ExecutionProgress*'[C:\Users\eksrow\gdrive\projects\vscode\node native hello world\build\binding.vcxproj].

\binding.cc(21):注意:转换丢失限定符

格式化:

"const Nan::AsyncProgressWorker::ExecutionProgress*"

'Nan::AsyncProgressWorker::ExecutionProgress*'

我通过在私有成员*executionProgress;中添加关键字const来解决这个问题;。但我不明白为什么这会解决问题,常量变量一旦设置就不应该被更改。为什么要编译?

问题2:这个很特别:

\binding.cc(22):错误C3867:"KeyboardEventWorker::HookCallback":非标准语法;使用"&"创建指向成员的指针[C:\Users\eksrow\gdrive\projects\vscode\node native hello world\build\binding.vcxproj]

我在网上查了很多例子,它们都有相同的语法:

  1. SetWindowsHookEx#1
  2. SetWindowsHookEx#2

关于这一行,我看不出我的代码和他们的代码有什么不同。

如果我按照编译器所说的去做,并在那一行中添加一个与号,它会给出一个完全不同的错误:

\binding.cc(22):错误C2276:"&":对绑定成员的非法操作函数表达式[C:\Users\eksrow\gdrive\projects\vscode\node native hello world\build\binding.vcxproj]..\binding.cc(22):错误C2660:"SetWindowsHookExA":函数不接受3个参数[C:\Users\eksrow\gdrive\projects\vscode\node本机hello world\build\binding.vcxproj]

对于问题#1,您正确地将const限定符标识为问题。

之所以可以在声明const成员变量后将其赋值,是因为const位于const AsyncProgressWorker::ExecutionProgress *executionProgress中。这是指向常量AsyncProgressWorker::ExecutionProgress的变量指针。这意味着你可以改变指针的值(例如,像上面的例子一样重新分配它),但你不能改变它指向的数据。这个问题的最高答案对这个概念有很好的解释。

对于问题#2,错误是由于试图将类的成员函数作为函数回调传递而引起的。这根本不可能(好吧,没有变通方法…见下文)-成员方法与函数不同,这正是SetWindowsHookEx所期望的。您可以将回调函数设为static,但之后将无法访问_hook成员。

这里有一个外部页面,提供了一个(非常破解的)解决这个问题的方法。它应该允许您以当前尝试的方式使用SetWindowsHookEx。但是,我建议您重新考虑应用程序的挂钩方式,看看是否有方法将单个全局函数或静态成员函数注册为应用程序的回调。

与您的问题无关:除非您在示例中省略了代码,否则您永远不会解开SetWindowsHookEx中设置的钩子。查看MSDN中的UnhookWindowsHookEx