| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- import { useEffect, useRef, useState, useCallback } from 'react';
- import ScrcpyConfig from './ScrcpyConfig.js';
- // 截屏逻辑:监听设备预览事件,轮询 adb 截屏并展示
- export function ScreenShotLogic() {
- const [currentDevice, setCurrentDevice] = useState(null);
- const [imageSrc, setImageSrc] = useState(null);
- const stopFlag = useRef(false);
- const waitForLoadRef = useRef(null);
- const activeDeviceRef = useRef(null);
- const loopIdRef = useRef(null);
- const frameCounterRef = useRef(0);
-
- // 从配置文件读取参数
- const pollInterval = ScrcpyConfig['poll-interval'] || 100;
- const imageLoadTimeout = ScrcpyConfig['image-load-timeout'] || 500;
- // 截屏循环:请求截图 -> 显示 -> 等待加载 -> 再请求下一帧
- const startLoop = useCallback(async (device) => {
- // 避免同时多个循环
- const loopId = Symbol('loop');
- loopIdRef.current = loopId;
- const runOnce = async () => {
- // 检查是否应该停止循环
- if (stopFlag.current || loopIdRef.current !== loopId || activeDeviceRef.current !== device) {
- return;
- }
- try {
- // 请求屏幕截图
- if (!window.electronAPI || !window.electronAPI.captureScreenshot) {
- console.warn('截屏 API 不可用');
- await delay(pollInterval);
- runOnce();
- return;
- }
- // 请求截图(传递配置参数)
- const res = await window.electronAPI.captureScreenshot(device, {
- format: ScrcpyConfig['screencap-format'],
- quality: ScrcpyConfig['screencap-quality'],
- scale: ScrcpyConfig['screencap-scale']
- });
-
- if (!res?.success || !res.data) {
- // 截图失败,等待后重试
- await delay(pollInterval);
- runOnce();
- } else {
- // 截图成功,更新图片
- const stamp = frameCounterRef.current++;
- const format = ScrcpyConfig['screencap-format'] || 'png';
- const mimeType = format === 'jpeg' ? 'image/jpeg' : 'image/png';
- const dataUrl = `data:${mimeType};base64,${res.data}#${stamp}`;
-
- // 创建等待图片加载的 Promise
- const waitPromise = new Promise((resolve) => {
- waitForLoadRef.current = resolve;
- });
-
- // 更新图片源(会触发图片加载)
- setImageSrc(dataUrl);
-
- // 等待图片加载完成(onLoad 触发)或超时(使用配置的超时时间),然后立即请求下一帧
- await Promise.race([waitPromise, delay(imageLoadTimeout)]);
-
- // 继续请求下一帧截图
- runOnce();
- }
- } catch (err) {
- console.error('截屏循环异常:', err);
- await delay(pollInterval);
- runOnce();
- }
- };
- // 开始循环
- runOnce();
- }, []);
- // 监听来自 Devices 的开始/停止预览事件
- useEffect(() => {
- const handleStart = (e) => {
- const device = e.detail?.device;
- if (!device) return;
-
- // 停止之前的循环(如果有)
- stopFlag.current = true;
-
- // 启动新的预览循环
- stopFlag.current = false;
- activeDeviceRef.current = device;
- setCurrentDevice(device);
- setImageSrc(null); // 清空之前的图片
- startLoop(device);
- };
- const handleStop = (e) => {
- const device = e.detail?.device;
- // 只有当前预览设备才停止
- if (!device || device === activeDeviceRef.current) {
- stopFlag.current = true;
- activeDeviceRef.current = null;
- loopIdRef.current = null;
- setCurrentDevice(null);
- setImageSrc(null);
- }
- };
- window.addEventListener('start-preview', handleStart);
- window.addEventListener('stop-preview', handleStop);
- return () => {
- window.removeEventListener('start-preview', handleStart);
- window.removeEventListener('stop-preview', handleStop);
- stopFlag.current = true;
- };
- }, [startLoop]);
- // 提供给组件的 onLoad 回调,通知图片已加载,可以请求下一帧
- const notifyImageLoaded = useCallback(() => {
- if (waitForLoadRef.current) {
- waitForLoadRef.current();
- waitForLoadRef.current = null;
- }
- }, []);
- return {
- currentDevice,
- imageSrc,
- notifyImageLoaded,
- };
- }
- function delay(ms) {
- return new Promise((resolve) => setTimeout(resolve, ms));
- }
|