illuma-rpa 1.0.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/.github/workflows/publish.yml +129 -0
- package/LICENSE +107 -0
- package/README.md +202 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/keyboard.d.ts +82 -0
- package/dist/keyboard.d.ts.map +1 -0
- package/dist/keyboard.js +116 -0
- package/dist/keyboard.js.map +1 -0
- package/dist/mouse.d.ts +61 -0
- package/dist/mouse.d.ts.map +1 -0
- package/dist/mouse.js +107 -0
- package/dist/mouse.js.map +1 -0
- package/dist/native.d.ts +63 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +91 -0
- package/dist/native.js.map +1 -0
- package/dist/screen.d.ts +39 -0
- package/dist/screen.d.ts.map +1 -0
- package/dist/screen.js +43 -0
- package/dist/screen.js.map +1 -0
- package/dist/window.d.ts +61 -0
- package/dist/window.d.ts.map +1 -0
- package/dist/window.js +66 -0
- package/dist/window.js.map +1 -0
- package/libnut-core/CHANGELOG.md +122 -0
- package/libnut-core/LICENSE.md +201 -0
- package/libnut-core/README.md +26 -0
- package/libnut-core/index.d.ts +82 -0
- package/libnut-core/index.js +51 -0
- package/libnut-core/package-lock.json +1430 -0
- package/libnut-core/package.json +59 -0
- package/libnut-core/patch-packagename.js +18 -0
- package/libnut-core/permissionCheck.js +82 -0
- package/package.json +61 -0
- package/src/index.ts +10 -0
- package/src/keyboard.ts +125 -0
- package/src/mouse.ts +114 -0
- package/src/native.ts +103 -0
- package/src/screen.ts +59 -0
- package/src/window.ts +89 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "libnut",
|
|
3
|
+
"version": "2.7.1",
|
|
4
|
+
"description": "libnut is an N-API module for desktop automation with node",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"typings": "index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"clean": "cmake-js clean",
|
|
9
|
+
"patch": "node ./patch-packagename.js",
|
|
10
|
+
"build:debug": "cmake-js rebuild --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\" --debug",
|
|
11
|
+
"build:release": "cmake-js rebuild --CDCMAKE_OSX_ARCHITECTURES=\"arm64;x86_64\"",
|
|
12
|
+
"prepublishOnly": "npm run build:release",
|
|
13
|
+
"publish:next": "npm publish --tag next"
|
|
14
|
+
},
|
|
15
|
+
"homepage": "https://nutjs.dev",
|
|
16
|
+
"author": {
|
|
17
|
+
"name": "dry Software UG (haftungsbeschränkt)",
|
|
18
|
+
"email": "info@dry.software",
|
|
19
|
+
"url": "https://dry.software"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/nut-tree/nut.js/issues"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"GUI",
|
|
26
|
+
"Automation",
|
|
27
|
+
"mouse",
|
|
28
|
+
"keyboard",
|
|
29
|
+
"screenshot",
|
|
30
|
+
"image",
|
|
31
|
+
"desktop",
|
|
32
|
+
"screen",
|
|
33
|
+
"recognition",
|
|
34
|
+
"autohotkey"
|
|
35
|
+
],
|
|
36
|
+
"license": "Apache-2.0",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"bindings": "1.5.0"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"cmake-js": "7.3.0",
|
|
42
|
+
"node-addon-api": "7.1.0"
|
|
43
|
+
},
|
|
44
|
+
"optionalDependencies": {
|
|
45
|
+
"@nut-tree/node-mac-permissions": "2.2.1"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">=10.15.3"
|
|
49
|
+
},
|
|
50
|
+
"os": [
|
|
51
|
+
"darwin",
|
|
52
|
+
"linux",
|
|
53
|
+
"win32"
|
|
54
|
+
],
|
|
55
|
+
"cpu": [
|
|
56
|
+
"x64",
|
|
57
|
+
"arm64"
|
|
58
|
+
]
|
|
59
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const { join } = require("path");
|
|
3
|
+
|
|
4
|
+
if (process.env.CI) {
|
|
5
|
+
const filename = join(__dirname, "package.json");
|
|
6
|
+
const packageJson = require(filename);
|
|
7
|
+
|
|
8
|
+
const plattformPackageName = `@nut-tree/libnut-${process.platform}`;
|
|
9
|
+
packageJson.name = plattformPackageName;
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
fs.writeFileSync(filename, JSON.stringify(packageJson, null, 2));
|
|
13
|
+
} catch (err) {
|
|
14
|
+
console.log(err);
|
|
15
|
+
process.exit(-1);
|
|
16
|
+
}
|
|
17
|
+
console.log(`Patched package name to '${plattformPackageName}'`);
|
|
18
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
let libnut = require("bindings")("libnut");
|
|
2
|
+
|
|
3
|
+
let hasScreenRecordingPermission = false;
|
|
4
|
+
let hasAccessibilityPermission = false;
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
const permissions = require("@nut-tree/node-mac-permissions");
|
|
8
|
+
|
|
9
|
+
const wrapWithWarning = (message, nativeFunction) => (...args) => {
|
|
10
|
+
console.warn(message);
|
|
11
|
+
return nativeFunction(...args);
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
const askForAccessibility = (nativeFunction, functionName) => {
|
|
15
|
+
if (process.platform !== 'darwin' || hasAccessibilityPermission) {
|
|
16
|
+
return nativeFunction;
|
|
17
|
+
}
|
|
18
|
+
const accessibilityStatus = permissions.getAuthStatus("accessibility");
|
|
19
|
+
|
|
20
|
+
if (accessibilityStatus === 'authorized') {
|
|
21
|
+
hasAccessibilityPermission = true;
|
|
22
|
+
return nativeFunction;
|
|
23
|
+
} else if (accessibilityStatus === 'not determined' || accessibilityStatus === 'denied') {
|
|
24
|
+
permissions.askForAccessibilityAccess();
|
|
25
|
+
return wrapWithWarning(`##### WARNING! The application running this script tries to access accessibility features to execute ${functionName}! Please grant requested access and visit https://github.com/nut-tree/nut.js#macos for further information. #####`, nativeFunction);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const askForScreenRecording = (nativeFunction, functionName) => {
|
|
29
|
+
if (process.platform !== 'darwin' || hasScreenRecordingPermission) {
|
|
30
|
+
return nativeFunction;
|
|
31
|
+
}
|
|
32
|
+
const screenCaptureStatus = permissions.getAuthStatus("screen");
|
|
33
|
+
|
|
34
|
+
if (screenCaptureStatus === 'authorized') {
|
|
35
|
+
hasScreenRecordingPermission = true;
|
|
36
|
+
return nativeFunction;
|
|
37
|
+
} else if (screenCaptureStatus === 'not determined' || screenCaptureStatus === 'denied') {
|
|
38
|
+
permissions.askForScreenCaptureAccess();
|
|
39
|
+
return wrapWithWarning(`##### WARNING! The application running this script tries to screen recording features to execute ${functionName}! Please grant the requested access and visit https://github.com/nut-tree/nut.js#macos for further information. #####`, nativeFunction);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const accessibilityAccess = [
|
|
44
|
+
"dragMouse",
|
|
45
|
+
"moveMouse",
|
|
46
|
+
"getMousePos",
|
|
47
|
+
"mouseClick",
|
|
48
|
+
"mouseToggle",
|
|
49
|
+
"scrollMouse",
|
|
50
|
+
"keyTap",
|
|
51
|
+
"keyToggle",
|
|
52
|
+
"typeString",
|
|
53
|
+
"getScreenSize",
|
|
54
|
+
"highlight",
|
|
55
|
+
"captureScreen",
|
|
56
|
+
"getWindows",
|
|
57
|
+
"getActiveWindow",
|
|
58
|
+
"getWindowRect",
|
|
59
|
+
"getWindowTitle",
|
|
60
|
+
"focusWindow",
|
|
61
|
+
"resizeWindow"
|
|
62
|
+
];
|
|
63
|
+
const screenCaptureAccess = [
|
|
64
|
+
"getWindowTitle",
|
|
65
|
+
"captureScreen",
|
|
66
|
+
];
|
|
67
|
+
|
|
68
|
+
for (const functionName of accessibilityAccess) {
|
|
69
|
+
const originalFunction = libnut[functionName];
|
|
70
|
+
libnut[functionName] = (...args) => askForAccessibility(originalFunction, functionName)(...args);
|
|
71
|
+
}
|
|
72
|
+
for (const functionName of screenCaptureAccess) {
|
|
73
|
+
const originalFunction = libnut[functionName];
|
|
74
|
+
libnut[functionName] = (...args) => askForScreenRecording(originalFunction, functionName)(...args);
|
|
75
|
+
}
|
|
76
|
+
} catch (e) {
|
|
77
|
+
console.warn(`Encountered error establishing macOS permission checks:`, e.message);
|
|
78
|
+
console.warn(`Returning original module.`);
|
|
79
|
+
libnut = require("bindings")("libnut");
|
|
80
|
+
} finally {
|
|
81
|
+
module.exports = libnut;
|
|
82
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "illuma-rpa",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Cross-platform desktop automation for Node.js - mouse, keyboard, screen capture",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"license": "Apache-2.0",
|
|
8
|
+
"author": "Illuma",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/illuma-ai/illuma-rpa.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/illuma-ai/illuma-rpa",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/illuma-ai/illuma-rpa/issues"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"clean": "rimraf dist",
|
|
19
|
+
"build": "pnpm run clean && tsc -p .",
|
|
20
|
+
"build:native": "cd libnut-core && npm run build:release",
|
|
21
|
+
"test": "jest",
|
|
22
|
+
"prepublishOnly": "pnpm run build",
|
|
23
|
+
"publish:npm": "npm publish --access public"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"automation",
|
|
27
|
+
"desktop",
|
|
28
|
+
"rpa",
|
|
29
|
+
"mouse",
|
|
30
|
+
"keyboard",
|
|
31
|
+
"screenshot",
|
|
32
|
+
"screen",
|
|
33
|
+
"ui-automation",
|
|
34
|
+
"robot",
|
|
35
|
+
"native",
|
|
36
|
+
"electron"
|
|
37
|
+
],
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=16"
|
|
40
|
+
},
|
|
41
|
+
"os": [
|
|
42
|
+
"win32",
|
|
43
|
+
"darwin",
|
|
44
|
+
"linux"
|
|
45
|
+
],
|
|
46
|
+
"cpu": [
|
|
47
|
+
"x64",
|
|
48
|
+
"arm64"
|
|
49
|
+
],
|
|
50
|
+
"dependencies": {
|
|
51
|
+
"jimp": "0.22.10"
|
|
52
|
+
},
|
|
53
|
+
"devDependencies": {
|
|
54
|
+
"@types/node": "^20.0.0",
|
|
55
|
+
"rimraf": "^5.0.0",
|
|
56
|
+
"typescript": "^5.3.0",
|
|
57
|
+
"jest": "^29.7.0",
|
|
58
|
+
"@types/jest": "^29.5.0",
|
|
59
|
+
"ts-jest": "^29.1.0"
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* illuma-rpa
|
|
3
|
+
* Cross-platform desktop automation for Node.js
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export { mouse, Mouse } from './mouse';
|
|
7
|
+
export { keyboard, Keyboard, Key } from './keyboard';
|
|
8
|
+
export { screen, Screen, Screenshot } from './screen';
|
|
9
|
+
export { window, Window, WindowInfo } from './window';
|
|
10
|
+
export { loadNativeBinding } from './native';
|
package/src/keyboard.ts
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keyboard control module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getNative } from './native';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Key constants for keyboard input
|
|
9
|
+
*/
|
|
10
|
+
export const Key = {
|
|
11
|
+
// Modifiers
|
|
12
|
+
Ctrl: 'control',
|
|
13
|
+
Control: 'control',
|
|
14
|
+
Alt: 'alt',
|
|
15
|
+
Shift: 'shift',
|
|
16
|
+
Meta: 'command', // Win key on Windows, Cmd on macOS
|
|
17
|
+
Win: 'command',
|
|
18
|
+
Cmd: 'command',
|
|
19
|
+
|
|
20
|
+
// Navigation
|
|
21
|
+
Up: 'up',
|
|
22
|
+
Down: 'down',
|
|
23
|
+
Left: 'left',
|
|
24
|
+
Right: 'right',
|
|
25
|
+
Home: 'home',
|
|
26
|
+
End: 'end',
|
|
27
|
+
PageUp: 'pageup',
|
|
28
|
+
PageDown: 'pagedown',
|
|
29
|
+
|
|
30
|
+
// Editing
|
|
31
|
+
Enter: 'enter',
|
|
32
|
+
Return: 'enter',
|
|
33
|
+
Tab: 'tab',
|
|
34
|
+
Backspace: 'backspace',
|
|
35
|
+
Delete: 'delete',
|
|
36
|
+
Escape: 'escape',
|
|
37
|
+
Esc: 'escape',
|
|
38
|
+
Space: 'space',
|
|
39
|
+
Insert: 'insert',
|
|
40
|
+
|
|
41
|
+
// Function keys
|
|
42
|
+
F1: 'f1', F2: 'f2', F3: 'f3', F4: 'f4',
|
|
43
|
+
F5: 'f5', F6: 'f6', F7: 'f7', F8: 'f8',
|
|
44
|
+
F9: 'f9', F10: 'f10', F11: 'f11', F12: 'f12',
|
|
45
|
+
|
|
46
|
+
// Other
|
|
47
|
+
PrintScreen: 'printscreen',
|
|
48
|
+
CapsLock: 'capslock',
|
|
49
|
+
NumLock: 'numlock',
|
|
50
|
+
ScrollLock: 'scrolllock',
|
|
51
|
+
} as const;
|
|
52
|
+
|
|
53
|
+
export type KeyType = typeof Key[keyof typeof Key] | string;
|
|
54
|
+
|
|
55
|
+
export class Keyboard {
|
|
56
|
+
private delay = 0;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Set delay between key presses (ms)
|
|
60
|
+
*/
|
|
61
|
+
setDelay(ms: number): void {
|
|
62
|
+
this.delay = ms;
|
|
63
|
+
getNative().setKeyboardDelay(ms);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Type a string of text
|
|
68
|
+
*/
|
|
69
|
+
async type(text: string): Promise<void> {
|
|
70
|
+
getNative().typeString(text);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Type text with delay between characters
|
|
75
|
+
*/
|
|
76
|
+
async typeDelayed(text: string, delayMs: number = 50): Promise<void> {
|
|
77
|
+
// Convert delay to characters per minute
|
|
78
|
+
const cpm = Math.round(60000 / delayMs);
|
|
79
|
+
getNative().typeStringDelayed(text, cpm);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Press and release a key or key combination
|
|
84
|
+
*/
|
|
85
|
+
async press(...keys: KeyType[]): Promise<void> {
|
|
86
|
+
if (keys.length === 0) return;
|
|
87
|
+
|
|
88
|
+
if (keys.length === 1) {
|
|
89
|
+
getNative().keyTap(keys[0]);
|
|
90
|
+
} else {
|
|
91
|
+
// Last key is the main key, others are modifiers
|
|
92
|
+
const mainKey = keys[keys.length - 1];
|
|
93
|
+
const modifiers = keys.slice(0, -1);
|
|
94
|
+
getNative().keyTap(mainKey, modifiers);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Hold a key down
|
|
100
|
+
*/
|
|
101
|
+
async hold(...keys: KeyType[]): Promise<void> {
|
|
102
|
+
for (const key of keys) {
|
|
103
|
+
getNative().keyToggle(key, 'down');
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Release a held key
|
|
109
|
+
*/
|
|
110
|
+
async release(...keys: KeyType[]): Promise<void> {
|
|
111
|
+
for (const key of keys) {
|
|
112
|
+
getNative().keyToggle(key, 'up');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Press a key combination (e.g., Ctrl+C)
|
|
118
|
+
*/
|
|
119
|
+
async combo(...keys: KeyType[]): Promise<void> {
|
|
120
|
+
await this.press(...keys);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Export singleton instance
|
|
125
|
+
export const keyboard = new Keyboard();
|
package/src/mouse.ts
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mouse control module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getNative } from './native';
|
|
6
|
+
|
|
7
|
+
export interface Point {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type MouseButton = 'left' | 'right' | 'middle';
|
|
13
|
+
|
|
14
|
+
export class Mouse {
|
|
15
|
+
private delay = 10;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Set delay between mouse actions (ms)
|
|
19
|
+
*/
|
|
20
|
+
setDelay(ms: number): void {
|
|
21
|
+
this.delay = ms;
|
|
22
|
+
getNative().setMouseDelay(ms);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Move mouse to absolute position
|
|
27
|
+
*/
|
|
28
|
+
async moveTo(x: number, y: number): Promise<void> {
|
|
29
|
+
getNative().moveMouse(x, y);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Move mouse smoothly to position
|
|
34
|
+
*/
|
|
35
|
+
async moveSmooth(x: number, y: number): Promise<void> {
|
|
36
|
+
getNative().moveMouseSmooth(x, y);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Click mouse button
|
|
41
|
+
*/
|
|
42
|
+
async click(button: MouseButton = 'left'): Promise<void> {
|
|
43
|
+
getNative().mouseClick(button, false);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Double click
|
|
48
|
+
*/
|
|
49
|
+
async doubleClick(button: MouseButton = 'left'): Promise<void> {
|
|
50
|
+
getNative().mouseClick(button, true);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Right click (convenience method)
|
|
55
|
+
*/
|
|
56
|
+
async rightClick(): Promise<void> {
|
|
57
|
+
await this.click('right');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Press mouse button down
|
|
62
|
+
*/
|
|
63
|
+
async down(button: MouseButton = 'left'): Promise<void> {
|
|
64
|
+
getNative().mouseToggle('down', button);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Release mouse button
|
|
69
|
+
*/
|
|
70
|
+
async up(button: MouseButton = 'left'): Promise<void> {
|
|
71
|
+
getNative().mouseToggle('up', button);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Drag from current position to target
|
|
76
|
+
*/
|
|
77
|
+
async drag(startX: number, startY: number, endX: number, endY: number): Promise<void> {
|
|
78
|
+
await this.moveTo(startX, startY);
|
|
79
|
+
await this.down();
|
|
80
|
+
await this.moveTo(endX, endY);
|
|
81
|
+
await this.up();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Drag to target from current position
|
|
86
|
+
*/
|
|
87
|
+
async dragTo(x: number, y: number): Promise<void> {
|
|
88
|
+
getNative().dragMouse(x, y);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Scroll mouse wheel
|
|
93
|
+
*/
|
|
94
|
+
async scroll(direction: 'up' | 'down' | 'left' | 'right', amount: number = 3): Promise<void> {
|
|
95
|
+
let x = 0, y = 0;
|
|
96
|
+
switch (direction) {
|
|
97
|
+
case 'up': y = amount; break;
|
|
98
|
+
case 'down': y = -amount; break;
|
|
99
|
+
case 'left': x = -amount; break;
|
|
100
|
+
case 'right': x = amount; break;
|
|
101
|
+
}
|
|
102
|
+
getNative().scrollMouse(x, y);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Get current mouse position
|
|
107
|
+
*/
|
|
108
|
+
getPosition(): Point {
|
|
109
|
+
return getNative().getMousePos();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Export singleton instance
|
|
114
|
+
export const mouse = new Mouse();
|
package/src/native.ts
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native binding loader
|
|
3
|
+
* Automatically loads the correct platform-specific binary
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
|
|
8
|
+
export interface NativeBinding {
|
|
9
|
+
// Keyboard
|
|
10
|
+
setKeyboardDelay(ms: number): void;
|
|
11
|
+
keyTap(key: string, modifier?: string | string[]): void;
|
|
12
|
+
keyToggle(key: string, down: string, modifier?: string | string[]): void;
|
|
13
|
+
typeString(str: string): void;
|
|
14
|
+
typeStringDelayed(str: string, cpm: number): void;
|
|
15
|
+
|
|
16
|
+
// Mouse
|
|
17
|
+
setMouseDelay(delay: number): void;
|
|
18
|
+
moveMouse(x: number, y: number): void;
|
|
19
|
+
moveMouseSmooth(x: number, y: number): void;
|
|
20
|
+
mouseClick(button?: string, double?: boolean): void;
|
|
21
|
+
mouseToggle(down?: string, button?: string): void;
|
|
22
|
+
dragMouse(x: number, y: number): void;
|
|
23
|
+
scrollMouse(x: number, y: number): void;
|
|
24
|
+
getMousePos(): { x: number; y: number };
|
|
25
|
+
|
|
26
|
+
// Screen
|
|
27
|
+
getScreenSize(): { width: number; height: number };
|
|
28
|
+
screen: {
|
|
29
|
+
capture(x?: number, y?: number, width?: number, height?: number): {
|
|
30
|
+
width: number;
|
|
31
|
+
height: number;
|
|
32
|
+
image: Buffer;
|
|
33
|
+
byteWidth: number;
|
|
34
|
+
bitsPerPixel: number;
|
|
35
|
+
bytesPerPixel: number;
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Window
|
|
40
|
+
getWindows(): number[];
|
|
41
|
+
getActiveWindow(): number;
|
|
42
|
+
getWindowRect(handle: number): { x: number; y: number; width: number; height: number };
|
|
43
|
+
getWindowTitle(handle: number): string;
|
|
44
|
+
focusWindow(handle: number): void;
|
|
45
|
+
resizeWindow(handle: number, size: { width: number; height: number }): void;
|
|
46
|
+
moveWindow(handle: number, pos: { x: number; y: number }): void;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
let native: NativeBinding | null = null;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Load the native binding for the current platform
|
|
53
|
+
*/
|
|
54
|
+
export function loadNativeBinding(): NativeBinding {
|
|
55
|
+
if (native) {
|
|
56
|
+
return native;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const platform = process.platform;
|
|
60
|
+
const arch = process.arch;
|
|
61
|
+
const packageName = `illuma-rpa-${platform}-${arch}`;
|
|
62
|
+
|
|
63
|
+
// Try loading from optional dependency
|
|
64
|
+
try {
|
|
65
|
+
native = require(packageName);
|
|
66
|
+
return native!;
|
|
67
|
+
} catch {
|
|
68
|
+
// Fallback: try loading from local build
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Try loading from local libnut-core build
|
|
72
|
+
const localPaths = [
|
|
73
|
+
path.join(__dirname, '../libnut-core/build/Release/libnut.node'),
|
|
74
|
+
path.join(__dirname, '../../libnut-core/build/Release/libnut.node'),
|
|
75
|
+
path.join(process.cwd(), 'libnut-core/build/Release/libnut.node'),
|
|
76
|
+
];
|
|
77
|
+
|
|
78
|
+
for (const localPath of localPaths) {
|
|
79
|
+
try {
|
|
80
|
+
native = require(localPath);
|
|
81
|
+
return native!;
|
|
82
|
+
} catch {
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
throw new Error(
|
|
88
|
+
`Failed to load native binding for ${platform}-${arch}.\n` +
|
|
89
|
+
`Please ensure one of the following:\n` +
|
|
90
|
+
` 1. Install the platform package: npm install ${packageName}\n` +
|
|
91
|
+
` 2. Build from source: cd libnut-core && npm run build:release`
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Get the native binding (lazy load)
|
|
97
|
+
*/
|
|
98
|
+
export function getNative(): NativeBinding {
|
|
99
|
+
if (!native) {
|
|
100
|
+
loadNativeBinding();
|
|
101
|
+
}
|
|
102
|
+
return native!;
|
|
103
|
+
}
|
package/src/screen.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screen capture module
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { getNative } from './native';
|
|
6
|
+
|
|
7
|
+
export interface Screenshot {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
image: Buffer;
|
|
11
|
+
byteWidth: number;
|
|
12
|
+
bitsPerPixel: number;
|
|
13
|
+
bytesPerPixel: number;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export interface ScreenSize {
|
|
17
|
+
width: number;
|
|
18
|
+
height: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class Screen {
|
|
22
|
+
/**
|
|
23
|
+
* Capture the entire screen
|
|
24
|
+
*/
|
|
25
|
+
async capture(): Promise<Screenshot> {
|
|
26
|
+
return getNative().screen.capture();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Capture a region of the screen
|
|
31
|
+
*/
|
|
32
|
+
async captureRegion(x: number, y: number, width: number, height: number): Promise<Screenshot> {
|
|
33
|
+
return getNative().screen.capture(x, y, width, height);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Get the screen size
|
|
38
|
+
*/
|
|
39
|
+
getSize(): ScreenSize {
|
|
40
|
+
return getNative().getScreenSize();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get screen width
|
|
45
|
+
*/
|
|
46
|
+
getWidth(): number {
|
|
47
|
+
return this.getSize().width;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get screen height
|
|
52
|
+
*/
|
|
53
|
+
getHeight(): number {
|
|
54
|
+
return this.getSize().height;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Export singleton instance
|
|
59
|
+
export const screen = new Screen();
|