Skip to content

Commit 2cbcb39

Browse files
authored
Fix native overlay drag event support
Closes #202
1 parent 3ae587e commit 2cbcb39

5 files changed

Lines changed: 148 additions & 2 deletions

File tree

.github/workflows/ci.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,9 @@ jobs:
3434

3535
- name: Build
3636
run: npm run build
37+
38+
- name: Build native cursor overlay helper
39+
run: npm run native:build-overlay
40+
41+
- name: Smoke native cursor overlay helper
42+
run: npm run native:smoke-overlay

.github/workflows/release.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,9 @@ jobs:
8585
- name: Build native cursor overlay helper
8686
run: npm run native:build-overlay
8787

88+
- name: Smoke native cursor overlay helper
89+
run: npm run native:smoke-overlay
90+
8891
- name: Package Windows installer
8992
run: npm run package:win
9093

native/cursor-overlay-helper/Program.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,9 +78,9 @@ private static void HandleCommandLine(OverlayForm overlayForm, SynchronizationCo
7878
switch (command.Type)
7979
{
8080
case "show":
81-
if (command.Event is not ("move" or "click"))
81+
if (command.Event is not ("move" or "click" or "drag"))
8282
{
83-
WriteError("invalid_command", "Show command event must be move or click.");
83+
WriteError("invalid_command", "Show command event must be move, click, or drag.");
8484
return;
8585
}
8686

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"build": "electron-vite build",
99
"native:build": "node scripts/build-cursor-overlay-helper.cjs",
1010
"native:build-overlay": "npm run native:build",
11+
"native:smoke-overlay": "node scripts/smoke-cursor-overlay-helper.cjs",
1112
"package:win": "npm run build && npm run native:build && electron-builder --win --x64 --publish never && node scripts/sign-win-artifacts.cjs --update-latest-yml",
1213
"package:win:verify-uiaccess": "node scripts/verify-win-uiaccess-package.cjs",
1314
"signing:create-dev-cert": "node scripts/create-dev-signing-cert.cjs",
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
const { spawn } = require('node:child_process');
2+
const { existsSync } = require('node:fs');
3+
const { join, resolve } = require('node:path');
4+
5+
const projectRoot = resolve(__dirname, '..');
6+
const helperPath = join(
7+
projectRoot,
8+
'build',
9+
'native',
10+
'cursor-overlay-helper',
11+
'win-x64',
12+
'SwitchifyCursorOverlay.exe'
13+
);
14+
15+
const timeoutMs = 5_000;
16+
let stdoutBuffer = '';
17+
let stderrBuffer = '';
18+
let settled = false;
19+
let sawReady = false;
20+
let shutdownSent = false;
21+
let timeout = null;
22+
let helper = null;
23+
24+
if (!existsSync(helperPath)) {
25+
fail(`Cursor overlay helper was not found: ${helperPath}`);
26+
}
27+
28+
helper = spawn(helperPath, [], {
29+
stdio: ['pipe', 'pipe', 'pipe'],
30+
windowsHide: true
31+
});
32+
33+
timeout = setTimeout(() => {
34+
fail(`Cursor overlay helper smoke test timed out.${stderrBuffer ? ` stderr: ${stderrBuffer.trim()}` : ''}`);
35+
}, timeoutMs);
36+
37+
helper.once('error', (error) => {
38+
fail(`Cursor overlay helper failed to start: ${error.message}`);
39+
});
40+
41+
helper.once('exit', (code, signal) => {
42+
if (!settled && !shutdownSent) {
43+
fail(`Cursor overlay helper exited before shutdown: ${signal ?? code ?? 'unknown'}`);
44+
}
45+
});
46+
47+
helper.stdout.on('data', (chunk) => {
48+
stdoutBuffer += String(chunk);
49+
readStdoutLines();
50+
});
51+
52+
helper.stderr.on('data', (chunk) => {
53+
stderrBuffer += String(chunk);
54+
});
55+
56+
function readStdoutLines() {
57+
while (stdoutBuffer.includes('\n')) {
58+
const newlineIndex = stdoutBuffer.indexOf('\n');
59+
const line = stdoutBuffer.slice(0, newlineIndex).trim();
60+
stdoutBuffer = stdoutBuffer.slice(newlineIndex + 1);
61+
if (line) {
62+
handleMessage(line);
63+
}
64+
}
65+
}
66+
67+
function handleMessage(line) {
68+
let message;
69+
try {
70+
message = JSON.parse(line);
71+
} catch (error) {
72+
fail(`Cursor overlay helper returned malformed output: ${line}`);
73+
return;
74+
}
75+
76+
if (message.type === 'error') {
77+
fail(`Cursor overlay helper reported ${message.code ?? 'error'}: ${message.message ?? 'unknown error'}`);
78+
return;
79+
}
80+
81+
if (message.type === 'ready' && !sawReady) {
82+
sawReady = true;
83+
smokeEvents();
84+
}
85+
}
86+
87+
function smokeEvents() {
88+
for (const event of ['move', 'click', 'drag']) {
89+
writeCommand({
90+
type: 'show',
91+
event,
92+
x: 100,
93+
y: 100,
94+
size: 96,
95+
durationMs: 50,
96+
crosshairs: false,
97+
persistent: false,
98+
color: {
99+
red: 211,
100+
green: 47,
101+
blue: 47
102+
}
103+
});
104+
}
105+
106+
setTimeout(() => {
107+
shutdownSent = true;
108+
writeCommand({ type: 'shutdown' });
109+
helper.stdin.end();
110+
clearTimeout(timeout);
111+
settled = true;
112+
console.log('Cursor overlay helper smoke test passed.');
113+
setTimeout(() => {
114+
if (helper && !helper.killed) {
115+
helper.kill();
116+
}
117+
}, 1_000).unref();
118+
}, 100);
119+
}
120+
121+
function writeCommand(command) {
122+
helper.stdin.write(`${JSON.stringify(command)}\n`);
123+
}
124+
125+
function fail(message) {
126+
if (settled) return;
127+
settled = true;
128+
if (timeout) {
129+
clearTimeout(timeout);
130+
}
131+
if (helper && !helper.killed) {
132+
helper.kill();
133+
}
134+
console.error(message);
135+
process.exitCode = 1;
136+
}

0 commit comments

Comments
 (0)