@momasiku/dsh-pilot 0.5.7 → 0.5.9

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.
@@ -1,214 +1,280 @@
1
- # pilot / _dsh-win32.ps1 - the Win32 bridge and per-monitor DPI awareness, shared
2
- # by the one-shot scripts and by the persistent worker.
3
- #
4
- # Every block is idempotent: a process that already has the type does not compile
5
- # it again, so the same file can be dot-sourced by several entry points.
6
- $ErrorActionPreference = 'Stop'
7
-
8
- if (-not ('DshInput' -as [type])) {
9
- # ---------------------------------------------------------------- Win32 bridge
10
- $nativeSource = @'
11
- using System;
12
- using System.Runtime.InteropServices;
13
- using System.Text;
14
- using System.Windows.Forms;
15
-
16
- public static class DshInput {
17
- [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
18
- [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
19
-
20
- [DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
21
- [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT p);
22
- [DllImport("user32.dll")] public static extern void mouse_event(uint flags, uint dx, uint dy, int data, IntPtr extra);
23
- [DllImport("user32.dll")] public static extern void keybd_event(byte vk, byte scan, uint flags, IntPtr extra);
24
- [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
25
- [DllImport("user32.dll")] public static extern IntPtr GetWindow(IntPtr h, uint cmd);
26
- [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
27
- [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd);
28
- [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
29
- [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
30
- [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
31
- [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
32
- [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
33
- [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
34
- [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
35
- [DllImport("user32.dll")] public static extern bool SetProcessDpiAwarenessContext(IntPtr value);
36
- [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);
37
- [DllImport("user32.dll")] public static extern int GetSystemMetrics(int index);
38
-
39
- // The wheel flags keep their Win32 names on purpose. PowerShell resolves type
40
- // members case-insensitively and a constant shadows a method that differs only
41
- // in case, so a constant named WHEEL made [DshInput]::Wheel(...) fail with
42
- // "does not contain a method named 'Wheel'" - the scroll action never worked.
43
- // Do not shorten these back.
44
- public const uint MOVE = 0x0001, LEFTDOWN = 0x0002, LEFTUP = 0x0004, RIGHTDOWN = 0x0008,
45
- RIGHTUP = 0x0010, MIDDLEDOWN = 0x0020, MIDDLEUP = 0x0040, MOUSEEVENTF_WHEEL = 0x0800,
46
- MOUSEEVENTF_HWHEEL = 0x1000;
47
- public const uint KEYUP = 0x0002;
48
- public const byte VK_LWIN = 0x5B, VK_RWIN = 0x5C;
49
-
50
- public static bool BecomeDpiAware() {
51
- try { if (SetProcessDpiAwarenessContext(new IntPtr(-4))) return true; } catch {}
52
- try { if (SetProcessDpiAwareness(2) == 0) return true; } catch {}
53
- try { if (SetProcessDPIAware()) return true; } catch {}
54
- return false;
55
- }
56
- public static POINT Cursor() { POINT p; GetCursorPos(out p); return p; }
57
- public static RECT WindowRect(IntPtr h) { RECT r; GetWindowRect(h, out r); return r; }
58
- public static string WindowTitle(IntPtr h) {
59
- var sb = new StringBuilder(512);
60
- GetWindowTextW(h, sb, sb.Capacity);
61
- return sb.ToString();
62
- }
63
- public static string WindowClass(IntPtr h) {
64
- var sb = new StringBuilder(256);
65
- GetClassNameW(h, sb, sb.Capacity);
66
- return sb.ToString();
67
- }
68
- public static string ForegroundTitle() { return WindowTitle(GetForegroundWindow()); }
69
- public static string ForegroundClass() { return WindowClass(GetForegroundWindow()); }
70
- public static int ForegroundPid() {
71
- uint pid = 0;
72
- GetWindowThreadProcessId(GetForegroundWindow(), out pid);
73
- return (int) pid;
74
- }
75
- public static IntPtr Owner(IntPtr h) { return GetWindow(h, 4); }
76
-
77
- public static void WinKey(bool down) {
78
- byte vk = VK_LWIN;
79
- keybd_event(vk, 0, down ? 0u : KEYUP, IntPtr.Zero);
80
- }
81
- public static void SendKeysText(string sequence) { SendKeys.SendWait(sequence); }
82
- public static void Wheel(int delta) { mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, IntPtr.Zero); }
83
- public static void HWheel(int delta) { mouse_event(MOUSEEVENTF_HWHEEL, 0, 0, delta, IntPtr.Zero); }
84
- public static void Button(string which, bool down) {
85
- uint flag;
86
- if (which == "right") flag = down ? RIGHTDOWN : RIGHTUP;
87
- else if (which == "middle") flag = down ? MIDDLEDOWN : MIDDLEUP;
88
- else flag = down ? LEFTDOWN : LEFTUP;
89
- mouse_event(flag, 0, 0, 0, IntPtr.Zero);
90
- }
91
-
92
- // Taskbar buttons live in Explorer's windows, so activation walks to the
93
- // root owner: SetForegroundWindow on a child is a silent no-op.
94
- public static bool Activate(IntPtr h) {
95
- IntPtr root = h;
96
- for (int i = 0; i < 8; i++) {
97
- IntPtr owner = Owner(root);
98
- if (owner == IntPtr.Zero) break;
99
- root = owner;
100
- }
101
- if (IsIconic(root)) ShowWindow(root, 9);
102
- bool raised = SetForegroundWindow(root);
103
- if (!raised) {
104
- // Windows blocks foreground stealing from a foreign process; the
105
- // documented workaround is to attach to the foreground thread first.
106
- uint fgPid = 0;
107
- IntPtr fg = GetForegroundWindow();
108
- uint fgThread = GetWindowThreadProcessId(fg, out fgPid);
109
- uint myPid = 0;
110
- uint myThread = GetWindowThreadProcessId(root, out myPid);
111
- if (fgThread != myThread) {
112
- AttachThreadInput(fgThread, myThread, true);
113
- raised = SetForegroundWindow(root);
114
- AttachThreadInput(fgThread, myThread, false);
115
- }
116
- }
117
- return raised;
118
- }
119
- [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
120
-
121
- // Foreground is a scarce, externally-arbitrated resource: another process
122
- // (or the desktop host itself) can take it between two of our steps, which
123
- // would send an injected click or keystroke to the wrong application. So
124
- // every action re-asserts its target immediately before injecting input
125
- // and verifies the result instead of assuming the focus it asked for held.
126
- public static bool IsForeground(IntPtr h) { return GetForegroundWindow() == h; }
127
- public static bool ForceForeground(IntPtr h) {
128
- if (IsForeground(h)) return true;
129
- if (IsIconic(h)) ShowWindow(h, 9);
130
- if (!IsWindowVisible(h)) ShowWindow(h, 5);
131
- IntPtr fg = GetForegroundWindow();
132
- uint otherPid = 0, myPid = 0;
133
- uint fgThread = GetWindowThreadProcessId(fg, out otherPid);
134
- uint myThread = GetWindowThreadProcessId(h, out myPid);
135
- bool attached = false;
136
- if (fgThread != 0 && fgThread != myThread) {
137
- attached = AttachThreadInput(fgThread, myThread, true);
138
- if (!attached) attached = AttachThreadInput(myThread, fgThread, true);
139
- }
140
- SetForegroundWindow(h);
141
- BringWindowToTop(h);
142
- if (attached) {
143
- AttachThreadInput(fgThread, myThread, false);
144
- AttachThreadInput(myThread, fgThread, false);
145
- }
146
- return IsForeground(h);
147
- }
148
- public static bool IsAlive(IntPtr h) { return IsWindow(h); }
149
- [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr h);
150
- [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);
151
-
152
- // Top-level window inventory. `Process.MainWindowHandle` reports 0 for a
153
- // window that is hidden or minimized to the tray, which makes the whole
154
- // application invisible to a MainWindowHandle-based scan; EnumWindows sees
155
- // every top-level window regardless of visibility.
156
- public delegate bool EnumProc(IntPtr h, IntPtr l);
157
- [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);
158
- public static IntPtr[] TopLevelWindows() {
159
- var found = new System.Collections.Generic.List<IntPtr>();
160
- EnumWindows((h, l) => { found.Add(h); return true; }, IntPtr.Zero);
161
- return found.ToArray();
162
- }
163
- }
164
- '@
165
- $null = Add-Type -TypeDefinition $nativeSource -Language CSharp -ReferencedAssemblies System.Windows.Forms
166
- $null = [DshInput]::BecomeDpiAware()
167
- }
168
-
169
- if (-not ('DshProbe' -as [type])) {
170
- # ---------------------------------------------------------------- Win32 bridge
171
- $nativeSource = @'
172
- using System;
173
- using System.Runtime.InteropServices;
174
- using System.Text;
175
- public static class DshProbe {
176
- [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
177
- [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
178
- [DllImport("user32.dll")] public static extern IntPtr WindowFromPoint(POINT p);
179
- [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
180
- [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
181
- [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
182
- [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
183
- [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
184
- [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
185
- [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
186
- [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT p);
187
- [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
188
- [DllImport("user32.dll")] public static extern bool SetProcessDpiAwarenessContext(IntPtr value);
189
- [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);
190
- [DllImport("user32.dll")] public static extern int GetSystemMetrics(int index);
191
-
192
- public static bool BecomeDpiAware() {
193
- try { if (SetProcessDpiAwarenessContext(new IntPtr(-4))) return true; } catch {}
194
- try { if (SetProcessDpiAwareness(2) == 0) return true; } catch {}
195
- try { if (SetProcessDPIAware()) return true; } catch {}
196
- return false;
197
- }
198
- public static RECT WindowRect(IntPtr h) { RECT r; GetWindowRect(h, out r); return r; }
199
- public static POINT Cursor() { POINT p; GetCursorPos(out p); return p; }
200
- public static string WindowTitle(IntPtr h) {
201
- var sb = new StringBuilder(512);
202
- GetWindowTextW(h, sb, sb.Capacity);
203
- return sb.ToString();
204
- }
205
- public static string WindowClass(IntPtr h) {
206
- var sb = new StringBuilder(256);
207
- GetClassNameW(h, sb, sb.Capacity);
208
- return sb.ToString();
209
- }
210
- }
211
- '@
212
- $null = Add-Type -TypeDefinition $nativeSource -Language CSharp
213
- $null = [DshProbe]::BecomeDpiAware()
1
+ # pilot / _dsh-win32.ps1 - the Win32 bridge and per-monitor DPI awareness, shared
2
+ # by the one-shot scripts and by the persistent worker.
3
+ #
4
+ # Every block is idempotent: a process that already has the type does not compile
5
+ # it again, so the same file can be dot-sourced by several entry points.
6
+ $ErrorActionPreference = 'Stop'
7
+
8
+ if (-not ('DshInput' -as [type])) {
9
+ # ---------------------------------------------------------------- Win32 bridge
10
+ $nativeSource = @'
11
+ using System;
12
+ using System.Runtime.InteropServices;
13
+ using System.Text;
14
+ using System.Windows.Forms;
15
+
16
+ public static class DshInput {
17
+ [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
18
+ [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
19
+
20
+ [DllImport("user32.dll")] public static extern bool SetCursorPos(int x, int y);
21
+ [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT p);
22
+ [DllImport("user32.dll")] public static extern void mouse_event(uint flags, uint dx, uint dy, int data, IntPtr extra);
23
+ [DllImport("user32.dll")] public static extern void keybd_event(byte vk, byte scan, uint flags, IntPtr extra);
24
+ [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
25
+ [DllImport("user32.dll")] public static extern IntPtr GetWindow(IntPtr h, uint cmd);
26
+ [DllImport("user32.dll")] public static extern bool SetForegroundWindow(IntPtr h);
27
+ [DllImport("user32.dll")] public static extern bool ShowWindow(IntPtr h, int cmd);
28
+ [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
29
+ [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
30
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
31
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
32
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
33
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
34
+ [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
35
+ [DllImport("user32.dll")] public static extern bool SetProcessDpiAwarenessContext(IntPtr value);
36
+ [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);
37
+ [DllImport("user32.dll")] public static extern int GetSystemMetrics(int index);
38
+
39
+ // The wheel flags keep their Win32 names on purpose. PowerShell resolves type
40
+ // members case-insensitively and a constant shadows a method that differs only
41
+ // in case, so a constant named WHEEL made [DshInput]::Wheel(...) fail with
42
+ // "does not contain a method named 'Wheel'" - the scroll action never worked.
43
+ // Do not shorten these back.
44
+ public const uint MOVE = 0x0001, LEFTDOWN = 0x0002, LEFTUP = 0x0004, RIGHTDOWN = 0x0008,
45
+ RIGHTUP = 0x0010, MIDDLEDOWN = 0x0020, MIDDLEUP = 0x0040, MOUSEEVENTF_WHEEL = 0x0800,
46
+ MOUSEEVENTF_HWHEEL = 0x1000;
47
+ public const uint KEYUP = 0x0002;
48
+ public const byte VK_LWIN = 0x5B, VK_RWIN = 0x5C;
49
+
50
+ public static bool BecomeDpiAware() {
51
+ try { if (SetProcessDpiAwarenessContext(new IntPtr(-4))) return true; } catch {}
52
+ try { if (SetProcessDpiAwareness(2) == 0) return true; } catch {}
53
+ try { if (SetProcessDPIAware()) return true; } catch {}
54
+ return false;
55
+ }
56
+ public static POINT Cursor() { POINT p; GetCursorPos(out p); return p; }
57
+ public static RECT WindowRect(IntPtr h) { RECT r; GetWindowRect(h, out r); return r; }
58
+ public static string WindowTitle(IntPtr h) {
59
+ var sb = new StringBuilder(512);
60
+ GetWindowTextW(h, sb, sb.Capacity);
61
+ return sb.ToString();
62
+ }
63
+ public static string WindowClass(IntPtr h) {
64
+ var sb = new StringBuilder(256);
65
+ GetClassNameW(h, sb, sb.Capacity);
66
+ return sb.ToString();
67
+ }
68
+ public static string ForegroundTitle() { return WindowTitle(GetForegroundWindow()); }
69
+ public static string ForegroundClass() { return WindowClass(GetForegroundWindow()); }
70
+ public static int ForegroundPid() {
71
+ uint pid = 0;
72
+ GetWindowThreadProcessId(GetForegroundWindow(), out pid);
73
+ return (int) pid;
74
+ }
75
+ public static IntPtr Owner(IntPtr h) { return GetWindow(h, 4); }
76
+
77
+ public static void WinKey(bool down) {
78
+ byte vk = VK_LWIN;
79
+ keybd_event(vk, 0, down ? 0u : KEYUP, IntPtr.Zero);
80
+ }
81
+ public static void SendKeysText(string sequence) { SendKeys.SendWait(sequence); }
82
+ public static void Wheel(int delta) { mouse_event(MOUSEEVENTF_WHEEL, 0, 0, delta, IntPtr.Zero); }
83
+ public static void HWheel(int delta) { mouse_event(MOUSEEVENTF_HWHEEL, 0, 0, delta, IntPtr.Zero); }
84
+ public static void Button(string which, bool down) {
85
+ uint flag;
86
+ if (which == "right") flag = down ? RIGHTDOWN : RIGHTUP;
87
+ else if (which == "middle") flag = down ? MIDDLEDOWN : MIDDLEUP;
88
+ else flag = down ? LEFTDOWN : LEFTUP;
89
+ mouse_event(flag, 0, 0, 0, IntPtr.Zero);
90
+ }
91
+
92
+ // Taskbar buttons live in Explorer's windows, so activation walks to the
93
+ // root owner: SetForegroundWindow on a child is a silent no-op.
94
+ public static bool Activate(IntPtr h) {
95
+ IntPtr root = h;
96
+ for (int i = 0; i < 8; i++) {
97
+ IntPtr owner = Owner(root);
98
+ if (owner == IntPtr.Zero) break;
99
+ root = owner;
100
+ }
101
+ if (IsIconic(root)) ShowWindow(root, 9);
102
+ bool raised = SetForegroundWindow(root);
103
+ if (!raised) {
104
+ // Windows blocks foreground stealing from a foreign process; the
105
+ // documented workaround is to attach to the foreground thread first.
106
+ uint fgPid = 0;
107
+ IntPtr fg = GetForegroundWindow();
108
+ uint fgThread = GetWindowThreadProcessId(fg, out fgPid);
109
+ uint myPid = 0;
110
+ uint myThread = GetWindowThreadProcessId(root, out myPid);
111
+ if (fgThread != myThread) {
112
+ AttachThreadInput(fgThread, myThread, true);
113
+ raised = SetForegroundWindow(root);
114
+ AttachThreadInput(fgThread, myThread, false);
115
+ }
116
+ }
117
+ return raised;
118
+ }
119
+ [DllImport("user32.dll")] public static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool attach);
120
+
121
+ // Foreground is a scarce, externally-arbitrated resource: another process
122
+ // (or the desktop host itself) can take it between two of our steps, which
123
+ // would send an injected click or keystroke to the wrong application. So
124
+ // every action re-asserts its target immediately before injecting input
125
+ // and verifies the result instead of assuming the focus it asked for held.
126
+ public static bool IsForeground(IntPtr h) { return GetForegroundWindow() == h; }
127
+ public static bool ForceForeground(IntPtr h) {
128
+ if (IsForeground(h)) return true;
129
+ if (IsIconic(h)) ShowWindow(h, 9);
130
+ if (!IsWindowVisible(h)) ShowWindow(h, 5);
131
+ IntPtr fg = GetForegroundWindow();
132
+ uint otherPid = 0, myPid = 0;
133
+ uint fgThread = GetWindowThreadProcessId(fg, out otherPid);
134
+ uint myThread = GetWindowThreadProcessId(h, out myPid);
135
+ bool attached = false;
136
+ if (fgThread != 0 && fgThread != myThread) {
137
+ attached = AttachThreadInput(fgThread, myThread, true);
138
+ if (!attached) attached = AttachThreadInput(myThread, fgThread, true);
139
+ }
140
+ SetForegroundWindow(h);
141
+ BringWindowToTop(h);
142
+ if (attached) {
143
+ AttachThreadInput(fgThread, myThread, false);
144
+ AttachThreadInput(myThread, fgThread, false);
145
+ }
146
+ return IsForeground(h);
147
+ }
148
+ public static bool IsAlive(IntPtr h) { return IsWindow(h); }
149
+ [DllImport("user32.dll")] public static extern bool IsWindow(IntPtr h);
150
+ [DllImport("user32.dll")] public static extern bool BringWindowToTop(IntPtr h);
151
+
152
+ // Top-level window inventory. `Process.MainWindowHandle` reports 0 for a
153
+ // window that is hidden or minimized to the tray, which makes the whole
154
+ // application invisible to a MainWindowHandle-based scan; EnumWindows sees
155
+ // every top-level window regardless of visibility.
156
+ public delegate bool EnumProc(IntPtr h, IntPtr l);
157
+ [DllImport("user32.dll")] public static extern bool EnumWindows(EnumProc cb, IntPtr l);
158
+ public static IntPtr[] TopLevelWindows() {
159
+ var found = new System.Collections.Generic.List<IntPtr>();
160
+ EnumWindows((h, l) => { found.Add(h); return true; }, IntPtr.Zero);
161
+ return found.ToArray();
162
+ }
163
+ }
164
+ '@
165
+ # Compiling this bridge costs ~1 s idle and far more under load, and the worker
166
+ # pays it on every cold start - before it can answer "ready". Compile once into a
167
+ # DLL keyed by a hash of the source, then load that. Any edit to the source yields
168
+ # a new hash and so a new DLL, so a stale cache can never shadow a fix.
169
+ # -OutputAssembly does not load the types into the session, hence the -Path pass;
170
+ # if the cached file is unusable we fall back to compiling in memory.
171
+ $inputStamp = [BitConverter]::ToString(
172
+ [System.Security.Cryptography.SHA256]::Create().ComputeHash(
173
+ [System.Text.Encoding]::UTF8.GetBytes($nativeSource))).Replace('-', '').Substring(0, 16)
174
+ $inputDll = Join-Path $env:TEMP ('dsh-pilot-DshInput-' + $inputStamp + '.dll')
175
+ if (-not (Test-Path $inputDll)) {
176
+ $null = Add-Type -TypeDefinition $nativeSource -Language CSharp -ReferencedAssemblies System.Windows.Forms -OutputAssembly $inputDll
177
+ }
178
+ try { $null = Add-Type -Path $inputDll } catch {
179
+ $null = Add-Type -TypeDefinition $nativeSource -Language CSharp -ReferencedAssemblies System.Windows.Forms
180
+ }
181
+ $null = [DshInput]::BecomeDpiAware()
182
+ }
183
+
184
+ if (-not ('DshProbe' -as [type])) {
185
+ # ---------------------------------------------------------------- Win32 bridge
186
+ $nativeSource = @'
187
+ using System;
188
+ using System.Runtime.InteropServices;
189
+ using System.Text;
190
+ public static class DshProbe {
191
+ [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left, Top, Right, Bottom; }
192
+ [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
193
+ [DllImport("user32.dll")] public static extern IntPtr WindowFromPoint(POINT p);
194
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetWindowTextW(IntPtr h, StringBuilder s, int n);
195
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern int GetClassNameW(IntPtr h, StringBuilder s, int n);
196
+ [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr h, out RECT r);
197
+ [DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr h);
198
+ [DllImport("user32.dll")] public static extern bool IsIconic(IntPtr h);
199
+ [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
200
+ [DllImport("user32.dll")] public static extern uint GetWindowThreadProcessId(IntPtr h, out uint pid);
201
+ [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT p);
202
+ [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
203
+ [DllImport("user32.dll")] public static extern bool SetProcessDpiAwarenessContext(IntPtr value);
204
+ [DllImport("shcore.dll")] public static extern int SetProcessDpiAwareness(int value);
205
+ [DllImport("user32.dll")] public static extern int GetSystemMetrics(int index);
206
+
207
+ public static bool BecomeDpiAware() {
208
+ try { if (SetProcessDpiAwarenessContext(new IntPtr(-4))) return true; } catch {}
209
+ try { if (SetProcessDpiAwareness(2) == 0) return true; } catch {}
210
+ try { if (SetProcessDPIAware()) return true; } catch {}
211
+ return false;
212
+ }
213
+ public static RECT WindowRect(IntPtr h) { RECT r; GetWindowRect(h, out r); return r; }
214
+ public static POINT Cursor() { POINT p; GetCursorPos(out p); return p; }
215
+ public static string WindowTitle(IntPtr h) {
216
+ var sb = new StringBuilder(512);
217
+ GetWindowTextW(h, sb, sb.Capacity);
218
+ return sb.ToString();
219
+ }
220
+ public static string WindowClass(IntPtr h) {
221
+ var sb = new StringBuilder(256);
222
+ GetClassNameW(h, sb, sb.Capacity);
223
+ return sb.ToString();
224
+ }
225
+
226
+ // Monitor inventory, re-enumerated on every call.
227
+ //
228
+ // System.Windows.Forms.Screen.AllScreens is a static cache that only refreshes
229
+ // when the process pumps WM_DISPLAYCHANGE. The warm worker (desktop-worker.ps1)
230
+ // is a -NonInteractive read loop with no message pump, so that cache is never
231
+ // invalidated: after a resolution change it keeps reporting the geometry it saw
232
+ // at startup. That is how a frame came back with <screens>0,0,1600,900</screens>
233
+ // beside <image_size>1024x768</image_size> - two answers to the same question,
234
+ // in the very result the coordinate contract is read from. EnumDisplayMonitors
235
+ // has no cache to go stale.
236
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
237
+ public struct MONITORINFOEX {
238
+ public int cbSize;
239
+ public RECT rcMonitor;
240
+ public RECT rcWork;
241
+ public int dwFlags;
242
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string szDevice;
243
+ }
244
+ public delegate bool MonitorEnumProc(IntPtr hMonitor, IntPtr hdc, ref RECT lprcMonitor, IntPtr dwData);
245
+ [DllImport("user32.dll")] public static extern bool EnumDisplayMonitors(IntPtr hdc, IntPtr clip, MonitorEnumProc cb, IntPtr data);
246
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern bool GetMonitorInfoW(IntPtr hMonitor, ref MONITORINFOEX info);
247
+
248
+ // One line per monitor: device|primary|left|top|right|bottom
249
+ public static string[] Monitors() {
250
+ var rows = new System.Collections.Generic.List<string>();
251
+ MonitorEnumProc cb = delegate(IntPtr hMon, IntPtr hdc, ref RECT r, IntPtr data) {
252
+ var info = new MONITORINFOEX();
253
+ info.cbSize = Marshal.SizeOf(typeof(MONITORINFOEX));
254
+ if (GetMonitorInfoW(hMon, ref info)) {
255
+ bool primary = (info.dwFlags & 1) != 0;
256
+ rows.Add(info.szDevice + "|" + (primary ? "1" : "0") + "|" +
257
+ info.rcMonitor.Left + "|" + info.rcMonitor.Top + "|" +
258
+ info.rcMonitor.Right + "|" + info.rcMonitor.Bottom);
259
+ } else {
260
+ rows.Add("?|0|" + r.Left + "|" + r.Top + "|" + r.Right + "|" + r.Bottom);
261
+ }
262
+ return true;
263
+ };
264
+ EnumDisplayMonitors(IntPtr.Zero, IntPtr.Zero, cb, IntPtr.Zero);
265
+ return rows.ToArray();
266
+ }
267
+ }
268
+ '@
269
+ $probeStamp = [BitConverter]::ToString(
270
+ [System.Security.Cryptography.SHA256]::Create().ComputeHash(
271
+ [System.Text.Encoding]::UTF8.GetBytes($nativeSource))).Replace('-', '').Substring(0, 16)
272
+ $probeDll = Join-Path $env:TEMP ('dsh-pilot-DshProbe-' + $probeStamp + '.dll')
273
+ if (-not (Test-Path $probeDll)) {
274
+ $null = Add-Type -TypeDefinition $nativeSource -Language CSharp -OutputAssembly $probeDll
275
+ }
276
+ try { $null = Add-Type -Path $probeDll } catch {
277
+ $null = Add-Type -TypeDefinition $nativeSource -Language CSharp
278
+ }
279
+ $null = [DshProbe]::BecomeDpiAware()
214
280
  }
package/package.json CHANGED
@@ -1,58 +1,58 @@
1
- {
2
- "name": "@momasiku/dsh-pilot",
3
- "version": "0.5.7",
4
- "description": "Desktop vision and control for DeepSeek Harness - the whole Windows machine, any application, not browser automation: screen_view captures the live screen as an image the model can see, desktop_control drives the mouse, keyboard, and windows against the exact same pixel space; desktop_sequence runs a whole batch of actions in one call and looks once at the end.",
5
- "license": "MIT",
6
- "author": "momasiku",
7
- "type": "module",
8
- "main": "lib/index.js",
9
- "exports": {
10
- ".": "./lib/index.js",
11
- "./cordis.patch.yml": "./cordis.patch.yml",
12
- "./package.json": "./package.json"
13
- },
14
- "files": [
15
- "lib/index.js",
16
- "lib/scripts",
17
- "cordis.patch.yml",
18
- "README.md"
19
- ],
20
- "publishConfig": {
21
- "access": "public"
22
- },
23
- "dsh": {
24
- "bundle": {
25
- "patch": "./cordis.patch.yml"
26
- }
27
- },
28
- "keywords": [
29
- "dsh",
30
- "dsh-plugin",
31
- "deepseek-harness",
32
- "computer-use",
33
- "desktop-automation",
34
- "screenshot",
35
- "vision",
36
- "windows"
37
- ],
38
- "engines": {
39
- "node": "^22.19.0 || >=24.0.0"
40
- },
41
- "peerDependencies": {
42
- "@deepseek-ai/cordis": "^4.0.2",
43
- "@deepseek-ai/dsh-attachment": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
44
- "@deepseek-ai/dsh-llm": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
45
- "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0"
46
- },
47
- "dependencies": {
48
- "@deepseek-ai/schemastery": "^3.18.2"
49
- },
50
- "repository": {
51
- "type": "git",
52
- "url": "git+https://github.com/momasiku/dsh-pilot.git"
53
- },
54
- "homepage": "https://github.com/momasiku/dsh-pilot#readme",
55
- "bugs": {
56
- "url": "https://github.com/momasiku/dsh-pilot/issues"
57
- }
58
- }
1
+ {
2
+ "name": "@momasiku/dsh-pilot",
3
+ "version": "0.5.9",
4
+ "description": "Desktop vision and control for DeepSeek Harness - the whole Windows machine, any application, not browser automation: screen_view captures the live screen as an image the model can see, desktop_control drives the mouse, keyboard, and windows against the exact same pixel space; desktop_sequence runs a whole batch of actions in one call and looks once at the end.",
5
+ "license": "MIT",
6
+ "author": "momasiku",
7
+ "type": "module",
8
+ "main": "lib/index.js",
9
+ "exports": {
10
+ ".": "./lib/index.js",
11
+ "./cordis.patch.yml": "./cordis.patch.yml",
12
+ "./package.json": "./package.json"
13
+ },
14
+ "files": [
15
+ "lib/index.js",
16
+ "lib/scripts",
17
+ "cordis.patch.yml",
18
+ "README.md"
19
+ ],
20
+ "publishConfig": {
21
+ "access": "public"
22
+ },
23
+ "dsh": {
24
+ "bundle": {
25
+ "patch": "./cordis.patch.yml"
26
+ }
27
+ },
28
+ "keywords": [
29
+ "dsh",
30
+ "dsh-plugin",
31
+ "deepseek-harness",
32
+ "computer-use",
33
+ "desktop-automation",
34
+ "screenshot",
35
+ "vision",
36
+ "windows"
37
+ ],
38
+ "engines": {
39
+ "node": "^22.19.0 || >=24.0.0"
40
+ },
41
+ "peerDependencies": {
42
+ "@deepseek-ai/cordis": "^4.0.2",
43
+ "@deepseek-ai/dsh-attachment": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
44
+ "@deepseek-ai/dsh-llm": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0",
45
+ "@deepseek-ai/dsh-tools": ">=0.1.5-rc.2 <0.2.0 || >=0.2.0-rc.1 <0.3.0-0"
46
+ },
47
+ "dependencies": {
48
+ "@deepseek-ai/schemastery": "^3.18.2"
49
+ },
50
+ "repository": {
51
+ "type": "git",
52
+ "url": "git+https://github.com/momasiku/dsh-pilot.git"
53
+ },
54
+ "homepage": "https://github.com/momasiku/dsh-pilot#readme",
55
+ "bugs": {
56
+ "url": "https://github.com/momasiku/dsh-pilot/issues"
57
+ }
58
+ }