windows-input.mjs 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142
  1. import { execFile } from 'node:child_process'
  2. import { join } from 'node:path'
  3. export function windowsFrame(display, dimensions, physicalBounds) {
  4. return { display: display.id, ...dimensions, bounds: display.bounds, scaleFactor: display.scaleFactor, physicalBounds }
  5. }
  6. export function sameWindowsDisplay(frame, display, physicalBounds) {
  7. return frame?.display === display.id && frame.scaleFactor === display.scaleFactor
  8. && JSON.stringify(frame.bounds) === JSON.stringify(display.bounds)
  9. && JSON.stringify(frame.physicalBounds) === JSON.stringify(physicalBounds)
  10. }
  11. export class WindowsInput {
  12. constructor(root, packaged, execute = execFile) {
  13. this.helper = join(root, packaged ? 'computer-helper.exe' : 'computer-helper-dev.exe')
  14. this.execute = execute; this.controllers = new Set(); this.pending = new Set(); this.available = false
  15. }
  16. async call(value) {
  17. const controller = new AbortController()
  18. this.controllers.add(controller)
  19. let pending
  20. try {
  21. pending = new Promise((resolve, reject) => {
  22. const child = this.execute(this.helper, [], { timeout: 10000, signal: controller.signal, windowsHide: true, maxBuffer: 65536 }, (error, stdout, stderr) => {
  23. if (error) { this.available = false; reject(new Error(String(stderr || '').trim() || 'Windows 电脑助手不可用,请检查桌面会话或重新安装客户端')); return }
  24. try { const result = JSON.parse(stdout); if (result.ok !== true) throw new Error(); resolve(result) }
  25. catch { this.available = false; reject(new Error('Windows 电脑助手响应无效')) }
  26. })
  27. child.stdin.on('error', () => {})
  28. child.stdin.end(JSON.stringify(value))
  29. })
  30. this.pending.add(pending)
  31. return await pending
  32. } finally { this.controllers.delete(controller); this.pending.delete(pending) }
  33. }
  34. async probe() {
  35. try { await this.call({ operation: 'probe' }); this.available = true }
  36. catch { this.available = false }
  37. return this.available
  38. }
  39. cancel() { for (const controller of this.controllers) controller.abort(); this.available = false; return Promise.allSettled([...this.pending]) }
  40. }