@ponydev/dsh-phone 0.3.0 → 0.3.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.1 — 2026-10-25
4
+
5
+ ### 修复
6
+ - 云手机在平台侧切换分辨率后画面比例不跟随:预览每 3s 用 `screen-info?fresh` 检测 `wm size`,变化时自动重连流并按新尺寸重启 screenrecord
7
+ - 顶部新增当前流分辨率显示(如 `540×960 · 58fps · 20ms`)
8
+
3
9
  ## 0.3.0 — 2026-10-24
4
10
 
5
11
  ### 新增
package/lib/adb.js CHANGED
@@ -309,11 +309,11 @@ export class Adb {
309
309
  }
310
310
 
311
311
  /** 设备物理分辨率(wm size),客户端用它把画面坐标换算成输入坐标;缓存 60s。 */
312
- async screenInfo(serial) {
312
+ async screenInfo(serial, options = {}) {
313
313
  await this.assertReady(serial)
314
314
  const cached = this._screens.get(serial)
315
315
  const now = Date.now()
316
- if (cached && now - cached.at < 60_000) return cached.info
316
+ if (!options.fresh && cached && now - cached.at < 60_000) return cached.info
317
317
  const { stdout } = await this._run(['-s', serial, 'shell', 'wm', 'size'], { timeout: 5000 })
318
318
  const info = parseWmSize(stdout.toString('utf8'))
319
319
  if (!info) throw fail('bad-screen-info', '无法读取设备分辨率')
package/lib/client.js CHANGED
@@ -392,7 +392,7 @@ window.__ModuleLoader__.load({
392
392
  connect: (address) => unwrap('connect', { address }),
393
393
  disconnect: (serial) => unwrap('disconnect', { serial }),
394
394
  input: (serial, event) => unwrap('input', { serial, event }),
395
- screenInfo: (serial) => unwrap('screen-info', { serial }),
395
+ screenInfo: (serial, options) => unwrap('screen-info', { serial, fresh: Boolean(options && options.fresh) }),
396
396
  ping: (serial) => unwrap('ping', { serial }),
397
397
  targets: () => unwrap('targets'),
398
398
  removeTarget: (address) => unwrap('targets/remove', { address }),
@@ -663,7 +663,8 @@ window.__ModuleLoader__.load({
663
663
  let pps = null
664
664
  let frames = 0
665
665
  let waitingKey = true
666
- let reportedSize = false
666
+ let lastWidth = 0
667
+ let lastHeight = 0
667
668
 
668
669
  const resetDecoder = () => {
669
670
  if (decoder) {
@@ -694,9 +695,10 @@ window.__ModuleLoader__.load({
694
695
  frames += 1
695
696
  waitingKey = false
696
697
  if (onFrame) onFrame()
697
- if (!reportedSize) {
698
- reportedSize = true
699
- if (onSize) onSize(frame.displayWidth, frame.displayHeight)
698
+ if (frame.displayWidth !== lastWidth || frame.displayHeight !== lastHeight) {
699
+ lastWidth = frame.displayWidth
700
+ lastHeight = frame.displayHeight
701
+ if (onSize) onSize(lastWidth, lastHeight)
700
702
  }
701
703
  } finally {
702
704
  frame.close()
@@ -811,6 +813,7 @@ window.__ModuleLoader__.load({
811
813
  const [attempt, setAttempt] = useState(0)
812
814
  const [toast, setToast] = useState(null)
813
815
  const [fps, setFps] = useState(0)
816
+ const [streamSize, setStreamSize] = useState(null)
814
817
  const [rtt, setRtt] = useState(null)
815
818
  const frameCounter = useRef({ count: 0, at: typeof performance !== 'undefined' ? performance.now() : Date.now() })
816
819
  const streamStatus = useStream(
@@ -821,7 +824,10 @@ window.__ModuleLoader__.load({
821
824
  attempt,
822
825
  quality,
823
826
  (w, h) => {
824
- if (w > 0 && h > 0) setRatio(w / h)
827
+ if (w > 0 && h > 0) {
828
+ setRatio(w / h)
829
+ setStreamSize({ width: w, height: h })
830
+ }
825
831
  },
826
832
  () => {
827
833
  frameCounter.current.count += 1
@@ -831,17 +837,27 @@ window.__ModuleLoader__.load({
831
837
  useEffect(() => {
832
838
  if (!serial) return undefined
833
839
  let alive = true
834
- api
835
- .screenInfo(serial)
836
- .then((info) => {
837
- if (alive && info && info.width && info.height && info.width > 0 && info.height > 0) {
838
- setDeviceSize({ width: info.width, height: info.height })
839
- setRatio(info.width / info.height)
840
- }
841
- })
842
- .catch(() => {})
840
+ let last = null
841
+ const apply = (info) => {
842
+ if (!info || !info.width || !info.height || info.width < 2 || info.height < 2) return
843
+ const changed = last && (last.width !== info.width || last.height !== info.height)
844
+ last = { width: info.width, height: info.height }
845
+ setDeviceSize(last)
846
+ setRatio(info.width / info.height)
847
+ // 设备分辨率变了(云手机平台切换):重连流,让 Host 按新尺寸重启 screenrecord
848
+ if (changed) setAttempt((value) => value + 1)
849
+ }
850
+ const check = async () => {
851
+ try {
852
+ const info = await api.screenInfo(serial, { fresh: true })
853
+ if (alive) apply(info)
854
+ } catch {}
855
+ }
856
+ check()
857
+ const timer = setInterval(check, 3000)
843
858
  return () => {
844
859
  alive = false
860
+ clearInterval(timer)
845
861
  }
846
862
  }, [serial])
847
863
 
@@ -1038,6 +1054,7 @@ window.__ModuleLoader__.load({
1038
1054
  ratio,
1039
1055
  immersive,
1040
1056
  deviceSize,
1057
+ streamSize,
1041
1058
  frameUrl,
1042
1059
  error: errorNow,
1043
1060
  loading: loadingNow,
@@ -1657,7 +1674,16 @@ window.__ModuleLoader__.load({
1657
1674
  qualityLabel(quality, t),
1658
1675
  )
1659
1676
  : null,
1660
- selected ? h('span', { className: 'dph-perf', title: t('quality') }, preview.fps + 'fps · ' + (preview.rtt == null ? '—' : preview.rtt + 'ms')) : null,
1677
+ selected
1678
+ ? h(
1679
+ 'span',
1680
+ { className: 'dph-perf', title: t('quality') },
1681
+ (preview.streamSize ? preview.streamSize.width + '×' + preview.streamSize.height + ' · ' : '') +
1682
+ preview.fps +
1683
+ 'fps · ' +
1684
+ (preview.rtt == null ? '—' : preview.rtt + 'ms'),
1685
+ )
1686
+ : null,
1661
1687
  h('div', { className: 'dph-grow' }),
1662
1688
  rightButtons,
1663
1689
  ),
package/lib/index.js CHANGED
@@ -95,7 +95,7 @@ export function apply(ctx, rawConfig) {
95
95
  case 'ping':
96
96
  return ok(await adb.ping(String(payload.serial || '')))
97
97
  case 'screen-info':
98
- return ok(await adb.screenInfo(String(payload.serial || '')))
98
+ return ok(await adb.screenInfo(String(payload.serial || ''), { fresh: payload.fresh === true }))
99
99
  case 'disconnect':
100
100
  return ok(await adb.disconnect(String(payload.serial || '')))
101
101
  case 'input':
@@ -151,7 +151,7 @@ export function apply(ctx, rawConfig) {
151
151
  if (preset) {
152
152
  openOptions = { bitRate: preset.bitRate }
153
153
  try {
154
- const info = await adb.screenInfo(serial)
154
+ const info = await adb.screenInfo(serial, { fresh: true })
155
155
  const dims = streamSizeFor(info, preset.shortSide)
156
156
  if (dims) openOptions.size = dims.width + 'x' + dims.height
157
157
  } catch {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ponydev/dsh-phone",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "DSH Web 插件:右侧栏预览并点按控制已连接的 Android 设备(adb)",
5
5
  "keywords": [
6
6
  "dsh",