appium-novawindows2-driver 0.1.3 → 0.1.5

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.
Files changed (103) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +557 -557
  3. package/build/lib/commands/actions.d.ts.map +1 -1
  4. package/build/lib/commands/actions.js +3 -4
  5. package/build/lib/commands/actions.js.map +1 -1
  6. package/build/lib/commands/app.d.ts.map +1 -1
  7. package/build/lib/commands/app.js +53 -45
  8. package/build/lib/commands/app.js.map +1 -1
  9. package/build/lib/commands/device.d.ts.map +1 -1
  10. package/build/lib/commands/device.js +2 -0
  11. package/build/lib/commands/device.js.map +1 -1
  12. package/build/lib/commands/element.d.ts.map +1 -1
  13. package/build/lib/commands/element.js +42 -12
  14. package/build/lib/commands/element.js.map +1 -1
  15. package/build/lib/commands/extension.d.ts.map +1 -1
  16. package/build/lib/commands/extension.js +29 -17
  17. package/build/lib/commands/extension.js.map +1 -1
  18. package/build/lib/commands/file.d.ts +5 -0
  19. package/build/lib/commands/file.d.ts.map +1 -0
  20. package/build/lib/commands/file.js +49 -0
  21. package/build/lib/commands/file.js.map +1 -0
  22. package/build/lib/commands/functions.d.ts.map +1 -1
  23. package/build/lib/commands/functions.js +189 -187
  24. package/build/lib/commands/functions.js.map +1 -1
  25. package/build/lib/commands/index.d.ts +3 -0
  26. package/build/lib/commands/index.d.ts.map +1 -1
  27. package/build/lib/commands/index.js +2 -0
  28. package/build/lib/commands/index.js.map +1 -1
  29. package/build/lib/commands/powershell.d.ts.map +1 -1
  30. package/build/lib/commands/powershell.js +114 -68
  31. package/build/lib/commands/powershell.js.map +1 -1
  32. package/build/lib/constraints.d.ts +18 -0
  33. package/build/lib/constraints.d.ts.map +1 -1
  34. package/build/lib/constraints.js +18 -0
  35. package/build/lib/constraints.js.map +1 -1
  36. package/build/lib/driver.d.ts.map +1 -1
  37. package/build/lib/driver.js +35 -4
  38. package/build/lib/driver.js.map +1 -1
  39. package/build/lib/powershell/converter.d.ts.map +1 -1
  40. package/build/lib/powershell/converter.js +12 -0
  41. package/build/lib/powershell/converter.js.map +1 -1
  42. package/build/lib/powershell/elements.d.ts.map +1 -1
  43. package/build/lib/powershell/elements.js +270 -265
  44. package/build/lib/powershell/elements.js.map +1 -1
  45. package/build/lib/winapi/user32.js.map +1 -1
  46. package/build/lib/xpath/core.d.ts +2 -2
  47. package/build/lib/xpath/core.d.ts.map +1 -1
  48. package/build/lib/xpath/core.js +32 -26
  49. package/build/lib/xpath/core.js.map +1 -1
  50. package/build/lib/xpath/functions.d.ts +1 -1
  51. package/build/lib/xpath/functions.d.ts.map +1 -1
  52. package/build/lib/xpath/functions.js +2 -2
  53. package/build/lib/xpath/functions.js.map +1 -1
  54. package/build/tsconfig.tsbuildinfo +1 -0
  55. package/package.json +67 -62
  56. package/.github/ISSUE_TEMPLATE/bug_report.yml +0 -97
  57. package/.github/ISSUE_TEMPLATE/feature_request.yml +0 -33
  58. package/.github/PULL_REQUEST_TEMPLATE.md +0 -28
  59. package/.github/workflows/lint-build.yml +0 -30
  60. package/.github/workflows/release.yml +0 -39
  61. package/.releaserc +0 -41
  62. package/CHANGELOG.md +0 -33
  63. package/eslint.config.mjs +0 -11
  64. package/examples/api_test.js +0 -69
  65. package/examples/concurrency_test.js +0 -82
  66. package/examples/debug_test.js +0 -36
  67. package/examples/stress_test.js +0 -94
  68. package/examples/verify_driver.js +0 -142
  69. package/lib/commands/actions.ts +0 -229
  70. package/lib/commands/app.ts +0 -227
  71. package/lib/commands/device.ts +0 -41
  72. package/lib/commands/element.ts +0 -242
  73. package/lib/commands/extension.ts +0 -640
  74. package/lib/commands/functions.ts +0 -192
  75. package/lib/commands/index.ts +0 -28
  76. package/lib/commands/powershell.ts +0 -256
  77. package/lib/commands/system.ts +0 -7
  78. package/lib/constants.ts +0 -1
  79. package/lib/constraints.ts +0 -43
  80. package/lib/driver.ts +0 -266
  81. package/lib/enums.ts +0 -96
  82. package/lib/powershell/common.ts +0 -137
  83. package/lib/powershell/conditions.ts +0 -169
  84. package/lib/powershell/converter.ts +0 -373
  85. package/lib/powershell/core.ts +0 -29
  86. package/lib/powershell/elements.ts +0 -584
  87. package/lib/powershell/index.ts +0 -7
  88. package/lib/powershell/regex.ts +0 -77
  89. package/lib/powershell/types.ts +0 -208
  90. package/lib/util.ts +0 -52
  91. package/lib/winapi/types/index.ts +0 -7
  92. package/lib/winapi/types/input.ts +0 -12
  93. package/lib/winapi/types/keyeventf.ts +0 -14
  94. package/lib/winapi/types/mouseeventf.ts +0 -37
  95. package/lib/winapi/types/scancode.ts +0 -96
  96. package/lib/winapi/types/systemmetric.ts +0 -215
  97. package/lib/winapi/types/virtualkey.ts +0 -354
  98. package/lib/winapi/types/xmousebutton.ts +0 -8
  99. package/lib/winapi/user32.ts +0 -842
  100. package/lib/xpath/core.ts +0 -699
  101. package/lib/xpath/functions.ts +0 -366
  102. package/lib/xpath/index.ts +0 -2
  103. package/tsconfig.json +0 -13
