| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- import { useRef, useCallback, useState, useEffect } from 'react';
- // 触摸事件处理逻辑:坐标转换和手势模拟
- export function useTouchEvents(currentDevice, imageRef) {
- const isDragging = useRef(false);
- const startPos = useRef({ x: 0, y: 0 });
- const lastPos = useRef({ x: 0, y: 0 });
- const touchStartTime = useRef(0);
- const [deviceResolution, setDeviceResolution] = useState({ width: 1280, height: 2400 });
- // 获取设备实际分辨率
- useEffect(() => {
- const fetchDeviceResolution = async () => {
- if (!currentDevice || !window.electronAPI || !window.electronAPI.getDeviceResolution) {
- // 如果 API 不可用,使用默认值
- return;
- }
- try {
- const result = await window.electronAPI.getDeviceResolution(currentDevice);
- if (result?.success && result.width && result.height) {
- setDeviceResolution({ width: result.width, height: result.height });
- }
- } catch (err) {
- console.warn('获取设备分辨率失败,使用默认值:', err);
- }
- };
- if (currentDevice) {
- fetchDeviceResolution();
- }
- }, [currentDevice]);
- // 将鼠标坐标转换为设备坐标
- const convertToDeviceCoords = useCallback((clientX, clientY) => {
- if (!imageRef.current) {
- return null;
- }
- const img = imageRef.current;
- const rect = img.getBoundingClientRect();
-
- // 获取图片的实际显示尺寸(考虑 object-fit: contain)
- // 图片可能不会完全填满容器,需要计算实际显示区域
- let displayWidth, displayHeight, offsetX, offsetY;
-
- if (img.naturalWidth && img.naturalHeight) {
- // 获取图片的原始尺寸
- const imgAspect = img.naturalWidth / img.naturalHeight;
- const containerAspect = rect.width / rect.height;
-
- if (imgAspect > containerAspect) {
- // 图片更宽,以宽度为准(左右可能有黑边)
- displayWidth = rect.width;
- displayHeight = rect.width / imgAspect;
- offsetX = 0;
- offsetY = (rect.height - displayHeight) / 2;
- } else {
- // 图片更高,以高度为准(上下可能有黑边)
- displayHeight = rect.height;
- displayWidth = rect.height * imgAspect;
- offsetX = (rect.width - displayWidth) / 2;
- offsetY = 0;
- }
- } else {
- // 如果图片尺寸未知,使用容器尺寸
- displayWidth = rect.width;
- displayHeight = rect.height;
- offsetX = 0;
- offsetY = 0;
- }
-
- // 计算鼠标相对于实际显示区域的位置
- const relativeX = (clientX - rect.left - offsetX) / displayWidth;
- const relativeY = (clientY - rect.top - offsetY) / displayHeight;
-
- // 检查是否在有效显示区域内(0-1之间)
- if (relativeX < 0 || relativeX > 1 || relativeY < 0 || relativeY > 1) {
- // 点击在显示区域外(黑边区域),返回 null
- return null;
- }
-
- // 转换为设备坐标
- const deviceX = Math.round(relativeX * deviceResolution.width);
- const deviceY = Math.round(relativeY * deviceResolution.height);
-
- // 确保坐标在设备范围内
- const clampedX = Math.max(0, Math.min(deviceResolution.width - 1, deviceX));
- const clampedY = Math.max(0, Math.min(deviceResolution.height - 1, deviceY));
-
- return { x: clampedX, y: clampedY };
- }, [imageRef, deviceResolution]);
- // 发送 tap 事件到设备
- const sendTap = useCallback(async (x, y) => {
- if (!currentDevice || !window.electronAPI || !window.electronAPI.sendTap) {
- console.warn('Tap API 不可用或设备未连接');
- return;
- }
- try {
- const result = await window.electronAPI.sendTap(currentDevice, x, y);
- if (!result?.success) {
- console.error('Tap 失败:', result?.error);
- }
- } catch (err) {
- console.error('Tap 异常:', err);
- }
- }, [currentDevice]);
- // 发送 swipe 事件到设备
- const sendSwipe = useCallback(async (x1, y1, x2, y2, duration = 300) => {
- if (!currentDevice || !window.electronAPI || !window.electronAPI.sendSwipe) {
- console.warn('Swipe API 不可用或设备未连接');
- return;
- }
- try {
- const result = await window.electronAPI.sendSwipe(currentDevice, x1, y1, x2, y2, duration);
- if (!result?.success) {
- console.error('Swipe 失败:', result?.error);
- }
- } catch (err) {
- console.error('Swipe 异常:', err);
- }
- }, [currentDevice]);
- // 处理鼠标按下
- const handleMouseDown = useCallback((e) => {
- if (!currentDevice || !imageRef.current) return;
-
- e.preventDefault();
- isDragging.current = true;
- touchStartTime.current = Date.now();
-
- const deviceCoords = convertToDeviceCoords(e.clientX, e.clientY);
- if (deviceCoords) {
- startPos.current = deviceCoords;
- lastPos.current = deviceCoords;
- }
- }, [currentDevice, imageRef, convertToDeviceCoords]);
- // 处理鼠标移动
- const handleMouseMove = useCallback((e) => {
- if (!isDragging.current || !currentDevice || !imageRef.current) return;
-
- e.preventDefault();
-
- const deviceCoords = convertToDeviceCoords(e.clientX, e.clientY);
- if (deviceCoords) {
- lastPos.current = deviceCoords;
- }
- }, [currentDevice, imageRef, convertToDeviceCoords]);
- // 处理鼠标释放
- const handleMouseUp = useCallback((e) => {
- if (!isDragging.current || !currentDevice) return;
-
- e.preventDefault();
- isDragging.current = false;
-
- const touchDuration = Date.now() - touchStartTime.current;
- const distance = Math.sqrt(
- Math.pow(lastPos.current.x - startPos.current.x, 2) +
- Math.pow(lastPos.current.y - startPos.current.y, 2)
- );
-
- // 判断是 tap 还是 swipe
- // 如果移动距离小于 10 像素且时间小于 300ms,认为是 tap
- if (distance < 10 && touchDuration < 300) {
- // Tap 操作
- sendTap(startPos.current.x, startPos.current.y);
- } else if (distance >= 10) {
- // Swipe 操作
- const swipeDuration = Math.max(100, Math.min(1000, touchDuration));
- sendSwipe(
- startPos.current.x,
- startPos.current.y,
- lastPos.current.x,
- lastPos.current.y,
- swipeDuration
- );
- }
- }, [currentDevice, sendTap, sendSwipe]);
- // 处理鼠标离开(防止拖拽到外部时无法触发 mouseup)
- const handleMouseLeave = useCallback((e) => {
- if (isDragging.current) {
- handleMouseUp(e);
- }
- }, [handleMouseUp]);
- return {
- handleMouseDown,
- handleMouseMove,
- handleMouseUp,
- handleMouseLeave,
- };
- }
|