SetWindowsHookEx в модуле node.js с использованием node-nan

Я пытаюсь создать приложение Electron node.js, которое может выполнять определенные функции, используя глобальные привязки клавиш. К сожалению, глобальный API-интерфейс связывания клавиш в Electron не работает в играх, поэтому мне нужно создать собственный модуль узла, который будет прослушивать эти события клавиш низкого уровня.

Поэтому я использую node-gyp для компиляции проекта с Visual Studio 2015 и Nan, чтобы обеспечить связь между узлом и c ++. Мне удалось заставить оба аспекта проекта работать отдельно (низкоуровневые привязки клавиш и node.js).<-> Нан связи) но у меня возникли проблемы с их объединением. Я также признаю, что у меня очень мало опыта работы с 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 * ‘to’ Nan:
: AsyncProgressWorker :: ExecutionProgress * ‘
[C: \ Users \ eksrow \ GDrive \ Проекты \ vscode \ узел-нативной привет-мир \ сборка \ bindin
g.vcxproj].

..\ binding.cc (21): примечание: конверсия теряет квалификаторы

отформатирован:

‘const Nan :: AsyncProgressWorker :: ExecutionProgress *’

‘Nan :: AsyncProgressWorker :: ExecutionProgress *’

Эту проблему мне удалось решить, добавив ключевое слово const в приватный член * executeProgress ;. Но я не понимаю, почему это все исправит, переменные const не должны изменяться после их установки. Почему это компилируется?

Проблема № 2: Эта очень необычная:

..\ binding.cc (22): ошибка C3867: ‘KeyboardEventWorker :: HookCallback’:
нестандартный синтаксис; использовать&создать указатель на член
[C: \ Users \ eksrow \ GDrive \ Проекты \ vscode \ узел-нативной привет-мир \ сборка \ binding.vcxproj]

Я посмотрел много примеров в Интернете, и все они имеют одинаковый синтаксис относительно этого:

  1. SetWindowsHookEx # 1
  2. SetWindowsHookEx # 2

Я не вижу разницы между моим кодом и их в отношении этой строки.

Если я делаю то, что говорит компилятор, и добавляю амперсанд в эту строку, это дает совершенно другую ошибку:

..\ binding.cc (22): ошибка C2276: ‘&’: незаконная операция на связанном члене
выражение функции [C: \ Users \ eksrow \ gdrive \ proj
ЕКТС \ vscode \ узел-нативной привет-мир \ сборка \ binding.vcxproj] .. \ binding.cc (22): ошибка C2660: ‘SetWindowsHookExA’: функция не работает
принять 3 аргумента [C: \ Users \ eksrow \ gdrive \ project
s \ vscode \ узел-нативной привет-мир \ сборка \ binding.vcxproj]

1

Решение

Для задачи № 1, Вы правильно определили const классификатор как проблема.

Причину, которую вы можете указать const переменная-член после объявления этого из-за размещения const в const AsyncProgressWorker::ExecutionProgress *executionProgress, Это указатель на переменную AsyncProgressWorker :: ExecutionProgress. Это означает, что вы можете изменить значение указателя (например, переназначить его, как в примере выше), но вы не можете изменить данные, на которые он указывает. Лучший ответ на этот вопрос имеет очень хорошее объяснение этой концепции.

Для задачи № 2, ошибка вызвана попыткой передать функцию-член вашего класса как функцию обратного вызова. Это просто невозможно (ну, без обходного пути … см. Ниже) — метод-член — это не то же самое, что функция. SetWindowsHookEx ожидает. Вы могли бы сделать вашу функцию обратного вызова static, но тогда не сможет получить доступ к _hook член.

Вот внешняя страница с (очень хакерским) обходным решением для этой точной проблемы. Это должно позволить вам использовать SetWindowsHookEx так, как вы сейчас пытаетесь его использовать. Однако я бы рекомендовал переосмыслить способ подключения вашего приложения и вместо этого посмотреть, есть ли способ зарегистрировать одну глобальную функцию или статическую функцию-член в качестве обратного вызова для вашего приложения.

Не имеет отношения к вашему вопросу: если вы не пропустили код в своем примере, вы никогда не отцепите хук, установленный в SetWindowsHookEx, Посмотрите на MSDN для UnhookWindowsHookEx.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]