@asdf-overlay/core 0.9.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.
Binary file
package/addon-x64.node ADDED
Binary file
Binary file
Binary file
Binary file
package/lib/addon.d.ts ADDED
@@ -0,0 +1,16 @@
1
+ import { OverlayEventEmitter } from './index.js';
2
+ import { CopyRect, Cursor, PercentLength } from './types.js';
3
+ export type Addon = {
4
+ attach(dllDir: string, pid: number, timeout?: number): Promise<number>;
5
+ overlaySetPosition(id: number, winId: number, x: PercentLength, y: PercentLength): Promise<void>;
6
+ overlaySetAnchor(id: number, winId: number, x: PercentLength, y: PercentLength): Promise<void>;
7
+ overlaySetMargin(id: number, winId: number, top: PercentLength, right: PercentLength, bottom: PercentLength, left: PercentLength): Promise<void>;
8
+ overlayListenInput(id: number, winId: number, cursor: boolean, keyboard: boolean): Promise<void>;
9
+ overlayBlockInput(id: number, winId: number, block: boolean): Promise<void>;
10
+ overlaySetBlockingCursor(id: number, winId: number, cursor?: Cursor): Promise<void>;
11
+ overlayUpdateBitmap(id: number, winId: number, width: number, data: Buffer): Promise<void>;
12
+ overlayUpdateShtex(id: number, winId: number, width: number, height: number, handle: Buffer, rect?: CopyRect): Promise<void>;
13
+ overlayClearSurface(id: number, winId: number): Promise<void>;
14
+ overlayCallNextEvent(id: number, emitter: OverlayEventEmitter, emit: OverlayEventEmitter['emit']): Promise<boolean>;
15
+ overlayDestroy(id: number): void;
16
+ };
package/lib/addon.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/lib/index.d.ts ADDED
@@ -0,0 +1,102 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import { CursorInput, KeyboardInput } from './input.js';
3
+ import { PercentLength, CopyRect, Cursor } from './types.js';
4
+ export * from './types.js';
5
+ export * from './util.js';
6
+ declare const idSym: unique symbol;
7
+ export type OverlayEventEmitter = EventEmitter<{
8
+ added: [id: number, width: number, height: number];
9
+ resized: [id: number, width: number, height: number];
10
+ cursor_input: [id: number, input: CursorInput];
11
+ keyboard_input: [id: number, input: KeyboardInput];
12
+ input_blocking_ended: [id: number];
13
+ destroyed: [id: number];
14
+ error: [err: unknown];
15
+ disconnected: [];
16
+ }>;
17
+ export declare class Overlay {
18
+ readonly event: OverlayEventEmitter;
19
+ readonly [idSym]: number;
20
+ private constructor();
21
+ /**
22
+ * Update overlay position relative to window
23
+ * @param id target window id
24
+ * @param x x position
25
+ * @param y y position
26
+ */
27
+ setPosition(id: number, x: PercentLength, y: PercentLength): Promise<void>;
28
+ /**
29
+ * Update overlay anchor
30
+ * @param id target window id
31
+ * @param x x anchor
32
+ * @param y y anchor
33
+ */
34
+ setAnchor(id: number, x: PercentLength, y: PercentLength): Promise<void>;
35
+ /**
36
+ * Update overlay margin
37
+ * @param id target window id
38
+ * @param top top margin
39
+ * @param right right margin
40
+ * @param bottom bottom margin
41
+ * @param left left margin
42
+ */
43
+ setMargin(id: number, top: PercentLength, right: PercentLength, bottom: PercentLength, left: PercentLength): Promise<void>;
44
+ /**
45
+ * Listen to window input without blocking
46
+ * @param id target window id
47
+ * @param cursor listen cursor input or not
48
+ * @param keyboard listen keyboard input or not
49
+ */
50
+ listenInput(id: number, cursor: boolean, keyboard: boolean): Promise<void>;
51
+ /**
52
+ * Block window input and listen them
53
+ * @param id target window id
54
+ * @param block set true to block input, false to release
55
+ */
56
+ blockInput(id: number, block: boolean): Promise<void>;
57
+ /**
58
+ * Set cursor while in input blocking mode
59
+ * @param id target window id
60
+ * @param cursor cursor to set. Do not supply this value to hide cursor.
61
+ */
62
+ setBlockingCursor(id: number, cursor?: Cursor): Promise<void>;
63
+ /**
64
+ * Update overlay using bitmap buffer. The size of overlay is `width x (data.byteLength / 4 / width)`
65
+ * @param id target window id
66
+ * @param width width of the bitmap
67
+ * @param data bgra formatted bitmap
68
+ */
69
+ updateBitmap(id: number, width: number, data: Buffer): Promise<void>;
70
+ /**
71
+ * Update overlay using D3D11 shared texture.
72
+ * @param id target window id
73
+ * @param width width of the surface
74
+ * @param height height of the surface
75
+ * @param handle NT Handle of shared D3D11 Texture
76
+ * @param rect Area to update
77
+ */
78
+ updateShtex(id: number, width: number, height: number, handle: Buffer, rect?: CopyRect): Promise<void>;
79
+ /**
80
+ * Clear overlay
81
+ * @param id target window id
82
+ */
83
+ clearSurface(id: number): Promise<void>;
84
+ /**
85
+ * Destroy overlay
86
+ */
87
+ destroy(): void;
88
+ /**
89
+ * Attach overlay to target process
90
+ *
91
+ * Name must be unique or it will fail if there is a connection with same name
92
+ * @param dllDir path to dlls
93
+ * @param pid target process pid
94
+ * @param timeout Timeout for injection, in milliseconds. Will wait indefinitely if not provided.
95
+ * @returns new {@link Overlay} object
96
+ */
97
+ static attach(dllDir: string, pid: number, timeout?: number): Promise<Overlay>;
98
+ }
99
+ /**
100
+ * Default dll directory path
101
+ */
102
+ export declare function defaultDllDir(): string;
package/lib/index.js ADDED
@@ -0,0 +1,162 @@
1
+ import path from 'node:path';
2
+ import { arch } from 'node:process';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { EventEmitter } from 'node:events';
5
+ export * from './types.js';
6
+ export * from './util.js';
7
+ const addon = loadAddon();
8
+ function loadAddon() {
9
+ const nodeModule = { exports: {} };
10
+ let name;
11
+ switch (arch) {
12
+ case 'arm64': {
13
+ name = '../addon-aarch64.node';
14
+ break;
15
+ }
16
+ case 'x64': {
17
+ name = '../addon-x64.node';
18
+ break;
19
+ }
20
+ default: throw new Error(`Unsupported arch: ${arch}`);
21
+ }
22
+ process.dlopen(nodeModule, path.resolve(path.dirname(fileURLToPath(new URL(import.meta.url))), name));
23
+ return nodeModule.exports;
24
+ }
25
+ const idSym = Symbol('id');
26
+ export class Overlay {
27
+ event = new EventEmitter();
28
+ [idSym];
29
+ constructor(id) {
30
+ this[idSym] = id;
31
+ void (async () => {
32
+ // wait until next tick so no events are lost
33
+ await new Promise((resolve) => {
34
+ process.nextTick(resolve);
35
+ });
36
+ try {
37
+ for (;;) {
38
+ const hasNext = await addon.overlayCallNextEvent(id, this.event, (name, ...args) => this.event.emit(name, ...args));
39
+ if (!hasNext)
40
+ break;
41
+ }
42
+ }
43
+ catch (err) {
44
+ if (this.event.listenerCount('error') != 0) {
45
+ this.event.emit('error', err);
46
+ }
47
+ else {
48
+ throw err;
49
+ }
50
+ }
51
+ finally {
52
+ this.destroy();
53
+ }
54
+ })();
55
+ }
56
+ /**
57
+ * Update overlay position relative to window
58
+ * @param id target window id
59
+ * @param x x position
60
+ * @param y y position
61
+ */
62
+ async setPosition(id, x, y) {
63
+ await addon.overlaySetPosition(this[idSym], id, x, y);
64
+ }
65
+ /**
66
+ * Update overlay anchor
67
+ * @param id target window id
68
+ * @param x x anchor
69
+ * @param y y anchor
70
+ */
71
+ async setAnchor(id, x, y) {
72
+ await addon.overlaySetAnchor(this[idSym], id, x, y);
73
+ }
74
+ /**
75
+ * Update overlay margin
76
+ * @param id target window id
77
+ * @param top top margin
78
+ * @param right right margin
79
+ * @param bottom bottom margin
80
+ * @param left left margin
81
+ */
82
+ async setMargin(id, top, right, bottom, left) {
83
+ await addon.overlaySetMargin(this[idSym], id, top, right, bottom, left);
84
+ }
85
+ /**
86
+ * Listen to window input without blocking
87
+ * @param id target window id
88
+ * @param cursor listen cursor input or not
89
+ * @param keyboard listen keyboard input or not
90
+ */
91
+ async listenInput(id, cursor, keyboard) {
92
+ await addon.overlayListenInput(this[idSym], id, cursor, keyboard);
93
+ }
94
+ /**
95
+ * Block window input and listen them
96
+ * @param id target window id
97
+ * @param block set true to block input, false to release
98
+ */
99
+ async blockInput(id, block) {
100
+ await addon.overlayBlockInput(this[idSym], id, block);
101
+ }
102
+ /**
103
+ * Set cursor while in input blocking mode
104
+ * @param id target window id
105
+ * @param cursor cursor to set. Do not supply this value to hide cursor.
106
+ */
107
+ async setBlockingCursor(id, cursor) {
108
+ await addon.overlaySetBlockingCursor(this[idSym], id, cursor);
109
+ }
110
+ /**
111
+ * Update overlay using bitmap buffer. The size of overlay is `width x (data.byteLength / 4 / width)`
112
+ * @param id target window id
113
+ * @param width width of the bitmap
114
+ * @param data bgra formatted bitmap
115
+ */
116
+ async updateBitmap(id, width, data) {
117
+ await addon.overlayUpdateBitmap(this[idSym], id, width, data);
118
+ }
119
+ /**
120
+ * Update overlay using D3D11 shared texture.
121
+ * @param id target window id
122
+ * @param width width of the surface
123
+ * @param height height of the surface
124
+ * @param handle NT Handle of shared D3D11 Texture
125
+ * @param rect Area to update
126
+ */
127
+ async updateShtex(id, width, height, handle, rect) {
128
+ await addon.overlayUpdateShtex(this[idSym], id, width, height, handle, rect);
129
+ }
130
+ /**
131
+ * Clear overlay
132
+ * @param id target window id
133
+ */
134
+ async clearSurface(id) {
135
+ await addon.overlayClearSurface(this[idSym], id);
136
+ }
137
+ /**
138
+ * Destroy overlay
139
+ */
140
+ destroy() {
141
+ addon.overlayDestroy(this[idSym]);
142
+ this.event.emit('disconnected');
143
+ }
144
+ /**
145
+ * Attach overlay to target process
146
+ *
147
+ * Name must be unique or it will fail if there is a connection with same name
148
+ * @param dllDir path to dlls
149
+ * @param pid target process pid
150
+ * @param timeout Timeout for injection, in milliseconds. Will wait indefinitely if not provided.
151
+ * @returns new {@link Overlay} object
152
+ */
153
+ static async attach(dllDir, pid, timeout) {
154
+ return new Overlay(await addon.attach(dllDir, pid, timeout));
155
+ }
156
+ }
157
+ /**
158
+ * Default dll directory path
159
+ */
160
+ export function defaultDllDir() {
161
+ return path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../');
162
+ }
package/lib/input.d.ts ADDED
@@ -0,0 +1,82 @@
1
+ import { Key } from './index.js';
2
+ export type CursorInput = {
3
+ clientX: number;
4
+ clientY: number;
5
+ windowX: number;
6
+ windowY: number;
7
+ } & ({
8
+ kind: 'Enter';
9
+ } | {
10
+ kind: 'Leave';
11
+ } | {
12
+ kind: 'Action';
13
+ state: InputState;
14
+ doubleClick: boolean;
15
+ action: CursorAction;
16
+ } | {
17
+ kind: 'Move';
18
+ } | {
19
+ kind: 'Scroll';
20
+ axis: ScrollAxis;
21
+ /**
22
+ * Scroll tick delta
23
+ */
24
+ delta: number;
25
+ });
26
+ export type KeyboardInput = {
27
+ kind: 'Key';
28
+ key: Key;
29
+ /**
30
+ * Key input state
31
+ */
32
+ state: InputState;
33
+ } | {
34
+ kind: 'Char';
35
+ ch: string;
36
+ } | {
37
+ kind: 'Ime';
38
+ ime: Ime;
39
+ };
40
+ export type Ime = {
41
+ kind: 'Enabled';
42
+ lang: string;
43
+ conversion: ImeConversion;
44
+ } | {
45
+ kind: 'Changed';
46
+ /** ETF language tag(BCP 47) */
47
+ lang: string;
48
+ } | {
49
+ kind: 'ChangedConversion';
50
+ conversion: ImeConversion;
51
+ } | {
52
+ kind: 'CandidateChanged';
53
+ list: ImeCandidateList;
54
+ } | {
55
+ kind: 'CandidateClosed';
56
+ } | {
57
+ kind: 'Compose';
58
+ text: string;
59
+ caret: number;
60
+ } | {
61
+ kind: 'Commit';
62
+ text: string;
63
+ } | {
64
+ kind: 'Disabled';
65
+ };
66
+ export type ImeCandidateList = {
67
+ pageStartIndex: number;
68
+ pageSize: number;
69
+ selectedIndex: number;
70
+ candidates: string[];
71
+ };
72
+ export declare const enum ImeConversion {
73
+ None = 0,
74
+ Native = 1,
75
+ Fullshape = 2,
76
+ NoConversion = 4,
77
+ HanjaConvert = 8,
78
+ Katakana = 16
79
+ }
80
+ export type InputState = 'Pressed' | 'Released';
81
+ export type CursorAction = 'Left' | 'Right' | 'Middle' | 'Back' | 'Forward';
82
+ export type ScrollAxis = 'X' | 'Y';
package/lib/input.js ADDED
@@ -0,0 +1,9 @@
1
+ export var ImeConversion;
2
+ (function (ImeConversion) {
3
+ ImeConversion[ImeConversion["None"] = 0] = "None";
4
+ ImeConversion[ImeConversion["Native"] = 1] = "Native";
5
+ ImeConversion[ImeConversion["Fullshape"] = 2] = "Fullshape";
6
+ ImeConversion[ImeConversion["NoConversion"] = 4] = "NoConversion";
7
+ ImeConversion[ImeConversion["HanjaConvert"] = 8] = "HanjaConvert";
8
+ ImeConversion[ImeConversion["Katakana"] = 16] = "Katakana";
9
+ })(ImeConversion || (ImeConversion = {}));
package/lib/types.d.ts ADDED
@@ -0,0 +1,66 @@
1
+ export type PercentLength = {
2
+ ty: 'percent' | 'length';
3
+ value: number;
4
+ };
5
+ export type CopyRect = {
6
+ dstX: number;
7
+ dstY: number;
8
+ src: Rect;
9
+ };
10
+ export type Rect = {
11
+ x: number;
12
+ y: number;
13
+ width: number;
14
+ height: number;
15
+ };
16
+ export type Key = {
17
+ /**
18
+ * Windows virtual key code
19
+ */
20
+ code: number;
21
+ /**
22
+ * Extended flag
23
+ */
24
+ extended: boolean;
25
+ };
26
+ export declare enum Cursor {
27
+ Default = 0,
28
+ Help = 1,
29
+ Pointer = 2,
30
+ Progress = 3,
31
+ Wait = 4,
32
+ Cell = 5,
33
+ Crosshair = 6,
34
+ Text = 7,
35
+ VerticalText = 8,
36
+ Alias = 9,
37
+ Copy = 10,
38
+ Move = 11,
39
+ NotAllowed = 12,
40
+ Grab = 13,
41
+ Grabbing = 14,
42
+ ColResize = 15,
43
+ RowResize = 16,
44
+ EastWestResize = 17,
45
+ NorthSouthResize = 18,
46
+ NorthEastSouthWestResize = 19,
47
+ NorthWestSouthEastResize = 20,
48
+ ZoomIn = 21,
49
+ ZoomOut = 22,
50
+ UpArrow = 23,
51
+ Pin = 24,
52
+ Person = 25,
53
+ Pen = 26,
54
+ Cd = 27,
55
+ PanMiddle = 28,
56
+ PanMiddleHorizontal = 29,
57
+ PanMiddleVertical = 30,
58
+ PanEast = 31,
59
+ PanNorth = 32,
60
+ PanNorthEast = 33,
61
+ PanNorthWest = 34,
62
+ PanSouth = 35,
63
+ PanSouthEast = 36,
64
+ PanSouthWest = 37,
65
+ PanWest = 38
66
+ }
package/lib/types.js ADDED
@@ -0,0 +1,45 @@
1
+ export var Cursor;
2
+ (function (Cursor) {
3
+ Cursor[Cursor["Default"] = 0] = "Default";
4
+ Cursor[Cursor["Help"] = 1] = "Help";
5
+ Cursor[Cursor["Pointer"] = 2] = "Pointer";
6
+ Cursor[Cursor["Progress"] = 3] = "Progress";
7
+ Cursor[Cursor["Wait"] = 4] = "Wait";
8
+ Cursor[Cursor["Cell"] = 5] = "Cell";
9
+ Cursor[Cursor["Crosshair"] = 6] = "Crosshair";
10
+ Cursor[Cursor["Text"] = 7] = "Text";
11
+ Cursor[Cursor["VerticalText"] = 8] = "VerticalText";
12
+ Cursor[Cursor["Alias"] = 9] = "Alias";
13
+ Cursor[Cursor["Copy"] = 10] = "Copy";
14
+ Cursor[Cursor["Move"] = 11] = "Move";
15
+ Cursor[Cursor["NotAllowed"] = 12] = "NotAllowed";
16
+ Cursor[Cursor["Grab"] = 13] = "Grab";
17
+ Cursor[Cursor["Grabbing"] = 14] = "Grabbing";
18
+ Cursor[Cursor["ColResize"] = 15] = "ColResize";
19
+ Cursor[Cursor["RowResize"] = 16] = "RowResize";
20
+ Cursor[Cursor["EastWestResize"] = 17] = "EastWestResize";
21
+ Cursor[Cursor["NorthSouthResize"] = 18] = "NorthSouthResize";
22
+ Cursor[Cursor["NorthEastSouthWestResize"] = 19] = "NorthEastSouthWestResize";
23
+ Cursor[Cursor["NorthWestSouthEastResize"] = 20] = "NorthWestSouthEastResize";
24
+ Cursor[Cursor["ZoomIn"] = 21] = "ZoomIn";
25
+ Cursor[Cursor["ZoomOut"] = 22] = "ZoomOut";
26
+ // Windows additional cursors
27
+ Cursor[Cursor["UpArrow"] = 23] = "UpArrow";
28
+ Cursor[Cursor["Pin"] = 24] = "Pin";
29
+ Cursor[Cursor["Person"] = 25] = "Person";
30
+ Cursor[Cursor["Pen"] = 26] = "Pen";
31
+ Cursor[Cursor["Cd"] = 27] = "Cd";
32
+ // panning
33
+ Cursor[Cursor["PanMiddle"] = 28] = "PanMiddle";
34
+ Cursor[Cursor["PanMiddleHorizontal"] = 29] = "PanMiddleHorizontal";
35
+ Cursor[Cursor["PanMiddleVertical"] = 30] = "PanMiddleVertical";
36
+ Cursor[Cursor["PanEast"] = 31] = "PanEast";
37
+ Cursor[Cursor["PanNorth"] = 32] = "PanNorth";
38
+ Cursor[Cursor["PanNorthEast"] = 33] = "PanNorthEast";
39
+ Cursor[Cursor["PanNorthWest"] = 34] = "PanNorthWest";
40
+ Cursor[Cursor["PanSouth"] = 35] = "PanSouth";
41
+ Cursor[Cursor["PanSouthEast"] = 36] = "PanSouthEast";
42
+ Cursor[Cursor["PanSouthWest"] = 37] = "PanSouthWest";
43
+ Cursor[Cursor["PanWest"] = 38] = "PanWest";
44
+ })(Cursor || (Cursor = {}));
45
+ ;
package/lib/util.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ import { Key, PercentLength } from './index.js';
2
+ export declare function percent(value: number): PercentLength;
3
+ export declare function length(value: number): PercentLength;
4
+ export declare function key(code: number, extended?: boolean): Key;
package/lib/util.js ADDED
@@ -0,0 +1,18 @@
1
+ export function percent(value) {
2
+ return {
3
+ ty: 'percent',
4
+ value,
5
+ };
6
+ }
7
+ export function length(value) {
8
+ return {
9
+ ty: 'length',
10
+ value,
11
+ };
12
+ }
13
+ export function key(code, extended = false) {
14
+ return {
15
+ code,
16
+ extended,
17
+ };
18
+ }
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@asdf-overlay/core",
3
+ "version": "0.9.0",
4
+ "description": "Asdf overlay core Node addon",
5
+ "main": "./lib/index.js",
6
+ "type": "module",
7
+ "author": "storycraft <storycraft@pancake.sh>",
8
+ "homepage": "https://github.com/storycraft/asdf-overlay#readme",
9
+ "license": "MIT OR Apache-2.0",
10
+ "bugs": {
11
+ "url": "https://github.com/storycraft/asdf-overlay/issues"
12
+ },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/storycraft/asdf-overlay"
16
+ },
17
+ "os": [
18
+ "win32"
19
+ ],
20
+ "cpu": [
21
+ "x64",
22
+ "arm64"
23
+ ],
24
+ "exports": {
25
+ ".": {
26
+ "types": "./lib/index.d.ts",
27
+ "default": "./lib/index.js"
28
+ },
29
+ "./*": {
30
+ "types": "./lib/*.d.ts",
31
+ "default": "./lib/*.js"
32
+ }
33
+ },
34
+ "types": "./lib/index.d.ts",
35
+ "files": [
36
+ "lib/**/*",
37
+ "addon-x64.node",
38
+ "addon-aarch64.node",
39
+ "asdf_overlay-x64.dll",
40
+ "asdf_overlay-x86.dll",
41
+ "asdf_overlay-aarch64.dll"
42
+ ],
43
+ "devDependencies": {
44
+ "@types/node": "^24.1.0",
45
+ "typescript": "^5.8.3"
46
+ },
47
+ "scripts": {
48
+ "build-dll": "cargo xtask build-dll --",
49
+ "cargo-build": "cargo xtask build-node --",
50
+ "build:debug": "npm run cargo-build && npm run build-dll && tsc",
51
+ "build:dist": "tsc",
52
+ "build": "npm run cargo-build -- --release && npm run build-dll -- --release && npm run build:dist"
53
+ }
54
+ }