refresh-computer-tools 0.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 +96 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +95 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +60 -0
- package/dist/index.js +321 -0
- package/dist/index.js.map +1 -0
- package/package.json +44 -0
package/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# refresh-computer-tools
|
|
2
|
+
|
|
3
|
+
macOS computer automation via Swift CoreGraphics. Screenshot, click, type, key press, scroll, drag, hover, zoom — all from the command line or as a library.
|
|
4
|
+
|
|
5
|
+
No Python, no pyobjc, no third-party dependencies. Uses Swift and `screencapture`, which are built into every Mac.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g refresh-computer-tools
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or run directly:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx refresh-computer-tools screenshot
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## CLI
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Screenshot (captures all displays, returns JPEG base64)
|
|
23
|
+
refresh-computer-tools screenshot
|
|
24
|
+
|
|
25
|
+
# Click at model coordinates (max 1280px on longest axis)
|
|
26
|
+
refresh-computer-tools click 640 416
|
|
27
|
+
refresh-computer-tools click 640 416 --button right
|
|
28
|
+
|
|
29
|
+
# Double-click
|
|
30
|
+
refresh-computer-tools double-click 640 416
|
|
31
|
+
|
|
32
|
+
# Type text (uses pbcopy + Cmd+V)
|
|
33
|
+
refresh-computer-tools type "Hello world"
|
|
34
|
+
|
|
35
|
+
# Key press with optional modifiers
|
|
36
|
+
refresh-computer-tools key-press return
|
|
37
|
+
refresh-computer-tools key-press space --modifiers command
|
|
38
|
+
refresh-computer-tools key-press a --modifiers command,shift
|
|
39
|
+
|
|
40
|
+
# Scroll
|
|
41
|
+
refresh-computer-tools scroll --dx 0 --dy -3
|
|
42
|
+
|
|
43
|
+
# Mouse move
|
|
44
|
+
refresh-computer-tools mouse-move 640 416
|
|
45
|
+
|
|
46
|
+
# Hover (move + wait)
|
|
47
|
+
refresh-computer-tools hover 640 416 --duration 600
|
|
48
|
+
|
|
49
|
+
# Drag
|
|
50
|
+
refresh-computer-tools drag 100 100 500 500
|
|
51
|
+
refresh-computer-tools drag 100 100 500 500 --button right --duration 400
|
|
52
|
+
|
|
53
|
+
# Zoom (crop a region from a screenshot)
|
|
54
|
+
refresh-computer-tools zoom 200 200 600 600
|
|
55
|
+
|
|
56
|
+
# Screen size (model coordinate space)
|
|
57
|
+
refresh-computer-tools screen-size
|
|
58
|
+
|
|
59
|
+
# Display info
|
|
60
|
+
refresh-computer-tools displays
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
All coordinates are in model space (the longest screen axis is scaled to 1280px). Output is JSON.
|
|
64
|
+
|
|
65
|
+
## Library
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
import { click, keyPress, typeText, captureScreenshot, getScreenSize } from 'refresh-computer-tools';
|
|
69
|
+
|
|
70
|
+
const screenshot = captureScreenshot();
|
|
71
|
+
// { image: 'base64...', format: 'jpeg', imagePath: '/tmp/...', thumbnailPath: '/tmp/...' }
|
|
72
|
+
|
|
73
|
+
const result = click(640, 416);
|
|
74
|
+
// { clicked: true, x: 756, y: 492, image: '...', ... }
|
|
75
|
+
|
|
76
|
+
const size = getScreenSize();
|
|
77
|
+
// { width: 1280, height: 831 }
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## How it works
|
|
81
|
+
|
|
82
|
+
- **Screenshots**: `screencapture -x` (captures all displays into one image)
|
|
83
|
+
- **Input actions**: Swift CoreGraphics via `swift -` (CGEvent API for mouse, keyboard, scroll)
|
|
84
|
+
- **Image processing**: `sips` (resize, format conversion, thumbnails)
|
|
85
|
+
- **Display detection**: Swift AppKit `NSScreen.screens`
|
|
86
|
+
- **Coordinate mapping**: Model space (max 1280px) mapped to logical screen coordinates
|
|
87
|
+
|
|
88
|
+
## Requirements
|
|
89
|
+
|
|
90
|
+
- macOS
|
|
91
|
+
- Node.js 18+
|
|
92
|
+
- Accessibility permission for the terminal app (System Settings > Privacy & Security > Accessibility)
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
MIT
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for macOS computer automation.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx refresh-computer-tools screenshot
|
|
7
|
+
* npx refresh-computer-tools click 400 300
|
|
8
|
+
* npx refresh-computer-tools click 400 300 --button right
|
|
9
|
+
* npx refresh-computer-tools double-click 400 300
|
|
10
|
+
* npx refresh-computer-tools type "Hello world"
|
|
11
|
+
* npx refresh-computer-tools key-press space --modifiers command
|
|
12
|
+
* npx refresh-computer-tools scroll --dx 0 --dy -3
|
|
13
|
+
* npx refresh-computer-tools mouse-move 400 300
|
|
14
|
+
* npx refresh-computer-tools hover 400 300 --duration 600
|
|
15
|
+
* npx refresh-computer-tools drag 100 100 500 500
|
|
16
|
+
* npx refresh-computer-tools zoom 200 200 600 600
|
|
17
|
+
* npx refresh-computer-tools screen-size
|
|
18
|
+
* npx refresh-computer-tools displays
|
|
19
|
+
*
|
|
20
|
+
* All coordinates are in model space (max 1280px on longest axis).
|
|
21
|
+
* Output is JSON with the action result and a base64 follow-up screenshot.
|
|
22
|
+
* Pass --no-screenshot to skip the follow-up screenshot.
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI for macOS computer automation.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx refresh-computer-tools screenshot
|
|
7
|
+
* npx refresh-computer-tools click 400 300
|
|
8
|
+
* npx refresh-computer-tools click 400 300 --button right
|
|
9
|
+
* npx refresh-computer-tools double-click 400 300
|
|
10
|
+
* npx refresh-computer-tools type "Hello world"
|
|
11
|
+
* npx refresh-computer-tools key-press space --modifiers command
|
|
12
|
+
* npx refresh-computer-tools scroll --dx 0 --dy -3
|
|
13
|
+
* npx refresh-computer-tools mouse-move 400 300
|
|
14
|
+
* npx refresh-computer-tools hover 400 300 --duration 600
|
|
15
|
+
* npx refresh-computer-tools drag 100 100 500 500
|
|
16
|
+
* npx refresh-computer-tools zoom 200 200 600 600
|
|
17
|
+
* npx refresh-computer-tools screen-size
|
|
18
|
+
* npx refresh-computer-tools displays
|
|
19
|
+
*
|
|
20
|
+
* All coordinates are in model space (max 1280px on longest axis).
|
|
21
|
+
* Output is JSON with the action result and a base64 follow-up screenshot.
|
|
22
|
+
* Pass --no-screenshot to skip the follow-up screenshot.
|
|
23
|
+
*/
|
|
24
|
+
import { captureScreenshot, click, typeText, keyPress, scroll, mouseMove, hover, drag, zoom, getScreenSize, getDisplayBounds, } from './index.js';
|
|
25
|
+
const args = process.argv.slice(2);
|
|
26
|
+
const command = args[0];
|
|
27
|
+
function flag(name) {
|
|
28
|
+
const idx = args.indexOf(`--${name}`);
|
|
29
|
+
return idx >= 0 && idx + 1 < args.length ? args[idx + 1] : undefined;
|
|
30
|
+
}
|
|
31
|
+
function num(pos) {
|
|
32
|
+
const v = Number(args[pos]);
|
|
33
|
+
if (!Number.isFinite(v)) {
|
|
34
|
+
console.error(`Expected a number at position ${pos}, got: ${args[pos]}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
return v;
|
|
38
|
+
}
|
|
39
|
+
function output(result) {
|
|
40
|
+
const obj = result;
|
|
41
|
+
const { image, ...rest } = obj;
|
|
42
|
+
if (image && typeof image === 'string') {
|
|
43
|
+
rest.imageLength = image.length;
|
|
44
|
+
}
|
|
45
|
+
console.log(JSON.stringify(rest, null, 2));
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
switch (command) {
|
|
49
|
+
case 'screenshot':
|
|
50
|
+
output(captureScreenshot());
|
|
51
|
+
break;
|
|
52
|
+
case 'click':
|
|
53
|
+
output(click(num(1), num(2), flag('button') ?? 'left', false));
|
|
54
|
+
break;
|
|
55
|
+
case 'double-click':
|
|
56
|
+
output(click(num(1), num(2), flag('button') ?? 'left', true));
|
|
57
|
+
break;
|
|
58
|
+
case 'type':
|
|
59
|
+
output(typeText(args[1] ?? ''));
|
|
60
|
+
break;
|
|
61
|
+
case 'key-press':
|
|
62
|
+
output(keyPress(args[1] ?? '', (flag('modifiers') ?? '').split(',').filter(Boolean)));
|
|
63
|
+
break;
|
|
64
|
+
case 'scroll':
|
|
65
|
+
output(scroll(Number(flag('dx') ?? 0), Number(flag('dy') ?? 0)));
|
|
66
|
+
break;
|
|
67
|
+
case 'mouse-move':
|
|
68
|
+
output(mouseMove(num(1), num(2)));
|
|
69
|
+
break;
|
|
70
|
+
case 'hover':
|
|
71
|
+
output(hover(num(1), num(2), Number(flag('duration') ?? 600)));
|
|
72
|
+
break;
|
|
73
|
+
case 'drag':
|
|
74
|
+
output(drag(num(1), num(2), num(3), num(4), flag('button') ?? 'left', Number(flag('duration') ?? 400)));
|
|
75
|
+
break;
|
|
76
|
+
case 'zoom':
|
|
77
|
+
output(zoom(num(1), num(2), num(3), num(4)));
|
|
78
|
+
break;
|
|
79
|
+
case 'screen-size':
|
|
80
|
+
console.log(JSON.stringify(getScreenSize()));
|
|
81
|
+
break;
|
|
82
|
+
case 'displays':
|
|
83
|
+
console.log(JSON.stringify(getDisplayBounds(), null, 2));
|
|
84
|
+
break;
|
|
85
|
+
default:
|
|
86
|
+
console.error(`Unknown command: ${command ?? '(none)'}`);
|
|
87
|
+
console.error('Commands: screenshot, click, double-click, type, key-press, scroll, mouse-move, hover, drag, zoom, screen-size, displays');
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (err) {
|
|
92
|
+
console.error(`Error: ${err instanceof Error ? err.message : String(err)}`);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS computer automation via Swift CoreGraphics.
|
|
3
|
+
*
|
|
4
|
+
* Every action uses `swift -` to post CGEvents — no pyobjc, no Electron,
|
|
5
|
+
* no third-party dependencies. Works from any Node.js process on macOS.
|
|
6
|
+
*/
|
|
7
|
+
export interface DisplayBounds {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
originX: number;
|
|
11
|
+
originY: number;
|
|
12
|
+
scale: number;
|
|
13
|
+
displayCount: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ScreenshotResult {
|
|
16
|
+
image: string;
|
|
17
|
+
format: string;
|
|
18
|
+
imagePath: string;
|
|
19
|
+
thumbnailPath: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function runSwift(script: string, timeout?: number): string;
|
|
22
|
+
export declare function getDisplayBounds(): DisplayBounds;
|
|
23
|
+
export declare function captureScreenshot(label?: string): ScreenshotResult;
|
|
24
|
+
export declare function captureFollowUpScreenshot(delayMs?: number): ScreenshotResult;
|
|
25
|
+
export declare function getScreenSize(bounds?: DisplayBounds): {
|
|
26
|
+
width: number;
|
|
27
|
+
height: number;
|
|
28
|
+
};
|
|
29
|
+
export declare function click(mx: number, my: number, button?: string, doubleClick?: boolean, bounds?: DisplayBounds): ScreenshotResult & {
|
|
30
|
+
clicked: boolean;
|
|
31
|
+
x: number;
|
|
32
|
+
y: number;
|
|
33
|
+
};
|
|
34
|
+
export declare function typeText(text: string): ScreenshotResult & {
|
|
35
|
+
typed: boolean;
|
|
36
|
+
length: number;
|
|
37
|
+
};
|
|
38
|
+
export declare function keyPress(key: string, modifiers?: string[]): ScreenshotResult & {
|
|
39
|
+
pressed: boolean;
|
|
40
|
+
key: string;
|
|
41
|
+
};
|
|
42
|
+
export declare function scroll(deltaX?: number, deltaY?: number): ScreenshotResult & {
|
|
43
|
+
scrolled: boolean;
|
|
44
|
+
};
|
|
45
|
+
export declare function mouseMove(mx: number, my: number, bounds?: DisplayBounds): ScreenshotResult & {
|
|
46
|
+
moved: boolean;
|
|
47
|
+
x: number;
|
|
48
|
+
y: number;
|
|
49
|
+
};
|
|
50
|
+
export declare function hover(mx: number, my: number, durationMs?: number, bounds?: DisplayBounds): ScreenshotResult & {
|
|
51
|
+
hovered: boolean;
|
|
52
|
+
x: number;
|
|
53
|
+
y: number;
|
|
54
|
+
};
|
|
55
|
+
export declare function drag(startMx: number, startMy: number, endMx: number, endMy: number, button?: string, durationMs?: number, bounds?: DisplayBounds): ScreenshotResult & {
|
|
56
|
+
dragged: boolean;
|
|
57
|
+
};
|
|
58
|
+
export declare function zoom(startMx: number, startMy: number, endMx: number, endMy: number, bounds?: DisplayBounds): ScreenshotResult & {
|
|
59
|
+
zoomed: boolean;
|
|
60
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* macOS computer automation via Swift CoreGraphics.
|
|
3
|
+
*
|
|
4
|
+
* Every action uses `swift -` to post CGEvents — no pyobjc, no Electron,
|
|
5
|
+
* no third-party dependencies. Works from any Node.js process on macOS.
|
|
6
|
+
*/
|
|
7
|
+
import { execSync } from 'node:child_process';
|
|
8
|
+
import { readFileSync, unlinkSync } from 'node:fs';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Swift runner
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
export function runSwift(script, timeout = 10_000) {
|
|
15
|
+
const full = `import Foundation\nimport CoreGraphics\n${script}`;
|
|
16
|
+
try {
|
|
17
|
+
return execSync('swift -', {
|
|
18
|
+
input: full,
|
|
19
|
+
encoding: 'utf-8',
|
|
20
|
+
timeout,
|
|
21
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
22
|
+
}).trim();
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const stderr = err?.stderr?.toString?.() ?? '';
|
|
26
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
27
|
+
throw new Error(`Swift CoreGraphics failed: ${stderr || msg}`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
// Display detection (Swift — works outside Electron)
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
export function getDisplayBounds() {
|
|
34
|
+
const script = `
|
|
35
|
+
import AppKit
|
|
36
|
+
var displays: [[String: Any]] = []
|
|
37
|
+
for screen in NSScreen.screens {
|
|
38
|
+
let f = screen.frame
|
|
39
|
+
displays.append(["x": f.origin.x, "y": f.origin.y, "w": f.size.width, "h": f.size.height])
|
|
40
|
+
}
|
|
41
|
+
let scale = NSScreen.screens.map { $0.backingScaleFactor }.max() ?? 1.0
|
|
42
|
+
let data = try! JSONSerialization.data(withJSONObject: ["ds": displays, "s": scale])
|
|
43
|
+
print(String(data: data, encoding: .utf8)!)
|
|
44
|
+
`;
|
|
45
|
+
const raw = JSON.parse(runSwift(script, 20_000));
|
|
46
|
+
const ds = raw.ds;
|
|
47
|
+
const minX = Math.min(...ds.map(d => d.x));
|
|
48
|
+
const minY = Math.min(...ds.map(d => d.y));
|
|
49
|
+
const maxX = Math.max(...ds.map(d => d.x + d.w));
|
|
50
|
+
const maxY = Math.max(...ds.map(d => d.y + d.h));
|
|
51
|
+
return {
|
|
52
|
+
width: Math.round(maxX - minX),
|
|
53
|
+
height: Math.round(maxY - minY),
|
|
54
|
+
originX: Math.round(minX),
|
|
55
|
+
originY: Math.round(minY),
|
|
56
|
+
scale: raw.s,
|
|
57
|
+
displayCount: ds.length,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
// ---------------------------------------------------------------------------
|
|
61
|
+
// Screenshot (screencapture + sips — no Python)
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
export function captureScreenshot(label = 'main') {
|
|
64
|
+
const ts = Date.now();
|
|
65
|
+
const tmpPath = join(tmpdir(), `refresh-screenshot-${label}-${ts}.png`);
|
|
66
|
+
execSync(`screencapture -x "${tmpPath}"`, { timeout: 10_000 });
|
|
67
|
+
const bounds = getDisplayBounds();
|
|
68
|
+
if (bounds.scale > 1) {
|
|
69
|
+
try {
|
|
70
|
+
execSync(`sips -Z ${Math.max(bounds.width, bounds.height)} "${tmpPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
71
|
+
}
|
|
72
|
+
catch { /* best-effort Retina downscale */ }
|
|
73
|
+
}
|
|
74
|
+
const modelPath = tmpPath.replace(/\.png$/, '-model.jpg');
|
|
75
|
+
let base64;
|
|
76
|
+
let format = 'png';
|
|
77
|
+
try {
|
|
78
|
+
execSync(`sips -s format jpeg -s formatOptions 70 -Z 1280 "${tmpPath}" --out "${modelPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
79
|
+
base64 = readFileSync(modelPath).toString('base64');
|
|
80
|
+
format = 'jpeg';
|
|
81
|
+
try {
|
|
82
|
+
unlinkSync(modelPath);
|
|
83
|
+
}
|
|
84
|
+
catch { /* ignore */ }
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
base64 = readFileSync(tmpPath).toString('base64');
|
|
88
|
+
}
|
|
89
|
+
const thumbPath = tmpPath.replace(/\.png$/, '-thumb.jpg');
|
|
90
|
+
let thumbnailPath = '';
|
|
91
|
+
try {
|
|
92
|
+
const thumbMaxDim = label === 'main' ? 800 : 400;
|
|
93
|
+
const thumbQuality = label === 'main' ? 60 : 30;
|
|
94
|
+
execSync(`sips -s format jpeg -s formatOptions ${thumbQuality} -Z ${thumbMaxDim} "${tmpPath}" --out "${thumbPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
95
|
+
thumbnailPath = thumbPath;
|
|
96
|
+
}
|
|
97
|
+
catch { /* thumbnail failed */ }
|
|
98
|
+
return { image: base64, format, imagePath: tmpPath, thumbnailPath };
|
|
99
|
+
}
|
|
100
|
+
export function captureFollowUpScreenshot(delayMs = 500) {
|
|
101
|
+
if (delayMs > 0) {
|
|
102
|
+
execSync(`sleep ${delayMs / 1000}`, { timeout: delayMs + 2000 });
|
|
103
|
+
}
|
|
104
|
+
return captureScreenshot('followup');
|
|
105
|
+
}
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// Screen size (model coordinate space)
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
const MODEL_MAX_DIM = 1280;
|
|
110
|
+
export function getScreenSize(bounds) {
|
|
111
|
+
const b = bounds ?? getDisplayBounds();
|
|
112
|
+
if (b.width <= MODEL_MAX_DIM && b.height <= MODEL_MAX_DIM) {
|
|
113
|
+
return { width: b.width, height: b.height };
|
|
114
|
+
}
|
|
115
|
+
const ratio = Math.min(MODEL_MAX_DIM / b.width, MODEL_MAX_DIM / b.height);
|
|
116
|
+
return { width: Math.round(b.width * ratio), height: Math.round(b.height * ratio) };
|
|
117
|
+
}
|
|
118
|
+
// ---------------------------------------------------------------------------
|
|
119
|
+
// Coordinate mapping
|
|
120
|
+
// ---------------------------------------------------------------------------
|
|
121
|
+
function modelToScreen(mx, my, bounds) {
|
|
122
|
+
const b = bounds ?? getDisplayBounds();
|
|
123
|
+
const model = getScreenSize(b);
|
|
124
|
+
return {
|
|
125
|
+
x: Math.round(mx * (b.width / model.width) + b.originX),
|
|
126
|
+
y: Math.round(my * (b.height / model.height) + b.originY),
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
function resolvePoint(mx, my, bounds) {
|
|
130
|
+
const rawX = Math.round(Number(mx));
|
|
131
|
+
const rawY = Math.round(Number(my));
|
|
132
|
+
if (!Number.isFinite(rawX) || !Number.isFinite(rawY)) {
|
|
133
|
+
throw new Error(`Invalid coordinates: x=${mx} y=${my}`);
|
|
134
|
+
}
|
|
135
|
+
return modelToScreen(rawX, rawY, bounds);
|
|
136
|
+
}
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Key codes
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
const KEY_CODES = {
|
|
141
|
+
'return': 36, 'enter': 36, 'tab': 48, 'space': 49, 'delete': 51,
|
|
142
|
+
'escape': 53, 'esc': 53, 'up': 126, 'down': 125, 'left': 123,
|
|
143
|
+
'right': 124, 'home': 115, 'end': 119, 'pageup': 116, 'pagedown': 121,
|
|
144
|
+
'f1': 122, 'f2': 120, 'f3': 99, 'f4': 118, 'f5': 96, 'f6': 97,
|
|
145
|
+
'f7': 98, 'f8': 100, 'f9': 101, 'f10': 109, 'f11': 103, 'f12': 111,
|
|
146
|
+
'a': 0, 'b': 11, 'c': 8, 'd': 2, 'e': 14, 'f': 3, 'g': 5, 'h': 4,
|
|
147
|
+
'i': 34, 'j': 38, 'k': 40, 'l': 37, 'm': 46, 'n': 45, 'o': 31,
|
|
148
|
+
'p': 35, 'q': 12, 'r': 15, 's': 1, 't': 17, 'u': 32, 'v': 9,
|
|
149
|
+
'w': 13, 'x': 7, 'y': 16, 'z': 6,
|
|
150
|
+
'0': 29, '1': 18, '2': 19, '3': 20, '4': 21, '5': 23, '6': 22,
|
|
151
|
+
'7': 26, '8': 28, '9': 25,
|
|
152
|
+
};
|
|
153
|
+
function resolveKeyCode(key) {
|
|
154
|
+
return KEY_CODES[key.toLowerCase()] ?? 0;
|
|
155
|
+
}
|
|
156
|
+
function resolveModifierFlags(modifiers) {
|
|
157
|
+
let flags = 0;
|
|
158
|
+
for (const m of modifiers) {
|
|
159
|
+
switch (m.toLowerCase()) {
|
|
160
|
+
case 'command':
|
|
161
|
+
case 'cmd':
|
|
162
|
+
flags |= 0x100000;
|
|
163
|
+
break;
|
|
164
|
+
case 'shift':
|
|
165
|
+
flags |= 0x20000;
|
|
166
|
+
break;
|
|
167
|
+
case 'option':
|
|
168
|
+
case 'alt':
|
|
169
|
+
flags |= 0x80000;
|
|
170
|
+
break;
|
|
171
|
+
case 'control':
|
|
172
|
+
case 'ctrl':
|
|
173
|
+
flags |= 0x40000;
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return flags;
|
|
178
|
+
}
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Actions — each returns a follow-up screenshot
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
export function click(mx, my, button = 'left', doubleClick = false, bounds) {
|
|
183
|
+
const { x, y } = resolvePoint(mx, my, bounds);
|
|
184
|
+
const isRight = button === 'right';
|
|
185
|
+
const downType = isRight ? 3 : 1;
|
|
186
|
+
const upType = isRight ? 4 : 2;
|
|
187
|
+
const mb = isRight ? 1 : 0;
|
|
188
|
+
const count = doubleClick ? 2 : 1;
|
|
189
|
+
const lines = [];
|
|
190
|
+
for (let i = 0; i < count; i++) {
|
|
191
|
+
lines.push(`if let e = CGEvent(mouseEventSource: nil, mouseType: CGEventType(rawValue: UInt32(${downType}))!, mouseCursorPosition: CGPoint(x: ${x}, y: ${y}), mouseButton: CGMouseButton(rawValue: UInt32(${mb}))!) { e.post(tap: .cghidEventTap) }`, 'Thread.sleep(forTimeInterval: 0.05)', `if let e = CGEvent(mouseEventSource: nil, mouseType: CGEventType(rawValue: UInt32(${upType}))!, mouseCursorPosition: CGPoint(x: ${x}, y: ${y}), mouseButton: CGMouseButton(rawValue: UInt32(${mb}))!) { e.post(tap: .cghidEventTap) }`, 'Thread.sleep(forTimeInterval: 0.05)');
|
|
192
|
+
}
|
|
193
|
+
runSwift(lines.join('\n'));
|
|
194
|
+
return { clicked: true, x, y, ...captureFollowUpScreenshot() };
|
|
195
|
+
}
|
|
196
|
+
export function typeText(text) {
|
|
197
|
+
if (!text) {
|
|
198
|
+
throw new Error('No text provided');
|
|
199
|
+
}
|
|
200
|
+
execSync('pbcopy', { input: text, timeout: 5000 });
|
|
201
|
+
runSwift([
|
|
202
|
+
'if let down = CGEvent(keyboardEventSource: nil, virtualKey: 9, keyDown: true) {',
|
|
203
|
+
'\tdown.flags = [.maskCommand]',
|
|
204
|
+
'\tdown.post(tap: .cghidEventTap)',
|
|
205
|
+
'}',
|
|
206
|
+
'Thread.sleep(forTimeInterval: 0.02)',
|
|
207
|
+
'if let up = CGEvent(keyboardEventSource: nil, virtualKey: 9, keyDown: false) {',
|
|
208
|
+
'\tup.post(tap: .cghidEventTap)',
|
|
209
|
+
'}',
|
|
210
|
+
].join('\n'));
|
|
211
|
+
return { typed: true, length: text.length, ...captureFollowUpScreenshot() };
|
|
212
|
+
}
|
|
213
|
+
export function keyPress(key, modifiers = []) {
|
|
214
|
+
if (!key) {
|
|
215
|
+
throw new Error('No key provided');
|
|
216
|
+
}
|
|
217
|
+
const keyCode = resolveKeyCode(key);
|
|
218
|
+
const modFlag = resolveModifierFlags(modifiers);
|
|
219
|
+
const lines = [`if let down = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(${keyCode}), keyDown: true) {`];
|
|
220
|
+
if (modFlag > 0) {
|
|
221
|
+
lines.push(`\tdown.flags = CGEventFlags(rawValue: UInt64(${modFlag}))`);
|
|
222
|
+
}
|
|
223
|
+
lines.push('\tdown.post(tap: .cghidEventTap)', '}', 'Thread.sleep(forTimeInterval: 0.02)', `if let up = CGEvent(keyboardEventSource: nil, virtualKey: CGKeyCode(${keyCode}), keyDown: false) {`, '\tup.post(tap: .cghidEventTap)', '}');
|
|
224
|
+
runSwift(lines.join('\n'));
|
|
225
|
+
return { pressed: true, key, ...captureFollowUpScreenshot() };
|
|
226
|
+
}
|
|
227
|
+
export function scroll(deltaX = 0, deltaY = 0) {
|
|
228
|
+
const h = Math.round(deltaX);
|
|
229
|
+
const v = Math.round(deltaY);
|
|
230
|
+
if (h !== 0 || v !== 0) {
|
|
231
|
+
runSwift(`if let scroll = CGEvent(scrollWheelEvent2Source: nil, units: .line, wheelCount: 2, wheel1: Int32(${-v}), wheel2: Int32(${-h}), wheel3: 0) { scroll.post(tap: .cghidEventTap) }`);
|
|
232
|
+
}
|
|
233
|
+
return { scrolled: true, ...captureFollowUpScreenshot() };
|
|
234
|
+
}
|
|
235
|
+
export function mouseMove(mx, my, bounds) {
|
|
236
|
+
const { x, y } = resolvePoint(mx, my, bounds);
|
|
237
|
+
runSwift(`if let move = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: CGPoint(x: ${x}, y: ${y}), mouseButton: .left) { move.post(tap: .cghidEventTap) }`);
|
|
238
|
+
return { moved: true, x, y, ...captureFollowUpScreenshot(300) };
|
|
239
|
+
}
|
|
240
|
+
export function hover(mx, my, durationMs = 600, bounds) {
|
|
241
|
+
const { x, y } = resolvePoint(mx, my, bounds);
|
|
242
|
+
const ms = Math.max(50, Math.round(Number(durationMs) || 600));
|
|
243
|
+
runSwift(`if let move = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: CGPoint(x: ${x}, y: ${y}), mouseButton: .left) { move.post(tap: .cghidEventTap) }`);
|
|
244
|
+
return { hovered: true, x, y, ...captureFollowUpScreenshot(ms) };
|
|
245
|
+
}
|
|
246
|
+
export function drag(startMx, startMy, endMx, endMy, button = 'left', durationMs = 400, bounds) {
|
|
247
|
+
const start = resolvePoint(startMx, startMy, bounds);
|
|
248
|
+
const end = resolvePoint(endMx, endMy, bounds);
|
|
249
|
+
const isRight = button === 'right';
|
|
250
|
+
const downType = isRight ? 3 : 1;
|
|
251
|
+
const upType = isRight ? 4 : 2;
|
|
252
|
+
const dragType = isRight ? 7 : 6;
|
|
253
|
+
const mb = `CGMouseButton(rawValue: UInt32(${isRight ? 1 : 0}))!`;
|
|
254
|
+
const steps = Math.max(4, Math.min(30, Math.round(Math.max(Math.abs(end.x - start.x), Math.abs(end.y - start.y)) / 20)));
|
|
255
|
+
const stepDelay = Math.max(0.01, Math.min(0.08, Math.max(20, Math.round(Number(durationMs) || 400)) / steps / 1000));
|
|
256
|
+
const lines = [
|
|
257
|
+
`if let e = CGEvent(mouseEventSource: nil, mouseType: .mouseMoved, mouseCursorPosition: CGPoint(x: ${start.x}, y: ${start.y}), mouseButton: ${mb}) { e.post(tap: .cghidEventTap) }`,
|
|
258
|
+
'Thread.sleep(forTimeInterval: 0.02)',
|
|
259
|
+
`if let e = CGEvent(mouseEventSource: nil, mouseType: CGEventType(rawValue: UInt32(${downType}))!, mouseCursorPosition: CGPoint(x: ${start.x}, y: ${start.y}), mouseButton: ${mb}) { e.post(tap: .cghidEventTap) }`,
|
|
260
|
+
'Thread.sleep(forTimeInterval: 0.02)',
|
|
261
|
+
];
|
|
262
|
+
for (let i = 1; i <= steps; i++) {
|
|
263
|
+
const t = i / steps;
|
|
264
|
+
const px = Math.round(start.x + (end.x - start.x) * t);
|
|
265
|
+
const py = Math.round(start.y + (end.y - start.y) * t);
|
|
266
|
+
lines.push(`if let e = CGEvent(mouseEventSource: nil, mouseType: CGEventType(rawValue: UInt32(${dragType}))!, mouseCursorPosition: CGPoint(x: ${px}, y: ${py}), mouseButton: ${mb}) { e.post(tap: .cghidEventTap) }`, `Thread.sleep(forTimeInterval: ${stepDelay.toFixed(3)})`);
|
|
267
|
+
}
|
|
268
|
+
lines.push(`if let e = CGEvent(mouseEventSource: nil, mouseType: CGEventType(rawValue: UInt32(${upType}))!, mouseCursorPosition: CGPoint(x: ${end.x}, y: ${end.y}), mouseButton: ${mb}) { e.post(tap: .cghidEventTap) }`);
|
|
269
|
+
runSwift(lines.join('\n'), Math.max(10_000, Math.round(Number(durationMs) || 400) + 5000));
|
|
270
|
+
return { dragged: true, ...captureFollowUpScreenshot(300) };
|
|
271
|
+
}
|
|
272
|
+
export function zoom(startMx, startMy, endMx, endMy, bounds) {
|
|
273
|
+
const b = bounds ?? getDisplayBounds();
|
|
274
|
+
const start = resolvePoint(startMx, startMy, b);
|
|
275
|
+
const end = resolvePoint(endMx, endMy, b);
|
|
276
|
+
const left = Math.max(b.originX, Math.min(start.x, end.x));
|
|
277
|
+
const top = Math.max(b.originY, Math.min(start.y, end.y));
|
|
278
|
+
const right = Math.min(b.originX + b.width, Math.max(start.x, end.x));
|
|
279
|
+
const bottom = Math.min(b.originY + b.height, Math.max(start.y, end.y));
|
|
280
|
+
const w = Math.max(1, right - left);
|
|
281
|
+
const h = Math.max(1, bottom - top);
|
|
282
|
+
const imgX = left - b.originX;
|
|
283
|
+
const imgY = top - b.originY;
|
|
284
|
+
const tmpPath = join(tmpdir(), `refresh-screenshot-zoom-${Date.now()}.png`);
|
|
285
|
+
execSync(`screencapture -x "${tmpPath}"`, { timeout: 10_000 });
|
|
286
|
+
if (b.scale > 1) {
|
|
287
|
+
try {
|
|
288
|
+
execSync(`sips -Z ${Math.max(b.width, b.height)} "${tmpPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
289
|
+
}
|
|
290
|
+
catch { /* best-effort */ }
|
|
291
|
+
}
|
|
292
|
+
const cropPath = tmpPath.replace(/\.png$/, '-crop.png');
|
|
293
|
+
execSync(`sips -c ${h} ${w} --cropOffset ${imgY} ${imgX} "${tmpPath}" --out "${cropPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
294
|
+
const modelPath = cropPath.replace(/\.png$/, '-model.jpg');
|
|
295
|
+
let base64;
|
|
296
|
+
let format = 'png';
|
|
297
|
+
try {
|
|
298
|
+
const ratio = Math.min(MODEL_MAX_DIM / w, MODEL_MAX_DIM / h);
|
|
299
|
+
const tw = Math.max(1, Math.round(w * ratio));
|
|
300
|
+
const th = Math.max(1, Math.round(h * ratio));
|
|
301
|
+
execSync(`sips -s format jpeg -s formatOptions 80 -z ${th} ${tw} "${cropPath}" --out "${modelPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
302
|
+
base64 = readFileSync(modelPath).toString('base64');
|
|
303
|
+
format = 'jpeg';
|
|
304
|
+
try {
|
|
305
|
+
unlinkSync(modelPath);
|
|
306
|
+
}
|
|
307
|
+
catch { /* ignore */ }
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
base64 = readFileSync(cropPath).toString('base64');
|
|
311
|
+
}
|
|
312
|
+
let thumbnailPath = '';
|
|
313
|
+
try {
|
|
314
|
+
const thumbPath = cropPath.replace(/\.png$/, '-thumb.jpg');
|
|
315
|
+
execSync(`sips -s format jpeg -s formatOptions 50 -Z 400 "${cropPath}" --out "${thumbPath}"`, { timeout: 10_000, stdio: 'pipe' });
|
|
316
|
+
thumbnailPath = thumbPath;
|
|
317
|
+
}
|
|
318
|
+
catch { /* ignore */ }
|
|
319
|
+
return { zoomed: true, image: base64, format, imagePath: cropPath, thumbnailPath };
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "refresh-computer-tools",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "macOS computer automation via Swift CoreGraphics — screenshot, click, type, key press, scroll, drag",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"refresh-computer-tools": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"prepublishOnly": "npm run build"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"macos",
|
|
21
|
+
"computer-use",
|
|
22
|
+
"screenshot",
|
|
23
|
+
"click",
|
|
24
|
+
"automation",
|
|
25
|
+
"swift",
|
|
26
|
+
"coregraphics",
|
|
27
|
+
"cgevent"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"repository": {
|
|
31
|
+
"type": "git",
|
|
32
|
+
"url": "https://github.com/refreshdotdev/computer-tools"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18"
|
|
36
|
+
},
|
|
37
|
+
"os": [
|
|
38
|
+
"darwin"
|
|
39
|
+
],
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@types/node": "^22.0.0",
|
|
42
|
+
"typescript": "^5.7.0"
|
|
43
|
+
}
|
|
44
|
+
}
|