usecomputer 0.0.3 → 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/CHANGELOG.md +67 -0
- package/README.md +324 -0
- package/build.zig +95 -11
- package/build.zig.zon +5 -0
- package/dist/bridge-contract.test.js +61 -67
- package/dist/bridge.d.ts.map +1 -1
- package/dist/bridge.js +241 -46
- package/dist/cli-parsing.test.js +34 -11
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +323 -28
- package/dist/coord-map.d.ts +14 -0
- package/dist/coord-map.d.ts.map +1 -0
- package/dist/coord-map.js +75 -0
- package/dist/coord-map.test.d.ts +2 -0
- package/dist/coord-map.test.d.ts.map +1 -0
- package/dist/coord-map.test.js +157 -0
- package/dist/darwin-arm64/usecomputer.node +0 -0
- package/dist/darwin-x64/usecomputer.node +0 -0
- package/dist/debug-point-image.d.ts +8 -0
- package/dist/debug-point-image.d.ts.map +1 -0
- package/dist/debug-point-image.js +43 -0
- package/dist/debug-point-image.test.d.ts +2 -0
- package/dist/debug-point-image.test.d.ts.map +1 -0
- package/dist/debug-point-image.test.js +44 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/lib.d.ts +26 -0
- package/dist/lib.d.ts.map +1 -0
- package/dist/lib.js +88 -0
- package/dist/native-click-smoke.test.js +69 -29
- package/dist/native-lib.d.ts +59 -1
- package/dist/native-lib.d.ts.map +1 -1
- package/dist/terminal-table.d.ts +10 -0
- package/dist/terminal-table.d.ts.map +1 -0
- package/dist/terminal-table.js +55 -0
- package/dist/terminal-table.test.d.ts +2 -0
- package/dist/terminal-table.test.d.ts.map +1 -0
- package/dist/terminal-table.test.js +41 -0
- package/dist/types.d.ts +45 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +19 -5
- package/src/bridge-contract.test.ts +68 -73
- package/src/bridge.ts +293 -53
- package/src/cli-parsing.test.ts +61 -0
- package/src/cli.ts +393 -32
- package/src/coord-map.test.ts +178 -0
- package/src/coord-map.ts +105 -0
- package/src/debug-point-image.test.ts +50 -0
- package/src/debug-point-image.ts +69 -0
- package/src/index.ts +3 -1
- package/src/lib.ts +125 -0
- package/src/native-click-smoke.test.ts +81 -63
- package/src/native-lib.ts +39 -1
- package/src/terminal-table.test.ts +44 -0
- package/src/terminal-table.ts +88 -0
- package/src/types.ts +50 -0
- package/zig/src/lib.zig +1966 -270
- package/zig/src/main.zig +382 -0
- package/zig/src/scroll.zig +213 -0
- package/zig/src/window.zig +123 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Helpers for querying visible macOS windows via stable CoreGraphics APIs.
|
|
2
|
+
|
|
3
|
+
const std = @import("std");
|
|
4
|
+
const builtin = @import("builtin");
|
|
5
|
+
|
|
6
|
+
const c = if (builtin.target.os.tag == .macos) @cImport({
|
|
7
|
+
@cInclude("CoreGraphics/CoreGraphics.h");
|
|
8
|
+
@cInclude("CoreFoundation/CoreFoundation.h");
|
|
9
|
+
}) else struct {};
|
|
10
|
+
|
|
11
|
+
pub const Rect = struct {
|
|
12
|
+
x: f64,
|
|
13
|
+
y: f64,
|
|
14
|
+
width: f64,
|
|
15
|
+
height: f64,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
pub const WindowInfo = struct {
|
|
19
|
+
id: u32,
|
|
20
|
+
owner_pid: i32,
|
|
21
|
+
owner_name: []const u8,
|
|
22
|
+
title: []const u8,
|
|
23
|
+
bounds: Rect,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
pub fn forEachVisibleWindow(
|
|
27
|
+
comptime Context: type,
|
|
28
|
+
context: *Context,
|
|
29
|
+
callback: *const fn (ctx: *Context, info: WindowInfo) anyerror!void,
|
|
30
|
+
) !void {
|
|
31
|
+
if (builtin.target.os.tag != .macos) {
|
|
32
|
+
return error.UnsupportedPlatform;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const options = c.kCGWindowListOptionOnScreenOnly | c.kCGWindowListExcludeDesktopElements;
|
|
36
|
+
const windows = c.CGWindowListCopyWindowInfo(options, c.kCGNullWindowID);
|
|
37
|
+
if (windows == null) {
|
|
38
|
+
return error.WindowQueryFailed;
|
|
39
|
+
}
|
|
40
|
+
defer c.CFRelease(windows);
|
|
41
|
+
|
|
42
|
+
const count: usize = @intCast(c.CFArrayGetCount(windows));
|
|
43
|
+
var i: usize = 0;
|
|
44
|
+
while (i < count) : (i += 1) {
|
|
45
|
+
const value = c.CFArrayGetValueAtIndex(windows, @intCast(i));
|
|
46
|
+
if (value == null) {
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const dictionary: c.CFDictionaryRef = @ptrCast(value);
|
|
51
|
+
|
|
52
|
+
var id_raw: i64 = 0;
|
|
53
|
+
if (!readNumberI64(dictionary, c.kCGWindowNumber, &id_raw)) {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (id_raw <= 0) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var owner_pid_raw: i64 = 0;
|
|
61
|
+
if (!readNumberI64(dictionary, c.kCGWindowOwnerPID, &owner_pid_raw)) {
|
|
62
|
+
owner_pid_raw = 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
var bounds: c.CGRect = undefined;
|
|
66
|
+
if (!readBoundsRect(dictionary, &bounds)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
var owner_name_buffer: [256]u8 = undefined;
|
|
71
|
+
const owner_name = readString(dictionary, c.kCGWindowOwnerName, &owner_name_buffer);
|
|
72
|
+
var title_buffer: [256]u8 = undefined;
|
|
73
|
+
const title = readString(dictionary, c.kCGWindowName, &title_buffer);
|
|
74
|
+
|
|
75
|
+
try callback(context, .{
|
|
76
|
+
.id = @intCast(id_raw),
|
|
77
|
+
.owner_pid = @intCast(owner_pid_raw),
|
|
78
|
+
.owner_name = owner_name,
|
|
79
|
+
.title = title,
|
|
80
|
+
.bounds = .{
|
|
81
|
+
.x = std.math.round(bounds.origin.x),
|
|
82
|
+
.y = std.math.round(bounds.origin.y),
|
|
83
|
+
.width = std.math.round(bounds.size.width),
|
|
84
|
+
.height = std.math.round(bounds.size.height),
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
fn readNumberI64(dictionary: c.CFDictionaryRef, key: c.CFStringRef, out: *i64) bool {
|
|
91
|
+
const value = c.CFDictionaryGetValue(dictionary, key);
|
|
92
|
+
if (value == null) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
const number: c.CFNumberRef = @ptrCast(value);
|
|
96
|
+
return c.CFNumberGetValue(number, c.kCFNumberSInt64Type, out) != 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fn readBoundsRect(dictionary: c.CFDictionaryRef, out: *c.CGRect) bool {
|
|
100
|
+
const value = c.CFDictionaryGetValue(dictionary, c.kCGWindowBounds);
|
|
101
|
+
if (value == null) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
const bounds_dictionary: c.CFDictionaryRef = @ptrCast(value);
|
|
105
|
+
return c.CGRectMakeWithDictionaryRepresentation(bounds_dictionary, out);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
fn readString(
|
|
109
|
+
dictionary: c.CFDictionaryRef,
|
|
110
|
+
key: c.CFStringRef,
|
|
111
|
+
buffer: *[256]u8,
|
|
112
|
+
) []const u8 {
|
|
113
|
+
const value = c.CFDictionaryGetValue(dictionary, key);
|
|
114
|
+
if (value == null) {
|
|
115
|
+
return "";
|
|
116
|
+
}
|
|
117
|
+
const str_ref: c.CFStringRef = @ptrCast(value);
|
|
118
|
+
if (c.CFStringGetCString(str_ref, buffer, buffer.len, c.kCFStringEncodingUTF8) == 0) {
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
const content = std.mem.sliceTo(buffer, 0);
|
|
122
|
+
return content;
|
|
123
|
+
}
|