dsh-android-tool 0.0.0-stage → 0.1.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.
@@ -0,0 +1,98 @@
1
+ /**
2
+ * 独立 scrcpy 窗口:给需要 60fps 真实操作的人用。
3
+ * 侧边栏的「打开 scrcpy 窗口」按钮走这里。
4
+ */
5
+
6
+ import { spawn } from 'node:child_process'
7
+ import { existsSync } from 'node:fs'
8
+ import { splitArgs } from './config.js'
9
+
10
+ function killTree(child) {
11
+ if (child === undefined || child === null || child.killed) return
12
+ try {
13
+ if (process.platform === 'win32') {
14
+ const killer = spawn('taskkill', ['/PID', String(child.pid), '/T', '/F'], { stdio: 'ignore', windowsHide: true })
15
+ killer.on('error', () => {})
16
+ } else {
17
+ child.kill('SIGKILL')
18
+ }
19
+ } catch {
20
+ // 忽略
21
+ }
22
+ }
23
+
24
+ export class ScrcpyWindow {
25
+ /**
26
+ * @param {object} options
27
+ * @param {import('./adb.js').Adb} options.adb
28
+ * @param {() => object} options.getConfig
29
+ * @param {object} [options.logger]
30
+ */
31
+ constructor(options) {
32
+ this.adb = options.adb
33
+ this.getConfig = options.getConfig
34
+ this.logger = options.logger
35
+ this.child = undefined
36
+ this.serial = ''
37
+ this.startedAt = 0
38
+ this.lastError = ''
39
+ }
40
+
41
+ status() {
42
+ return {
43
+ running: this.child !== undefined && this.child.exitCode === null,
44
+ serial: this.serial,
45
+ startedAt: this.startedAt,
46
+ error: this.lastError || undefined,
47
+ }
48
+ }
49
+
50
+ /** 启动独立窗口。 */
51
+ launch(serial) {
52
+ const target = String(serial ?? '').trim()
53
+ if (target.length === 0) return { ok: false, error: '没有选中设备。' }
54
+ if (this.status().running) {
55
+ return { ok: true, already: true, serial: this.serial }
56
+ }
57
+ const paths = this.adb.resolveScrcpy()
58
+ if (!existsSync(paths.scrcpyPath)) {
59
+ return { ok: false, error: `找不到 scrcpy:${paths.scrcpyPath}` }
60
+ }
61
+ const settings = this.getConfig()
62
+ const args = ['-s', target, '--window-title', `Android - ${target}`, ...splitArgs(settings.scrcpyExtraArgs)]
63
+ let child
64
+ try {
65
+ child = spawn(paths.scrcpyPath, args, { windowsHide: false, stdio: 'ignore' })
66
+ } catch (error) {
67
+ this.lastError = error instanceof Error ? error.message : String(error)
68
+ return { ok: false, error: this.lastError }
69
+ }
70
+ this.child = child
71
+ this.serial = target
72
+ this.startedAt = Date.now()
73
+ this.lastError = ''
74
+ child.on('error', (error) => {
75
+ this.lastError = error instanceof Error ? error.message : String(error)
76
+ this.logger?.warn?.(`dsh-android-tool: scrcpy 窗口启动失败 ${this.lastError}`)
77
+ })
78
+ child.on('exit', () => {
79
+ if (this.child === child) {
80
+ this.child = undefined
81
+ this.serial = ''
82
+ }
83
+ })
84
+ return { ok: true, serial: target, pid: child.pid }
85
+ }
86
+
87
+ /** 关闭独立窗口。 */
88
+ stop() {
89
+ if (this.child !== undefined) killTree(this.child)
90
+ this.child = undefined
91
+ this.serial = ''
92
+ return { ok: true }
93
+ }
94
+
95
+ dispose() {
96
+ this.stop()
97
+ }
98
+ }