@@ -1,842 +0,0 @@
1
- import { Orientation } from '@appium/types';
2
- import {
3
- load,
4
- struct,
5
- union,
6
- sizeof,
7
- array,
8
- proto,
9
- opaque,
10
- pointer,
11
- alias,
12
- types,
13
- address,
14
- } from 'koffi';
15
- import {
16
- InputType,
17
- KeyEventFlags,
18
- MouseEventFlags,
19
- ScanCode,
20
- VirtualKey,
21
- XMouseButton,
22
- } from './types';
23
- import { SystemMetric } from './types/systemmetric';
24
- import { errors } from '@appium/base-driver';
25
- import bezier, { EasingFunction } from 'bezier-easing';
26
- import { sleep } from '../util';
27
- import { Key } from '../enums';
28
-
29
- interface Event {
30
- type: InputType,
31
- u: {
32
- ki?: KeyboardInputStruct,
33
- mi?: MouseInputStruct,
34
- hi?: HardwareInputStruct,
35
- }
36
- }
37
-
38
- interface KeyboardEvent extends Event {
39
- type: typeof InputType.INPUT_KEYBOARD,
40
- u: {
41
- ki: {
42
- wVk: VirtualKey | 0,
43
- wScan: ScanCode | 0,
44
- dwFlags: KeyEventFlags,
45
- time: unknown,
46
- dwExtraInfo: unknown,
47
- } & KeyboardInputStruct,
48
- },
49
- }
50
-
51
- interface MouseEvent extends Event {
52
- type: typeof InputType.INPUT_MOUSE,
53
- u: {
54
- mi: {
55
- dx: unknown,
56
- dy: unknown,
57
- mouseData: XMouseButton | number,
58
- dwFlags: MouseEventFlags,
59
- time: unknown,
60
- dwExtraInfo: unknown,
61
- } & MouseInputStruct,
62
- },
63
- }
64
-
65
- interface Point {
66
- x: number,
67
- y: number,
68
- }
69
-
70
- interface DeviceModeAnsi {
71
- dmDeviceName: string | null,
72
- dmSpecVersion: number,
73
- dmDriverVersion: number,
74
- dmSize: number,
75
- dmDriverExtra: number,
76
- dmFields: number,
77
- u1: {
78
- s1: {
79
- dmOrientation: number,
80
- dmPaperSize: number,
81
- dmPaperLength: number,
82
- dmPaperWidth: number,
83
- dmScale: number,
84
- dmCopies: number,
85
- dmDefaultSource: number,
86
- dmPrintQuality: number,
87
- },
88
- dmPosition: Point,
89
- s2: {
90
- dmPosition: Point,
91
- dmDisplayOrientation: number,
92
- dmDisplayFixedOutput: number,
93
- },
94
- },
95
- dmColor: number,
96
- dmDuplex: number,
97
- dmYResolution: number,
98
- dmTTOption: number,
99
- dmCollate: number,
100
- dmFormName: string | null,
101
- dmLogPixels: number,
102
- dmBitsPerPel: number,
103
- dmPelsWidth: number,
104
- dmPelsHeight: number,
105
- u2: {
106
- dmDisplayFlags: number,
107
- dmNup: number,
108
- },
109
- dmDisplayFrequency: number,
110
- dmICMMethod: number,
111
- dmICMIntent: number,
112
- dmMediaType: number,
113
- dmDitherType: number,
114
- dmReserved1: number,
115
- dmReserved2: number,
116
- dmPanningWidth: number,
117
- dmPanningHeight: number,
118
- }
119
-
120
- // TODO: remove eslint-disable-next-line when used
121
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
122
- interface HardwareInputEvent extends Event {
123
- type: typeof InputType.INPUT_HARDWARE,
124
- u: {
125
- hi: {
126
- uMsg: unknown,
127
- wParamL: unknown,
128
- wParamH: unknown,
129
- } & HardwareInputStruct,
130
- },
131
- }
132
-
133
- type PointStruct = {
134
- x: unknown,
135
- y: unknown,
136
- }
137
-
138
- type InputUnion = {
139
- ki: unknown,
140
- mi: unknown,
141
- hi: unknown,
142
- }
143
-
144
- type MouseInputStruct = {
145
- dx: unknown,
146
- dy: unknown,
147
- mouseData: unknown,
148
- dwFlags: unknown,
149
- time: unknown,
150
- dwExtraInfo: unknown,
151
- }
152
-
153
- type KeyboardInputStruct = {
154
- wVk: unknown,
155
- wScan: unknown,
156
- dwFlags: unknown,
157
- time: unknown,
158
- dwExtraInfo: unknown,
159
- }
160
-
161
- type HardwareInputStruct = {
162
- uMsg: unknown,
163
- wParamL: unknown,
164
- wParamH: unknown,
165
- }
166
-
167
- const easingFunctions = Object.freeze({
168
- 'linear': (x: number) => x,
169
- 'ease': bezier(0.25, 1, 0.25, 1),
170
- 'ease-in': bezier(0.42, 0, 1, 1),
171
- 'ease-out': bezier(0, 0, 0.58, 1),
172
- 'ease-in-out': bezier(0.42, 0, 0.58, 1),
173
- } as const);
174
-
175
- const UINT32_MAX = 0xFFFFFFFF;
176
- const UINT16_MAX = 0xFFFF;
177
-
178
- const user32 = load('user32.dll');
179
-
180
- const POINT = struct('POINT', {
181
- x: 'long',
182
- y: 'long',
183
- } satisfies PointStruct);
184
-
185
- const MOUSEINPUT = struct('MOUSEINPUT', {
186
- dx: 'long',
187
- dy: 'long',
188
- mouseData: 'uint32',
189
- dwFlags: 'uint32',
190
- time: 'uint32',
191
- dwExtraInfo: 'uintptr',
192
- } satisfies MouseInputStruct);
193
-
194
- const KEYBDINPUT = struct('KEYBDINPUT', {
195
- wVk: 'uint16',
196
- wScan: 'uint16',
197
- dwFlags: 'uint32',
198
- time: 'uint32',
199
- dwExtraInfo: 'uintptr',
200
- } satisfies KeyboardInputStruct);
201
-
202
- const HARDWAREINPUT = struct('HARDWAREINPUT', {
203
- uMsg: 'uint32',
204
- wParamL: 'uint16',
205
- wParamH: 'uint16',
206
- } satisfies HardwareInputStruct);
207
-
208
- const INPUT = struct('INPUT', {
209
- type: 'uint32',
210
- u: union({
211
- mi: MOUSEINPUT,
212
- ki: KEYBDINPUT,
213
- hi: HARDWAREINPUT,
214
- } satisfies InputUnion)
215
- });
216
-
217
- const DEVMODEA = struct('DEVMODEA', {
218
- dmDeviceName: array('char', 32, 'String'),
219
- dmSpecVersion: 'uint16',
220
- dmDriverVersion: 'uint16',
221
- dmSize: 'uint16',
222
- dmDriverExtra: 'uint16',
223
- dmFields: 'uint32',
224
- u1: union({
225
- s1: struct({
226
- dmOrientation: 'short',
227
- dmPaperSize: 'short',
228
- dmPaperLength: 'short',
229
- dmPaperWidth: 'short',
230
- dmScale: 'short',
231
- dmCopies: 'short',
232
- dmDefaultSource: 'short',
233
- dmPrintQuality: 'short',
234
- }),
235
- dmPosition: POINT,
236
- s2: struct({
237
- dmPosition: POINT,
238
- dmDisplayOrientation: 'uint32',
239
- dmDisplayFixedOutput: 'uint32',
240
- }),
241
- }),
242
- dmColor: 'short',
243
- dmDuplex: 'short',
244
- dmYResolution: 'short',
245
- dmTTOption: 'short',
246
- dmCollate: 'short',
247
- dmFormName: array('char', 32, 'String'),
248
- dmLogPixels: 'uint16',
249
- dmBitsPerPel: 'uint32',
250
- dmPelsWidth: 'uint32',
251
- dmPelsHeight: 'uint32',
252
- u2: union({
253
- dmDisplayFlags: 'uint32',
254
- dmNup: 'uint32',
255
- }),
256
- dmDisplayFrequency: 'uint32',
257
- dmICMMethod: 'uint32',
258
- dmICMIntent: 'uint32',
259
- dmMediaType: 'uint32',
260
- dmDitherType: 'uint32',
261
- dmReserved1: 'uint32',
262
- dmReserved2: 'uint32',
263
- dmPanningWidth: 'uint32',
264
- dmPanningHeight: 'uint32',
265
- });
266
-
267
- const BOOL = alias('BOOL', types.bool);
268
- const DWORD = alias('DWORD', types.uint32_t);
269
- const HANDLE = pointer('HANDLE', opaque());
270
- const LONG_PTR = pointer('LONG_PTR', types.long);
271
- const LPDWORD = pointer('LPDWORD', DWORD);
272
- const HWND = alias('HWND', HANDLE);
273
- const LPARAM = alias('LPARAM', LONG_PTR);
274
- const LPSTR = pointer('LPSTR', 'char');
275
-
276
- const EnumWindowsProc = proto('BOOL __stdcall EnumWindowsProc (HWND hwnd, LPARAM lParam)');
277
-
278
- type BOOL = boolean;
279
- type DWORD = number;
280
- type HANDLE = unknown;
281
- type LONG_PTR = number;
282
- type LPDWORD = number;
283
- type HWND = unknown;
284
- type LPARAM = number;
285
- type LPSTR = Buffer;
286
-
287
- type EnumWindowsProc = (hWnd: HWND, lParam: LPARAM) => BOOL;
288
-
289
- // TODO: update all functions to have their parameters aliased properly
290
- const SendInput = user32.func(/* c */ `unsigned int __stdcall SendInput(unsigned int cInputs, INPUT *pInputs, int cbSize)`) as (cInputs: number, pInouts: Event[], cbSize: number) => number;
291
- const GetSystemMetrics = user32.func(/* c */ `int __stdcall GetSystemMetrics(int nIndex)`) as (nIndex: SystemMetric) => number;
292
- const SetProcessDPIAware = user32.func(/* c */ `bool __stdcall SetProcessDPIAware()`) as () => boolean;
293
- const GetDpiForSystem = user32.func(/* c */ `unsigned int __stdcall GetDpiForSystem()`) as () => number;
294
- const GetCursorPos = user32.func(/* c */ `bool __stdcall GetCursorPos(_Out_ POINT *lpPoint)`) as (lpPoint: Point) => boolean;
295
- const EnumDisplaySettingsA = user32.func(/* c */ `bool __stdcall EnumDisplaySettingsA(str lpszDeviceName, uint iModeNum, _Out_ DEVMODEA *lpDevMode)`) as (lpszDeviceName: string | null, iModeNum: number, lpDevMode: Buffer) => boolean;
296
- // end TODO
297
-
298
- const GetWindowThreadProcessId = user32.func(/* c */ `DWORD __stdcall GetWindowThreadProcessId(HWND hWnd, _Out_ LPDWORD lpdwProcessId)`) as (hWnd: HWND, lpdwProcessId: [LPDWORD | null]) => DWORD;
299
- const GetWindowTextA = user32.func(/* c */ `int __stdcall GetWindowTextA(HWND hWnd, LPSTR lpString, int nMaxCount)`) as (hWnd: HWND, lpString: LPSTR, nMaxCount: number) => number;
300
- const IsWindowVisible = user32.func(/* c */ `BOOL __stdcall IsWindowVisible(HWND hWnd)`) as (hWnd: HWND) => BOOL;
301
- const EnumWindows = user32.func(/* c */ `BOOL __stdcall EnumWindows(EnumWindowsProc *enumProc, LPARAM lParam)`) as (enumProc: EnumWindowsProc, lParam: LPARAM) => BOOL;
302
- const SetForegroundWindow = user32.func(/* c */ `BOOL __stdcall SetForegroundWindow(HWND hWnd)`) as (hWnd: HWND) => BOOL;
303
-
304
- function makeKeyboardEvent(args: {
305
- /** A virtual-key code. The code must be a value in the range 1 to 254. If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0. */
306
- vk?: VirtualKey,
307
- /** A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application. */
308
- scan?: ScanCode | string,
309
- /** Set to true if the key should be pressed, and false if key is should be released. */
310
- down: boolean,
311
- }
312
- ): KeyboardEvent {
313
- let flags: KeyEventFlags = 0;
314
-
315
- if ((args.scan === undefined && args.vk === undefined) || (args.scan !== undefined && args.vk !== undefined)) {
316
- throw new errors.InvalidArgumentError('You should provide either vk or scan, but not both.');
317
- }
318
-
319
- switch (typeof args.scan) {
320
- case 'string':
321
- if (args.scan.length !== 1) {
322
- throw new errors.InvalidArgumentError(`scan parameter expects a single character, but received ${args.scan.length}.`);
323
- }
324
-
325
- flags |= KeyEventFlags.KEYEVENTF_UNICODE;
326
- args.scan = args.scan.charCodeAt(0) as ScanCode;
327
- break;
328
- case 'number':
329
- flags |= KeyEventFlags.KEYEVENTF_SCANCODE;
330
- break;
331
- }
332
-
333
- if (!args.down) {
334
- flags |= KeyEventFlags.KEYEVENTF_KEYUP;
335
- }
336
-
337
- return {
338
- type: InputType.INPUT_KEYBOARD,
339
- u: {
340
- ki: {
341
- wVk: args.vk ?? 0,
342
- wScan: args.scan as ScanCode ?? 0,
343
- dwFlags: flags as KeyEventFlags ?? 0,
344
- time: 0,
345
- dwExtraInfo: 0,
346
- }
347
- }
348
- };
349
- }
350
-
351
- function makeEmptyMouseEvent(): MouseEvent {
352
- return {
353
- type: InputType.INPUT_MOUSE,
354
- u: {
355
- mi: {
356
- dx: 0,
357
- dy: 0,
358
- mouseData: 0,
359
- dwFlags: 0,
360
- time: 0,
361
- dwExtraInfo: 0,
362
- }
363
- }
364
- };
365
- }
366
-
367
- function makeMouseDownEvents(button: number): MouseEvent[] {
368
- const mouseEvent: MouseEvent = makeEmptyMouseEvent();
369
-
370
- switch (button) {
371
- case 0:
372
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTDOWN;
373
- break;
374
- case 1:
375
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MIDDLEDOWN;
376
- break;
377
- case 2:
378
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTDOWN;
379
- break;
380
- case 3:
381
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_XDOWN;
382
- mouseEvent.u.mi.mouseData = XMouseButton.XBUTTON1;
383
- break;
384
- case 4:
385
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_XDOWN;
386
- mouseEvent.u.mi.mouseData = XMouseButton.XBUTTON2;
387
- break;
388
- default:
389
- throw new errors.InvalidArgumentError('button parameter should be a positive integer between 0 and 4.');
390
- }
391
-
392
- return [mouseEvent];
393
- }
394
-
395
- function makeMouseUpEvents(button: number): MouseEvent[] {
396
- const mouseEvent: MouseEvent = makeEmptyMouseEvent();
397
-
398
- switch (button) {
399
- case 0:
400
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_LEFTUP;
401
- break;
402
- case 1:
403
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MIDDLEUP;
404
- break;
405
- case 2:
406
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_RIGHTUP;
407
- break;
408
- case 3:
409
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_XUP;
410
- mouseEvent.u.mi.mouseData = XMouseButton.XBUTTON1;
411
- break;
412
- case 4:
413
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_XUP;
414
- mouseEvent.u.mi.mouseData = XMouseButton.XBUTTON2;
415
- break;
416
- default:
417
- throw new errors.InvalidArgumentError('button parameter should be a positive integer between 0 and 4.');
418
- }
419
-
420
- return [mouseEvent];
421
- }
422
-
423
- function makeMouseMoveEvents(args: {
424
- /** The absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the x coordinate of the mouse; relative data is specified as the number of pixels moved. */
425
- x: number,
426
- /** The absolute position of the mouse, or the amount of motion since the last mouse event was generated, depending on the value of the dwFlags member. Absolute data is specified as the y coordinate of the mouse; relative data is specified as the number of pixels moved. */
427
- y: number,
428
- /** Set to true if the event is a mouse wheel move, and false if it's a mouse move. */
429
- wheel: boolean,
430
- /** Set to true if the event is a mouse move with relative coordinates. This argument is ignored for mouse wheel move. */
431
- relative?: boolean,
432
- /** Set to screen resolution [width, height] when the mouse move is absolute. */
433
- screenResolutionAndRefreshRate?: ReturnType<typeof getScreenResolutionAndRefreshRate>;
434
- }
435
- ): MouseEvent[] {
436
- const { x, y, wheel, relative, screenResolutionAndRefreshRate} = args;
437
-
438
- if (wheel) {
439
- const mouseEvents: MouseEvent[] = [];
440
-
441
- if (x !== 0) {
442
- const horizontalScrollEvent = makeEmptyMouseEvent();
443
- horizontalScrollEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_HWHEEL;
444
- horizontalScrollEvent.u.mi.mouseData = x;
445
- mouseEvents.push(horizontalScrollEvent);
446
- }
447
-
448
- if (y !== 0) {
449
- const verticalScrollEvent = makeEmptyMouseEvent();
450
- verticalScrollEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_WHEEL;
451
- verticalScrollEvent.u.mi.mouseData = y;
452
- }
453
-
454
- return mouseEvents;
455
- }
456
-
457
- const mouseEvent: MouseEvent = makeEmptyMouseEvent();
458
-
459
- if (!screenResolutionAndRefreshRate) {
460
- throw new errors.InvalidArgumentError('screenResolution parameter must be set for absolute mouse move.');
461
- }
462
-
463
- const [screenWidth, screenHeight] = screenResolutionAndRefreshRate;
464
-
465
- mouseEvent.u.mi.dx = relative ? Math.trunc(x) : Math.trunc((x * UINT16_MAX) / screenWidth);
466
- mouseEvent.u.mi.dy = relative ? Math.trunc(y) : Math.trunc((y * UINT16_MAX) / screenHeight);
467
- mouseEvent.u.mi.dwFlags = MouseEventFlags.MOUSEEVENTF_MOVE;
468
-
469
- if (!relative) {
470
- mouseEvent.u.mi.dwFlags |= MouseEventFlags.MOUSEEVENTF_ABSOLUTE;
471
- }
472
-
473
- return [mouseEvent];
474
- }
475
-
476
- function charToKeyboardEvents(char: string, down: boolean, forceUnicode: boolean = false): KeyboardEvent[] {
477
- const charCode = char.charCodeAt(0);
478
- if ((charCode & 0xF000) === 0xE000) {
479
- switch (char) {
480
- case Key.CANCEL:
481
- return [makeKeyboardEvent({ vk: VirtualKey.VK_CANCEL, down })];
482
- case Key.HELP:
483
- return [makeKeyboardEvent({ vk: VirtualKey.VK_HELP, down })];
484
- case Key.BACKSPACE:
485
- return [makeKeyboardEvent({ vk: VirtualKey.VK_BACK, down })];
486
- case Key.TAB:
487
- return [makeKeyboardEvent({ vk: VirtualKey.VK_TAB, down })];
488
- case Key.CLEAR:
489
- return [makeKeyboardEvent({ vk: VirtualKey.VK_CLEAR, down })];
490
- case Key.RETURN:
491
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RETURN, down })];
492
- case Key.ENTER:
493
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RETURN, down })];
494
- case Key.SHIFT:
495
- return [makeKeyboardEvent({ vk: VirtualKey.VK_SHIFT, down })];
496
- case Key.CONTROL:
497
- return [makeKeyboardEvent({ vk: VirtualKey.VK_CONTROL, down })];
498
- case Key.ALT:
499
- return [makeKeyboardEvent({ vk: VirtualKey.VK_MENU, down })];
500
- case Key.PAUSE:
501
- return [makeKeyboardEvent({ vk: VirtualKey.VK_PAUSE, down })];
502
- case Key.ESCAPE:
503
- return [makeKeyboardEvent({ vk: VirtualKey.VK_ESCAPE, down })];
504
- case Key.SPACE:
505
- return [makeKeyboardEvent({ vk: VirtualKey.VK_SPACE, down })];
506
- case Key.PAGE_UP:
507
- return [makeKeyboardEvent({ vk: VirtualKey.VK_PRIOR, down })];
508
- case Key.PAGE_DOWN:
509
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NEXT, down })];
510
- case Key.END:
511
- return [makeKeyboardEvent({ vk: VirtualKey.VK_END, down })];
512
- case Key.HOME:
513
- return [makeKeyboardEvent({ vk: VirtualKey.VK_HOME, down })];
514
- case Key.LEFT:
515
- return [makeKeyboardEvent({ vk: VirtualKey.VK_LEFT, down })];
516
- case Key.UP:
517
- return [makeKeyboardEvent({ vk: VirtualKey.VK_UP, down })];
518
- case Key.RIGHT:
519
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RIGHT, down })];
520
- case Key.DOWN:
521
- return [makeKeyboardEvent({ vk: VirtualKey.VK_DOWN, down })];
522
- case Key.INSERT:
523
- return [makeKeyboardEvent({ vk: VirtualKey.VK_INSERT, down })];
524
- case Key.DELETE:
525
- return [makeKeyboardEvent({ vk: VirtualKey.VK_DELETE, down })];
526
- case Key.SEMICOLON:
527
- return [makeKeyboardEvent({ scan: ScanCode.SEMICOLON, down })];
528
- case Key.EQUALS:
529
- return [makeKeyboardEvent({ scan: ScanCode.EQUAL, down })];
530
- case Key.NUMPAD0:
531
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD0, down })];
532
- case Key.NUMPAD1:
533
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD1, down })];
534
- case Key.NUMPAD2:
535
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD2, down })];
536
- case Key.NUMPAD3:
537
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD3, down })];
538
- case Key.NUMPAD4:
539
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD4, down })];
540
- case Key.NUMPAD5:
541
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD5, down })];
542
- case Key.NUMPAD6:
543
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD6, down })];
544
- case Key.NUMPAD7:
545
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD7, down })];
546
- case Key.NUMPAD8:
547
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD8, down })];
548
- case Key.NUMPAD9:
549
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD9, down })];
550
- case Key.MULTIPLY:
551
- return [makeKeyboardEvent({ vk: VirtualKey.VK_MULTIPLY, down })];
552
- case Key.ADD:
553
- return [makeKeyboardEvent({ vk: VirtualKey.VK_ADD, down })];
554
- case Key.SEPARATOR:
555
- return [makeKeyboardEvent({ vk: VirtualKey.VK_SEPARATOR, down })];
556
- case Key.SUBTRACT:
557
- return [makeKeyboardEvent({ vk: VirtualKey.VK_SUBTRACT, down })];
558
- case Key.DECIMAL:
559
- return [makeKeyboardEvent({ vk: VirtualKey.VK_DECIMAL, down })];
560
- case Key.DIVIDE:
561
- return [makeKeyboardEvent({ vk: VirtualKey.VK_DIVIDE, down })];
562
- case Key.F1:
563
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F1, down })];
564
- case Key.F2:
565
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F2, down })];
566
- case Key.F3:
567
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F3, down })];
568
- case Key.F4:
569
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F4, down })];
570
- case Key.F5:
571
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F5, down })];
572
- case Key.F6:
573
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F6, down })];
574
- case Key.F7:
575
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F7, down })];
576
- case Key.F8:
577
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F8, down })];
578
- case Key.F9:
579
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F9, down })];
580
- case Key.F10:
581
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F10, down })];
582
- case Key.F11:
583
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F11, down })];
584
- case Key.F12:
585
- return [makeKeyboardEvent({ vk: VirtualKey.VK_F12, down })];
586
- case Key.META:
587
- return [makeKeyboardEvent({ vk: VirtualKey.VK_LWIN, down })];
588
- case Key.ZENKAKUHANKAKU:
589
- return [makeKeyboardEvent({ vk: VirtualKey.VK_OEM_AUTO, down })];
590
- case Key.R_SHIFT:
591
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RSHIFT, down })];
592
- case Key.R_CONTROL:
593
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RCONTROL, down })];
594
- case Key.R_ALT:
595
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RMENU, down })];
596
- case Key.R_META:
597
- return [makeKeyboardEvent({ vk: VirtualKey.VK_RWIN, down })];
598
- case Key.R_PAGEUP:
599
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD9, down })];
600
- case Key.R_PAGEDOWN:
601
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD3, down })];
602
- case Key.R_END:
603
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD1, down })];
604
- case Key.R_HOME:
605
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD7, down })];
606
- case Key.R_ARROWLEFT:
607
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD4, down })];
608
- case Key.R_ARROWUP:
609
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD8, down })];
610
- case Key.R_ARROWRIGHT:
611
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD6, down })];
612
- case Key.R_ARROWDOWN:
613
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD2, down })];
614
- case Key.R_INSERT:
615
- return [makeKeyboardEvent({ vk: VirtualKey.VK_NUMPAD0, down })];
616
- case Key.R_DELETE:
617
- return [makeKeyboardEvent({ vk: VirtualKey.VK_DECIMAL, down })];
618
- default:
619
- throw new errors.InvalidArgumentError(`Invalid character \\u${charCode.toString(16)}.`);
620
- }
621
- }
622
-
623
- // Currently only [a-z0-9] are sent as scan code through performAction (in order for them to work in hotkeys).
624
- if (!forceUnicode) {
625
- if (/[a-z]/.test(char)) {
626
- return [makeKeyboardEvent({ scan: ScanCode[char.toUpperCase() as keyof typeof ScanCode], down })];
627
- }
628
- if (/[0-9]/.test(char)) {
629
- return [makeKeyboardEvent({ scan: ScanCode[`N${char}` as keyof typeof ScanCode], down })];
630
- }
631
- }
632
-
633
- return [makeKeyboardEvent({ scan: char, down })];
634
- }
635
-
636
- function sendKeyInput(char: string, down: boolean, forceUnicode: boolean = false): void {
637
- const events = charToKeyboardEvents(char, down, forceUnicode);
638
- const returnCode = SendInput(events.length, events, sizeof(INPUT));
639
-
640
- assertSuccessSendInputReturnCode(returnCode);
641
- }
642
-
643
- function sendMouseButtonInput(button: number, down: boolean) {
644
- const events = down ? makeMouseDownEvents(button) : makeMouseUpEvents(button);
645
- const returnCode = SendInput(events.length, events, sizeof(INPUT));
646
-
647
- assertSuccessSendInputReturnCode(returnCode);
648
- }
649
-
650
- async function sendMouseMoveInput(args: { x: number, y: number, relative: boolean, duration: number, easingFunction?: string }): Promise<void> {
651
- const { duration } = args;
652
- let { x, y, easingFunction, relative } = args;
653
- const screenResolutionAndRefreshRate = getScreenResolutionAndRefreshRate();
654
- const [, , refreshRate] = screenResolutionAndRefreshRate;
655
- const updateInterval = 1000 / refreshRate;
656
- const iterations = Math.max(Math.floor(duration / updateInterval), 1);
657
-
658
- const cursorPosition = {
659
- x: 0,
660
- y: 0,
661
- } satisfies Point;
662
-
663
- if (GetCursorPos(cursorPosition) && iterations > 1) {
664
- if (relative) {
665
- x += cursorPosition.x;
666
- y += cursorPosition.y;
667
- }
668
-
669
- // setting relative to false since coordinates are now absolute
670
- relative = false;
671
- } else {
672
- // ignore easing function of it can't retrieve current cursor position
673
- // this is preventing the method from failing
674
- easingFunction = undefined;
675
- }
676
-
677
- if (easingFunction) {
678
- let calculatePoint: EasingFunction;
679
-
680
- // the lines below assume that the validation has been made on createSession
681
- if (easingFunction.startsWith('cubic-bezier')) {
682
- const bezierArgs = /\((.*?)\)/.exec(easingFunction)?.groups?.[0]
683
- .split(',').map((n) => parseFloat(n.trim())) ?? [0, 0, 1, 1];
684
-
685
- calculatePoint = bezier.apply(bezierArgs);
686
- } else {
687
- calculatePoint = easingFunctions[easingFunction];
688
- }
689
-
690
- for (let i = 1; i < iterations; i++) {
691
- setTimeout(() => {
692
- const normalizedProgress = (i + 1) / iterations;
693
- const easedProgress = i !== iterations - 1 ? calculatePoint(normalizedProgress) : 1;
694
- const interpolatedX = cursorPosition.x + (x - cursorPosition.x) * easedProgress;
695
- const interpolatedY = cursorPosition.y + (y - cursorPosition.y) * easedProgress;
696
-
697
- const events = makeMouseMoveEvents({ x: interpolatedX, y: interpolatedY, wheel: false, screenResolutionAndRefreshRate });
698
- const returnCode = SendInput(events.length, events, sizeof(INPUT));
699
-
700
- assertSuccessSendInputReturnCode(returnCode);
701
- }, i * updateInterval);
702
- }
703
- } else {
704
- const events = makeMouseMoveEvents({ x, y, wheel: false, screenResolutionAndRefreshRate });
705
- const returnCode = SendInput(events.length, events, sizeof(INPUT));
706
-
707
- assertSuccessSendInputReturnCode(returnCode);
708
- }
709
-
710
- await sleep(duration);
711
- }
712
-
713
- function sendMouseScrollInput(x: number, y: number) {
714
- const events = makeMouseMoveEvents({ x, y, wheel: true });
715
- const returnCode = SendInput(events.length, events, sizeof(INPUT));
716
-
717
- assertSuccessSendInputReturnCode(returnCode);
718
- }
719
-
720
- function assertSuccessSendInputReturnCode(returnCode: number) {
721
- if (returnCode === UINT32_MAX) {
722
- throw new errors.UnknownError('An error occurred while executing SendInput.');
723
- }
724
- }
725
-
726
- // TODO: Remove eslint-disable-next-line when used
727
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
728
- function getResolutionScalingFactor(): number {
729
- const dpi = GetDpiForSystem();
730
- const scalingFactor = dpi / 96;
731
-
732
- // @ts-expect-error temporary quick and dirty version of memoization
733
- getResolutionScalingFactor = () => scalingFactor;
734
-
735
- return scalingFactor;
736
- }
737
-
738
- function getScreenResolutionAndRefreshRate(): [number, number, number] {
739
- const width = GetSystemMetrics(SystemMetric.SM_CXSCREEN);
740
- const height = GetSystemMetrics(SystemMetric.SM_CYSCREEN);
741
- let refreshRate: number | null = null;
742
-
743
- const buffer = Buffer.alloc(sizeof(DEVMODEA));
744
- EnumDisplaySettingsA(null, -1, buffer);
745
- const deviceMode = { dmDisplayFrequency: buffer.readUInt32LE(120) } as DeviceModeAnsi;
746
- refreshRate = deviceMode.dmDisplayFrequency;
747
-
748
- const resolution = [width, height, refreshRate] satisfies ReturnType<typeof getScreenResolutionAndRefreshRate>;
749
-
750
- const nonMemoizedMethod = getScreenResolutionAndRefreshRate;
751
- const currentTime = new Date().getTime();
752
-
753
- // @ts-expect-error memoizing the function to prevent repeated calls that might crash Node.js
754
- getScreenResolutionAndRefreshRate = () => {
755
- if (new Date().getTime() - currentTime > 1000) {
756
- // @ts-expect-error reset memoization after 1 second
757
- getScreenResolutionAndRefreshRate = nonMemoizedMethod;
758
- }
759
- return resolution;
760
- };
761
-
762
- return resolution;
763
- }
764
-
765
- export function keyDown(char: string, forceUnicode: boolean = false): void {
766
- sendKeyInput(char, true, forceUnicode);
767
- }
768
-
769
- export function keyUp(char: string, forceUnicode: boolean = false): void {
770
- sendKeyInput(char, false, forceUnicode);
771
- }
772
-
773
- export async function mouseMoveRelative(x: number, y: number, duration: number = 0, easingFunction?: string): Promise<void> {
774
- await sendMouseMoveInput({x, y, relative: true, duration, easingFunction});
775
- }
776
-
777
- export function mouseScroll(x: number, y: number): void {
778
- sendMouseScrollInput(x, y);
779
- }
780
-
781
- export async function mouseMoveAbsolute(x: number, y: number, duration: number = 0, easingFunction?: string): Promise<void> {
782
- await sendMouseMoveInput({x, y, relative: false, duration, easingFunction});
783
- }
784
-
785
- export function mouseDown(button: number = 0): void {
786
- sendMouseButtonInput(button, true);
787
- }
788
-
789
- export function mouseUp(button: number = 0): void {
790
- sendMouseButtonInput(button, false);
791
- }
792
-
793
- export function getDisplayOrientation(): Orientation {
794
- const resolution = getScreenResolutionAndRefreshRate();
795
- return resolution[0] > resolution[1] ? 'LANDSCAPE' : 'PORTRAIT';
796
- }
797
-
798
- export function setDpiAwareness() {
799
- if (!SetProcessDPIAware()) {
800
- throw new errors.UnknownError('An error occurred while trying to set DPI awareness.');
801
- };
802
- }
803
-
804
- export function getWindowAllHandlesForProcessIds(processIds: number[]): number[] {
805
- const handles: number[] = [];
806
- EnumWindows((hWnd) => {
807
- const ptr: [LPDWORD | null] = [null];
808
- GetWindowThreadProcessId(hWnd, ptr);
809
- const pid = ptr[0];
810
- if (pid && processIds.includes(pid) && IsWindowVisible(hWnd)) {
811
- const buffer = Buffer.alloc(256); // Adjust size as needed
812
- GetWindowTextA(hWnd, buffer, buffer.length);
813
- const windowTitle = buffer.toString('utf8').replace(/\0/g, '');
814
-
815
- if (windowTitle) {
816
- handles.push(Number(address(hWnd)));
817
- }
818
- }
819
-
820
- return true;
821
- }, 0);
822
-
823
- return handles;
824
- }
825
-
826
- export function trySetForegroundWindow(windowHandle: number): boolean {
827
- return EnumWindows((hWnd) => {
828
- if (windowHandle === Number(address(hWnd))) {
829
- SetForegroundWindow(hWnd);
830
- return false;
831
- }
832
-
833
- return true;
834
- }, 0);
835
- }
836
-
837
- export function sendKeyboardEvents(inputs: (KeyboardEvent['u']['ki'])[]): number {
838
- return SendInput(inputs.length, inputs.map((ki) => ({
839
- type: InputType.INPUT_KEYBOARD,
840
- u: { ki },
841
- })), sizeof(INPUT));
842
- }