@jian-ai/remote-control 0.8.0 → 0.8.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jian-ai/remote-control",
3
- "version": "0.8.0",
3
+ "version": "0.8.2",
4
4
  "description": "Jian Remote Control worker — connect a computer to a Jian gateway over HTTPS",
5
5
  "type": "module",
6
6
  "bin": {
@@ -13,6 +13,8 @@
13
13
  "files": [
14
14
  "bin",
15
15
  "macos",
16
+ "linux",
17
+ "windows",
16
18
  "README.md"
17
19
  ],
18
20
  "engines": {
@@ -0,0 +1,500 @@
1
+ # Jian Remote Control — Windows computer-use helper
2
+ # JSON lines on stdin → JSON lines on stdout (same cmds as macOS/Linux helpers).
3
+ # Overlay: topmost transparent WinForms pointer (geometric white + blue glow).
4
+ # Input: SendInput with save/restore so agent clicks do not strand the user cursor.
5
+ # English-only errors.
6
+
7
+ $ErrorActionPreference = 'Stop'
8
+ Add-Type -AssemblyName System.Windows.Forms
9
+ Add-Type -AssemblyName System.Drawing
10
+
11
+ $script:PointerSize = 36
12
+ $script:HotspotX = 2
13
+ $script:HotspotY = 2
14
+ $script:TipX = 0.0
15
+ $script:TipY = 0.0
16
+ $script:HasTip = $false
17
+ $script:OverlayForm = $null
18
+ $script:SessionActive = $false
19
+
20
+ Add-Type @"
21
+ using System;
22
+ using System.Runtime.InteropServices;
23
+ public static class JianInput {
24
+ [StructLayout(LayoutKind.Sequential)]
25
+ public struct INPUT {
26
+ public uint type;
27
+ public InputUnion U;
28
+ }
29
+ [StructLayout(LayoutKind.Explicit)]
30
+ public struct InputUnion {
31
+ [FieldOffset(0)] public MOUSEINPUT mi;
32
+ [FieldOffset(0)] public KEYBDINPUT ki;
33
+ }
34
+ [StructLayout(LayoutKind.Sequential)]
35
+ public struct MOUSEINPUT {
36
+ public int dx;
37
+ public int dy;
38
+ public uint mouseData;
39
+ public uint dwFlags;
40
+ public uint time;
41
+ public IntPtr dwExtraInfo;
42
+ }
43
+ [StructLayout(LayoutKind.Sequential)]
44
+ public struct KEYBDINPUT {
45
+ public ushort wVk;
46
+ public ushort wScan;
47
+ public uint dwFlags;
48
+ public uint time;
49
+ public IntPtr dwExtraInfo;
50
+ }
51
+ [StructLayout(LayoutKind.Sequential)]
52
+ public struct POINT { public int X; public int Y; }
53
+
54
+ public const uint INPUT_MOUSE = 0;
55
+ public const uint INPUT_KEYBOARD = 1;
56
+ public const uint MOUSEEVENTF_MOVE = 0x0001;
57
+ public const uint MOUSEEVENTF_LEFTDOWN = 0x0002;
58
+ public const uint MOUSEEVENTF_LEFTUP = 0x0004;
59
+ public const uint MOUSEEVENTF_RIGHTDOWN = 0x0008;
60
+ public const uint MOUSEEVENTF_RIGHTUP = 0x0010;
61
+ public const uint MOUSEEVENTF_WHEEL = 0x0800;
62
+ public const uint MOUSEEVENTF_HWHEEL = 0x1000;
63
+ public const uint MOUSEEVENTF_ABSOLUTE = 0x8000;
64
+ public const uint KEYEVENTF_KEYUP = 0x0002;
65
+ public const uint KEYEVENTF_UNICODE = 0x0004;
66
+
67
+ [DllImport("user32.dll")] public static extern bool SetCursorPos(int X, int Y);
68
+ [DllImport("user32.dll")] public static extern bool GetCursorPos(out POINT lpPoint);
69
+ [DllImport("user32.dll")] public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
70
+ [DllImport("user32.dll")] public static extern int ShowCursor(bool bShow);
71
+ [DllImport("user32.dll")] public static extern short VkKeyScan(char ch);
72
+ [DllImport("user32.dll")] public static extern uint MapVirtualKey(uint uCode, uint uMapType);
73
+ }
74
+ "@
75
+
76
+ function Write-Response($obj) {
77
+ $json = ($obj | ConvertTo-Json -Compress -Depth 6)
78
+ [Console]::Out.WriteLine($json)
79
+ [Console]::Out.Flush()
80
+ }
81
+
82
+ function Write-Ok([hashtable]$extra = @{}) {
83
+ $body = @{ ok = $true }
84
+ foreach ($k in $extra.Keys) { $body[$k] = $extra[$k] }
85
+ Write-Response $body
86
+ }
87
+
88
+ function Write-Err([string]$message) {
89
+ Write-Response @{ ok = $false; error = $message }
90
+ }
91
+
92
+ function Get-PrimaryBounds {
93
+ [System.Windows.Forms.Screen]::PrimaryScreen.Bounds
94
+ }
95
+
96
+ function Ease-OutCubic([double]$t) {
97
+ $x = [Math]::Min(1.0, [Math]::Max(0.0, $t))
98
+ return 1.0 - [Math]::Pow(1.0 - $x, 3)
99
+ }
100
+
101
+ function Ensure-Overlay {
102
+ if ($script:OverlayForm -ne $null) { return }
103
+ $form = New-Object System.Windows.Forms.Form
104
+ $form.FormBorderStyle = [System.Windows.Forms.FormBorderStyle]::None
105
+ $form.ShowInTaskbar = $false
106
+ $form.TopMost = $true
107
+ $form.StartPosition = [System.Windows.Forms.FormStartPosition]::Manual
108
+ $form.Size = New-Object System.Drawing.Size($script:PointerSize, $script:PointerSize)
109
+ $form.BackColor = [System.Drawing.Color]::Magenta
110
+ $form.TransparencyKey = [System.Drawing.Color]::Magenta
111
+ $form.Opacity = 0.94
112
+ $form.Enabled = $false
113
+ $form.Add_Paint({
114
+ param($sender, $e)
115
+ $g = $e.Graphics
116
+ $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
117
+ $pts = @(
118
+ (New-Object System.Drawing.Point(2, 2)),
119
+ (New-Object System.Drawing.Point(2, 26)),
120
+ (New-Object System.Drawing.Point(10, 20)),
121
+ (New-Object System.Drawing.Point(15, 32)),
122
+ (New-Object System.Drawing.Point(20, 30)),
123
+ (New-Object System.Drawing.Point(13, 17)),
124
+ (New-Object System.Drawing.Point(22, 17))
125
+ )
126
+ $glowBrush = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(140, 58, 122, 214))
127
+ $glowPts = @(
128
+ (New-Object System.Drawing.Point(3, 4)),
129
+ (New-Object System.Drawing.Point(3, 28)),
130
+ (New-Object System.Drawing.Point(11, 22)),
131
+ (New-Object System.Drawing.Point(16, 34)),
132
+ (New-Object System.Drawing.Point(21, 32)),
133
+ (New-Object System.Drawing.Point(14, 19)),
134
+ (New-Object System.Drawing.Point(23, 19))
135
+ )
136
+ $g.FillPolygon($glowBrush, $glowPts)
137
+ $fill = New-Object System.Drawing.SolidBrush ([System.Drawing.Color]::FromArgb(255, 250, 250, 248))
138
+ $g.FillPolygon($fill, $pts)
139
+ $pen = New-Object System.Drawing.Pen ([System.Drawing.Color]::FromArgb(220, 23, 23, 22), 1.1)
140
+ $g.DrawPolygon($pen, $pts)
141
+ $glowBrush.Dispose(); $fill.Dispose(); $pen.Dispose()
142
+ })
143
+ $script:OverlayForm = $form
144
+ }
145
+
146
+ function Position-Overlay {
147
+ if ($script:OverlayForm -eq $null) { return }
148
+ $x = [int]($script:TipX - $script:HotspotX)
149
+ $y = [int]($script:TipY - $script:HotspotY)
150
+ $script:OverlayForm.Location = New-Object System.Drawing.Point($x, $y)
151
+ }
152
+
153
+ function Ensure-Session {
154
+ Ensure-Overlay
155
+ if (-not $script:HasTip) {
156
+ $b = Get-PrimaryBounds
157
+ $script:TipX = $b.Width / 2
158
+ $script:TipY = $b.Height / 2
159
+ $script:HasTip = $true
160
+ }
161
+ Position-Overlay
162
+ if (-not $script:OverlayForm.Visible) {
163
+ $script:OverlayForm.Show()
164
+ }
165
+ $script:OverlayForm.Opacity = 0.94
166
+ $script:OverlayForm.Invalidate()
167
+ $script:SessionActive = $true
168
+ [System.Windows.Forms.Application]::DoEvents()
169
+ }
170
+
171
+ function Set-Idle {
172
+ Ensure-Session
173
+ $script:OverlayForm.Opacity = 0.18
174
+ [System.Windows.Forms.Application]::DoEvents()
175
+ }
176
+
177
+ function End-Session {
178
+ if ($script:OverlayForm -ne $null) {
179
+ $script:OverlayForm.Hide()
180
+ $script:OverlayForm.Opacity = 0
181
+ }
182
+ $script:SessionActive = $false
183
+ $script:HasTip = $false
184
+ [System.Windows.Forms.Application]::DoEvents()
185
+ }
186
+
187
+ function Move-Tip([double]$x, [double]$y) {
188
+ $script:TipX = $x
189
+ $script:TipY = $y
190
+ $script:HasTip = $true
191
+ Ensure-Overlay
192
+ if ($script:SessionActive -or $true) {
193
+ if (-not $script:OverlayForm.Visible) { $script:OverlayForm.Show() }
194
+ }
195
+ Position-Overlay
196
+ $script:OverlayForm.Invalidate()
197
+ [System.Windows.Forms.Application]::DoEvents()
198
+ }
199
+
200
+ function Animate-Overlay([double]$tx, [double]$ty) {
201
+ Ensure-Session
202
+ $sx = $script:TipX
203
+ $sy = $script:TipY
204
+ $dx = $tx - $sx
205
+ $dy = $ty - $sy
206
+ $distance = [Math]::Sqrt($dx * $dx + $dy * $dy)
207
+ if ($distance -lt 1.5) {
208
+ Move-Tip $tx $ty
209
+ return
210
+ }
211
+ $duration = [Math]::Min(0.11, [Math]::Max(0.028, $distance * 0.00025))
212
+ $steps = [Math]::Max(1, [int][Math]::Ceiling($duration * 60))
213
+ $stepSleep = $duration / $steps
214
+ for ($i = 1; $i -le $steps; $i++) {
215
+ $t = Ease-OutCubic ($i / $steps)
216
+ Move-Tip ($sx + $dx * $t) ($sy + $dy * $t)
217
+ if ($i -lt $steps) { Start-Sleep -Milliseconds ([Math]::Max(1, [int]($stepSleep * 1000))) }
218
+ }
219
+ Move-Tip $tx $ty
220
+ }
221
+
222
+ function Get-CursorPos {
223
+ $p = New-Object JianInput+POINT
224
+ [void][JianInput]::GetCursorPos([ref]$p)
225
+ return @($p.X, $p.Y)
226
+ }
227
+
228
+ function Warp-Cursor([int]$x, [int]$y) {
229
+ [void][JianInput]::SetCursorPos($x, $y)
230
+ }
231
+
232
+ function With-PreservedCursor([scriptblock]$body) {
233
+ $saved = Get-CursorPos
234
+ [void][JianInput]::ShowCursor($false)
235
+ try {
236
+ & $body
237
+ } finally {
238
+ Warp-Cursor $saved[0] $saved[1]
239
+ Start-Sleep -Milliseconds 8
240
+ [void][JianInput]::ShowCursor($true)
241
+ }
242
+ }
243
+
244
+ function Send-MouseClick([string]$button, [int]$count) {
245
+ $down = if ($button -eq 'right') { [JianInput]::MOUSEEVENTF_RIGHTDOWN } else { [JianInput]::MOUSEEVENTF_LEFTDOWN }
246
+ $up = if ($button -eq 'right') { [JianInput]::MOUSEEVENTF_RIGHTUP } else { [JianInput]::MOUSEEVENTF_LEFTUP }
247
+ for ($i = 0; $i -lt $count; $i++) {
248
+ $inputs = @(
249
+ New-Object JianInput+INPUT
250
+ New-Object JianInput+INPUT
251
+ )
252
+ $inputs[0].type = [JianInput]::INPUT_MOUSE
253
+ $inputs[0].U.mi.dwFlags = $down
254
+ $inputs[1].type = [JianInput]::INPUT_MOUSE
255
+ $inputs[1].U.mi.dwFlags = $up
256
+ [void][JianInput]::SendInput(2, $inputs, [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
257
+ if ($i -lt $count - 1) { Start-Sleep -Milliseconds 40 }
258
+ }
259
+ }
260
+
261
+ function Click-At([double]$x, [double]$y, [string]$button, [int]$count) {
262
+ Animate-Overlay $x $y
263
+ With-PreservedCursor {
264
+ Warp-Cursor ([int]$x) ([int]$y)
265
+ Send-MouseClick $button $count
266
+ }
267
+ }
268
+
269
+ function Drag-To([double]$fx, [double]$fy, [double]$tx, [double]$ty) {
270
+ Animate-Overlay $fx $fy
271
+ With-PreservedCursor {
272
+ Warp-Cursor ([int]$fx) ([int]$fy)
273
+ $down = New-Object JianInput+INPUT
274
+ $down.type = [JianInput]::INPUT_MOUSE
275
+ $down.U.mi.dwFlags = [JianInput]::MOUSEEVENTF_LEFTDOWN
276
+ [void][JianInput]::SendInput(1, @($down), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
277
+ $distance = [Math]::Sqrt(($tx - $fx) * ($tx - $fx) + ($ty - $fy) * ($ty - $fy))
278
+ $steps = [Math]::Max(6, [Math]::Min(14, [int]($distance / 40) + 6))
279
+ for ($i = 1; $i -le $steps; $i++) {
280
+ $t = Ease-OutCubic ($i / $steps)
281
+ $px = $fx + ($tx - $fx) * $t
282
+ $py = $fy + ($ty - $fy) * $t
283
+ Move-Tip $px $py
284
+ Warp-Cursor ([int]$px) ([int]$py)
285
+ Start-Sleep -Milliseconds 6
286
+ }
287
+ $up = New-Object JianInput+INPUT
288
+ $up.type = [JianInput]::INPUT_MOUSE
289
+ $up.U.mi.dwFlags = [JianInput]::MOUSEEVENTF_LEFTUP
290
+ [void][JianInput]::SendInput(1, @($up), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
291
+ }
292
+ Move-Tip $tx $ty
293
+ }
294
+
295
+ function Scroll-At([double]$x, [double]$y, [string]$direction, [int]$amount) {
296
+ Animate-Overlay $x $y
297
+ $wheel = 0
298
+ $hwheel = 0
299
+ switch ($direction) {
300
+ 'up' { $wheel = 120 }
301
+ 'down' { $wheel = -120 }
302
+ 'left' { $hwheel = -120 }
303
+ 'right' { $hwheel = 120 }
304
+ }
305
+ With-PreservedCursor {
306
+ Warp-Cursor ([int]$x) ([int]$y)
307
+ for ($i = 0; $i -lt [Math]::Max(1, $amount); $i++) {
308
+ $inp = New-Object JianInput+INPUT
309
+ $inp.type = [JianInput]::INPUT_MOUSE
310
+ if ($wheel -ne 0) {
311
+ $inp.U.mi.dwFlags = [JianInput]::MOUSEEVENTF_WHEEL
312
+ $inp.U.mi.mouseData = [uint32]([int32]$wheel)
313
+ } else {
314
+ $inp.U.mi.dwFlags = [JianInput]::MOUSEEVENTF_HWHEEL
315
+ $inp.U.mi.mouseData = [uint32]([int32]$hwheel)
316
+ }
317
+ [void][JianInput]::SendInput(1, @($inp), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
318
+ Start-Sleep -Milliseconds 12
319
+ }
320
+ }
321
+ }
322
+
323
+ function Type-Text([string]$text) {
324
+ foreach ($ch in $text.ToCharArray()) {
325
+ if ($ch -eq "`n" -or $ch -eq "`r") {
326
+ Post-Key 0x0D
327
+ continue
328
+ }
329
+ if ($ch -eq "`t") {
330
+ Post-Key 0x09
331
+ continue
332
+ }
333
+ $inputs = @(
334
+ New-Object JianInput+INPUT
335
+ New-Object JianInput+INPUT
336
+ )
337
+ $inputs[0].type = [JianInput]::INPUT_KEYBOARD
338
+ $inputs[0].U.ki.wScan = [uint16][int][char]$ch
339
+ $inputs[0].U.ki.dwFlags = [JianInput]::KEYEVENTF_UNICODE
340
+ $inputs[1].type = [JianInput]::INPUT_KEYBOARD
341
+ $inputs[1].U.ki.wScan = [uint16][int][char]$ch
342
+ $inputs[1].U.ki.dwFlags = [JianInput]::KEYEVENTF_UNICODE -bor [JianInput]::KEYEVENTF_KEYUP
343
+ [void][JianInput]::SendInput(2, $inputs, [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
344
+ Start-Sleep -Milliseconds 2
345
+ }
346
+ }
347
+
348
+ function Post-Key([ushort]$vk, [uint32]$flags = 0) {
349
+ $down = New-Object JianInput+INPUT
350
+ $down.type = [JianInput]::INPUT_KEYBOARD
351
+ $down.U.ki.wVk = $vk
352
+ $down.U.ki.dwFlags = $flags
353
+ $up = New-Object JianInput+INPUT
354
+ $up.type = [JianInput]::INPUT_KEYBOARD
355
+ $up.U.ki.wVk = $vk
356
+ $up.U.ki.dwFlags = $flags -bor [JianInput]::KEYEVENTF_KEYUP
357
+ [void][JianInput]::SendInput(2, @($down, $up), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
358
+ }
359
+
360
+ function Parse-And-PostKey([string]$keySpec) {
361
+ $parts = $keySpec.Split('+') | ForEach-Object { $_.Trim().ToLowerInvariant() } | Where-Object { $_ }
362
+ if (-not $parts) { return $false }
363
+ $mods = @()
364
+ $key = $null
365
+ foreach ($part in $parts) {
366
+ switch ($part) {
367
+ { $_ -in @('cmd','command','meta','super','win','windows') } { $mods += 0x5B; break }
368
+ { $_ -in @('ctrl','control') } { $mods += 0x11; break }
369
+ { $_ -in @('alt','option','opt') } { $mods += 0x12; break }
370
+ 'shift' { $mods += 0x10; break }
371
+ default {
372
+ if ($null -ne $key) { return $false }
373
+ $key = $part
374
+ }
375
+ }
376
+ }
377
+ if ($null -eq $key) { return $false }
378
+ $named = @{
379
+ return = 0x0D; enter = 0x0D; tab = 0x09; escape = 0x1B; esc = 0x1B
380
+ delete = 0x2E; backspace = 0x08; space = 0x20
381
+ up = 0x26; down = 0x28; left = 0x25; right = 0x27
382
+ home = 0x24; end = 0x23; pageup = 0x21; pagedown = 0x22
383
+ }
384
+ $vk = $null
385
+ if ($named.ContainsKey($key)) { $vk = [ushort]$named[$key] }
386
+ elseif ($key.Length -eq 1) {
387
+ $scan = [JianInput]::VkKeyScan([char]$key[0])
388
+ if ($scan -eq -1) { return $false }
389
+ $vk = [ushort]($scan -band 0xFF)
390
+ }
391
+ elseif ($key.StartsWith('f') -and $key.Substring(1) -match '^\d+$') {
392
+ $n = [int]$key.Substring(1)
393
+ if ($n -ge 1 -and $n -le 12) { $vk = [ushort](0x70 + $n - 1) }
394
+ }
395
+ if ($null -eq $vk) { return $false }
396
+ foreach ($m in $mods) {
397
+ $down = New-Object JianInput+INPUT
398
+ $down.type = [JianInput]::INPUT_KEYBOARD
399
+ $down.U.ki.wVk = [ushort]$m
400
+ [void][JianInput]::SendInput(1, @($down), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
401
+ }
402
+ Post-Key $vk
403
+ for ($i = $mods.Count - 1; $i -ge 0; $i--) {
404
+ $up = New-Object JianInput+INPUT
405
+ $up.type = [JianInput]::INPUT_KEYBOARD
406
+ $up.U.ki.wVk = [ushort]$mods[$i]
407
+ $up.U.ki.dwFlags = [JianInput]::KEYEVENTF_KEYUP
408
+ [void][JianInput]::SendInput(1, @($up), [System.Runtime.InteropServices.Marshal]::SizeOf([type][JianInput+INPUT]))
409
+ }
410
+ return $true
411
+ }
412
+
413
+ function Geometry-Response {
414
+ $b = Get-PrimaryBounds
415
+ return @{
416
+ ok = $true
417
+ originX = 0
418
+ originY = 0
419
+ pointWidth = [double]$b.Width
420
+ pointHeight = [double]$b.Height
421
+ pixelWidth = [double]$b.Width
422
+ pixelHeight = [double]$b.Height
423
+ scaleFactor = 1.0
424
+ }
425
+ }
426
+
427
+ function Handle-Command($obj) {
428
+ $cmd = [string]$obj.cmd
429
+ switch ($cmd) {
430
+ 'ping' { Write-Ok; break }
431
+ 'geometry' { Write-Response (Geometry-Response); break }
432
+ 'ensureSession' { Ensure-Session; Write-Ok; break }
433
+ 'setIdle' { Set-Idle; Write-Ok; break }
434
+ 'endSession' { End-Session; Write-Ok; break }
435
+ 'move' {
436
+ Animate-Overlay ([double]$obj.pointX) ([double]$obj.pointY)
437
+ Write-Ok
438
+ break
439
+ }
440
+ 'click' {
441
+ $button = if ($obj.button) { [string]$obj.button } else { 'left' }
442
+ $count = if ($obj.count) { [int]$obj.count } else { 1 }
443
+ Click-At $script:TipX $script:TipY $button.ToLowerInvariant() $count
444
+ Write-Ok
445
+ break
446
+ }
447
+ 'clickAt' {
448
+ $button = if ($obj.button) { [string]$obj.button } else { 'left' }
449
+ $count = if ($obj.count) { [int]$obj.count } else { 1 }
450
+ Click-At ([double]$obj.pointX) ([double]$obj.pointY) $button.ToLowerInvariant() $count
451
+ Write-Ok
452
+ break
453
+ }
454
+ 'drag' {
455
+ Drag-To ([double]$obj.fromX) ([double]$obj.fromY) ([double]$obj.toX) ([double]$obj.toY)
456
+ Write-Ok
457
+ break
458
+ }
459
+ 'type' {
460
+ Type-Text ([string]$obj.text)
461
+ Write-Ok
462
+ break
463
+ }
464
+ 'key' {
465
+ if (Parse-And-PostKey ([string]$obj.key)) { Write-Ok }
466
+ else { Write-Err ("unrecognized key: " + $obj.key) }
467
+ break
468
+ }
469
+ 'scroll' {
470
+ Scroll-At ([double]$obj.pointX) ([double]$obj.pointY) ([string]$obj.direction).ToLowerInvariant() ([int]$obj.amount)
471
+ Write-Ok
472
+ break
473
+ }
474
+ default { Write-Err ("unknown cmd: " + $cmd) }
475
+ }
476
+ }
477
+
478
+ [Console]::InputEncoding = [System.Text.UTF8Encoding]::new($false)
479
+ [Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)
480
+
481
+ while ($true) {
482
+ $line = [Console]::In.ReadLine()
483
+ if ($null -eq $line) { break }
484
+ $line = $line.Trim()
485
+ if (-not $line) { continue }
486
+ try {
487
+ $obj = $line | ConvertFrom-Json
488
+ Handle-Command $obj
489
+ } catch {
490
+ [Console]::Error.WriteLine("computer-helper: $($_.Exception.Message)")
491
+ Write-Err $_.Exception.Message
492
+ }
493
+ [System.Windows.Forms.Application]::DoEvents()
494
+ }
495
+
496
+ End-Session
497
+ if ($script:OverlayForm -ne $null) {
498
+ $script:OverlayForm.Close()
499
+ $script:OverlayForm.Dispose()
500
+ }