@anusornneal/chat-relay 0.7.2 → 0.8.1

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,288 +0,0 @@
1
- param(
2
- [Parameter(Mandatory=$true)][string]$Operation,
3
- [Parameter(Mandatory=$true)][string]$InputBase64
4
- )
5
-
6
- $ErrorActionPreference = "Stop"
7
- $ProgressPreference = "SilentlyContinue"
8
-
9
- function Write-Result($Value) {
10
- $Value | ConvertTo-Json -Compress -Depth 8
11
- }
12
-
13
- function Fail($Code) {
14
- Write-Result ([pscustomobject]@{ ok = $false; error = $Code })
15
- exit 0
16
- }
17
-
18
- try {
19
- $inputJson = [Text.Encoding]::UTF8.GetString([Convert]::FromBase64String($InputBase64))
20
- $payload = if ($inputJson) { $inputJson | ConvertFrom-Json } else { [pscustomobject]@{} }
21
-
22
- Add-Type -AssemblyName System.Windows.Forms
23
- Add-Type -AssemblyName System.Drawing
24
- Add-Type @"
25
- using System;
26
- using System.Runtime.InteropServices;
27
-
28
- public static class ChatRelayNative {
29
- public const uint INPUT_MOUSE = 0;
30
- public const uint INPUT_KEYBOARD = 1;
31
- public const uint KEYEVENTF_KEYUP = 0x0002;
32
- public const uint KEYEVENTF_UNICODE = 0x0004;
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 UIntPtr dwExtraInfo;
42
- }
43
-
44
- [StructLayout(LayoutKind.Sequential)]
45
- public struct KEYBDINPUT {
46
- public ushort wVk;
47
- public ushort wScan;
48
- public uint dwFlags;
49
- public uint time;
50
- public UIntPtr dwExtraInfo;
51
- }
52
-
53
- [StructLayout(LayoutKind.Explicit)]
54
- public struct INPUTUNION {
55
- [FieldOffset(0)] public MOUSEINPUT mi;
56
- [FieldOffset(0)] public KEYBDINPUT ki;
57
- }
58
-
59
- [StructLayout(LayoutKind.Sequential)]
60
- public struct INPUT {
61
- public uint type;
62
- public INPUTUNION U;
63
- }
64
-
65
- [DllImport("user32.dll")] public static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);
66
- [DllImport("user32.dll")] public static extern bool SetCursorPos(int X, int Y);
67
- [DllImport("user32.dll")] public static extern bool SetProcessDPIAware();
68
- [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
69
-
70
- public static bool MouseButton(uint downFlag, uint upFlag) {
71
- var inputs = new INPUT[2];
72
- inputs[0].type = INPUT_MOUSE;
73
- inputs[0].U.mi.dwFlags = downFlag;
74
- inputs[1].type = INPUT_MOUSE;
75
- inputs[1].U.mi.dwFlags = upFlag;
76
- return SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) == 2;
77
- }
78
-
79
- public static bool Key(ushort virtualKey, bool down) {
80
- var input = new INPUT[1];
81
- input[0].type = INPUT_KEYBOARD;
82
- input[0].U.ki.wVk = virtualKey;
83
- input[0].U.ki.dwFlags = down ? 0u : KEYEVENTF_KEYUP;
84
- return SendInput(1, input, Marshal.SizeOf(typeof(INPUT))) == 1;
85
- }
86
-
87
- public static bool UnicodeText(string text) {
88
- foreach (char c in text) {
89
- var inputs = new INPUT[2];
90
- inputs[0].type = INPUT_KEYBOARD;
91
- inputs[0].U.ki.wScan = c;
92
- inputs[0].U.ki.dwFlags = KEYEVENTF_UNICODE;
93
- inputs[1].type = INPUT_KEYBOARD;
94
- inputs[1].U.ki.wScan = c;
95
- inputs[1].U.ki.dwFlags = KEYEVENTF_UNICODE | KEYEVENTF_KEYUP;
96
- if (SendInput(2, inputs, Marshal.SizeOf(typeof(INPUT))) != 2) return false;
97
- }
98
- return true;
99
- }
100
- }
101
- "@
102
-
103
- [ChatRelayNative]::SetProcessDPIAware() | Out-Null
104
- if (-not [System.Windows.Forms.SystemInformation]::UserInteractive) {
105
- Fail "session_unavailable"
106
- }
107
-
108
- if ($Operation -eq "screenshot") {
109
- $screens = @([System.Windows.Forms.Screen]::AllScreens)
110
- if ($screens.Count -eq 0) { Fail "session_unavailable" }
111
-
112
- $monitor = if ($null -ne $payload.monitor) { $payload.monitor } else { "primary" }
113
- $screen = $null
114
- $monitorIndex = -1
115
-
116
- if ([string]$monitor -eq "primary") {
117
- $screen = [System.Windows.Forms.Screen]::PrimaryScreen
118
- for ($i = 0; $i -lt $screens.Count; $i++) { if ($screens[$i].Primary) { $monitorIndex = $i; break } }
119
- } elseif ([string]$monitor -eq "secondary") {
120
- for ($i = 0; $i -lt $screens.Count; $i++) {
121
- if (-not $screens[$i].Primary) { $screen = $screens[$i]; $monitorIndex = $i; break }
122
- }
123
- if ($null -eq $screen) { Fail "monitor_not_found" }
124
- } else {
125
- $parsedIndex = 0
126
- if (-not [int]::TryParse([string]$monitor, [ref]$parsedIndex)) { Fail "invalid_monitor" }
127
- if ($parsedIndex -lt 0 -or $parsedIndex -ge $screens.Count) { Fail "monitor_not_found" }
128
- $screen = $screens[$parsedIndex]
129
- $monitorIndex = $parsedIndex
130
- }
131
-
132
- if ($null -eq $screen) { Fail "session_unavailable" }
133
- $bounds = $screen.Bounds
134
- if ($bounds.Width -le 0 -or $bounds.Height -le 0) { Fail "session_unavailable" }
135
-
136
- $source = New-Object System.Drawing.Bitmap $bounds.Width, $bounds.Height
137
- $graphics = [System.Drawing.Graphics]::FromImage($source)
138
- try {
139
- $graphics.CopyFromScreen($bounds.Left, $bounds.Top, 0, 0, $bounds.Size)
140
- } finally {
141
- $graphics.Dispose()
142
- }
143
-
144
- $codec = [System.Drawing.Imaging.ImageCodecInfo]::GetImageEncoders() |
145
- Where-Object { $_.MimeType -eq "image/jpeg" } |
146
- Select-Object -First 1
147
- if ($null -eq $codec) {
148
- $source.Dispose()
149
- Fail "capture_failed"
150
- }
151
-
152
- $maxBytes = 32768
153
- $targetWidth = [Math]::Min($bounds.Width, 960)
154
- $scale = $targetWidth / [double]$bounds.Width
155
- $targetHeight = [Math]::Max(1, [int][Math]::Round($bounds.Height * $scale))
156
- $qualities = @(70L, 55L, 42L, 32L, 24L)
157
- $bytes = $null
158
- $finalWidth = $targetWidth
159
- $finalHeight = $targetHeight
160
-
161
- for ($sizeAttempt = 0; $sizeAttempt -lt 4 -and $null -eq $bytes; $sizeAttempt++) {
162
- $resized = New-Object System.Drawing.Bitmap $targetWidth, $targetHeight
163
- $draw = [System.Drawing.Graphics]::FromImage($resized)
164
- try {
165
- $draw.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
166
- $draw.DrawImage($source, 0, 0, $targetWidth, $targetHeight)
167
- } finally {
168
- $draw.Dispose()
169
- }
170
-
171
- foreach ($quality in $qualities) {
172
- $stream = New-Object System.IO.MemoryStream
173
- $parameters = New-Object System.Drawing.Imaging.EncoderParameters 1
174
- $parameters.Param[0] = New-Object System.Drawing.Imaging.EncoderParameter(
175
- [System.Drawing.Imaging.Encoder]::Quality,
176
- $quality
177
- )
178
- try {
179
- $resized.Save($stream, $codec, $parameters)
180
- if ($stream.Length -le $maxBytes) {
181
- $bytes = $stream.ToArray()
182
- $finalWidth = $targetWidth
183
- $finalHeight = $targetHeight
184
- break
185
- }
186
- } finally {
187
- $parameters.Dispose()
188
- $stream.Dispose()
189
- }
190
- }
191
-
192
- $resized.Dispose()
193
- if ($null -eq $bytes) {
194
- $targetWidth = [Math]::Max(320, [int][Math]::Floor($targetWidth * 0.78))
195
- $targetHeight = [Math]::Max(180, [int][Math]::Round($bounds.Height * ($targetWidth / [double]$bounds.Width)))
196
- }
197
- }
198
-
199
- $source.Dispose()
200
- if ($null -eq $bytes) { Fail "screenshot_too_large" }
201
-
202
- Write-Result ([pscustomobject]@{
203
- ok = $true
204
- mimeType = "image/jpeg"
205
- data = [Convert]::ToBase64String($bytes)
206
- width = $finalWidth
207
- height = $finalHeight
208
- desktopOriginX = $bounds.Left
209
- desktopOriginY = $bounds.Top
210
- desktopWidth = $bounds.Width
211
- desktopHeight = $bounds.Height
212
- scaleX = $bounds.Width / [double]$finalWidth
213
- scaleY = $bounds.Height / [double]$finalHeight
214
- monitorIndex = $monitorIndex
215
- isPrimary = [bool]$screen.Primary
216
- deviceName = [string]$screen.DeviceName
217
- byteLength = $bytes.Length
218
- })
219
- exit 0
220
- }
221
-
222
- if ([ChatRelayNative]::GetForegroundWindow() -eq [IntPtr]::Zero) {
223
- Fail "session_unavailable"
224
- }
225
-
226
- if ($Operation -eq "mouse_click") {
227
- $screen = [System.Windows.Forms.Screen]::PrimaryScreen
228
- if ($null -eq $screen) { Fail "session_unavailable" }
229
- $bounds = $screen.Bounds
230
- $x = [int]$payload.x
231
- $y = [int]$payload.y
232
- if ($x -lt $bounds.Left -or $x -ge $bounds.Right -or $y -lt $bounds.Top -or $y -ge $bounds.Bottom) {
233
- Fail "invalid_coordinates"
234
- }
235
-
236
- switch ([string]$payload.button) {
237
- "left" { $down = 0x0002; $up = 0x0004 }
238
- "right" { $down = 0x0008; $up = 0x0010 }
239
- "middle" { $down = 0x0020; $up = 0x0040 }
240
- default { Fail "invalid_button" }
241
- }
242
-
243
- if (-not [ChatRelayNative]::SetCursorPos($x, $y)) { Fail "input_failed" }
244
- $clicks = [int]$payload.clicks
245
- for ($i = 0; $i -lt $clicks; $i++) {
246
- if (-not [ChatRelayNative]::MouseButton($down, $up)) { Fail "input_failed" }
247
- if ($i + 1 -lt $clicks) { Start-Sleep -Milliseconds 100 }
248
- }
249
-
250
- Write-Result ([pscustomobject]@{ ok = $true; action = "mouse_click" })
251
- exit 0
252
- }
253
-
254
- if ($Operation -eq "keyboard_input") {
255
- if ($null -ne $payload.text) {
256
- if (-not [ChatRelayNative]::UnicodeText([string]$payload.text)) { Fail "input_failed" }
257
- } else {
258
- $mods = New-Object System.Collections.Generic.List[uint16]
259
- if ($payload.ctrl) { $mods.Add(0x11) }
260
- if ($payload.alt) { $mods.Add(0x12) }
261
- if ($payload.shift) { $mods.Add(0x10) }
262
- if ($payload.win) { $mods.Add(0x5B) }
263
-
264
- foreach ($vk in $mods) {
265
- if (-not [ChatRelayNative]::Key($vk, $true)) { Fail "input_failed" }
266
- }
267
- try {
268
- $keyCode = [uint16]$payload.keyCode
269
- if (-not [ChatRelayNative]::Key($keyCode, $true)) { Fail "input_failed" }
270
- if (-not [ChatRelayNative]::Key($keyCode, $false)) { Fail "input_failed" }
271
- } finally {
272
- for ($i = $mods.Count - 1; $i -ge 0; $i--) {
273
- [ChatRelayNative]::Key($mods[$i], $false) | Out-Null
274
- }
275
- }
276
- }
277
-
278
- Write-Result ([pscustomobject]@{ ok = $true; action = "keyboard_input" })
279
- exit 0
280
- }
281
-
282
- Fail "unknown_desktop_operation"
283
- } catch {
284
- $message = [string]$_.Exception.Message
285
- if ($message -match "session_unavailable") { Fail "session_unavailable" }
286
- if ($Operation -eq "screenshot") { Fail "capture_failed" }
287
- Fail "input_failed"
288
- }