deepseek-computer-use 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.
@@ -0,0 +1,669 @@
1
+ using System;
2
+ using System.Drawing;
3
+ using System.Drawing.Drawing2D;
4
+ using System.Drawing.Imaging;
5
+ using System.IO;
6
+ using System.Runtime.InteropServices;
7
+ using System.Windows.Forms;
8
+
9
+ // "DSH is using your computer" indicator, modelled on Codex's overlays:
10
+ // * Display Overlay - a breathing accent border around the whole virtual screen
11
+ // (Codex: "border size breath" / "border offset breath")
12
+ // * Cursor Overlay - a virtual cursor that glides to every pointer action, with
13
+ // optional suppression of the real system cursor
14
+ // * Esc - kill switch; writes a cancel file the helper checks before
15
+ // it injects anything
16
+ // Everything is layered, per-pixel alpha, click-through and never takes focus.
17
+ public sealed class Config
18
+ {
19
+ public static string CancelFile = "";
20
+ public static string CursorFile = "";
21
+ public static string AccentHex = "#3f7fd8";
22
+ public static string Title = "DSH 正在使用您的电脑";
23
+ public static string Hint = "Esc 取消";
24
+ public static bool SuppressCursor = false;
25
+ public static int Corner1 = 0; // unused placeholder kept for arg compatibility
26
+ public static Color Accent = Color.FromArgb(63, 127, 216);
27
+ }
28
+
29
+ public static class Native
30
+ {
31
+ [StructLayout(LayoutKind.Sequential)] public struct POINT { public int X, Y; }
32
+ [StructLayout(LayoutKind.Sequential)] public struct SIZE { public int CX, CY; }
33
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
34
+ public struct BLENDFUNCTION { public byte BlendOp; public byte BlendFlags; public byte SourceConstantAlpha; public byte AlphaFormat; }
35
+
36
+ [DllImport("user32.dll")] public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, ref POINT pptDst, ref SIZE psize, IntPtr hdcSrc, ref POINT pptSrc, int crKey, ref BLENDFUNCTION pblend, int dwFlags);
37
+ [DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hWnd);
38
+ [DllImport("user32.dll")] public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
39
+ [DllImport("user32.dll")] public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, uint flags);
40
+ [DllImport("gdi32.dll")] public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
41
+ [DllImport("gdi32.dll")] public static extern bool DeleteDC(IntPtr hdc);
42
+ [DllImport("gdi32.dll")] public static extern IntPtr SelectObject(IntPtr hdc, IntPtr h);
43
+ [DllImport("gdi32.dll")] public static extern bool DeleteObject(IntPtr h);
44
+ [DllImport("user32.dll")] public static extern IntPtr SetSystemCursor(IntPtr hcur, uint id);
45
+ [DllImport("user32.dll")] public static extern bool SystemParametersInfo(uint action, uint param, IntPtr pv, uint winIni);
46
+ [DllImport("user32.dll")] public static extern IntPtr CreateCursor(IntPtr inst, int x, int y, int w, int h, byte[] andMask, byte[] xorMask);
47
+ [DllImport("user32.dll")] public static extern IntPtr CopyIcon(IntPtr hIcon);
48
+ [DllImport("user32.dll")] public static extern bool DestroyCursor(IntPtr hCursor);
49
+
50
+ public static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
51
+ public const uint SWP_NOSIZE = 0x0001, SWP_NOMOVE = 0x0002, SWP_NOACTIVATE = 0x0010, SWP_SHOWWINDOW = 0x0040;
52
+ public const int ULW_ALPHA = 2;
53
+ public const uint SPI_SETCURSORS = 0x0057;
54
+
55
+ public static bool LastLayerOk = true;
56
+ public static int LastLayerError = 0;
57
+
58
+ public static void ApplyLayered(Form form, Bitmap surface)
59
+ {
60
+ IntPtr screenDc = GetDC(IntPtr.Zero);
61
+ IntPtr memDc = CreateCompatibleDC(screenDc);
62
+ IntPtr hBitmap = surface.GetHbitmap(Color.FromArgb(0));
63
+ IntPtr oldBitmap = SelectObject(memDc, hBitmap);
64
+ try
65
+ {
66
+ POINT dst = new POINT { X = form.Left, Y = form.Top };
67
+ POINT src = new POINT { X = 0, Y = 0 };
68
+ SIZE size = new SIZE { CX = surface.Width, CY = surface.Height };
69
+ BLENDFUNCTION blend = new BLENDFUNCTION { BlendOp = 0, BlendFlags = 0, SourceConstantAlpha = 255, AlphaFormat = 1 };
70
+ LastLayerOk = UpdateLayeredWindow(form.Handle, screenDc, ref dst, ref size, memDc, ref src, 0, ref blend, ULW_ALPHA);
71
+ LastLayerError = LastLayerOk ? 0 : Marshal.GetLastWin32Error();
72
+ }
73
+ finally
74
+ {
75
+ SelectObject(memDc, oldBitmap);
76
+ DeleteObject(hBitmap);
77
+ DeleteDC(memDc);
78
+ ReleaseDC(IntPtr.Zero, screenDc);
79
+ }
80
+ }
81
+
82
+ public static void Raise(Form form)
83
+ {
84
+ try { SetWindowPos(form.Handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW); } catch { }
85
+ }
86
+
87
+ public static void SuppressSystemCursors(bool suppress)
88
+ {
89
+ try
90
+ {
91
+ if (!suppress) { SystemParametersInfo(SPI_SETCURSORS, 0, IntPtr.Zero, 0); return; }
92
+ byte[] andMask = new byte[128];
93
+ byte[] xorMask = new byte[128];
94
+ for (int i = 0; i < andMask.Length; i++) andMask[i] = 0xFF;
95
+ IntPtr blank = CreateCursor(IntPtr.Zero, 0, 0, 32, 32, andMask, xorMask);
96
+ if (blank == IntPtr.Zero) return;
97
+ uint[] ids = new uint[] { 32512, 32513, 32514, 32515, 32516, 32631, 32640, 32641, 32642, 32643, 32644, 32645, 32646, 32648, 32649, 32650, 32651, 32671 };
98
+ foreach (uint id in ids) SetSystemCursor(CopyIcon(blank), id);
99
+ DestroyCursor(blank);
100
+ }
101
+ catch { }
102
+ }
103
+ }
104
+
105
+ public sealed class CursorForm : Form
106
+ {
107
+ public PointF Position = new PointF(-2000, -2000);
108
+ public PointF Target = new PointF(-2000, -2000);
109
+ public DateTime Last = DateTime.MinValue;
110
+ public bool Live = false;
111
+ float pulse = 0f;
112
+ const int Box = 96;
113
+
114
+ public CursorForm()
115
+ {
116
+ FormBorderStyle = FormBorderStyle.None;
117
+ ShowInTaskbar = false;
118
+ TopMost = true;
119
+ StartPosition = FormStartPosition.Manual;
120
+ Size = new Size(Box, Box);
121
+ BackColor = Color.Black;
122
+ SetStyle(ControlStyles.Opaque, true);
123
+ }
124
+
125
+ protected override bool ShowWithoutActivation { get { return true; } }
126
+ protected override void OnPaint(PaintEventArgs e) { }
127
+ protected override void OnPaintBackground(PaintEventArgs e) { }
128
+
129
+ protected override CreateParams CreateParams
130
+ {
131
+ get
132
+ {
133
+ CreateParams cp = base.CreateParams;
134
+ cp.ExStyle |= 0x00080000 | 0x00000020 | 0x00000080 | 0x08000000 | 0x00000008;
135
+ return cp;
136
+ }
137
+ }
138
+
139
+ public void Aim(float x, float y)
140
+ {
141
+ Target = new PointF(x, y);
142
+ if (!Live) { Position = Target; Live = true; }
143
+ }
144
+
145
+ public void Tick(double idleMs)
146
+ {
147
+ Position = new PointF(
148
+ Position.X + (Target.X - Position.X) * 0.35f,
149
+ Position.Y + (Target.Y - Position.Y) * 0.35f);
150
+ pulse = (float)((Math.Sin(DateTime.UtcNow.Ticks / 900000.0) + 1.0) / 2.0);
151
+ double fade = 1.0; // stays visible for the whole overlay lifetime
152
+ Left = (int)Position.X - Box / 2;
153
+ Top = (int)Position.Y - Box / 2;
154
+
155
+ using (Bitmap surface = new Bitmap(Box, Box, PixelFormat.Format32bppArgb))
156
+ {
157
+ using (Graphics g = Graphics.FromImage(surface))
158
+ {
159
+ g.Clear(Color.Transparent);
160
+ g.SmoothingMode = SmoothingMode.AntiAlias;
161
+ int alpha = (int)(255 * fade);
162
+ float cx = Box / 2f, cy = Box / 2f;
163
+
164
+ // very soft halo so the pointer reads on busy backgrounds
165
+ using (GraphicsPath haloPath = new GraphicsPath())
166
+ {
167
+ haloPath.AddEllipse(cx - 26f, cy - 26f, 52f, 52f);
168
+ using (PathGradientBrush halo = new PathGradientBrush(haloPath))
169
+ {
170
+ halo.CenterColor = Color.FromArgb((int)(alpha * 0.20), Config.Accent);
171
+ halo.SurroundColors = new Color[] { Color.FromArgb(0, Config.Accent) };
172
+ g.FillPath(halo, haloPath);
173
+ }
174
+ }
175
+
176
+ // classic pointer, drawn with a dark outline and a soft drop shadow
177
+ PointF[] arrow = new PointF[] {
178
+ new PointF(cx - 9f, cy - 17f),
179
+ new PointF(cx - 9f, cy + 11f),
180
+ new PointF(cx - 3.5f, cy + 5.5f),
181
+ new PointF(cx + 0.5f, cy + 15f),
182
+ new PointF(cx + 5f, cy + 13f),
183
+ new PointF(cx + 1f, cy + 3.5f),
184
+ new PointF(cx + 8f, cy + 3.5f),
185
+ };
186
+ for (int pass = 3; pass >= 1; pass--)
187
+ {
188
+ using (SolidBrush shadow = new SolidBrush(Color.FromArgb((int)(alpha * 0.10), 0, 0, 0)))
189
+ using (Matrix m = new Matrix())
190
+ {
191
+ m.Translate(pass * 0.8f, pass * 0.9f);
192
+ GraphicsPath shifted = new GraphicsPath();
193
+ shifted.AddPolygon(arrow);
194
+ shifted.Transform(m);
195
+ g.FillPath(shadow, shifted);
196
+ shifted.Dispose();
197
+ }
198
+ }
199
+ using (SolidBrush fill = new SolidBrush(Color.FromArgb(alpha, 255, 255, 255)))
200
+ g.FillPolygon(fill, arrow);
201
+ using (Pen outline = new Pen(Color.FromArgb((int)(alpha * 0.85), 24, 32, 48), 1.5f))
202
+ {
203
+ outline.LineJoin = LineJoin.Round;
204
+ g.DrawPolygon(outline, arrow);
205
+ }
206
+ }
207
+ string dump = Environment.GetEnvironmentVariable("DSH_CU_DUMP");
208
+ if (!string.IsNullOrEmpty(dump))
209
+ {
210
+ try
211
+ {
212
+ surface.Save(dump, ImageFormat.Png);
213
+ System.IO.File.AppendAllText(dump + ".log",
214
+ DateTime.Now.ToString("HH:mm:ss.fff") + " visible=" + Visible + " handle=" + Handle.ToInt64() +
215
+ " bounds=" + Left + "," + Top + " " + Width + "x" + Height +
216
+ " layerOk=" + Native.LastLayerOk + " err=" + Native.LastLayerError + "\n");
217
+ }
218
+ catch { }
219
+ }
220
+ if (!Visible) Show();
221
+ Native.ApplyLayered(this, surface);
222
+ }
223
+ }
224
+ }
225
+
226
+ /// The status pill: auto-width glass chip with a status dot, the message, an Esc keycap
227
+ /// and a muted hint. It floats in the taskbar margin so it never covers app content.
228
+ public sealed class ChipForm : Form
229
+ {
230
+ const int PadX = 16;
231
+ const int Gap = 10;
232
+ const int Height0 = 36;
233
+
234
+ public ChipForm()
235
+ {
236
+ FormBorderStyle = FormBorderStyle.None;
237
+ ShowInTaskbar = false;
238
+ TopMost = true;
239
+ StartPosition = FormStartPosition.Manual;
240
+ Size = new Size(340, Height0);
241
+ BackColor = Color.Black;
242
+ SetStyle(ControlStyles.Opaque, true);
243
+ }
244
+
245
+ protected override bool ShowWithoutActivation { get { return true; } }
246
+ protected override void OnPaint(PaintEventArgs e) { }
247
+ protected override void OnPaintBackground(PaintEventArgs e) { }
248
+
249
+ protected override CreateParams CreateParams
250
+ {
251
+ get
252
+ {
253
+ CreateParams cp = base.CreateParams;
254
+ cp.ExStyle |= 0x00080000 | 0x00000020 | 0x00000080 | 0x08000000 | 0x00000008;
255
+ return cp;
256
+ }
257
+ }
258
+
259
+ public void Render(double phase)
260
+ {
261
+ using (Font strong = new Font("Microsoft YaHei UI", 12.5f, FontStyle.Regular, GraphicsUnit.Pixel))
262
+ using (Font weak = new Font("Microsoft YaHei UI", 11.5f, FontStyle.Regular, GraphicsUnit.Pixel))
263
+ using (Font key = new Font("Segoe UI", 10f, FontStyle.Regular, GraphicsUnit.Pixel))
264
+ {
265
+ const string message = "DSH 正在使用您的电脑";
266
+ const string tail = "取消";
267
+ SizeF mSize, tSize, kSize;
268
+ using (Bitmap probe = new Bitmap(1, 1))
269
+ using (Graphics pg = Graphics.FromImage(probe))
270
+ {
271
+ mSize = pg.MeasureString(message, strong);
272
+ tSize = pg.MeasureString(tail, weak);
273
+ kSize = pg.MeasureString("Esc", key);
274
+ }
275
+ int keyW = (int)kSize.Width + 12;
276
+ int keyH = 18;
277
+ int dotW = 14;
278
+ int width = PadX * 2 + dotW + Gap + (int)mSize.Width + Gap + keyW + 6 + (int)tSize.Width;
279
+ if (Width != width) Width = width;
280
+
281
+ using (Bitmap surface = new Bitmap(Width, Height0, PixelFormat.Format32bppArgb))
282
+ {
283
+ using (Graphics g = Graphics.FromImage(surface))
284
+ {
285
+ g.Clear(Color.Transparent);
286
+ g.SmoothingMode = SmoothingMode.AntiAlias;
287
+ g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
288
+
289
+ RectangleF rect = new RectangleF(0.5f, 0.5f, Width - 1f, Height0 - 1f);
290
+ using (GraphicsPath path = Rounded(rect, Height0 / 2f))
291
+ using (SolidBrush body = new SolidBrush(Color.FromArgb(196, 11, 14, 22)))
292
+ using (Pen border = new Pen(Color.FromArgb(60, 255, 255, 255), 1f))
293
+ {
294
+ g.FillPath(body, path);
295
+ g.DrawPath(border, path);
296
+ }
297
+
298
+ float x = PadX;
299
+ float midY = Height0 / 2f;
300
+
301
+ // status dot with a soft ring
302
+ int pulseA = 110 + (int)(110 * phase);
303
+ using (SolidBrush ring = new SolidBrush(Color.FromArgb((int)(pulseA * 0.30), Config.Accent)))
304
+ g.FillEllipse(ring, x - 4f, midY - 4f, 8f, 8f);
305
+ using (SolidBrush dot = new SolidBrush(Color.FromArgb(255, Config.Accent)))
306
+ g.FillEllipse(dot, x - 1.5f, midY - 1.5f, 3f, 3f);
307
+ x += dotW + Gap;
308
+
309
+ using (SolidBrush textStrong = new SolidBrush(Color.FromArgb(243, 241, 245, 252)))
310
+ g.DrawString(message, strong, textStrong, x, midY - mSize.Height / 2f + 1f);
311
+ x += mSize.Width + Gap;
312
+
313
+ // Esc keycap
314
+ RectangleF cap = new RectangleF(x, midY - keyH / 2f, keyW, keyH);
315
+ using (GraphicsPath capPath = Rounded(cap, 5f))
316
+ using (SolidBrush capFill = new SolidBrush(Color.FromArgb(46, 255, 255, 255)))
317
+ using (Pen capBorder = new Pen(Color.FromArgb(70, 255, 255, 255), 1f))
318
+ {
319
+ g.FillPath(capFill, capPath);
320
+ g.DrawPath(capBorder, capPath);
321
+ }
322
+ using (StringFormat center = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center })
323
+ using (SolidBrush capText = new SolidBrush(Color.FromArgb(225, 226, 232, 244)))
324
+ g.DrawString("Esc", key, capText, cap, center);
325
+ x += keyW + 6;
326
+
327
+ using (SolidBrush hint = new SolidBrush(Color.FromArgb(190, 170, 180, 200)))
328
+ g.DrawString(tail, weak, hint, x, midY - tSize.Height / 2f + 1f);
329
+ }
330
+ if (!Visible) Show();
331
+ Native.ApplyLayered(this, surface);
332
+ }
333
+ }
334
+ }
335
+
336
+ static GraphicsPath Rounded(RectangleF r, float radius)
337
+ {
338
+ GraphicsPath path = new GraphicsPath();
339
+ float d = radius * 2f;
340
+ path.AddArc(r.X, r.Y, d, d, 180, 90);
341
+ path.AddArc(r.Right - d, r.Y, d, d, 270, 90);
342
+ path.AddArc(r.Right - d, r.Bottom - d, d, d, 0, 90);
343
+ path.AddArc(r.X, r.Bottom - d, d, d, 90, 90);
344
+ path.CloseFigure();
345
+ return path;
346
+ }
347
+ }
348
+
349
+ /// One edge of the frame: a soft outward glow plus a crisp 2px core line.
350
+ public sealed class StripForm : Form
351
+ {
352
+ public StripForm()
353
+ {
354
+ FormBorderStyle = FormBorderStyle.None;
355
+ ShowInTaskbar = false;
356
+ TopMost = true;
357
+ StartPosition = FormStartPosition.Manual;
358
+ BackColor = Color.Black;
359
+ SetStyle(ControlStyles.Opaque, true);
360
+ }
361
+
362
+ protected override bool ShowWithoutActivation { get { return true; } }
363
+ protected override void OnPaint(PaintEventArgs e) { }
364
+ protected override void OnPaintBackground(PaintEventArgs e) { }
365
+
366
+ protected override CreateParams CreateParams
367
+ {
368
+ get
369
+ {
370
+ CreateParams cp = base.CreateParams;
371
+ cp.ExStyle |= 0x00080000 | 0x00000020 | 0x00000080 | 0x08000000 | 0x00000008;
372
+ return cp;
373
+ }
374
+ }
375
+
376
+ /// A crisp hairline with two faint halo strokes. Solid colours only: GDI+ gradient
377
+ /// brushes with transparent endpoints can composite as opaque black once the bitmap
378
+ /// goes through GetHbitmap/UpdateLayeredWindow.
379
+ public void RenderEdge(int w, int h, bool vertical, bool flip, int coreAlpha, int glowAlpha)
380
+ {
381
+ if (w <= 0 || h <= 0) return;
382
+ if (Width != w || Height != h) { Width = w; Height = h; }
383
+ using (Bitmap surface = new Bitmap(w, h, PixelFormat.Format32bppArgb))
384
+ {
385
+ using (Graphics g = Graphics.FromImage(surface))
386
+ {
387
+ g.Clear(Color.Transparent);
388
+ g.SmoothingMode = SmoothingMode.AntiAlias;
389
+ Color accent = Config.Accent;
390
+
391
+ // halo: widest + faintest first, then tighten
392
+ for (int i = 3; i >= 1; i--)
393
+ {
394
+ float width = i * 2.6f;
395
+ int alpha = Math.Max(6, glowAlpha / (i + 1));
396
+ using (Pen halo = new Pen(Color.FromArgb(alpha, accent), width))
397
+ {
398
+ halo.Alignment = PenAlignment.Center;
399
+ if (vertical)
400
+ {
401
+ float y = flip ? h - 1.5f : 1.5f;
402
+ g.DrawLine(halo, 0, y, w, y);
403
+ }
404
+ else
405
+ {
406
+ float x = flip ? w - 1.5f : 1.5f;
407
+ g.DrawLine(halo, x, 0, x, h);
408
+ }
409
+ }
410
+ }
411
+
412
+ // core hairline
413
+ using (Pen core = new Pen(Color.FromArgb(coreAlpha, accent), 1.4f))
414
+ {
415
+ core.Alignment = PenAlignment.Center;
416
+ if (vertical)
417
+ {
418
+ float y = flip ? h - 1.5f : 1.5f;
419
+ g.DrawLine(core, 0, y, w, y);
420
+ }
421
+ else
422
+ {
423
+ float x = flip ? w - 1.5f : 1.5f;
424
+ g.DrawLine(core, x, 0, x, h);
425
+ }
426
+ }
427
+ }
428
+ if (!Visible) Show();
429
+ Native.ApplyLayered(this, surface);
430
+ }
431
+ }
432
+ }
433
+
434
+ /// One rounded corner: the glow and core follow a quarter arc so the frame reads as a
435
+ /// single rounded rectangle instead of four straight strips.
436
+ public sealed class CornerForm : Form
437
+ {
438
+ public CornerForm()
439
+ {
440
+ FormBorderStyle = FormBorderStyle.None;
441
+ ShowInTaskbar = false;
442
+ TopMost = true;
443
+ StartPosition = FormStartPosition.Manual;
444
+ BackColor = Color.Black;
445
+ SetStyle(ControlStyles.Opaque, true);
446
+ }
447
+
448
+ protected override bool ShowWithoutActivation { get { return true; } }
449
+ protected override void OnPaint(PaintEventArgs e) { }
450
+ protected override void OnPaintBackground(PaintEventArgs e) { }
451
+
452
+ protected override CreateParams CreateParams
453
+ {
454
+ get
455
+ {
456
+ CreateParams cp = base.CreateParams;
457
+ cp.ExStyle |= 0x00080000 | 0x00000020 | 0x00000080 | 0x08000000 | 0x00000008;
458
+ return cp;
459
+ }
460
+ }
461
+
462
+ public void RenderCorner(int size, int radius, int quadrant, int coreAlpha, int glowAlpha)
463
+ {
464
+ if (Width != size || Height != size) { Width = size; Height = size; }
465
+ using (Bitmap surface = new Bitmap(size, size, PixelFormat.Format32bppArgb))
466
+ {
467
+ using (Graphics g = Graphics.FromImage(surface))
468
+ {
469
+ g.Clear(Color.Transparent);
470
+ g.SmoothingMode = SmoothingMode.AntiAlias;
471
+ float r = radius;
472
+ float inset = 1.4f;
473
+ RectangleF box;
474
+ float startAngle;
475
+ switch (quadrant)
476
+ {
477
+ case 0: box = new RectangleF(inset, inset, r * 2, r * 2); startAngle = 180; break;
478
+ case 1: box = new RectangleF(size - r * 2 - inset, inset, r * 2, r * 2); startAngle = 270; break;
479
+ case 2: box = new RectangleF(size - r * 2 - inset, size - r * 2 - inset, r * 2, r * 2); startAngle = 0; break;
480
+ default: box = new RectangleF(inset, size - r * 2 - inset, r * 2, r * 2); startAngle = 90; break;
481
+ }
482
+ // tight glow: two soft arcs
483
+ using (Pen wide = new Pen(Color.FromArgb(Math.Max(6, glowAlpha / 2), Config.Accent), 9f)) { wide.Alignment = PenAlignment.Inset; g.DrawArc(wide, box, startAngle, 90); }
484
+ using (Pen narrow = new Pen(Color.FromArgb(Math.Max(8, glowAlpha), Config.Accent), 4f)) { narrow.Alignment = PenAlignment.Inset; g.DrawArc(narrow, box, startAngle, 90); }
485
+ using (Pen core = new Pen(Color.FromArgb(coreAlpha, Config.Accent), 1.6f)) { core.Alignment = PenAlignment.Inset; g.DrawArc(core, box, startAngle, 90); }
486
+ }
487
+ if (!Visible) Show();
488
+ Native.ApplyLayered(this, surface);
489
+ }
490
+ }
491
+ }
492
+
493
+ internal sealed class Controller : ApplicationContext
494
+ {
495
+ readonly System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();
496
+ readonly StripForm _top = new StripForm();
497
+ readonly StripForm _bottom = new StripForm();
498
+ readonly StripForm _left = new StripForm();
499
+ readonly StripForm _right = new StripForm();
500
+ readonly CornerForm _c0 = new CornerForm(), _c1 = new CornerForm(), _c2 = new CornerForm(), _c3 = new CornerForm();
501
+ readonly ChipForm _chip = new ChipForm();
502
+ readonly CursorForm _cursor = new CursorForm();
503
+ readonly int _ttlMs;
504
+ readonly DateTime _deadline;
505
+ int _tick;
506
+ LowLevelKeyboardProc _hookProc;
507
+ IntPtr _hook;
508
+
509
+ [DllImport("user32.dll")] static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
510
+ [DllImport("user32.dll")] static extern bool UnhookWindowsHookEx(IntPtr hhk);
511
+ [DllImport("user32.dll")] static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
512
+ [DllImport("user32.dll")] static extern bool GetCursorPos(out PointNative pt);
513
+ [StructLayout(LayoutKind.Sequential)] struct PointNative { public int X, Y; }
514
+ delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
515
+
516
+ const int Radius = 18; // corner radius
517
+ const int Glow = 12; // band the halo fades inside
518
+
519
+ public Controller(int ttlMs)
520
+ {
521
+ _ttlMs = ttlMs;
522
+ _deadline = DateTime.UtcNow.AddMilliseconds(ttlMs);
523
+ _hookProc = Hook;
524
+ _hook = SetWindowsHookEx(13, _hookProc, IntPtr.Zero, 0);
525
+ _timer.Interval = 45;
526
+ _timer.Tick += (s, e) => Tick();
527
+ _timer.Start();
528
+ Tick();
529
+ }
530
+
531
+ IntPtr Hook(int nCode, IntPtr wParam, IntPtr lParam)
532
+ {
533
+ if (nCode >= 0 && (wParam == (IntPtr)0x0100 || wParam == (IntPtr)0x0104))
534
+ {
535
+ int vk = Marshal.ReadInt32(lParam);
536
+ if (vk == 0x1B)
537
+ {
538
+ try { if (Config.CancelFile.Length > 0) File.WriteAllText(Config.CancelFile, "cancelled " + DateTime.Now.ToString("o")); } catch { }
539
+ try { ExitThreadCore(); } catch { }
540
+ }
541
+ }
542
+ return CallNextHookEx(_hook, nCode, wParam, lParam);
543
+ }
544
+
545
+ void Tick()
546
+ {
547
+ _tick++;
548
+ if (DateTime.UtcNow > _deadline) { ExitThreadCore(); return; }
549
+
550
+ Rectangle screen = SystemInformation.VirtualScreen;
551
+ // slow 3.2s breath: the frame gets a little brighter and a touch wider
552
+ double phase = (Math.Sin(_tick / 26.0 - 1.57) + 1.0) / 2.0;
553
+ int coreAlpha = 170 + (int)Math.Round(70 * phase);
554
+ int glowAlpha = 26 + (int)Math.Round(20 * phase);
555
+ int thickness = Glow;
556
+
557
+ int x0 = screen.Left, y0 = screen.Top, w = screen.Width, h = screen.Height;
558
+
559
+ _top.RenderEdge(w - Radius * 2, thickness, true, false, coreAlpha, glowAlpha);
560
+ _top.Location = new Point(x0 + Radius, y0);
561
+ _bottom.RenderEdge(w - Radius * 2, thickness, true, true, coreAlpha, glowAlpha);
562
+ _bottom.Location = new Point(x0 + Radius, y0 + h - thickness);
563
+ _left.RenderEdge(thickness, h - Radius * 2, false, false, coreAlpha, glowAlpha);
564
+ _left.Location = new Point(x0, y0 + Radius);
565
+ _right.RenderEdge(thickness, h - Radius * 2, false, true, coreAlpha, glowAlpha);
566
+ _right.Location = new Point(x0 + w - thickness, y0 + Radius);
567
+
568
+ int cs = Radius + Glow;
569
+ _c0.RenderCorner(cs, Radius, 0, coreAlpha, glowAlpha); _c0.Location = new Point(x0, y0);
570
+ _c1.RenderCorner(cs, Radius, 1, coreAlpha, glowAlpha); _c1.Location = new Point(x0 + w - cs, y0);
571
+ _c2.RenderCorner(cs, Radius, 2, coreAlpha, glowAlpha); _c2.Location = new Point(x0 + w - cs, y0 + h - cs);
572
+ _c3.RenderCorner(cs, Radius, 3, coreAlpha, glowAlpha); _c3.Location = new Point(x0, y0 + h - cs);
573
+
574
+ if (_tick % 25 == 0)
575
+ {
576
+ Native.Raise(_top); Native.Raise(_bottom); Native.Raise(_left); Native.Raise(_right);
577
+ Native.Raise(_c0); Native.Raise(_c1); Native.Raise(_c2); Native.Raise(_c3); Native.Raise(_chip);
578
+ Native.Raise(_cursor);
579
+ }
580
+
581
+ _chip.Render(phase);
582
+ _chip.Location = new Point(x0 + (w - _chip.Width) / 2, y0 + h - 74);
583
+
584
+ // virtual cursor stands in for the real pointer while the overlay is up
585
+ try
586
+ {
587
+ if (Config.CursorFile.Length > 0 && File.Exists(Config.CursorFile))
588
+ {
589
+ string raw = File.ReadAllText(Config.CursorFile).Trim();
590
+ string[] parts = raw.Split(',');
591
+ if (parts.Length >= 3)
592
+ {
593
+ DateTime stamp = new DateTime(long.Parse(parts[2]));
594
+ if (stamp > _cursor.Last)
595
+ {
596
+ _cursor.Last = stamp;
597
+ _cursor.Aim(float.Parse(parts[0], System.Globalization.CultureInfo.InvariantCulture),
598
+ float.Parse(parts[1], System.Globalization.CultureInfo.InvariantCulture));
599
+ }
600
+ }
601
+ }
602
+ }
603
+ catch { }
604
+
605
+ if (!_cursor.Live)
606
+ {
607
+ PointNative p;
608
+ if (GetCursorPos(out p)) { _cursor.Position = new PointF(p.X, p.Y); _cursor.Target = _cursor.Position; }
609
+ _cursor.Live = true;
610
+ }
611
+ _cursor.Tick(0);
612
+ }
613
+
614
+ protected override void ExitThreadCore()
615
+ {
616
+ try { _timer.Stop(); } catch { }
617
+ try { if (_hook != IntPtr.Zero) UnhookWindowsHookEx(_hook); } catch { }
618
+ try
619
+ {
620
+ _top.Close(); _bottom.Close(); _left.Close(); _right.Close();
621
+ _c0.Close(); _c1.Close(); _c2.Close(); _c3.Close();
622
+ _chip.Close(); _cursor.Close();
623
+ }
624
+ catch { }
625
+ Native.SuppressSystemCursors(false);
626
+ base.ExitThreadCore();
627
+ }
628
+ }
629
+
630
+ internal static class Program
631
+ {
632
+ [DllImport("user32.dll")] private static extern bool SetProcessDpiAwarenessContext(IntPtr ctx);
633
+ [DllImport("user32.dll")] private static extern bool SetProcessDPIAware();
634
+
635
+ [STAThread]
636
+ private static void Main(string[] args)
637
+ {
638
+ // Per-monitor-v2: without this the process is DPI-virtualized, so a 1707x1067
639
+ // logical screen is scaled onto a 2560x1600 physical one - the frame gets blurry,
640
+ // sized wrong, and action coordinates land in the wrong place.
641
+ try { SetProcessDpiAwarenessContext(new IntPtr(-4)); } catch { }
642
+ try { SetProcessDPIAware(); } catch { }
643
+
644
+ int ttlMs = 20000;
645
+ for (int i = 0; i < args.Length - 1; i++)
646
+ {
647
+ string a = args[i];
648
+ if (a == "--cancel-file") Config.CancelFile = args[i + 1];
649
+ else if (a == "--cursor-file") Config.CursorFile = args[i + 1];
650
+ else if (a == "--accent") Config.AccentHex = args[i + 1];
651
+ else if (a == "--text") Config.Title = args[i + 1];
652
+ else if (a == "--hint") Config.Hint = args[i + 1];
653
+ else if (a == "--ttl-ms") int.TryParse(args[i + 1], out ttlMs);
654
+ }
655
+ Config.SuppressCursor = true; // Codex default
656
+ for (int i = 0; i < args.Length; i++) if (args[i] == "--no-suppress-cursor") Config.SuppressCursor = false;
657
+ try { Config.Accent = ColorTranslator.FromHtml(Config.AccentHex); } catch { }
658
+
659
+ if (Config.SuppressCursor)
660
+ {
661
+ Native.SuppressSystemCursors(true);
662
+ AppDomain.CurrentDomain.ProcessExit += (s, e) => Native.SuppressSystemCursors(false);
663
+ }
664
+
665
+ Application.EnableVisualStyles();
666
+ Application.Run(new Controller(ttlMs));
667
+ Native.SuppressSystemCursors(false);
668
+ }
669
+ }