106 lines
2.7 KiB
C++
106 lines
2.7 KiB
C++
|
#include <v8.h>
|
||
|
#include <nan.h>
|
||
|
#include <node.h>
|
||
|
#include <iostream>
|
||
|
#include <mutex>
|
||
|
|
||
|
using namespace std;
|
||
|
|
||
|
#include "NanException.h"
|
||
|
#include "NanEventCallback.h"
|
||
|
#include "src/KeyboardHook.h"
|
||
|
|
||
|
|
||
|
std::mutex callback_lock;
|
||
|
std::deque<std::shared_ptr<Nan::Callback>> callbacks;
|
||
|
std::deque<std::shared_ptr<KeyboardHook::KeyEvent>> queued_events;
|
||
|
std::unique_ptr<KeyboardHook> hook;
|
||
|
|
||
|
Nan::callback_t<> event_callback;
|
||
|
|
||
|
inline v8::Local<v8::Object> event_to_object(const std::shared_ptr<KeyboardHook::KeyEvent>& event) {
|
||
|
Nan::EscapableHandleScope scope;
|
||
|
|
||
|
auto object = Nan::New<v8::Object>();
|
||
|
object->Set(Nan::New<v8::String>("type").ToLocalChecked(), Nan::New<v8::Number>(event->type));
|
||
|
object->Set(Nan::New<v8::String>("key_code").ToLocalChecked(), Nan::New<v8::String>(event->code).ToLocalChecked());
|
||
|
|
||
|
object->Set(Nan::New<v8::String>("key_shift").ToLocalChecked(), Nan::New<v8::Boolean>(event->key_shift));
|
||
|
object->Set(Nan::New<v8::String>("key_alt").ToLocalChecked(), Nan::New<v8::Boolean>(event->key_alt));
|
||
|
object->Set(Nan::New<v8::String>("key_windows").ToLocalChecked(), Nan::New<v8::Boolean>(event->key_windows));
|
||
|
object->Set(Nan::New<v8::String>("key_ctrl").ToLocalChecked(), Nan::New<v8::Boolean>(event->key_ctrl));
|
||
|
|
||
|
return scope.Escape(object);
|
||
|
}
|
||
|
|
||
|
NAN_METHOD(RegisterCallback) {
|
||
|
if(!info[0]->IsFunction()) {
|
||
|
NAN_THROW_EXCEPTION(Error, "argument must be a function!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
auto callback = make_shared<Nan::Callback>(info[0].As<v8::Function>());
|
||
|
{
|
||
|
lock_guard lock(callback_lock);
|
||
|
callbacks.push_back(callback);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NAN_METHOD(UnregisterCallback) {
|
||
|
if(!info[0]->IsFunction()) {
|
||
|
NAN_THROW_EXCEPTION(Error, "argument must be a function!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
{
|
||
|
lock_guard lock(callback_lock);
|
||
|
|
||
|
callbacks.erase(std::remove_if(callbacks.begin(), callbacks.end(), [&](const std::shared_ptr<Nan::Callback>& callback){
|
||
|
return callback->GetFunction() == info[0];
|
||
|
}), callbacks.end());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NAN_MODULE_INIT(init) {
|
||
|
hook = make_unique<KeyboardHook>();
|
||
|
if(!hook->attach()) {
|
||
|
NAN_THROW_EXCEPTION(Error, "Failed to attach hook!");
|
||
|
return;
|
||
|
}
|
||
|
hook->callback_event = [&](const shared_ptr<KeyboardHook::KeyEvent>& event) {
|
||
|
{
|
||
|
lock_guard lock(callback_lock);
|
||
|
queued_events.push_back(event);
|
||
|
}
|
||
|
|
||
|
event_callback();
|
||
|
};
|
||
|
|
||
|
|
||
|
event_callback = Nan::async_callback([](){
|
||
|
Nan::HandleScope scope;
|
||
|
|
||
|
unique_lock lock(callback_lock);
|
||
|
auto events = queued_events;
|
||
|
auto calls = callbacks;
|
||
|
queued_events.clear();
|
||
|
lock.unlock();
|
||
|
|
||
|
|
||
|
for(const auto& event : events) {
|
||
|
auto object = event_to_object(event);
|
||
|
|
||
|
for(const auto& callback : calls) {
|
||
|
v8::Local<v8::Value> args[] = {
|
||
|
object
|
||
|
};
|
||
|
callback->Call(1, args);
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
NAN_EXPORT(target, RegisterCallback);
|
||
|
NAN_EXPORT(target, UnregisterCallback);
|
||
|
}
|
||
|
|
||
|
NODE_MODULE(MODULE_NAME, init)
|