node-native-win-utils 1.0.3 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/cpp/capturewindow.cpp +183 -0
- package/src/cpp/getWindowData.cpp +46 -0
- package/src/cpp/helpers.cpp +15 -0
- package/src/cpp/helpers.h +8 -0
- package/src/cpp/keyBoardHandler.cpp +165 -0
- package/src/cpp/main.cpp +16 -0
package/package.json
CHANGED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <iostream>
|
|
3
|
+
#include <Windows.h>
|
|
4
|
+
#include <dxgi.h>
|
|
5
|
+
#include <inspectable.h>
|
|
6
|
+
#include <dxgi1_2.h>
|
|
7
|
+
#include <d3d11.h>
|
|
8
|
+
#include <winrt/Windows.Foundation.h>
|
|
9
|
+
#include <winrt/Windows.System.h>
|
|
10
|
+
#include <winrt/Windows.Graphics.Capture.h>
|
|
11
|
+
#include <windows.graphics.capture.interop.h>
|
|
12
|
+
#include <windows.graphics.directx.direct3d11.interop.h>
|
|
13
|
+
#include <roerrorapi.h>
|
|
14
|
+
#include <shlobj_core.h>
|
|
15
|
+
#include <dwmapi.h>
|
|
16
|
+
#include <helpers.h>
|
|
17
|
+
|
|
18
|
+
#pragma comment(lib, "Dwmapi.lib")
|
|
19
|
+
#pragma comment(lib, "windowsapp.lib")
|
|
20
|
+
|
|
21
|
+
void CaptureWindow(const Napi::CallbackInfo &info)
|
|
22
|
+
{
|
|
23
|
+
|
|
24
|
+
Napi::Env env = info.Env();
|
|
25
|
+
|
|
26
|
+
if (info.Length() < 2 || !info[0].IsString() || !info[1].IsString())
|
|
27
|
+
{
|
|
28
|
+
Napi::TypeError::New(env, "Window name and file path must be provided as strings").ThrowAsJavaScriptException();
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
std::string windowName = info[0].As<Napi::String>().Utf8Value();
|
|
33
|
+
std::string filePath = info[1].As<Napi::String>().Utf8Value();
|
|
34
|
+
std::wstring outputFilePath = ToWChar(filePath);
|
|
35
|
+
HWND hwndTarget = GetWindowByName(windowName.c_str());
|
|
36
|
+
// Init COM
|
|
37
|
+
winrt::init_apartment(winrt::apartment_type::multi_threaded);
|
|
38
|
+
|
|
39
|
+
// Create Direct 3D Device
|
|
40
|
+
winrt::com_ptr<ID3D11Device> d3dDevice;
|
|
41
|
+
|
|
42
|
+
winrt::check_hresult(D3D11CreateDevice(nullptr, D3D_DRIVER_TYPE_HARDWARE, nullptr, D3D11_CREATE_DEVICE_BGRA_SUPPORT,
|
|
43
|
+
nullptr, 0, D3D11_SDK_VERSION, d3dDevice.put(), nullptr, nullptr));
|
|
44
|
+
|
|
45
|
+
winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice device;
|
|
46
|
+
const auto dxgiDevice = d3dDevice.as<IDXGIDevice>();
|
|
47
|
+
{
|
|
48
|
+
winrt::com_ptr<::IInspectable> inspectable;
|
|
49
|
+
winrt::check_hresult(CreateDirect3D11DeviceFromDXGIDevice(dxgiDevice.get(), inspectable.put()));
|
|
50
|
+
device = inspectable.as<winrt::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
auto idxgiDevice2 = dxgiDevice.as<IDXGIDevice2>();
|
|
54
|
+
winrt::com_ptr<IDXGIAdapter> adapter;
|
|
55
|
+
winrt::check_hresult(idxgiDevice2->GetParent(winrt::guid_of<IDXGIAdapter>(), adapter.put_void()));
|
|
56
|
+
winrt::com_ptr<IDXGIFactory2> factory;
|
|
57
|
+
winrt::check_hresult(adapter->GetParent(winrt::guid_of<IDXGIFactory2>(), factory.put_void()));
|
|
58
|
+
|
|
59
|
+
ID3D11DeviceContext *d3dContext = nullptr;
|
|
60
|
+
d3dDevice->GetImmediateContext(&d3dContext);
|
|
61
|
+
|
|
62
|
+
RECT rect{};
|
|
63
|
+
DwmGetWindowAttribute(hwndTarget, DWMWA_EXTENDED_FRAME_BOUNDS, &rect, sizeof(RECT));
|
|
64
|
+
const auto size = winrt::Windows::Graphics::SizeInt32{rect.right - rect.left, rect.bottom - rect.top};
|
|
65
|
+
|
|
66
|
+
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool m_framePool =
|
|
67
|
+
winrt::Windows::Graphics::Capture::Direct3D11CaptureFramePool::Create(
|
|
68
|
+
device,
|
|
69
|
+
winrt::Windows::Graphics::DirectX::DirectXPixelFormat::B8G8R8A8UIntNormalized,
|
|
70
|
+
2,
|
|
71
|
+
size);
|
|
72
|
+
|
|
73
|
+
const auto activationFactory = winrt::get_activation_factory<
|
|
74
|
+
winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
|
|
75
|
+
auto interopFactory = activationFactory.as<IGraphicsCaptureItemInterop>();
|
|
76
|
+
winrt::Windows::Graphics::Capture::GraphicsCaptureItem captureItem = {nullptr};
|
|
77
|
+
interopFactory->CreateForWindow(hwndTarget, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(),
|
|
78
|
+
reinterpret_cast<void **>(winrt::put_abi(captureItem)));
|
|
79
|
+
|
|
80
|
+
auto isFrameArrived = false;
|
|
81
|
+
winrt::com_ptr<ID3D11Texture2D> texture;
|
|
82
|
+
const auto session = m_framePool.CreateCaptureSession(captureItem);
|
|
83
|
+
m_framePool.FrameArrived([&](auto &framePool, auto &)
|
|
84
|
+
{
|
|
85
|
+
if (isFrameArrived) return;
|
|
86
|
+
auto frame = framePool.TryGetNextFrame();
|
|
87
|
+
|
|
88
|
+
struct __declspec(uuid("A9B3D012-3DF2-4EE3-B8D1-8695F457D3C1"))
|
|
89
|
+
IDirect3DDxgiInterfaceAccess : ::IUnknown
|
|
90
|
+
{
|
|
91
|
+
virtual HRESULT __stdcall GetInterface(GUID const& id, void** object) = 0;
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
auto access = frame.Surface().as<IDirect3DDxgiInterfaceAccess>();
|
|
95
|
+
access->GetInterface(winrt::guid_of<ID3D11Texture2D>(), texture.put_void());
|
|
96
|
+
isFrameArrived = true;
|
|
97
|
+
return; });
|
|
98
|
+
|
|
99
|
+
session.IsCursorCaptureEnabled(false);
|
|
100
|
+
session.StartCapture();
|
|
101
|
+
|
|
102
|
+
// Message pump
|
|
103
|
+
MSG msg;
|
|
104
|
+
clock_t timer = clock();
|
|
105
|
+
while (!isFrameArrived)
|
|
106
|
+
{
|
|
107
|
+
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
|
|
108
|
+
DispatchMessage(&msg);
|
|
109
|
+
|
|
110
|
+
if (clock() - timer > 20000)
|
|
111
|
+
{
|
|
112
|
+
// TODO: try to make here a better error handling
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
session.Close();
|
|
118
|
+
|
|
119
|
+
D3D11_TEXTURE2D_DESC capturedTextureDesc;
|
|
120
|
+
texture->GetDesc(&capturedTextureDesc);
|
|
121
|
+
|
|
122
|
+
capturedTextureDesc.Usage = D3D11_USAGE_STAGING;
|
|
123
|
+
capturedTextureDesc.BindFlags = 0;
|
|
124
|
+
capturedTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
|
|
125
|
+
capturedTextureDesc.MiscFlags = 0;
|
|
126
|
+
|
|
127
|
+
winrt::com_ptr<ID3D11Texture2D> userTexture = nullptr;
|
|
128
|
+
winrt::check_hresult(d3dDevice->CreateTexture2D(&capturedTextureDesc, NULL, userTexture.put()));
|
|
129
|
+
|
|
130
|
+
d3dContext->CopyResource(userTexture.get(), texture.get());
|
|
131
|
+
|
|
132
|
+
D3D11_MAPPED_SUBRESOURCE resource;
|
|
133
|
+
winrt::check_hresult(d3dContext->Map(userTexture.get(), NULL, D3D11_MAP_READ, 0, &resource));
|
|
134
|
+
|
|
135
|
+
BITMAPINFO lBmpInfo;
|
|
136
|
+
|
|
137
|
+
// BMP 32 bpp
|
|
138
|
+
ZeroMemory(&lBmpInfo, sizeof(BITMAPINFO));
|
|
139
|
+
lBmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
140
|
+
lBmpInfo.bmiHeader.biBitCount = 32;
|
|
141
|
+
lBmpInfo.bmiHeader.biCompression = BI_RGB;
|
|
142
|
+
lBmpInfo.bmiHeader.biWidth = capturedTextureDesc.Width;
|
|
143
|
+
lBmpInfo.bmiHeader.biHeight = capturedTextureDesc.Height;
|
|
144
|
+
lBmpInfo.bmiHeader.biPlanes = 1;
|
|
145
|
+
lBmpInfo.bmiHeader.biSizeImage = capturedTextureDesc.Width * capturedTextureDesc.Height * 4;
|
|
146
|
+
|
|
147
|
+
std::unique_ptr<BYTE> pBuf(new BYTE[lBmpInfo.bmiHeader.biSizeImage]);
|
|
148
|
+
UINT lBmpRowPitch = capturedTextureDesc.Width * 4;
|
|
149
|
+
auto sptr = static_cast<BYTE *>(resource.pData);
|
|
150
|
+
auto dptr = pBuf.get() + lBmpInfo.bmiHeader.biSizeImage - lBmpRowPitch;
|
|
151
|
+
|
|
152
|
+
UINT lRowPitch = std::min<UINT>(lBmpRowPitch, resource.RowPitch);
|
|
153
|
+
|
|
154
|
+
for (size_t h = 0; h < capturedTextureDesc.Height; ++h)
|
|
155
|
+
{
|
|
156
|
+
memcpy_s(dptr, lBmpRowPitch, sptr, lRowPitch);
|
|
157
|
+
sptr += resource.RowPitch;
|
|
158
|
+
dptr -= lBmpRowPitch;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Save bitmap buffer into the provided output file path
|
|
162
|
+
FILE *lfile = nullptr;
|
|
163
|
+
|
|
164
|
+
if (auto lerr = _wfopen_s(&lfile, outputFilePath.c_str(), L"wb"); lerr != 0)
|
|
165
|
+
return;
|
|
166
|
+
|
|
167
|
+
if (lfile != nullptr)
|
|
168
|
+
{
|
|
169
|
+
BITMAPFILEHEADER bmpFileHeader;
|
|
170
|
+
|
|
171
|
+
bmpFileHeader.bfReserved1 = 0;
|
|
172
|
+
bmpFileHeader.bfReserved2 = 0;
|
|
173
|
+
bmpFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lBmpInfo.bmiHeader.biSizeImage;
|
|
174
|
+
bmpFileHeader.bfType = 'MB';
|
|
175
|
+
bmpFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
|
|
176
|
+
|
|
177
|
+
fwrite(&bmpFileHeader, sizeof(BITMAPFILEHEADER), 1, lfile);
|
|
178
|
+
fwrite(&lBmpInfo.bmiHeader, sizeof(BITMAPINFOHEADER), 1, lfile);
|
|
179
|
+
fwrite(pBuf.get(), lBmpInfo.bmiHeader.biSizeImage, 1, lfile);
|
|
180
|
+
|
|
181
|
+
fclose(lfile);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <Windows.h>
|
|
3
|
+
#include <iostream>
|
|
4
|
+
#include <dwmapi.h>
|
|
5
|
+
#include <helpers.h>
|
|
6
|
+
|
|
7
|
+
Napi::Value GetWindowData(const Napi::CallbackInfo &info)
|
|
8
|
+
{
|
|
9
|
+
Napi::Env env = info.Env();
|
|
10
|
+
|
|
11
|
+
if (info.Length() < 1 || !info[0].IsString())
|
|
12
|
+
{
|
|
13
|
+
Napi::TypeError::New(env, "Window name must be provided as a string").ThrowAsJavaScriptException();
|
|
14
|
+
return env.Null();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
std::string windowName = info[0].As<Napi::String>().Utf8Value();
|
|
18
|
+
|
|
19
|
+
HWND windowHandle = GetWindowByName(windowName.c_str());
|
|
20
|
+
|
|
21
|
+
if (windowHandle == NULL)
|
|
22
|
+
{
|
|
23
|
+
Napi::Error::New(env, "Window not found").ThrowAsJavaScriptException();
|
|
24
|
+
return env.Null();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
RECT windowRect;
|
|
28
|
+
DwmGetWindowAttribute(windowHandle, DWMWA_EXTENDED_FRAME_BOUNDS, &windowRect, sizeof(windowRect));
|
|
29
|
+
HDC hdc = GetDC(windowHandle);
|
|
30
|
+
int dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
|
|
31
|
+
int dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
|
32
|
+
ReleaseDC(windowHandle, hdc);
|
|
33
|
+
|
|
34
|
+
int width = windowRect.right - windowRect.left;
|
|
35
|
+
int height = windowRect.bottom - windowRect.top;
|
|
36
|
+
int x = windowRect.left;
|
|
37
|
+
int y = windowRect.top;
|
|
38
|
+
|
|
39
|
+
Napi::Object result = Napi::Object::New(env);
|
|
40
|
+
result.Set("width", Napi::Number::New(env, width));
|
|
41
|
+
result.Set("height", Napi::Number::New(env, height));
|
|
42
|
+
result.Set("x", Napi::Number::New(env, x));
|
|
43
|
+
result.Set("y", Napi::Number::New(env, y));
|
|
44
|
+
|
|
45
|
+
return result;
|
|
46
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
|
|
2
|
+
#include "helpers.h"
|
|
3
|
+
|
|
4
|
+
std::wstring ToWChar(const std::string &str)
|
|
5
|
+
{
|
|
6
|
+
int bufferSize = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
|
|
7
|
+
std::wstring wstr(bufferSize, 0);
|
|
8
|
+
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, &wstr[0], bufferSize);
|
|
9
|
+
return wstr;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
HWND GetWindowByName(const char *windowName)
|
|
13
|
+
{
|
|
14
|
+
return FindWindowA(NULL, windowName);
|
|
15
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <Windows.h>
|
|
3
|
+
#include <thread>
|
|
4
|
+
#include <iostream>
|
|
5
|
+
|
|
6
|
+
// Global variable to store the JavaScript callback function
|
|
7
|
+
Napi::ThreadSafeFunction globalJsCallbackKeyDown;
|
|
8
|
+
Napi::ThreadSafeFunction globalJsCallbackKeyUp;
|
|
9
|
+
|
|
10
|
+
// Global variable to store the previous key state
|
|
11
|
+
bool isKeyPressed = false;
|
|
12
|
+
bool handleKeyUp = false;
|
|
13
|
+
bool handleKeyDown = false;
|
|
14
|
+
bool monitorThreadRunning = false;
|
|
15
|
+
int previousKeyState;
|
|
16
|
+
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
|
17
|
+
{
|
|
18
|
+
if (nCode >= 0)
|
|
19
|
+
{
|
|
20
|
+
if (wParam == WM_KEYDOWN)
|
|
21
|
+
{
|
|
22
|
+
KBDLLHOOKSTRUCT *kbdStruct = (KBDLLHOOKSTRUCT *)lParam;
|
|
23
|
+
int keyCode = kbdStruct->vkCode;
|
|
24
|
+
|
|
25
|
+
// Handle the keyCode here or call your JavaScript callback
|
|
26
|
+
// std::cout << "Key Code: " << keyCode << std::endl;
|
|
27
|
+
|
|
28
|
+
if (keyCode != previousKeyState || !isKeyPressed)
|
|
29
|
+
{
|
|
30
|
+
isKeyPressed = true;
|
|
31
|
+
previousKeyState = keyCode;
|
|
32
|
+
if (handleKeyDown)
|
|
33
|
+
{
|
|
34
|
+
int *keyCodeCopy = new int(keyCode); // Create a copy of the keyCode value
|
|
35
|
+
|
|
36
|
+
napi_status status = globalJsCallbackKeyDown.BlockingCall(
|
|
37
|
+
keyCodeCopy,
|
|
38
|
+
[](Napi::Env env, Napi::Function jsCallback, int *keyCodePtr)
|
|
39
|
+
{
|
|
40
|
+
Napi::HandleScope scope(env);
|
|
41
|
+
int keyCode = *keyCodePtr;
|
|
42
|
+
jsCallback.Call({Napi::Number::New(env, keyCode)});
|
|
43
|
+
delete keyCodePtr; // Clean up the dynamically allocated keyCode copy
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (status != napi_ok)
|
|
47
|
+
{
|
|
48
|
+
// Handle the error
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
else if (wParam == WM_KEYUP)
|
|
54
|
+
{
|
|
55
|
+
KBDLLHOOKSTRUCT *kbdStruct = (KBDLLHOOKSTRUCT *)lParam;
|
|
56
|
+
int keyCode = kbdStruct->vkCode;
|
|
57
|
+
|
|
58
|
+
if (keyCode == previousKeyState)
|
|
59
|
+
{
|
|
60
|
+
isKeyPressed = false;
|
|
61
|
+
if (handleKeyUp)
|
|
62
|
+
{
|
|
63
|
+
int *keyCodeCopy = new int(keyCode); // Create a copy of the keyCode value
|
|
64
|
+
napi_status status = globalJsCallbackKeyUp.BlockingCall(
|
|
65
|
+
keyCodeCopy,
|
|
66
|
+
[](Napi::Env env, Napi::Function jsCallback, int *keyCodePtr)
|
|
67
|
+
{
|
|
68
|
+
Napi::HandleScope scope(env);
|
|
69
|
+
int keyCode = *keyCodePtr;
|
|
70
|
+
jsCallback.Call({Napi::Number::New(env, keyCode)});
|
|
71
|
+
delete keyCodePtr; // Clean up the dynamically allocated keyCode copy
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (status != napi_ok)
|
|
75
|
+
{
|
|
76
|
+
// Handle the error
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Function to monitor keyboard events
|
|
87
|
+
void MonitorKeyboardEvents()
|
|
88
|
+
{
|
|
89
|
+
HHOOK keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
|
|
90
|
+
if (keyboardHook == NULL)
|
|
91
|
+
{
|
|
92
|
+
// Error setting hook
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Main loop to process keyboard events
|
|
97
|
+
MSG message;
|
|
98
|
+
while (GetMessage(&message, NULL, 0, 0) > 0)
|
|
99
|
+
{
|
|
100
|
+
TranslateMessage(&message);
|
|
101
|
+
DispatchMessage(&message);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
UnhookWindowsHookEx(keyboardHook);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Function called from JavaScript to set the callback function
|
|
108
|
+
Napi::Value SetKeyDownCallback(const Napi::CallbackInfo &info)
|
|
109
|
+
{
|
|
110
|
+
Napi::Env env = info.Env();
|
|
111
|
+
|
|
112
|
+
// Get the callback function from the arguments
|
|
113
|
+
Napi::Function jsCallback = info[0].As<Napi::Function>();
|
|
114
|
+
|
|
115
|
+
// Create a ThreadSafeFunction with the JavaScript callback
|
|
116
|
+
globalJsCallbackKeyDown = Napi::ThreadSafeFunction::New(
|
|
117
|
+
env,
|
|
118
|
+
jsCallback,
|
|
119
|
+
"KeyDownCallback",
|
|
120
|
+
0,
|
|
121
|
+
1,
|
|
122
|
+
[](Napi::Env)
|
|
123
|
+
{
|
|
124
|
+
// Finalizer callback (optional)
|
|
125
|
+
});
|
|
126
|
+
handleKeyDown = true;
|
|
127
|
+
if (!monitorThreadRunning)
|
|
128
|
+
{
|
|
129
|
+
std::thread monitorThread(MonitorKeyboardEvents);
|
|
130
|
+
monitorThread.detach();
|
|
131
|
+
|
|
132
|
+
monitorThreadRunning = true;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return env.Undefined();
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Function called from JavaScript to set the callback function
|
|
139
|
+
Napi::Value SetKeyUpCallback(const Napi::CallbackInfo &info)
|
|
140
|
+
{
|
|
141
|
+
Napi::Env env = info.Env();
|
|
142
|
+
|
|
143
|
+
// Get the callback function from the arguments
|
|
144
|
+
Napi::Function jsCallback = info[0].As<Napi::Function>();
|
|
145
|
+
|
|
146
|
+
// Create a ThreadSafeFunction with the JavaScript callback
|
|
147
|
+
globalJsCallbackKeyUp = Napi::ThreadSafeFunction::New(
|
|
148
|
+
env,
|
|
149
|
+
jsCallback,
|
|
150
|
+
"KeyUpCallback",
|
|
151
|
+
0,
|
|
152
|
+
1,
|
|
153
|
+
[](Napi::Env)
|
|
154
|
+
{
|
|
155
|
+
// Finalizer callback (optional)
|
|
156
|
+
});
|
|
157
|
+
handleKeyUp = true;
|
|
158
|
+
if (!monitorThreadRunning)
|
|
159
|
+
{
|
|
160
|
+
std::thread monitorThread(MonitorKeyboardEvents);
|
|
161
|
+
monitorThread.detach();
|
|
162
|
+
monitorThreadRunning = true;
|
|
163
|
+
}
|
|
164
|
+
return env.Undefined();
|
|
165
|
+
}
|
package/src/cpp/main.cpp
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
#include <helpers.cpp>
|
|
3
|
+
#include "captureWindow.cpp"
|
|
4
|
+
#include <getWindowData.cpp>
|
|
5
|
+
#include <keyBoardHandler.cpp>
|
|
6
|
+
|
|
7
|
+
Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
8
|
+
{
|
|
9
|
+
exports.Set("getWindowData", Napi::Function::New(env, GetWindowData));
|
|
10
|
+
exports.Set("captureWindow", Napi::Function::New(env, CaptureWindow));
|
|
11
|
+
exports.Set("keyDownHandler", Napi::Function::New(env, SetKeyDownCallback));
|
|
12
|
+
exports.Set("keyUpHandler", Napi::Function::New(env, SetKeyUpCallback));
|
|
13
|
+
return exports;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
NODE_API_MODULE(addon, Init)
|