dsh-desktop-windows 0.1.9 → 0.2.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.
- package/package.json +1 -1
- package/src/main.js +48 -19
- package/src/screenshot-preload.js +2 -0
- package/src/screenshot.html +4 -1
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.1
|
|
4
|
+
"version": "0.2.1",
|
|
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",
|
package/src/main.js
CHANGED
|
@@ -411,11 +411,13 @@ function openShotWindow() {
|
|
|
411
411
|
return
|
|
412
412
|
}
|
|
413
413
|
shotWindow = new BrowserWindow({
|
|
414
|
-
fullscreen: true,
|
|
415
414
|
frame: false,
|
|
416
415
|
resizable: false,
|
|
416
|
+
movable: false,
|
|
417
|
+
fullscreen: true,
|
|
417
418
|
alwaysOnTop: true,
|
|
418
419
|
skipTaskbar: true,
|
|
420
|
+
show: false, // 截图加载完成后再显示,避免黑屏闪烁
|
|
419
421
|
webPreferences: {
|
|
420
422
|
contextIsolation: true,
|
|
421
423
|
nodeIntegration: false,
|
|
@@ -425,10 +427,6 @@ function openShotWindow() {
|
|
|
425
427
|
})
|
|
426
428
|
shotWindow.setAlwaysOnTop(true, 'screen-saver')
|
|
427
429
|
shotWindow.loadFile(path.join(__dirname, 'screenshot.html'))
|
|
428
|
-
shotWindow.once('ready-to-show', () => {
|
|
429
|
-
shotWindow.show()
|
|
430
|
-
shotWindow.focus()
|
|
431
|
-
})
|
|
432
430
|
shotWindow.webContents.once('did-finish-load', () => {
|
|
433
431
|
if (pendingShot && !shotWindow.isDestroyed()) {
|
|
434
432
|
shotWindow.webContents.send('screenshot:data', pendingShot.toDataURL())
|
|
@@ -439,11 +437,20 @@ function openShotWindow() {
|
|
|
439
437
|
})
|
|
440
438
|
}
|
|
441
439
|
|
|
442
|
-
|
|
440
|
+
// 截图在选区窗口内加载完成 → 再显示窗口(避免黑屏"小窗口")
|
|
441
|
+
function onShotLoaded() {
|
|
442
|
+
if (shotWindow && !shotWindow.isDestroyed()) {
|
|
443
|
+
shotWindow.show()
|
|
444
|
+
shotWindow.focus()
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/** 选区确认:裁剪 → 剪贴板 → 恢复主窗口并粘贴。 */
|
|
443
449
|
function onShotDone(rect) {
|
|
444
450
|
const image = pendingShot
|
|
445
451
|
pendingShot = null
|
|
446
452
|
if (shotWindow && !shotWindow.isDestroyed()) shotWindow.destroy()
|
|
453
|
+
showMainWindow() // 恢复显示聊天窗口
|
|
447
454
|
if (!image || !rect) return
|
|
448
455
|
const sf = screen.getPrimaryDisplay().scaleFactor || 1
|
|
449
456
|
const r = {
|
|
@@ -455,23 +462,34 @@ function onShotDone(rect) {
|
|
|
455
462
|
if (r.width <= 0 || r.height <= 0) return
|
|
456
463
|
const cropped = image.crop(r)
|
|
457
464
|
clipboard.writeImage(cropped)
|
|
465
|
+
// 等主窗口就绪后再聚焦输入框并粘贴(失败则提示手动 Ctrl+V)
|
|
458
466
|
if (mainWindow && !mainWindow.isDestroyed()) {
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
}
|
|
468
|
-
|
|
467
|
+
setTimeout(async () => {
|
|
468
|
+
let focused = false
|
|
469
|
+
try {
|
|
470
|
+
focused = await mainWindow.webContents.executeJavaScript(
|
|
471
|
+
`(() => { const el = document.querySelector('textarea, [contenteditable="true"]'); if (el) { el.focus(); return true } return false })()`
|
|
472
|
+
)
|
|
473
|
+
} catch {
|
|
474
|
+
focused = false
|
|
475
|
+
}
|
|
476
|
+
if (focused) {
|
|
477
|
+
mainWindow.webContents.paste()
|
|
478
|
+
} else {
|
|
479
|
+
dialog.showMessageBox(mainWindow, {
|
|
480
|
+
type: 'info',
|
|
481
|
+
message: '截图已复制到剪贴板,请在聊天输入框按 Ctrl+V 粘贴',
|
|
482
|
+
buttons: ['好'],
|
|
483
|
+
})
|
|
484
|
+
}
|
|
485
|
+
}, 400)
|
|
469
486
|
}
|
|
470
487
|
}
|
|
471
488
|
|
|
472
489
|
function onShotCancel() {
|
|
473
490
|
pendingShot = null
|
|
474
491
|
if (shotWindow && !shotWindow.isDestroyed()) shotWindow.destroy()
|
|
492
|
+
showMainWindow() // 恢复显示聊天窗口
|
|
475
493
|
}
|
|
476
494
|
|
|
477
495
|
/* ------------------------------------------------------------------ *
|
|
@@ -627,9 +645,12 @@ if (!gotLock) {
|
|
|
627
645
|
ipcMain.on('dsh-desktop:reload', () => {
|
|
628
646
|
if (mainWindow) mainWindow.webContents.reload()
|
|
629
647
|
})
|
|
630
|
-
//
|
|
648
|
+
// 选区截图:隐藏主窗口 → 截全屏 → 选区窗口 → 裁剪 → 剪贴板 → 粘贴
|
|
631
649
|
ipcMain.handle('dsh-desktop:capture', async () => {
|
|
632
650
|
try {
|
|
651
|
+
// 先隐藏主窗口,避免截到聊天框本身
|
|
652
|
+
if (mainWindow && !mainWindow.isDestroyed()) mainWindow.hide()
|
|
653
|
+
await new Promise((r) => setTimeout(r, 250))
|
|
633
654
|
const display = screen.getPrimaryDisplay()
|
|
634
655
|
const sf = display.scaleFactor || 1
|
|
635
656
|
const sources = await desktopCapturer.getSources({
|
|
@@ -639,12 +660,19 @@ if (!gotLock) {
|
|
|
639
660
|
height: Math.round(display.size.height * sf),
|
|
640
661
|
},
|
|
641
662
|
})
|
|
642
|
-
if (!sources.length)
|
|
663
|
+
if (!sources.length) {
|
|
664
|
+
showMainWindow()
|
|
665
|
+
return { ok: false, error: '未找到屏幕源' }
|
|
666
|
+
}
|
|
643
667
|
pendingShot = sources[0].thumbnail
|
|
644
|
-
if (pendingShot.isEmpty())
|
|
668
|
+
if (pendingShot.isEmpty()) {
|
|
669
|
+
showMainWindow()
|
|
670
|
+
return { ok: false, error: '截图为空' }
|
|
671
|
+
}
|
|
645
672
|
openShotWindow()
|
|
646
673
|
return { ok: true }
|
|
647
674
|
} catch (e) {
|
|
675
|
+
showMainWindow()
|
|
648
676
|
return { ok: false, error: String((e && e.message) || e) }
|
|
649
677
|
}
|
|
650
678
|
})
|
|
@@ -657,6 +685,7 @@ if (!gotLock) {
|
|
|
657
685
|
// 选区截图结果
|
|
658
686
|
ipcMain.on('screenshot:done', (_e, rect) => onShotDone(rect))
|
|
659
687
|
ipcMain.on('screenshot:cancel', () => onShotCancel())
|
|
688
|
+
ipcMain.on('screenshot:loaded', () => onShotLoaded())
|
|
660
689
|
if (external) log('reusing external dsh service on port ' + port)
|
|
661
690
|
})
|
|
662
691
|
|
package/src/screenshot.html
CHANGED
|
@@ -58,8 +58,11 @@
|
|
|
58
58
|
|
|
59
59
|
// 接收主进程传来的截图 dataURL
|
|
60
60
|
window.__screenshot.onData((dataUrl) => {
|
|
61
|
+
bg.onload = () => {
|
|
62
|
+
window.__screenshot.loaded()
|
|
63
|
+
setTimeout(() => (hint.style.opacity = '0.9'), 100)
|
|
64
|
+
}
|
|
61
65
|
bg.src = dataUrl
|
|
62
|
-
setTimeout(() => (hint.style.opacity = '0.9'), 100)
|
|
63
66
|
})
|
|
64
67
|
|
|
65
68
|
const updateMask = () => {
|