@gurugokul/doomscroller 0.0.0-stage → 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.
Files changed (57) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +21 -0
  3. package/README.md +300 -2
  4. package/dist/adapters/claude-code-hooks.js +171 -0
  5. package/dist/adapters/claude-code-hooks.js.map +1 -0
  6. package/dist/adapters/cli-wrapper.js +230 -0
  7. package/dist/adapters/cli-wrapper.js.map +1 -0
  8. package/dist/adapters/file-activity.js +78 -0
  9. package/dist/adapters/file-activity.js.map +1 -0
  10. package/dist/adapters/hook.js +17 -0
  11. package/dist/adapters/hook.js.map +1 -0
  12. package/dist/adapters/hotkey.js +50 -0
  13. package/dist/adapters/hotkey.js.map +1 -0
  14. package/dist/adapters/ide-activity.js +245 -0
  15. package/dist/adapters/ide-activity.js.map +1 -0
  16. package/dist/adapters/ports.js +3 -0
  17. package/dist/adapters/ports.js.map +1 -0
  18. package/dist/adapters/wrapper-tracker.js +77 -0
  19. package/dist/adapters/wrapper-tracker.js.map +1 -0
  20. package/dist/cli.js +315 -0
  21. package/dist/cli.js.map +1 -0
  22. package/dist/core/config.js +192 -0
  23. package/dist/core/config.js.map +1 -0
  24. package/dist/core/daemon.js +123 -0
  25. package/dist/core/daemon.js.map +1 -0
  26. package/dist/core/ipc.js +214 -0
  27. package/dist/core/ipc.js.map +1 -0
  28. package/dist/core/logger.js +53 -0
  29. package/dist/core/logger.js.map +1 -0
  30. package/dist/core/sound.js +28 -0
  31. package/dist/core/sound.js.map +1 -0
  32. package/dist/core/state-machine.js +268 -0
  33. package/dist/core/state-machine.js.map +1 -0
  34. package/dist/core/stats.js +109 -0
  35. package/dist/core/stats.js.map +1 -0
  36. package/dist/core/targets.js +23 -0
  37. package/dist/core/targets.js.map +1 -0
  38. package/dist/core/types.js +6 -0
  39. package/dist/core/types.js.map +1 -0
  40. package/dist/index.js +15 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/util/errors.js +16 -0
  43. package/dist/util/errors.js.map +1 -0
  44. package/dist/util/paths.js +70 -0
  45. package/dist/util/paths.js.map +1 -0
  46. package/dist/windows/cpu-probe.js +108 -0
  47. package/dist/windows/cpu-probe.js.map +1 -0
  48. package/dist/windows/key-listener.js +198 -0
  49. package/dist/windows/key-listener.js.map +1 -0
  50. package/dist/windows/win32.js +155 -0
  51. package/dist/windows/win32.js.map +1 -0
  52. package/dist/windows/window-controller.js +3 -0
  53. package/dist/windows/window-controller.js.map +1 -0
  54. package/package.json +57 -4
  55. package/scripts/cpu-sampler.ps1 +83 -0
  56. package/scripts/key-watcher.ps1 +132 -0
  57. package/scripts/win32-window.ps1 +344 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cpu-probe.js","sourceRoot":"","sources":["../../src/windows/cpu-probe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.GlobalKeyListener = void 0;
