dsh-desktop-windows 0.2.5 → 0.2.7

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/screenshot.html +59 -33
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-desktop-windows",
3
3
  "productName": "DeepSeek Harness Desktop",
4
- "version": "0.2.5",
4
+ "version": "0.2.7",
5
5
  "description": "DeepSeek Harness 桌面版(Windows)· Electron desktop shell for DeepSeek Harness (dsh web) — 双击即用,无需终端 / double-click to run the harness in a standalone window",
6
6
  "main": "src/main.js",
7
7
  "license": "MIT",
@@ -7,8 +7,28 @@
7
7
  * { margin: 0; padding: 0; box-sizing: border-box; user-select: none; }
8
8
  html, body { width: 100%; height: 100%; overflow: hidden; background: #000; cursor: crosshair; }
9
9
  #stage { position: fixed; inset: 0; }
10
- #stage img { width: 100%; height: 100%; object-fit: fill; display: block; }
11
- #cv { position: fixed; inset: 0; pointer-events: none; z-index: 2; }
10
+ #stage img {
11
+ width: 100%; height: 100%; object-fit: fill; display: block;
12
+ -webkit-user-drag: none; user-drag: none; draggable: false;
13
+ pointer-events: none; /* 避免 img 拦截鼠标事件/触发拖拽 */
14
+ }
15
+ /* 遮罩:全屏半透明黑 + clip-path 挖洞(GPU 加速,每帧只改字符串) */
16
+ #mask {
17
+ position: fixed; inset: 0; z-index: 2; pointer-events: none;
18
+ background: rgba(0, 0, 0, 0.45);
19
+ clip-path: polygon(0px 0px, 0px 0px, 0px 0px);
20
+ }
21
+ /* 选区框:border div,transform 定位 + 尺寸更新 */
22
+ #sel {
23
+ position: fixed; z-index: 3; pointer-events: none;
24
+ border: 1.5px solid #2563eb; background: rgba(37, 99, 235, 0.08);
25
+ transform-origin: 0 0;
26
+ }
27
+ #sel .sz {
28
+ position: absolute; left: 0; top: -22px;
29
+ background: #2563eb; color: #fff;
30
+ font: 11px/18px sans-serif; padding: 0 6px; border-radius: 4px; white-space: nowrap;
31
+ }
12
32
  .handle {
13
33
  position: fixed; width: 9px; height: 9px; background: #2563eb;
14
34
  border: 1px solid #fff; border-radius: 2px; display: none;
@@ -40,7 +60,8 @@
40
60
  </head>
41
61
  <body>
42
62
  <div id="stage"><img id="bg" alt=""></div>
43
- <canvas id="cv"></canvas>
63
+ <div id="mask"></div>
64
+ <div id="sel"><div class="sz"></div></div>
44
65
  <div id="hN" class="handle" style="cursor:n-resize"></div>
45
66
  <div id="hS" class="handle" style="cursor:s-resize"></div>
46
67
  <div id="hE" class="handle" style="cursor:e-resize"></div>
@@ -58,11 +79,12 @@
58
79
 
59
80
  <script>
60
81
  var bg = document.getElementById('bg')
82
+ var mask = document.getElementById('mask')
83
+ var sel = document.getElementById('sel')
84
+ var sz = sel.querySelector('.sz')
61
85
  var toolbar = document.getElementById('toolbar')
62
86
  var hint = document.getElementById('hint')
63
87
  var tip = document.getElementById('tip')
64
- var cv = document.getElementById('cv')
65
- var cx = cv.getContext('2d')
66
88
  var handles = {
67
89
  n: document.getElementById('hN'), s: document.getElementById('hS'),
68
90
  e: document.getElementById('hE'), w: document.getElementById('hW'),
@@ -70,7 +92,6 @@
70
92
  se: document.getElementById('hSE'), sw: document.getElementById('hSW'),
71
93
  }
72
94
  var W = window.innerWidth, H = window.innerHeight
73
- cv.width = W; cv.height = H
74
95
  var MIN = 8
75
96
  var rect = null
76
97
  var mode = 'draw' // draw | adjust
@@ -80,7 +101,7 @@
80
101
  window.__screenshot.onData(function (dataUrl) {
81
102
  bg.onload = function () {
82
103
  window.__screenshot.loaded()
83
- draw()
104
+ update()
84
105
  setTimeout(function () { hint.style.opacity = '0.9' }, 100)
85
106
  }
86
107
  bg.src = dataUrl
@@ -94,28 +115,29 @@
94
115
  return { x: x, y: y, w: w, h: h }
95
116
  }
96
117
 
97
- // Canvas 一次性绘制遮罩 + 选区 + 尺寸(高性能)
98
- function draw() {
99
- cx.clearRect(0, 0, W, H)
100
- cx.fillStyle = 'rgba(0,0,0,0.45)'
101
- if (!rect) { cx.fillRect(0, 0, W, H); return }
102
- cx.fillRect(0, 0, W, rect.y)
103
- cx.fillRect(0, rect.y + rect.h, W, H - rect.y - rect.h)
104
- cx.fillRect(0, rect.y, rect.x, rect.h)
105
- cx.fillRect(rect.x + rect.w, rect.y, W - rect.x - rect.w, rect.h)
106
- cx.strokeStyle = '#2563eb'
107
- cx.lineWidth = 1.5
108
- cx.strokeRect(rect.x + 0.75, rect.y + 0.75, rect.w, rect.h)
109
- cx.fillStyle = '#2563eb'
110
- cx.font = '12px sans-serif'
111
- cx.fillText(Math.round(rect.w) + ' × ' + Math.round(rect.h), rect.x + 4, Math.max(14, rect.y - 6))
118
+ // 每帧只更新 2 个元素:mask clip-path(GPU)+ sel 的位置尺寸
119
+ function update() {
120
+ if (!rect) {
121
+ mask.style.clipPath = 'polygon(0px 0px, 0px 0px, 0px 0px, 0px 0px, 0px 0px)'
122
+ sel.style.display = 'none'
123
+ hideHandles()
124
+ return
125
+ }
126
+ var x = rect.x, y = rect.y, w = rect.w, h = rect.h
127
+ // clip-path:外框逆时针 + 选区顺时针 → 挖洞
128
+ mask.style.clipPath =
129
+ 'polygon(0px 0px, ' + W + 'px 0px, ' + W + 'px ' + H + 'px, 0px ' + H + 'px, 0px 0px, ' +
130
+ x + 'px ' + y + 'px, ' + (x + w) + 'px ' + y + 'px, ' + (x + w) + 'px ' + (y + h) + 'px, ' + x + 'px ' + (y + h) + 'px, ' + x + 'px ' + y + 'px)'
131
+ sel.style.display = 'block'
132
+ sel.style.transform = 'translate(' + x + 'px, ' + y + 'px)'
133
+ sel.style.width = w + 'px'
134
+ sel.style.height = h + 'px'
135
+ sz.textContent = Math.round(w) + ' × ' + Math.round(h)
136
+ updateHandles()
112
137
  }
113
138
 
114
139
  function updateHandles() {
115
- if (mode !== 'adjust' || !rect) {
116
- for (var k in handles) handles[k].style.display = 'none'
117
- return
118
- }
140
+ if (mode !== 'adjust' || !rect) { hideHandles(); return }
119
141
  var x = rect.x, y = rect.y, w = rect.w, h = rect.h
120
142
  var pos = {
121
143
  n: [x + w / 2, y], s: [x + w / 2, y + h],
@@ -129,13 +151,16 @@
129
151
  }
130
152
  }
131
153
 
132
- function scheduleDraw() {
154
+ function hideHandles() {
155
+ for (var k in handles) handles[k].style.display = 'none'
156
+ }
157
+
158
+ function scheduleUpdate() {
133
159
  if (rafPending) return
134
160
  rafPending = true
135
161
  requestAnimationFrame(function () {
136
162
  rafPending = false
137
- draw()
138
- updateHandles()
163
+ update()
139
164
  })
140
165
  }
141
166
 
@@ -145,6 +170,7 @@
145
170
 
146
171
  document.addEventListener('mousedown', function (e) {
147
172
  if (e.button !== 0) return
173
+ e.preventDefault() // 阻止 img 拖拽等默认行为,确保 mousemove 正常触发
148
174
  if (mode === 'draw') {
149
175
  drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
150
176
  return
@@ -161,7 +187,7 @@
161
187
  toolbar.style.display = 'none'
162
188
  hint.style.opacity = '0.9'
163
189
  drag = { type: 'draw', x0: e.clientX, y0: e.clientY }
164
- scheduleDraw()
190
+ scheduleUpdate()
165
191
  }
166
192
  })
167
193
 
@@ -182,7 +208,7 @@
182
208
  if (drag.dir.indexOf('n') !== -1) { r.y = o.y + dy; r.h = o.h - dy }
183
209
  rect = clampRect(r)
184
210
  }
185
- scheduleDraw()
211
+ scheduleUpdate()
186
212
  })
187
213
 
188
214
  document.addEventListener('mouseup', function () {
@@ -195,11 +221,11 @@
195
221
  t.style.left = Math.min(rect.x + rect.w + 10, W - 250) + 'px'
196
222
  t.style.top = (rect.y + rect.h + 14 > H - 60 ? rect.y - 60 : rect.y + rect.h + 14) + 'px'
197
223
  hint.style.opacity = '0'
198
- scheduleDraw() // 显示手柄
224
+ scheduleUpdate()
199
225
  }
200
226
  })
201
227
 
202
- // 关键修复:点击工具栏(确定/取消)不触发 document 的画框逻辑
228
+ // 关键:点击工具栏(确定/取消)不触发 document 的画框逻辑
203
229
  toolbar.addEventListener('mousedown', function (e) { e.stopPropagation() })
204
230
 
205
231
  document.getElementById('okBtn').onclick = function () {