node-native-win-utils 1.4.0 → 2.1.0
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/README.md +29 -82
- package/binding.gyp +2 -0
- package/dist/dirnameLocal.cjs +4 -0
- package/dist/dirnameLocal.d.cts +1 -0
- package/dist/dirnameLocal.d.mts +1 -0
- package/dist/dirnameLocal.mjs +2 -0
- package/dist/{index.js → index.cjs} +46 -15
- package/dist/{index.d.ts → index.d.cts} +24 -12
- package/dist/index.d.mts +191 -0
- package/dist/index.mjs +177 -0
- package/dist/keyCodes.d.mts +101 -0
- package/dist/keyCodes.mjs +201 -0
- package/node22.json +16 -0
- package/package.json +19 -9
- package/prebuilds/win32-x64/node-native-win-utils.node +0 -0
- package/src/cpp/keyboard.cpp +141 -140
- package/src/cpp/main.cpp +9 -3
- package/src/cpp/{capturewindow.cpp → screenshot.cpp} +174 -2
- package/src/dirnameLocal.mts +3 -0
- package/src/index.mts +454 -0
- package/src/keyCodes.mts +203 -0
- package/dllCopy.js +0 -14
- package/include/opencv2/core/affine.hpp +0 -678
- package/include/opencv2/core/async.hpp +0 -105
- package/include/opencv2/core/base.hpp +0 -664
- package/include/opencv2/core/bindings_utils.hpp +0 -325
- package/include/opencv2/core/bufferpool.hpp +0 -40
- package/include/opencv2/core/check.hpp +0 -170
- package/include/opencv2/core/core.hpp +0 -48
- package/include/opencv2/core/core_c.h +0 -3128
- package/include/opencv2/core/cuda/block.hpp +0 -211
- package/include/opencv2/core/cuda/border_interpolate.hpp +0 -722
- package/include/opencv2/core/cuda/color.hpp +0 -309
- package/include/opencv2/core/cuda/common.hpp +0 -131
- package/include/opencv2/core/cuda/datamov_utils.hpp +0 -113
- package/include/opencv2/core/cuda/detail/color_detail.hpp +0 -2018
- package/include/opencv2/core/cuda/detail/reduce.hpp +0 -365
- package/include/opencv2/core/cuda/detail/reduce_key_val.hpp +0 -502
- package/include/opencv2/core/cuda/detail/transform_detail.hpp +0 -392
- package/include/opencv2/core/cuda/detail/type_traits_detail.hpp +0 -191
- package/include/opencv2/core/cuda/detail/vec_distance_detail.hpp +0 -121
- package/include/opencv2/core/cuda/dynamic_smem.hpp +0 -88
- package/include/opencv2/core/cuda/emulation.hpp +0 -269
- package/include/opencv2/core/cuda/filters.hpp +0 -293
- package/include/opencv2/core/cuda/funcattrib.hpp +0 -79
- package/include/opencv2/core/cuda/functional.hpp +0 -805
- package/include/opencv2/core/cuda/limits.hpp +0 -128
- package/include/opencv2/core/cuda/reduce.hpp +0 -209
- package/include/opencv2/core/cuda/saturate_cast.hpp +0 -292
- package/include/opencv2/core/cuda/scan.hpp +0 -258
- package/include/opencv2/core/cuda/simd_functions.hpp +0 -869
- package/include/opencv2/core/cuda/transform.hpp +0 -75
- package/include/opencv2/core/cuda/type_traits.hpp +0 -90
- package/include/opencv2/core/cuda/utility.hpp +0 -230
- package/include/opencv2/core/cuda/vec_distance.hpp +0 -232
- package/include/opencv2/core/cuda/vec_math.hpp +0 -923
- package/include/opencv2/core/cuda/vec_traits.hpp +0 -288
- package/include/opencv2/core/cuda/warp.hpp +0 -139
- package/include/opencv2/core/cuda/warp_reduce.hpp +0 -76
- package/include/opencv2/core/cuda/warp_shuffle.hpp +0 -162
- package/include/opencv2/core/cuda.hpp +0 -1279
- package/include/opencv2/core/cuda.inl.hpp +0 -763
- package/include/opencv2/core/cuda_stream_accessor.hpp +0 -86
- package/include/opencv2/core/cuda_types.hpp +0 -144
- package/include/opencv2/core/cv_cpu_dispatch.h +0 -381
- package/include/opencv2/core/cv_cpu_helper.h +0 -550
- package/include/opencv2/core/cvdef.h +0 -973
- package/include/opencv2/core/cvstd.hpp +0 -190
- package/include/opencv2/core/cvstd.inl.hpp +0 -197
- package/include/opencv2/core/cvstd_wrapper.hpp +0 -154
- package/include/opencv2/core/detail/async_promise.hpp +0 -71
- package/include/opencv2/core/detail/dispatch_helper.impl.hpp +0 -49
- package/include/opencv2/core/detail/exception_ptr.hpp +0 -27
- package/include/opencv2/core/directx.hpp +0 -184
- package/include/opencv2/core/dualquaternion.hpp +0 -979
- package/include/opencv2/core/dualquaternion.inl.hpp +0 -487
- package/include/opencv2/core/eigen.hpp +0 -402
- package/include/opencv2/core/fast_math.hpp +0 -433
- package/include/opencv2/core/hal/hal.hpp +0 -256
- package/include/opencv2/core/hal/interface.h +0 -190
- package/include/opencv2/core/hal/intrin.hpp +0 -939
- package/include/opencv2/core/hal/intrin_avx.hpp +0 -3177
- package/include/opencv2/core/hal/intrin_avx512.hpp +0 -3090
- package/include/opencv2/core/hal/intrin_cpp.hpp +0 -3321
- package/include/opencv2/core/hal/intrin_forward.hpp +0 -191
- package/include/opencv2/core/hal/intrin_lasx.hpp +0 -3236
- package/include/opencv2/core/hal/intrin_msa.hpp +0 -1887
- package/include/opencv2/core/hal/intrin_neon.hpp +0 -2610
- package/include/opencv2/core/hal/intrin_rvv.hpp +0 -3320
- package/include/opencv2/core/hal/intrin_rvv071.hpp +0 -2545
- package/include/opencv2/core/hal/intrin_rvv_scalable.hpp +0 -2080
- package/include/opencv2/core/hal/intrin_sse.hpp +0 -3467
- package/include/opencv2/core/hal/intrin_sse_em.hpp +0 -180
- package/include/opencv2/core/hal/intrin_vsx.hpp +0 -1608
- package/include/opencv2/core/hal/intrin_wasm.hpp +0 -2782
- package/include/opencv2/core/hal/msa_macros.h +0 -1558
- package/include/opencv2/core/hal/simd_utils.impl.hpp +0 -186
- package/include/opencv2/core/llapi/llapi.h +0 -102
- package/include/opencv2/core/mat.hpp +0 -3775
- package/include/opencv2/core/mat.inl.hpp +0 -3422
- package/include/opencv2/core/matx.hpp +0 -1536
- package/include/opencv2/core/neon_utils.hpp +0 -128
- package/include/opencv2/core/ocl.hpp +0 -917
- package/include/opencv2/core/ocl_genbase.hpp +0 -69
- package/include/opencv2/core/opencl/ocl_defs.hpp +0 -82
- package/include/opencv2/core/opencl/opencl_info.hpp +0 -212
- package/include/opencv2/core/opencl/opencl_svm.hpp +0 -81
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_clblas.hpp +0 -602
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_clfft.hpp +0 -146
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_core.hpp +0 -371
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_core_wrappers.hpp +0 -272
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl.hpp +0 -62
- package/include/opencv2/core/opencl/runtime/autogenerated/opencl_gl_wrappers.hpp +0 -42
- package/include/opencv2/core/opencl/runtime/opencl_clblas.hpp +0 -53
- package/include/opencv2/core/opencl/runtime/opencl_clfft.hpp +0 -53
- package/include/opencv2/core/opencl/runtime/opencl_core.hpp +0 -84
- package/include/opencv2/core/opencl/runtime/opencl_core_wrappers.hpp +0 -47
- package/include/opencv2/core/opencl/runtime/opencl_gl.hpp +0 -53
- package/include/opencv2/core/opencl/runtime/opencl_gl_wrappers.hpp +0 -47
- package/include/opencv2/core/opencl/runtime/opencl_svm_20.hpp +0 -48
- package/include/opencv2/core/opencl/runtime/opencl_svm_definitions.hpp +0 -42
- package/include/opencv2/core/opencl/runtime/opencl_svm_hsa_extension.hpp +0 -166
- package/include/opencv2/core/opengl.hpp +0 -733
- package/include/opencv2/core/openvx/ovx_defs.hpp +0 -48
- package/include/opencv2/core/operations.hpp +0 -610
- package/include/opencv2/core/optim.hpp +0 -302
- package/include/opencv2/core/ovx.hpp +0 -28
- package/include/opencv2/core/parallel/backend/parallel_for.openmp.hpp +0 -72
- package/include/opencv2/core/parallel/backend/parallel_for.tbb.hpp +0 -153
- package/include/opencv2/core/parallel/parallel_backend.hpp +0 -90
- package/include/opencv2/core/persistence.hpp +0 -1350
- package/include/opencv2/core/private/cv_cpu_include_simd_declarations.hpp +0 -30
- package/include/opencv2/core/private.cuda.hpp +0 -169
- package/include/opencv2/core/private.hpp +0 -896
- package/include/opencv2/core/quaternion.hpp +0 -1696
- package/include/opencv2/core/quaternion.inl.hpp +0 -1063
- package/include/opencv2/core/saturate.hpp +0 -180
- package/include/opencv2/core/simd_intrinsics.hpp +0 -87
- package/include/opencv2/core/softfloat.hpp +0 -514
- package/include/opencv2/core/sse_utils.hpp +0 -652
- package/include/opencv2/core/traits.hpp +0 -417
- package/include/opencv2/core/types.hpp +0 -2457
- package/include/opencv2/core/types_c.h +0 -2126
- package/include/opencv2/core/utility.hpp +0 -1229
- package/include/opencv2/core/utils/allocator_stats.hpp +0 -29
- package/include/opencv2/core/utils/allocator_stats.impl.hpp +0 -158
- package/include/opencv2/core/utils/buffer_area.private.hpp +0 -136
- package/include/opencv2/core/utils/configuration.private.hpp +0 -22
- package/include/opencv2/core/utils/filesystem.hpp +0 -82
- package/include/opencv2/core/utils/filesystem.private.hpp +0 -66
- package/include/opencv2/core/utils/fp_control.private.hpp +0 -29
- package/include/opencv2/core/utils/fp_control_utils.hpp +0 -69
- package/include/opencv2/core/utils/instrumentation.hpp +0 -125
- package/include/opencv2/core/utils/lock.private.hpp +0 -119
- package/include/opencv2/core/utils/logger.defines.hpp +0 -42
- package/include/opencv2/core/utils/logger.hpp +0 -218
- package/include/opencv2/core/utils/logtag.hpp +0 -28
- package/include/opencv2/core/utils/plugin_loader.private.hpp +0 -165
- package/include/opencv2/core/utils/tls.hpp +0 -235
- package/include/opencv2/core/utils/trace.hpp +0 -252
- package/include/opencv2/core/utils/trace.private.hpp +0 -421
- package/include/opencv2/core/va_intel.hpp +0 -75
- package/include/opencv2/core/version.hpp +0 -26
- package/include/opencv2/core/vsx_utils.hpp +0 -1047
- package/include/opencv2/core.hpp +0 -3365
- package/include/opencv2/imgcodecs/imgcodecs.hpp +0 -48
- package/include/opencv2/imgcodecs/imgcodecs_c.h +0 -1
- package/include/opencv2/imgcodecs/ios.h +0 -59
- package/include/opencv2/imgcodecs/legacy/constants_c.h +0 -54
- package/include/opencv2/imgcodecs/macosx.h +0 -20
- package/include/opencv2/imgcodecs.hpp +0 -407
- package/include/opencv2/imgproc/bindings.hpp +0 -34
- package/include/opencv2/imgproc/detail/gcgraph.hpp +0 -395
- package/include/opencv2/imgproc/hal/hal.hpp +0 -246
- package/include/opencv2/imgproc/hal/interface.h +0 -46
- package/include/opencv2/imgproc/imgproc.hpp +0 -48
- package/include/opencv2/imgproc/imgproc_c.h +0 -1177
- package/include/opencv2/imgproc/segmentation.hpp +0 -141
- package/include/opencv2/imgproc/types_c.h +0 -659
- package/include/opencv2/imgproc.hpp +0 -5035
- package/include/opencv2/opencv_modules.hpp +0 -17
- package/include/tesseract/baseapi.h +0 -820
- package/include/tesseract/capi.h +0 -485
- package/include/tesseract/export.h +0 -37
- package/include/tesseract/ltrresultiterator.h +0 -235
- package/include/tesseract/ocrclass.h +0 -158
- package/include/tesseract/osdetect.h +0 -139
- package/include/tesseract/pageiterator.h +0 -364
- package/include/tesseract/publictypes.h +0 -281
- package/include/tesseract/renderer.h +0 -334
- package/include/tesseract/resultiterator.h +0 -250
- package/include/tesseract/tesseract.h +0 -40
- package/include/tesseract/unichar.h +0 -174
- package/include/tesseract/version.h +0 -34
- package/include/tesseract/version.h.in +0 -34
- package/libs/libjpeg-turbo.lib +0 -0
- package/libs/libpng.lib +0 -0
- package/libs/opencv_core470.lib +0 -0
- package/libs/opencv_imgcodecs470.lib +0 -0
- package/libs/opencv_imgproc470.lib +0 -0
- package/libs/tesseract.lib +0 -0
- package/libs/zlib.lib +0 -0
- /package/dist/{keyCodes.js → keyCodes.cjs} +0 -0
- /package/dist/{keyCodes.d.ts → keyCodes.d.cts} +0 -0
package/src/cpp/keyboard.cpp
CHANGED
|
@@ -2,166 +2,167 @@
|
|
|
2
2
|
#include <Windows.h>
|
|
3
3
|
#include <thread>
|
|
4
4
|
#include <iostream>
|
|
5
|
+
#include <unordered_set>
|
|
6
|
+
#include <mutex>
|
|
7
|
+
#include <atomic>
|
|
5
8
|
|
|
6
|
-
// Global
|
|
9
|
+
// Global variables for JavaScript callback functions
|
|
7
10
|
Napi::ThreadSafeFunction globalJsCallbackKeyDown;
|
|
8
11
|
Napi::ThreadSafeFunction globalJsCallbackKeyUp;
|
|
9
12
|
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
}
|
|
13
|
+
// Thread-safe tracking of pressed keys
|
|
14
|
+
std::mutex pressedKeysMutex;
|
|
15
|
+
std::unordered_set<int> pressedKeys;
|
|
16
|
+
|
|
17
|
+
// Thread management
|
|
18
|
+
std::atomic<bool> handleKeyDown(false);
|
|
19
|
+
std::atomic<bool> handleKeyUp(false);
|
|
20
|
+
std::atomic<bool> monitorThreadRunning(false);
|
|
21
|
+
DWORD monitorThreadId = 0;
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// Environment Cleanup Hook
|
|
25
|
+
void CleanupHook() {
|
|
26
|
+
handleKeyDown = false;
|
|
27
|
+
handleKeyUp = false;
|
|
28
|
+
if(globalJsCallbackKeyDown) {
|
|
29
|
+
globalJsCallbackKeyDown.Release();
|
|
52
30
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
31
|
+
if(globalJsCallbackKeyUp) {
|
|
32
|
+
globalJsCallbackKeyUp.Release();
|
|
33
|
+
}
|
|
34
|
+
if (monitorThreadRunning) {
|
|
35
|
+
PostThreadMessage(monitorThreadId, WM_QUIT, 0, 0);
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
LRESULT CALLBACK KeyboardHookProc(int nCode, WPARAM wParam, LPARAM lParam) {
|
|
42
|
+
if (nCode >= 0) {
|
|
43
|
+
KBDLLHOOKSTRUCT* kbdStruct = reinterpret_cast<KBDLLHOOKSTRUCT*>(lParam);
|
|
44
|
+
int keyCode = kbdStruct->vkCode;
|
|
45
|
+
|
|
46
|
+
if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) {
|
|
47
|
+
std::lock_guard<std::mutex> lock(pressedKeysMutex);
|
|
48
|
+
if (pressedKeys.insert(keyCode).second) {
|
|
49
|
+
if (handleKeyDown) {
|
|
50
|
+
// Allocate copy on heap for thread-safe transfer
|
|
51
|
+
int* keyCopy = new int(keyCode);
|
|
52
|
+
globalJsCallbackKeyDown.BlockingCall(keyCopy,
|
|
53
|
+
[](Napi::Env env, Napi::Function jsCallback, int* keyCode) {
|
|
54
|
+
jsCallback.Call({Napi::Number::New(env, *keyCode)});
|
|
55
|
+
delete keyCode; // Clean up allocated memory
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP) {
|
|
61
|
+
std::lock_guard<std::mutex> lock(pressedKeysMutex);
|
|
62
|
+
if (pressedKeys.erase(keyCode)) {
|
|
63
|
+
if (handleKeyUp) {
|
|
64
|
+
// Allocate copy on heap for thread-safe transfer
|
|
65
|
+
int* keyCopy = new int(keyCode);
|
|
66
|
+
globalJsCallbackKeyUp.BlockingCall(keyCopy,
|
|
67
|
+
[](Napi::Env env, Napi::Function jsCallback, int* keyCode) {
|
|
68
|
+
jsCallback.Call({Napi::Number::New(env, *keyCode)});
|
|
69
|
+
delete keyCode; // Clean up allocated memory
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
78
73
|
}
|
|
79
|
-
}
|
|
80
74
|
}
|
|
81
|
-
|
|
75
|
+
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
void MonitorKeyboardEvents() {
|
|
79
|
+
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
|
|
80
|
+
|
|
81
|
+
HHOOK keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
|
|
82
|
+
if (!keyboardHook) {
|
|
83
|
+
CoUninitialize();
|
|
84
|
+
monitorThreadRunning = false;
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
MSG msg;
|
|
89
|
+
while (GetMessage(&msg, NULL, 0, 0) > 0) {
|
|
90
|
+
TranslateMessage(&msg);
|
|
91
|
+
DispatchMessage(&msg);
|
|
92
|
+
}
|
|
82
93
|
|
|
83
|
-
|
|
94
|
+
UnhookWindowsHookEx(keyboardHook);
|
|
95
|
+
CoUninitialize();
|
|
96
|
+
monitorThreadRunning = false;
|
|
97
|
+
monitorThreadId = 0;
|
|
84
98
|
}
|
|
85
99
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
HHOOK keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProc, NULL, 0);
|
|
90
|
-
if (keyboardHook == NULL)
|
|
91
|
-
{
|
|
92
|
-
// Error setting hook
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
100
|
+
Napi::Value SetKeyDownCallback(const Napi::CallbackInfo& info) {
|
|
101
|
+
Napi::Env env = info.Env();
|
|
102
|
+
Napi::Function jsCallback = info[0].As<Napi::Function>();
|
|
95
103
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
// Release existing callback
|
|
105
|
+
if (globalJsCallbackKeyDown) {
|
|
106
|
+
globalJsCallbackKeyDown.Release();
|
|
107
|
+
}
|
|
108
|
+
globalJsCallbackKeyDown = Napi::ThreadSafeFunction::New(
|
|
109
|
+
env, jsCallback, "KeyDownCallback", 0, 1);
|
|
110
|
+
handleKeyDown = true;
|
|
111
|
+
|
|
112
|
+
if (!monitorThreadRunning.exchange(true)) {
|
|
113
|
+
std::thread monitorThread(MonitorKeyboardEvents);
|
|
114
|
+
monitorThreadId = GetThreadId(monitorThread.native_handle());
|
|
115
|
+
monitorThread.detach();
|
|
116
|
+
}
|
|
103
117
|
|
|
104
|
-
|
|
118
|
+
return env.Undefined();
|
|
105
119
|
}
|
|
106
120
|
|
|
107
|
-
|
|
108
|
-
Napi::
|
|
109
|
-
|
|
110
|
-
|
|
121
|
+
Napi::Value SetKeyUpCallback(const Napi::CallbackInfo& info) {
|
|
122
|
+
Napi::Env env = info.Env();
|
|
123
|
+
Napi::Function jsCallback = info[0].As<Napi::Function>();
|
|
124
|
+
|
|
111
125
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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();
|
|
126
|
+
// Release existing callback
|
|
127
|
+
if (globalJsCallbackKeyUp) {
|
|
128
|
+
globalJsCallbackKeyUp.Release();
|
|
129
|
+
}
|
|
131
130
|
|
|
132
|
-
|
|
133
|
-
|
|
131
|
+
globalJsCallbackKeyUp = Napi::ThreadSafeFunction::New(
|
|
132
|
+
env, jsCallback, "KeyUpCallback", 0, 1);
|
|
133
|
+
handleKeyUp = true;
|
|
134
|
+
|
|
135
|
+
if (!monitorThreadRunning.exchange(true)) {
|
|
136
|
+
std::thread monitorThread(MonitorKeyboardEvents);
|
|
137
|
+
monitorThreadId = GetThreadId(monitorThread.native_handle());
|
|
138
|
+
monitorThread.detach();
|
|
139
|
+
}
|
|
134
140
|
|
|
135
|
-
|
|
141
|
+
return env.Undefined();
|
|
136
142
|
}
|
|
137
143
|
|
|
138
|
-
|
|
139
|
-
Napi::
|
|
140
|
-
|
|
141
|
-
|
|
144
|
+
Napi::Value UnsetKeyDownCallback(const Napi::CallbackInfo& info) {
|
|
145
|
+
Napi::Env env = info.Env();
|
|
146
|
+
handleKeyDown = false;
|
|
147
|
+
globalJsCallbackKeyDown.Release();
|
|
142
148
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
std::thread monitorThread(MonitorKeyboardEvents);
|
|
161
|
-
monitorThread.detach();
|
|
162
|
-
monitorThreadRunning = true;
|
|
163
|
-
}
|
|
164
|
-
return env.Undefined();
|
|
149
|
+
if (!handleKeyUp && monitorThreadRunning) {
|
|
150
|
+
PostThreadMessage(monitorThreadId, WM_QUIT, 0, 0);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return env.Undefined();
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
Napi::Value UnsetKeyUpCallback(const Napi::CallbackInfo& info) {
|
|
157
|
+
Napi::Env env = info.Env();
|
|
158
|
+
handleKeyUp = false;
|
|
159
|
+
globalJsCallbackKeyUp.Release();
|
|
160
|
+
|
|
161
|
+
if (!handleKeyDown && monitorThreadRunning) {
|
|
162
|
+
PostThreadMessage(monitorThreadId, WM_QUIT, 0, 0);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return env.Undefined();
|
|
165
166
|
}
|
|
166
167
|
|
|
167
168
|
Napi::Value TypeString(const Napi::CallbackInfo &info) {
|
package/src/cpp/main.cpp
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#include <napi.h>
|
|
2
2
|
#include <helpers.cpp>
|
|
3
|
-
#include <
|
|
3
|
+
#include <screenshot.cpp>
|
|
4
4
|
#include <getWindowData.cpp>
|
|
5
5
|
#include <keyboard.cpp>
|
|
6
6
|
#include <mouse.cpp>
|
|
@@ -11,8 +11,11 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
|
11
11
|
{
|
|
12
12
|
exports.Set("getWindowData", Napi::Function::New(env, GetWindowData));
|
|
13
13
|
exports.Set("captureWindowN", Napi::Function::New(env, CaptureWindow));
|
|
14
|
-
exports.Set("
|
|
15
|
-
exports.Set("
|
|
14
|
+
exports.Set("captureScreenAsync", Napi::Function::New(env, CaptureScreenAsync));
|
|
15
|
+
exports.Set("setKeyDownCallback", Napi::Function::New(env, SetKeyDownCallback));
|
|
16
|
+
exports.Set("setKeyUpCallback", Napi::Function::New(env, SetKeyUpCallback));
|
|
17
|
+
exports.Set("unsetKeyUpCallback", Napi::Function::New(env, UnsetKeyUpCallback));
|
|
18
|
+
exports.Set("unsetKeyDownCallback", Napi::Function::New(env, UnsetKeyDownCallback));
|
|
16
19
|
exports.Set("mouseMove", Napi::Function::New(env, MoveMouse));
|
|
17
20
|
exports.Set("mouseClick", Napi::Function::New(env, ClickMouse));
|
|
18
21
|
exports.Set("mouseDrag", Napi::Function::New(env, DragMouse));
|
|
@@ -26,6 +29,9 @@ Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
|
26
29
|
exports.Set("drawRectangle", Napi::Function::New(env, DrawRectangle));
|
|
27
30
|
exports.Set("getRegion", Napi::Function::New(env, GetRegion));
|
|
28
31
|
exports.Set("textRecognition", Napi::Function::New(env, TextRecognition));
|
|
32
|
+
static GdiPlusInitializer gdiplusInitializer;
|
|
33
|
+
// Register cleanup hook
|
|
34
|
+
env.AddCleanupHook(CleanupHook);
|
|
29
35
|
return exports;
|
|
30
36
|
}
|
|
31
37
|
|
|
@@ -15,9 +15,34 @@
|
|
|
15
15
|
#include <dwmapi.h>
|
|
16
16
|
#include <opencv2/core.hpp>
|
|
17
17
|
#include <opencv2/imgcodecs.hpp>
|
|
18
|
+
#include <vector>
|
|
19
|
+
#include <stdexcept>
|
|
20
|
+
#include <gdiplus.h>
|
|
21
|
+
#include <cstdlib>
|
|
22
|
+
|
|
23
|
+
#pragma comment (lib, "Gdiplus.lib")
|
|
24
|
+
|
|
25
|
+
using namespace Gdiplus;
|
|
26
|
+
using namespace Napi;
|
|
27
|
+
// Global GDI+ initialization token
|
|
28
|
+
ULONG_PTR gdiplusToken = 0;
|
|
29
|
+
|
|
30
|
+
// RAII wrapper for GDI+ initialization
|
|
31
|
+
class GdiPlusInitializer {
|
|
32
|
+
public:
|
|
33
|
+
GdiPlusInitializer() {
|
|
34
|
+
GdiplusStartupInput startupInput;
|
|
35
|
+
GdiplusStartup(&gdiplusToken, &startupInput, NULL);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
~GdiPlusInitializer() {
|
|
39
|
+
GdiplusShutdown(gdiplusToken);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
|
|
18
45
|
|
|
19
|
-
#pragma comment(lib, "Dwmapi.lib")
|
|
20
|
-
#pragma comment(lib, "windowsapp.lib")
|
|
21
46
|
|
|
22
47
|
Napi::Value CaptureWindow(const Napi::CallbackInfo &info)
|
|
23
48
|
{
|
|
@@ -171,3 +196,150 @@ Napi::Value CaptureWindow(const Napi::CallbackInfo &info)
|
|
|
171
196
|
|
|
172
197
|
return resultBuffer;
|
|
173
198
|
}
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class ScreenCaptureWorker : public AsyncWorker {
|
|
203
|
+
public:
|
|
204
|
+
ScreenCaptureWorker(Napi::Env env, Promise::Deferred deferred)
|
|
205
|
+
: AsyncWorker(env), deferred(deferred), buffer(nullptr), bufferSize(0) {}
|
|
206
|
+
|
|
207
|
+
~ScreenCaptureWorker() {
|
|
208
|
+
if (buffer) delete[] buffer;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
void Execute() override {
|
|
212
|
+
HDC hdcScreen = NULL;
|
|
213
|
+
HDC hdcMem = NULL;
|
|
214
|
+
HBITMAP hBitmap = NULL;
|
|
215
|
+
IStream* stream = NULL;
|
|
216
|
+
|
|
217
|
+
try {
|
|
218
|
+
// Step 1: Capture screen using GDI
|
|
219
|
+
hdcScreen = GetDC(NULL);
|
|
220
|
+
if (!hdcScreen) throw "Failed to get screen DC";
|
|
221
|
+
|
|
222
|
+
int width = GetSystemMetrics(SM_CXSCREEN);
|
|
223
|
+
int height = GetSystemMetrics(SM_CYSCREEN);
|
|
224
|
+
|
|
225
|
+
hdcMem = CreateCompatibleDC(hdcScreen);
|
|
226
|
+
if (!hdcMem) throw "Failed to create compatible DC";
|
|
227
|
+
|
|
228
|
+
hBitmap = CreateCompatibleBitmap(hdcScreen, width, height);
|
|
229
|
+
if (!hBitmap) throw "Failed to create bitmap";
|
|
230
|
+
|
|
231
|
+
SelectObject(hdcMem, hBitmap);
|
|
232
|
+
if (!BitBlt(hdcMem, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY)) {
|
|
233
|
+
throw "Failed to copy screen content";
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Step 2: Convert bitmap to PNG using GDI+
|
|
237
|
+
Bitmap bitmap(hBitmap, NULL);
|
|
238
|
+
if (bitmap.GetLastStatus() != Ok) {
|
|
239
|
+
throw "Failed to create GDI+ bitmap";
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Create in-memory stream to store PNG
|
|
243
|
+
if (CreateStreamOnHGlobal(NULL, TRUE, &stream) != S_OK) {
|
|
244
|
+
throw "Failed to create stream";
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
CLSID pngClsid;
|
|
248
|
+
if (GetEncoderClsid(L"image/png", &pngClsid) == -1) {
|
|
249
|
+
throw "Failed to get PNG encoder";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (bitmap.Save(stream, &pngClsid, NULL) != Ok) {
|
|
253
|
+
throw "Failed to save PNG to stream";
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Get PNG data from stream
|
|
257
|
+
STATSTG stat;
|
|
258
|
+
stream->Stat(&stat, STATFLAG_NONAME);
|
|
259
|
+
bufferSize = static_cast<DWORD>(stat.cbSize.QuadPart);
|
|
260
|
+
|
|
261
|
+
HGLOBAL hGlobal = NULL;
|
|
262
|
+
GetHGlobalFromStream(stream, &hGlobal);
|
|
263
|
+
buffer = static_cast<BYTE*>(GlobalLock(hGlobal));
|
|
264
|
+
if (!buffer) throw "Failed to lock stream memory";
|
|
265
|
+
|
|
266
|
+
// Copy to local buffer as stream will be released
|
|
267
|
+
BYTE* tempBuffer = new BYTE[bufferSize];
|
|
268
|
+
memcpy(tempBuffer, buffer, bufferSize);
|
|
269
|
+
buffer = tempBuffer;
|
|
270
|
+
|
|
271
|
+
// Cleanup
|
|
272
|
+
GlobalUnlock(hGlobal);
|
|
273
|
+
stream->Release();
|
|
274
|
+
DeleteObject(hBitmap);
|
|
275
|
+
DeleteDC(hdcMem);
|
|
276
|
+
ReleaseDC(NULL, hdcScreen);
|
|
277
|
+
}
|
|
278
|
+
catch (const char* error) {
|
|
279
|
+
SetError(error);
|
|
280
|
+
}
|
|
281
|
+
catch (...) {
|
|
282
|
+
SetError("Unknown error occurred during screen capture");
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Cleanup in case of exceptions
|
|
286
|
+
if (stream) stream->Release();
|
|
287
|
+
if (hBitmap) DeleteObject(hBitmap);
|
|
288
|
+
if (hdcMem) DeleteDC(hdcMem);
|
|
289
|
+
if (hdcScreen) ReleaseDC(NULL, hdcScreen);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
void OnOK() override {
|
|
293
|
+
Buffer<BYTE> result = Buffer<BYTE>::Copy(Env(), buffer, bufferSize);
|
|
294
|
+
deferred.Resolve(result);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
void OnError(const Napi::Error& e) override {
|
|
298
|
+
deferred.Reject(e.Value());
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
private:
|
|
302
|
+
Promise::Deferred deferred;
|
|
303
|
+
BYTE* buffer;
|
|
304
|
+
DWORD bufferSize;
|
|
305
|
+
|
|
306
|
+
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
|
|
307
|
+
UINT numEncoders = 0;
|
|
308
|
+
UINT size = 0;
|
|
309
|
+
|
|
310
|
+
if (GetImageEncodersSize(&numEncoders, &size) != Ok || size == 0)
|
|
311
|
+
return -1;
|
|
312
|
+
|
|
313
|
+
ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)malloc(size);
|
|
314
|
+
if (!pImageCodecInfo) return -1;
|
|
315
|
+
|
|
316
|
+
if (GetImageEncoders(numEncoders, size, pImageCodecInfo) != Ok) {
|
|
317
|
+
free(pImageCodecInfo);
|
|
318
|
+
return -1;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
for (UINT i = 0; i < numEncoders; i++) {
|
|
322
|
+
if (wcscmp(pImageCodecInfo[i].MimeType, format) == 0) {
|
|
323
|
+
*pClsid = pImageCodecInfo[i].Clsid;
|
|
324
|
+
free(pImageCodecInfo);
|
|
325
|
+
return i;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
free(pImageCodecInfo);
|
|
330
|
+
return -1;
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
|
|
334
|
+
Value CaptureScreenAsync(const CallbackInfo& info) {
|
|
335
|
+
Env env = info.Env();
|
|
336
|
+
Promise::Deferred deferred = Promise::Deferred::New(env);
|
|
337
|
+
ScreenCaptureWorker* worker = new ScreenCaptureWorker(env, deferred);
|
|
338
|
+
worker->Queue();
|
|
339
|
+
return deferred.Promise();
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
|