7
+ exports.parseHotkey = parseHotkey;
8
+ exports.matchesHotkey = matchesHotkey;
9
+ const node_child_process_1 = require("node:child_process");
10
+ const node_readline_1 = __importDefault(require("node:readline"));
11
+ const paths_1 = require("../util/paths");
12
+ const MODIFIERS = new Set(['ctrl', 'control', 'alt', 'shift', 'win', 'meta', 'cmd']);
13
+ function parseHotkey(spec) {
14
+ if (!spec)
15
+ return null;
16
+ const parts = spec
17
+ .split('+')
18
+ .map((part) => part.trim().toLowerCase())
19
+ .filter(Boolean);
20
+ if (parts.length === 0)
21
+ return null;
22
+ const result = { key: '', ctrl: false, alt: false, shift: false };
23
+ for (const part of parts) {
24
+ if (part === 'ctrl' || part === 'control') {
25
+ result.ctrl = true;
26
+ }
27
+ else if (part === 'alt') {
28
+ result.alt = true;
29
+ }
30
+ else if (part === 'shift') {
31
+ result.shift = true;
32
+ }
33
+ else if (part === 'win' || part === 'meta' || part === 'cmd') {
34
+ // Windows-key hotkeys are not supported by the polling watcher.
35
+ return null;
36
+ }
37
+ else if (!result.key) {
38
+ if (part === 'return')
39
+ result.key = 'ENTER';
40
+ else if (part === 'escape')
41
+ result.key = 'ESC';
42
+ else if (part.length === 1)
43
+ result.key = part.toUpperCase();
44
+ else
45
+ result.key = part.toUpperCase();
46
+ }
47
+ }
48
+ if (!result.key)
49
+ return null;
50
+ if (MODIFIERS.has(result.key.toLowerCase()))
51
+ return null;
52
+ return result;
53
+ }
54
+ function matchesHotkey(event, hotkey) {
55
+ return (event.key.toUpperCase() === hotkey.key.toUpperCase() &&
56
+ event.ctrl === hotkey.ctrl &&
57
+ event.alt === hotkey.alt &&
58
+ event.shift === hotkey.shift);
59
+ }
60
+ function toKeyEvent(value) {
61
+ if (typeof value.key !== 'string')
62
+ return null;
63
+ const pid = typeof value.pid === 'number' ? value.pid : Number(value.pid);
64
+ const hwnd = typeof value.hwnd === 'string' ? value.hwnd : String(value.hwnd ?? '');
65
+ const window = Number.isFinite(pid) && pid > 0 && hwnd && hwnd !== '0'
66
+ ? {
67
+ id: hwnd,
68
+ title: typeof value.title === 'string' ? value.title : '',
69
+ processName: typeof value.process === 'string' ? value.process : '',
70
+ pid,
71
+ }
72
+ : null;
73
+ return {
74
+ key: value.key.toUpperCase(),
75
+ ctrl: value.ctrl === true,
76
+ alt: value.alt === true,
77
+ shift: value.shift === true,
78
+ window,
79
+ at: typeof value.at === 'number' ? value.at : Date.now(),
80
+ };
81
+ }
82
+ /**
83
+ * A single PowerShell polling process feeds all key consumers (hotkey + IDE
84
+ * activity). It is restarted automatically if PowerShell dies.
85
+ */
86
+ class GlobalKeyListener {
87
+ logger;
88
+ hotkeyKey;
89
+ child = null;
90
+ listeners = new Set();
91
+ stopped = false;
92
+ restartTimer = null;
93
+ constructor(logger, hotkeyKey = 'D') {
94
+ this.logger = logger;
95
+ this.hotkeyKey = hotkeyKey;
96
+ }
97
+ onKey(listener) {
98
+ this.listeners.add(listener);
99
+ return () => this.listeners.delete(listener);
100
+ }
101
+ start() {
102
+ if (process.platform !== 'win32') {
103
+ this.logger.warn('global hotkey is only available on Windows');
104
+ return;
105
+ }
106
+ if (this.child || this.stopped)
107
+ return;
108
+ this.spawnWatcher();
109
+ }
110
+ stop() {
111
+ this.stopped = true;
112
+ if (this.restartTimer) {
113
+ clearTimeout(this.restartTimer);
114
+ this.restartTimer = null;
115
+ }
116
+ if (this.child) {
117
+ try {
118
+ this.child.kill();
119
+ }
120
+ catch {
121
+ // ignore
122
+ }
123
+ this.child = null;
124
+ }
125
+ }
126
+ spawnWatcher() {
127
+ let child;
128
+ try {
129
+ child = (0, node_child_process_1.spawn)('powershell.exe', [
130
+ '-NoProfile',
131
+ '-NonInteractive',
132
+ '-ExecutionPolicy',
133
+ 'Bypass',
134
+ '-File',
135
+ (0, paths_1.scriptPath)('key-watcher.ps1'),
136
+ '-ParentPid',
137
+ String(process.pid),
138
+ '-HotkeyKey',
139
+ this.hotkeyKey,
140
+ ], { windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
141
+ }
142
+ catch {
143
+ this.scheduleRestart();
144
+ return;
145
+ }
146
+ this.child = child;
147
+ const lines = node_readline_1.default.createInterface({ input: child.stdout });
148
+ lines.on('line', (line) => {
149
+ const trimmed = line.trim();
150
+ if (!trimmed.startsWith('{'))
151
+ return;
152
+ try {
153
+ const parsed = JSON.parse(trimmed);
154
+ if (parsed.type === 'ready') {
155
+ this.logger.info('global key listener ready');
156
+ return;
157
+ }
158
+ if (parsed.type !== 'key')
159
+ return;
160
+ const event = toKeyEvent(parsed);
161
+ if (!event)
162
+ return;
163
+ for (const listener of this.listeners) {
164
+ try {
165
+ listener(event);
166
+ }
167
+ catch (error) {
168
+ this.logger.debug(`key listener callback failed: ${String(error)}`);
169
+ }
170
+ }
171
+ }
172
+ catch {
173
+ // Ignore malformed lines.
174
+ }
175
+ });
176
+ child.stdout.on('error', () => { });
177
+ child.stderr.on('data', () => { });
178
+ child.stderr.on('error', () => { });
179
+ const onGone = () => {
180
+ if (this.child === child)
181
+ this.child = null;
182
+ this.scheduleRestart();
183
+ };
184
+ child.on('error', onGone);
185
+ child.on('close', onGone);
186
+ }
187
+ scheduleRestart() {
188
+ if (this.stopped || this.restartTimer)
189
+ return;
190
+ this.restartTimer = setTimeout(() => {
191
+ this.restartTimer = null;
192
+ if (!this.stopped && !this.child)
193
+ this.spawnWatcher();
194
+ }, 2500);
195
+ }
196
+ }
197
+ exports.GlobalKeyListener = GlobalKeyListener;
198
+ //# sourceMappingURL=key-listener.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"key-listener.js","sourceRoot":"","sources":["../../src/windows/key-listener.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,155 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Win32WindowController = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const errors_1 = require("../util/errors");
6
+ const paths_1 = require("../util/paths");
7
+ function runPowerShell(args, timeoutMs) {
8
+ return new Promise((resolve) => {
9
+ let stdout = '';
10
+ let stderr = '';
11
+ let settled = false;
12
+ let timedOut = false;
13
+ let child;
14
+ try {
15
+ child = (0, node_child_process_1.spawn)('powershell.exe', ['-NoProfile', '-NonInteractive', '-ExecutionPolicy', 'Bypass', ...args], { windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });
16
+ }
17
+ catch (error) {
18
+ resolve({ stdout: '', stderr: (0, errors_1.errorMessage)(error), code: null, timedOut: false });
19
+ return;
20
+ }
21
+ const finish = (code) => {
22
+ if (settled)
23
+ return;
24
+ settled = true;
25
+ clearTimeout(timer);
26
+ resolve({ stdout, stderr, code, timedOut });
27
+ };
28
+ const timer = setTimeout(() => {
29
+ timedOut = true;
30
+ try {
31
+ child.kill();
32
+ }
33
+ catch {
34
+ // ignore
35
+ }
36
+ finish(null);
37
+ }, timeoutMs);
38
+ child.stdout?.on('data', (chunk) => {
39
+ if (stdout.length < 2_000_000)
40
+ stdout += chunk.toString('utf8');
41
+ });
42
+ child.stderr?.on('data', (chunk) => {
43
+ if (stderr.length < 200_000)
44
+ stderr += chunk.toString('utf8');
45
+ });
46
+ child.on('error', (error) => {
47
+ stderr += (0, errors_1.errorMessage)(error);
48
+ finish(null);
49
+ });
50
+ child.on('close', (code) => finish(code));
51
+ });
52
+ }
53
+ function extractJson(text) {
54
+ const cleaned = text.replace(/^\uFEFF/, '');
55
+ const start = cleaned.indexOf('{');
56
+ const end = cleaned.lastIndexOf('}');
57
+ if (start < 0 || end <= start)
58
+ return null;
59
+ try {
60
+ const parsed = JSON.parse(cleaned.slice(start, end + 1));
61
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
62
+ ? parsed
63
+ : null;
64
+ }
65
+ catch {
66
+ return null;
67
+ }
68
+ }
69
+ function toWindow(value) {
70
+ if (!value || typeof value !== 'object' || Array.isArray(value))
71
+ return null;
72
+ const record = value;
73
+ const rawId = record.id;
74
+ const id = typeof rawId === 'string'
75
+ ? rawId
76
+ : typeof rawId === 'number' && Number.isFinite(rawId)
77
+ ? String(rawId)
78
+ : '';
79
+ const pid = typeof record.pid === 'number' ? record.pid : Number(record.pid);
80
+ if (!id || id === '0' || !Number.isFinite(pid) || pid <= 0)
81
+ return null;
82
+ return {
83
+ id,
84
+ title: typeof record.title === 'string' ? record.title : '',
85
+ processName: typeof record.processName === 'string' ? record.processName : '',
86
+ pid,
87
+ };
88
+ }
89
+ class Win32WindowController {
90
+ browser;
91
+ logger;
92
+ constructor(browser = 'auto', logger) {
93
+ this.browser = browser;
94
+ this.logger = logger;
95
+ }
96
+ async invoke(action, extraArgs, timeoutMs = 15000) {
97
+ if (process.platform !== 'win32') {
98
+ this.logger?.warn('window control is only available on Windows');
99
+ return null;
100
+ }
101
+ const result = await runPowerShell([
102
+ '-File',
103
+ (0, paths_1.scriptPath)('win32-window.ps1'),
104
+ '-Action',
105
+ action,
106
+ ...extraArgs,
107
+ ], timeoutMs);
108
+ const parsed = extractJson(result.stdout);
109
+ if (!parsed) {
110
+ this.logger?.debug(`win32 ${action} returned no JSON (code=${result.code}, timeout=${result.timedOut}): ${result.stderr.slice(0, 300)}`);
111
+ }
112
+ return parsed;
113
+ }
114
+ async getForegroundWindow() {
115
+ const result = await this.invoke('get-foreground', [], 8000);
116
+ if (!result?.ok)
117
+ return null;
118
+ return toWindow(result.window);
119
+ }
120
+ async minimizeWindow(handle) {
121
+ const result = await this.invoke('minimize', ['-Handle', handle.id], 8000);
122
+ if (!result?.ok) {
123
+ throw new Error(typeof result?.error === 'string' ? result.error : 'minimize failed');
124
+ }
125
+ }
126
+ async restoreAndFocusWindow(handle) {
127
+ // The PowerShell helper restores the window and applies the Alt-key
128
+ // foreground-lock workaround before calling SetForegroundWindow.
129
+ const result = await this.invoke('focus', ['-Handle', handle.id], 10000);
130
+ return Boolean(result?.ok && result.focused);
131
+ }
132
+ async openInNewBrowserWindow(url) {
133
+ const result = await this.invoke('open-url', ['-Url', url, '-Browser', this.browser], 22000);
134
+ if (!result?.ok)
135
+ return null;
136
+ return toWindow(result.window);
137
+ }
138
+ async findWindows(match) {
139
+ const args = [];
140
+ if (match.title)
141
+ args.push('-Title', match.title);
142
+ if (match.process)
143
+ args.push('-ProcessName', match.process);
144
+ if (args.length === 0)
145
+ return [];
146
+ const result = await this.invoke('find', args, 10000);
147
+ if (!result?.ok || !Array.isArray(result.windows))
148
+ return [];
149
+ return result.windows
150
+ .map((entry) => toWindow(entry))
151
+ .filter((entry) => entry !== null);
152
+ }
153
+ }
154
+ exports.Win32WindowController = Win32WindowController;
155
+ //# sourceMappingURL=win32.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"win32.js","sourceRoot":"","sources":["../../src/windows/win32.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=window-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"window-controller.js","sourceRoot":"","sources":["../../src/windows/window-controller.ts"],"names":[],"mappings":""}
package/package.json CHANGED
@@ -1,6 +1,59 @@
1
1
  {
2
2
  "name": "@gurugokul/doomscroller",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "Doomscroll while your AI coding agent works, then bring the agent window back when it finishes.",
5
+ "license": "MIT",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "author": "Gurugokul",
10
+ "bin": {
11
+ "doomscroller": "dist/index.js"
12
+ },
13
+ "main": "dist/index.js",
14
+ "files": [
15
+ "dist",
16
+ "scripts",
17
+ "README.md",
18
+ "LICENSE",
19
+ "CHANGELOG.md"
20
+ ],
21
+ "keywords": [
22
+ "ai",
23
+ "claude-code",
24
+ "copilot",
25
+ "antigravity",
26
+ "productivity",
27
+ "cli"
28
+ ],
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "git+https://github.com/Gurugokul05/doomscroller.git"
32
+ },
33
+ "bugs": {
34
+ "url": "https://github.com/Gurugokul05/doomscroller/issues"
35
+ },
36
+ "homepage": "https://github.com/Gurugokul05/doomscroller#readme",
37
+ "engines": {
38
+ "node": ">=20"
39
+ },
40
+ "scripts": {
41
+ "build": "tsc -p tsconfig.build.json",
42
+ "typecheck": "tsc -p tsconfig.json --noEmit",
43
+ "lint": "eslint \"src/**/*.ts\" \"tests/**/*.ts\" \"vitest.config.ts\"",
44
+ "test": "vitest run",
45
+ "test:watch": "vitest",
46
+ "start": "node dist/index.js",
47
+ "prepublishOnly": "npm run build && npm test"
48
+ },
49
+ "dependencies": {
50
+ "node-pty": "^1.0.0"
51
+ },
52
+ "devDependencies": {
53
+ "@types/node": "^22.10.0",
54
+ "eslint": "^10.13.0",
55
+ "typescript": "^5.7.0",
56
+ "typescript-eslint": "^8.72.0",
57
+ "vitest": "^2.1.0"
58
+ }
59
+ }
@@ -0,0 +1,83 @@
1
+ param(
2
+ [Parameter(Mandatory = $true)]
3
+ [int]$RootPid,
4
+ [int]$IntervalMs = 1000
5
+ )
6
+
7
+ $ErrorActionPreference = 'SilentlyContinue'
8
+ [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
9
+ $OutputEncoding = New-Object System.Text.UTF8Encoding($false)
10
+
11
+ function Write-Result([object]$Value) {
12
+ $json = ConvertTo-Json -InputObject $Value -Compress -Depth 4
13
+ [Console]::Out.WriteLine($json)
14
+ [Console]::Out.Flush()
15
+ }
16
+
17
+ function Get-ProcessTreeIds([int]$Root) {
18
+ $ids = New-Object 'System.Collections.Generic.HashSet[int]'
19
+ [void]$ids.Add($Root)
20
+
21
+ $all = @(Get-CimInstance Win32_Process -Property ProcessId, ParentProcessId -ErrorAction SilentlyContinue)
22
+ $changed = $true
23
+ $guard = 0
24
+ while ($changed -and $guard -lt 20) {
25
+ $guard++
26
+ $changed = $false
27
+ foreach ($process in $all) {
28
+ $childId = [int]$process.ProcessId
29
+ $parentId = [int]$process.ParentProcessId
30
+ if ($childId -eq 0) { continue }
31
+ if ($ids.Contains($parentId) -and -not $ids.Contains($childId)) {
32
+ [void]$ids.Add($childId)
33
+ $changed = $true
34
+ }
35
+ }
36
+ }
37
+ return @($ids)
38
+ }
39
+
40
+ $treeIds = @($RootPid)
41
+ $iteration = 0
42
+
43
+ while ($true) {
44
+ $rootProcess = Get-Process -Id $RootPid -ErrorAction SilentlyContinue
45
+ if ($null -eq $rootProcess) {
46
+ Write-Result @{
47
+ rootPid = $RootPid
48
+ cpuSeconds = 0
49
+ processes = 0
50
+ alive = $false
51
+ at = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
52
+ }
53
+ break
54
+ }
55
+
56
+ if ($iteration -gt 0 -and ($iteration % 5) -eq 0) {
57
+ $treeIds = Get-ProcessTreeIds $RootPid
58
+ }
59
+
60
+ $totalCpu = 0.0
61
+ $aliveProcesses = 0
62
+ foreach ($processIdValue in $treeIds) {
63
+ $child = Get-Process -Id $processIdValue -ErrorAction SilentlyContinue
64
+ if ($null -ne $child) {
65
+ try {
66
+ $totalCpu += $child.TotalProcessorTime.TotalSeconds
67
+ $aliveProcesses++
68
+ } catch {
69
+ }
70
+ }
71
+ }
72
+
73
+ Write-Result @{
74
+ rootPid = $RootPid
75
+ cpuSeconds = [Math]::Round($totalCpu, 3)
76
+ processes = $aliveProcesses
77
+ alive = $true
78
+ at = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
79
+ }
80
+
81
+ $iteration++
82
+ [System.Threading.Thread]::Sleep($IntervalMs)
83
+ }
@@ -0,0 +1,132 @@
1
+ param(
2
+ [int]$ParentPid = 0,
3
+ [string]$HotkeyKey = 'D',
4
+ [int]$IntervalMs = 15
5
+ )
6
+
7
+ $ErrorActionPreference = 'Stop'
8
+ [Console]::OutputEncoding = New-Object System.Text.UTF8Encoding($false)
9
+ $OutputEncoding = New-Object System.Text.UTF8Encoding($false)
10
+
11
+ Add-Type -TypeDefinition @'
12
+ using System;
13
+ using System.Text;
14
+ using System.Runtime.InteropServices;
15
+
16
+ public class DSDoomKeys
17
+ {
18
+ [DllImport("user32.dll")] public static extern short GetAsyncKeyState(int vKey);
19
+ [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
20
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowText(IntPtr hWnd, StringBuilder text, int count);
21
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowTextLength(IntPtr hWnd);
22
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint pid);
23
+
24
+ public static string Title(IntPtr h)
25
+ {
26
+ int length = GetWindowTextLength(h);
27
+ if (length <= 0) return string.Empty;
28
+ var builder = new StringBuilder(length + 1);
29
+ GetWindowText(h, builder, builder.Capacity);
30
+ return builder.ToString();
31
+ }
32
+
33
+ public static uint ProcessId(IntPtr h)
34
+ {
35
+ uint processId;
36
+ GetWindowThreadProcessId(h, out processId);
37
+ return processId;
38
+ }
39
+ }
40
+ '@
41
+
42
+ $specialKeys = @{
43
+ 'ENTER' = 0x0D
44
+ 'SPACE' = 0x20
45
+ 'TAB' = 0x09
46
+ 'ESC' = 0x1B
47
+ 'BACKSPACE' = 0x08
48
+ }
49
+ for ($index = 0; $index -lt 26; $index++) {
50
+ $specialKeys[[string][char](65 + $index)] = 65 + $index
51
+ }
52
+ for ($index = 0; $index -lt 10; $index++) {
53
+ $specialKeys[[string][char](48 + $index)] = 48 + $index
54
+ }
55
+ for ($index = 1; $index -le 12; $index++) {
56
+ $specialKeys["F$index"] = 111 + $index
57
+ }
58
+
59
+ $requested = ([string]$HotkeyKey).Trim().ToUpperInvariant()
60
+ if ($requested.StartsWith('VK_')) { $requested = $requested.Substring(3) }
61
+ if (-not $specialKeys.ContainsKey($requested)) { $requested = 'D' }
62
+
63
+ $watch = @{ 'ENTER' = 0x0D }
64
+ if (-not $watch.ContainsKey($requested)) { $watch[$requested] = $specialKeys[$requested] }
65
+
66
+ function Write-Result([object]$Value) {
67
+ $json = ConvertTo-Json -InputObject $Value -Compress -Depth 4
68
+ [Console]::Out.WriteLine($json)
69
+ [Console]::Out.Flush()
70
+ }
71
+
72
+ Write-Result @{ type = 'ready'; keys = @($watch.Keys) }
73
+
74
+ $down = @{}
75
+ $iteration = 0
76
+
77
+ while ($true) {
78
+ foreach ($keyName in @($watch.Keys)) {
79
+ $virtualKey = $watch[$keyName]
80
+ $isDown = (([DSDoomKeys]::GetAsyncKeyState($virtualKey)) -band 0x8000) -ne 0
81
+
82
+ if ($isDown -and -not $down.ContainsKey($keyName)) {
83
+ $down[$keyName] = $true
84
+
85
+ $ctrl = (([DSDoomKeys]::GetAsyncKeyState(0x11)) -band 0x8000) -ne 0
86
+ $alt = (([DSDoomKeys]::GetAsyncKeyState(0x12)) -band 0x8000) -ne 0
87
+ $shift = (([DSDoomKeys]::GetAsyncKeyState(0x10)) -band 0x8000) -ne 0
88
+
89
+ $windowHandle = [DSDoomKeys]::GetForegroundWindow()
90
+ $windowTitle = ''
91
+ $processNameValue = ''
92
+ $processIdValue = 0
93
+
94
+ if ($windowHandle -ne [IntPtr]::Zero) {
95
+ $windowTitle = [DSDoomKeys]::Title($windowHandle)
96
+ $processIdValue = [int][DSDoomKeys]::ProcessId($windowHandle)
97
+ if ($processIdValue -ne 0) {
98
+ try {
99
+ $processNameValue = (Get-Process -Id $processIdValue -ErrorAction Stop).ProcessName
100
+ } catch {
101
+ }
102
+ }
103
+ }
104
+
105
+ Write-Result @{
106
+ type = 'key'
107
+ key = $keyName
108
+ ctrl = $ctrl
109
+ alt = $alt
110
+ shift = $shift
111
+ hwnd = $windowHandle.ToInt64().ToString([System.Globalization.CultureInfo]::InvariantCulture)
112
+ title = $windowTitle
113
+ process = $processNameValue
114
+ pid = $processIdValue
115
+ at = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
116
+ }
117
+ } elseif (-not $isDown -and $down.ContainsKey($keyName)) {
118
+ $down.Remove($keyName)
119
+ }
120
+ }
121
+
122
+ $iteration++
123
+ if ($ParentPid -gt 0 -and ($iteration % 100 -eq 0)) {
124
+ try {
125
+ $null = Get-Process -Id $ParentPid -ErrorAction Stop
126
+ } catch {
127
+ break
128
+ }
129
+ }
130
+
131
+ [System.Threading.Thread]::Sleep($IntervalMs)
132
+ }