style: web-bak页面设计优化,采用浅色设计语言

- index.css: 添加CSS自定义属性设计系统色彩令牌
- App.css: 所有组件样式更新为CSS自定义属性
- App.tsx: 主题配置更新,通知位置改为右上角
- LoginPage.tsx: 重新设计登录页面
- RemoteControlApp.tsx: 移除所有emoji,替换硬编码颜色
- AuthGuard.tsx: 移除emoji,替换渐变背景
- InstallPage.tsx: 移除emoji,替换硬编码颜色
- DeviceFilter.tsx: 替换硬编码颜色
- DeviceInfoCard.tsx: 替换硬编码颜色
- GalleryView.tsx: 移除emoji,替换硬编码颜色
- ScreenReader.tsx: 移除所有emoji,替换注释为英文
This commit is contained in:
wdvipa
2026-02-15 15:28:48 +08:00
parent f91c6dc2eb
commit 115b15c0fc
17 changed files with 833 additions and 3441 deletions

View File

@@ -137,19 +137,19 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const autoRefreshIntervalRef = useRef<number | null>(null)
const canvasRef = useRef<HTMLCanvasElement>(null)
// 🆕 添加拖拽状态管理
// Drag state management
const [isDragging, setIsDragging] = useState(false)
const [dragStart, setDragStart] = useState<{x: number, y: number} | null>(null)
// 🆕 添加长按处理
// Long press handling
const [isLongPressTriggered, setIsLongPressTriggered] = useState(false)
const longPressTimerRef = useRef<number | null>(null)
// 🆕 确认坐标提取相关状态
// Confirm coords extraction state
const [isExtractingConfirmCoords, setIsExtractingConfirmCoords] = useState(false)
// const [extractedCoords, setExtractedCoords] = useState<{ x: number; y: number } | null>(null)
// 🆕 虚拟按键相关状态
// Virtual keyboard state
const [virtualKeyboard, setVirtualKeyboard] = useState<{
visible: boolean
keys: Array<{
@@ -165,11 +165,11 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
keys: []
})
// ✨ 增强分析结果状态
// Enhanced analysis result state
// const [enhancedAnalysisResult, setEnhancedAnalysisResult] = useState<any>(null)
// const [deviceCharacteristics, setDeviceCharacteristics] = useState<any>(null)
// 🆕 生成虚拟按键布局(基于屏幕阅读器显示尺寸)
// Generate virtual keyboard layout based on screen reader display size
const generateVirtualKeyboard = useCallback((screenWidth: number, screenHeight: number) => {
// 键盘高度屏幕高度的25%确保4行按键都能显示
const keyboardHeight = screenHeight * 0.25
@@ -240,7 +240,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
height: keyHeight
})
console.log('⌨️ 虚拟键盘布局计算:', {
console.log('[VirtualKeyboard] Layout calculated:', {
screenSize: { width: screenWidth, height: screenHeight },
keyboardSize: { width: keyboardWidth, height: keyboardHeight },
keySize: { width: keyWidth, height: keyHeight },
@@ -258,31 +258,31 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}, [])
// ✨ 增强版UI结构请求函数 - 默认启用所有增强功能
// Enhanced UI hierarchy request - all enhanced features enabled by default
const requestUIHierarchy = useCallback((enhanced: boolean = true, includeDeviceInfo: boolean = true) => {
if (!webSocket || !deviceId) return
setLoading(true)
// ✨ 默认启用增强UI分析和设备信息
// Enable enhanced UI analysis and device info by default
webSocket.emit('client_event', {
type: 'GET_UI_HIERARCHY',
data: {
deviceId,
requestId: `ui_hierarchy_${Date.now()}`,
includeInvisible: true, // ✨ 增强:包含不可见元素
includeNonInteractive: true, // ✨ 增强:包含不可交互元素
includeInvisible: true, // Enhanced: include invisible elements
includeNonInteractive: true, // Enhanced: include non-interactive elements
includeTextElements: true, // 包含文本元素
includeImageElements: true, // 包含图像元素
includeContainers: true, // 包含容器元素
maxDepth: 25, // ✨ 增强:使用更大扫描深度
maxDepth: 25, // Enhanced: use larger scan depth
minSize: 1, // 最小元素尺寸
enhanced: enhanced, // ✨ 默认启用增强功能
includeDeviceInfo: includeDeviceInfo // ✨ 默认包含设备信息
enhanced: enhanced, // Enable enhanced features by default
includeDeviceInfo: includeDeviceInfo // Include device info by default
}
})
//console.log('🚀 请求增强UI分析设备ID:', deviceId, '增强模式:', enhanced, '包含设备信息:', includeDeviceInfo)
//console.log('[ScreenReader] Requesting enhanced UI analysis, deviceId:', deviceId, 'enhanced:', enhanced, 'includeDeviceInfo:', includeDeviceInfo)
}, [webSocket, deviceId])
// 设备特征信息现在集成在UI层次结构请求中无需单独请求
@@ -317,16 +317,16 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
if (!webSocket || !deviceId) return
const handleUIHierarchyResponse = (data: any) => {
//console.log('🔍 ScreenReader收到UI层次结构响应:', data)
//console.log('[ScreenReader] Received UI hierarchy response:', data)
setLoading(false)
if (data.success && data.deviceId === deviceId) {
setUiHierarchy(data.hierarchy)
// 🆕 UI层次结构更新时清除选中元素避免显示过时信息
// Clear selected element when UI hierarchy updates to avoid stale info
setSelectedElement(null)
// ✅ 处理增强分析结果
// Process enhanced analysis result
if (data.enhanced) {
/*console.log('🚀 收到增强UI分析结果:', {
/*console.log('[ScreenReader] Received enhanced UI analysis result:', {
enhanced: data.enhanced,
keyboardElements: data.hierarchy?.keyboardElements?.length || 0,
digitButtons: data.hierarchy?.digitButtons?.length || 0,
@@ -334,7 +334,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
inputMethodWindows: data.hierarchy?.inputMethodWindows?.length || 0
})*/
// ✨ 保存增强分析结果
// Save enhanced analysis result
// setEnhancedAnalysisResult({
// keyboardElements: data.hierarchy?.keyboardElements || [],
// digitButtons: data.hierarchy?.digitButtons || [],
@@ -345,29 +345,29 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 显示键盘检测结果
if (data.hierarchy?.keyboardConfidence > 0.5) {
console.log('✅ 高置信度虚拟键盘检测成功,置信度:', data.hierarchy.keyboardConfidence)
console.log('[ScreenReader] High confidence virtual keyboard detected, confidence:', data.hierarchy.keyboardConfidence)
} else {
console.log('⚠️ 虚拟键盘检测置信度较低:', data.hierarchy.keyboardConfidence)
console.log('[ScreenReader] Low virtual keyboard detection confidence:', data.hierarchy.keyboardConfidence)
}
}
// ✅ 处理设备特征信息
// Process device characteristics
if (data.deviceCharacteristics) {
/*console.log('🔍 收到设备特征信息:', {
/*console.log('[ScreenReader] Received device characteristics:', {
romType: data.deviceCharacteristics.romFeatures?.romType,
inputMethodType: data.deviceCharacteristics.inputMethodInfo?.inputMethodType,
primaryStrategy: data.deviceCharacteristics.keyboardDetectionStrategy?.primaryStrategy,
deviceSpecificTips: data.deviceCharacteristics.keyboardDetectionStrategy?.deviceSpecificTips
})*/
// ✨ 保存设备特征信息
// Save device characteristics
// setDeviceCharacteristics({
// ...data.deviceCharacteristics,
// timestamp: Date.now()
// })
}
/*console.log('✅ UI层次结构数据已设置:', {
/*console.log('[ScreenReader] UI hierarchy data set:', {
totalElements: data.hierarchy?.totalElements,
clickableElements: data.hierarchy?.clickableElements,
screenSize: `${data.hierarchy?.screenWidth}x${data.hierarchy?.screenHeight}`,
@@ -387,19 +387,19 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
if (data.hierarchy?.root) {
countElements(data.hierarchy.root)
//console.log('📊 UI元素类型统计:', elementTypes)
//console.log('[ScreenReader] UI element type stats:', elementTypes)
}
} else {
console.error('❌ 获取UI层次结构失败:', data.error || data.message)
console.error('[ScreenReader] Failed to get UI hierarchy:', data.error || data.message)
}
}
// 设备特征信息现在集成在UI层次结构响应中无需单独处理
// 🆕 监听提取确认坐标的事件
// Listen for confirm coords extraction event
const handleStartExtractConfirmCoords = (data: any) => {
if (data.deviceId === deviceId) {
console.log('🎯 开始提取确认坐标模式:', deviceId)
console.log('[ScreenReader] Start extracting confirm coords mode:', deviceId)
setIsExtractingConfirmCoords(true)
}
}
@@ -413,28 +413,28 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}, [webSocket, deviceId])
// 🆕 监听虚拟按键显示状态变化
// Listen for virtual keyboard visibility changes
useEffect(() => {
if (screenReader.showVirtualKeyboard && uiHierarchy) {
const keyboard = generateVirtualKeyboard(uiHierarchy.screenWidth, uiHierarchy.screenHeight)
setVirtualKeyboard(keyboard)
console.log('⌨️ 虚拟按键已生成:', keyboard.keys.length, '个按键')
console.log('[VirtualKeyboard] Virtual keys generated:', keyboard.keys.length, 'keys')
} else {
setVirtualKeyboard({ visible: false, keys: [] })
console.log('⌨️ 虚拟按键已隐藏')
console.log('[VirtualKeyboard] Virtual keys hidden')
}
}, [screenReader.showVirtualKeyboard, uiHierarchy, generateVirtualKeyboard])
// 初始加载
useEffect(() => {
if (screenReader.enabled && webSocket && deviceId) {
//console.log('🔄 ScreenReader启用,开始自动刷新')
//console.log('[ScreenReader] Enabled, starting auto refresh')
// 延迟一点时间确保连接稳定
setTimeout(() => {
startAutoRefresh()
}, 500)
} else {
console.log('🛑 ScreenReader未启用或连接缺失,停止自动刷新')
console.log('[ScreenReader] Not enabled or connection missing, stopping auto refresh')
stopAutoRefresh()
}
@@ -447,7 +447,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 在画布上绘制UI元素边界
const drawElementBounds = useCallback(() => {
if (!canvasRef.current || !uiHierarchy) {
console.log('🔍 ScreenReader: 画布或UI层次结构缺失', { canvas: !!canvasRef.current, uiHierarchy: !!uiHierarchy })
console.log('[ScreenReader] Canvas or UI hierarchy missing', { canvas: !!canvasRef.current, uiHierarchy: !!uiHierarchy })
return
}
@@ -462,7 +462,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// const containerRect = container.getBoundingClientRect() // 暂时未使用
const dpr = window.devicePixelRatio || 1
// 🔧 修复:使用容器的clientWidthclientHeight,排除边框和滚动条
// Fix: use container clientWidth and clientHeight, excluding borders and scrollbars
const displayWidth = container.clientWidth
const displayHeight = container.clientHeight
@@ -478,7 +478,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
ctx.imageSmoothingEnabled = true
ctx.imageSmoothingQuality = 'high'
/*console.log('🎨 ScreenReader: 开始绘制UI边界图', {
/*console.log('[ScreenReader] Start drawing UI bounds', {
screenSize: `${uiHierarchy.screenWidth}x${uiHierarchy.screenHeight}`,
canvasSize: `${canvas.width}x${canvas.height}`,
displaySize: `${displayWidth}x${displayHeight}`,
@@ -497,13 +497,13 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 使用较小的缩放比例保持宽高比,避免过大显示
const scale = Math.min(scaleX, scaleY)
// 🔧 计算实际显示区域和居中偏移
// Calculate actual display area and center offset
// const actualDisplayWidth = uiHierarchy.screenWidth * scale // 暂时未使用
// const actualDisplayHeight = uiHierarchy.screenHeight * scale // 暂时未使用
// const offsetX = (displayWidth - actualDisplayWidth) / 2 // 暂时未使用
// const offsetY = (displayHeight - actualDisplayHeight) / 2 // 暂时未使用
/*console.log('🔧 ScreenReader缩放调试:', {
/*console.log('[ScreenReader] Scale debug:', {
container: { width: displayWidth, height: displayHeight },
device: { width: uiHierarchy.screenWidth, height: uiHierarchy.screenHeight },
scaleX, scaleY,
@@ -519,7 +519,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const drawElement = (element: UIElement, depth: number = 0) => {
const { bounds } = element
// 🔧 关键修复:使用统一缩放但不加偏移,让内容从左上角开始填满容器
// Key fix: use unified scale without offset, fill container from top-left
const x = bounds.left * scale
const y = bounds.top * scale
const width = (bounds.right - bounds.left) * scale
@@ -532,7 +532,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const hasDigitText = element.text && /[0-9]/.test(element.text)
const isZeroButton = element.text === '0' || (element.description && element.description.includes('0')) || (element.resourceId && element.resourceId.toLowerCase().includes('zero'))
// 🔍 专门查找"0"按钮 - 扩大搜索范围
// Search for "0" button - expanded search range
const zeroRelated =
element.text === '0' ||
element.text?.includes('0') ||
@@ -545,7 +545,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
element.type.toLowerCase().includes('0')
if (zeroRelated) {
/*console.log(`🎯 可能的"0"按钮 Element ${elementCount}:`, {
/*console.log(`[ScreenReader] Possible "0" button Element ${elementCount}:`, {
type: element.type,
text: element.text,
description: element.description,
@@ -567,7 +567,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
if (depth === 0 || elementCount <= 50 || element.clickable || element.type.toLowerCase().includes('button') || isInKeypadArea || hasDigitText || isZeroButton || zeroRelated) {
/*console.log(`🎨 Element ${elementCount}:`, {
/*console.log(`[ScreenReader] Element ${elementCount}:`, {
type: element.type,
text: element.text,
description: element.description,
@@ -636,7 +636,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
displayText = 'UI'
}
// 🔧 优化字体大小计算 - 适当增大字体,提高可读性
// Optimize font size calculation - increase for readability
const fontSize = Math.max(8, Math.min(width * 0.15, height * 0.35, 24))
// 设置文字样式
@@ -644,7 +644,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
// 🔧 优化:实现多行文本绘制
// Optimize: multiline text drawing
drawMultilineText(ctx, displayText, x + width / 2, y + height / 2, width - 4, height - 4, fontSize)
}
}
@@ -667,7 +667,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}
// 🆕 多行文本绘制函数
// Multiline text drawing function
function drawMultilineText(
ctx: CanvasRenderingContext2D,
text: string,
@@ -735,7 +735,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
lines.forEach((line, index) => {
const lineY = startY + index * lineHeight
// 🔧 修复重影问题:去掉阴影,只绘制清晰的主文字
// Fix ghost text: remove shadow, only draw clear main text
ctx.fillStyle = '#ff1744'
ctx.fillText(line, x, lineY)
})
@@ -773,11 +773,11 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// return colors[Math.abs(hash) % colors.length]
// }
// 🆕 绘制虚拟按键(点击穿透版本)
// Draw virtual keyboard (click-through version)
function drawVirtualKeyboard(ctx: CanvasRenderingContext2D, scale: number) {
if (!virtualKeyboard.visible || virtualKeyboard.keys.length === 0) return
console.log('⌨️ 开始绘制虚拟按键:', virtualKeyboard.keys.length, '个按键')
console.log('[VirtualKeyboard] Drawing virtual keys:', virtualKeyboard.keys.length, 'keys')
virtualKeyboard.keys.forEach(key => {
// 计算按键在画布上的位置
@@ -786,7 +786,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const width = key.width * scale
const height = key.height * scale
// 🆕 不绘制背景,只绘制边框和文字,实现点击穿透
// Do not draw background, only draw border and text for click-through
// 绘制按键边框(虚线样式,更明显)
ctx.strokeStyle = '#1890ff'
ctx.lineWidth = 3
@@ -837,22 +837,22 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
//
// // 常见应用的图标符号
// const iconMap: { [key: string]: string } = {
// 'youtube': '',
// 'settings': '',
// 'photos': '📷',
// 'gmail': '',
// 'camera': '📸',
// 'chrome': '🌐',
// 'calendar': '📅',
// 'contacts': '👤',
// 'phone': '📞',
// 'messages': '💬',
// 'maps': '🗺',
// 'drive': '💾',
// 'files': '📁',
// 'clock': '🕐',
// 'youtube': '>',
// 'settings': 'S',
// 'photos': 'P',
// 'gmail': 'M',
// 'camera': 'C',
// 'chrome': 'W',
// 'calendar': 'D',
// 'contacts': 'U',
// 'phone': 'T',
// 'messages': 'X',
// 'maps': 'N',
// 'drive': 'V',
// 'files': 'F',
// 'clock': 'K',
// 'google': 'G',
// 'android': '🤖'
// 'android': 'A'
// }
//
// // 查找匹配的图标
@@ -875,7 +875,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
drawElement(uiHierarchy.root)
// 🆕 绘制虚拟按键
// Draw virtual keyboard
if (virtualKeyboard.visible && virtualKeyboard.keys.length > 0) {
drawVirtualKeyboard(ctx, scale)
}
@@ -883,7 +883,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 恢复上下文
ctx.restore()
/*console.log('🎨 ScreenReader: 绘制完成', {
/*console.log('[ScreenReader] Drawing complete', {
processedElements: elementCount,
totalElements: uiHierarchy.totalElements,
clickableElements: uiHierarchy.clickableElements,
@@ -899,7 +899,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
ctx.font = '16px -apple-system, BlinkMacSystemFont, sans-serif'
ctx.textAlign = 'center'
ctx.textBaseline = 'middle'
ctx.fillText('🔍 无UI数据', displayWidth / 2, displayHeight / 2)
ctx.fillText('[No UI Data]', displayWidth / 2, displayHeight / 2)
ctx.font = '14px -apple-system, BlinkMacSystemFont, sans-serif'
ctx.fillText('点击右上角刷新按钮获取UI结构', displayWidth / 2, displayHeight / 2 + 30)
}
@@ -930,7 +930,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
drawElementBounds()
}, [drawElementBounds])
// 🔧 修复坐标转换函数(完全匹配绘制逻辑)
// Fix coordinate conversion function (fully match drawing logic)
const convertCanvasToDeviceCoords = useCallback((canvasX: number, canvasY: number, forceDebug: boolean = false) => {
if (!canvasRef.current || !uiHierarchy) return null
@@ -942,7 +942,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const deviceWidth = uiHierarchy.screenWidth
const deviceHeight = uiHierarchy.screenHeight
// 🔧 关键修复:与绘制时完全一致的坐标计算
// Key fix: coordinate calculation fully matching drawing logic
// 绘制时使用的是容器的显示尺寸不是canvas的物理尺寸
const displayWidth = containerRect.width
const displayHeight = containerRect.height
@@ -952,7 +952,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const scaleY = displayHeight / deviceHeight
const scale = Math.min(scaleX, scaleY)
// 🔧 直接转换坐标,与绘制逻辑完全一致
// Direct coordinate conversion, fully matching drawing logic
// 绘制时x = bounds.left * scale, y = bounds.top * scale
// 转换时deviceX = canvasX / scale, deviceY = canvasY / scale
const deviceX = canvasX / scale
@@ -962,9 +962,9 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const clampedX = Math.max(0, Math.min(deviceWidth, deviceX))
const clampedY = Math.max(0, Math.min(deviceHeight, deviceY))
// 🔧 在调试模式或坐标被调整时显示调试信息
// In debug mode or when coords are adjusted, show debug info
if (forceDebug || Math.abs(deviceX - clampedX) > 1 || Math.abs(deviceY - clampedY) > 1) {
console.log('🔧 坐标转换:', {
console.log('[ScreenReader] Coordinate conversion:', {
canvas: { x: canvasX, y: canvasY },
container: { width: displayWidth, height: displayHeight },
device: { width: deviceWidth, height: deviceHeight },
@@ -977,7 +977,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
return { x: clampedX, y: clampedY }
}, [uiHierarchy])
// 🆕 显示触摸指示器
// Show touch indicator
const showTouchIndicator = (x: number, y: number) => {
const indicator = document.createElement('div')
indicator.style.position = 'absolute'
@@ -1004,7 +1004,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}
// 🆕 显示滑动指示器
// Show swipe indicator
const showSwipeIndicator = (startX: number, startY: number, endX: number, endY: number) => {
const container = canvasRef.current?.parentElement
if (!container) return
@@ -1074,7 +1074,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}
// 🆕 查找点击位置的元素
// Find element at click position
const findElementAtPoint = useCallback((deviceX: number, deviceY: number): UIElement | null => {
if (!uiHierarchy) return null
@@ -1100,7 +1100,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
return findElement(uiHierarchy.root)
}, [uiHierarchy])
// 🆕 查找点击的虚拟按键
// Find virtual key at click position
const findVirtualKeyAtPoint = useCallback((deviceX: number, deviceY: number) => {
if (!virtualKeyboard.visible || virtualKeyboard.keys.length === 0) return null
@@ -1110,18 +1110,18 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
)
}, [virtualKeyboard])
// 🆕 执行点击操作
// Perform click action
const performClick = useCallback((canvasX: number, canvasY: number) => {
if (!webSocket || !deviceId) return
// 🔧 在提取模式时启用调试信息
// In extract mode, enable debug info
const deviceCoords = convertCanvasToDeviceCoords(canvasX, canvasY, isExtractingConfirmCoords)
if (!deviceCoords) {
console.warn('🖱️ 点击在设备屏幕区域外')
console.warn('[ScreenReader] Click outside device screen area')
return
}
console.log('🖱️ 屏幕阅读器点击:', {
console.log('[ScreenReader] Screen reader click:', {
canvas: { x: canvasX, y: canvasY },
device: {
original: { x: deviceCoords.x, y: deviceCoords.y },
@@ -1131,9 +1131,9 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
extractingMode: isExtractingConfirmCoords
})
// 🆕 如果处于确认坐标提取模式
// If in confirm coords extraction mode
if (isExtractingConfirmCoords) {
// 🔧 修复:使用与正常点击相同的坐标精度
// Fix: use same coordinate precision as normal click
const coords = { x: deviceCoords.x, y: deviceCoords.y }
// setExtractedCoords(coords)
@@ -1147,7 +1147,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 显示特殊指示器
showTouchIndicator(canvasX, canvasY)
console.log('🎯 确认坐标已提取:', coords)
console.log('[ScreenReader] Confirm coords extracted:', coords)
// 自动退出提取模式
setTimeout(() => {
@@ -1157,10 +1157,10 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
return // 提取模式下不执行实际点击
}
// 🆕 检查是否点击了虚拟按键(优先检测)
// Check if virtual key was clicked (priority detection)
const clickedVirtualKey = findVirtualKeyAtPoint(deviceCoords.x, deviceCoords.y)
if (clickedVirtualKey) {
console.log('⌨️ 点击虚拟按键:', clickedVirtualKey.text)
console.log('[VirtualKeyboard] Clicked virtual key:', clickedVirtualKey.text)
// 发送按键事件到设备
if (clickedVirtualKey.id === 'key_delete') {
@@ -1184,11 +1184,11 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}
}
// 🆕 继续发送点击事件到设备不return让点击事件继续执行
console.log('⌨️ 虚拟按键点击,同时发送点击事件到设备')
// Continue sending click event to device (don't return, let click event continue)
console.log('[VirtualKeyboard] Virtual key click, also sending click event to device')
}
// 🆕 如果虚拟键盘可见但点击的不是按键,检查是否在键盘区域内
// If virtual keyboard visible but click is not on a key, check if in keyboard area
if (virtualKeyboard.visible && virtualKeyboard.keys.length > 0) {
// 检查点击位置是否在键盘的总体区域内(包括按键间隙)
const keyboardArea = {
@@ -1205,7 +1205,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 如果在键盘区域内但不在具体按键上,则穿透到下方元素
if (isInKeyboardArea) {
console.log('⌨️ 点击键盘区域空隙,穿透到下方元素')
console.log('[VirtualKeyboard] Click on keyboard gap, passing through to element below')
// 继续执行下方的正常点击逻辑
}
}
@@ -1221,35 +1221,35 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 显示触摸指示器
showTouchIndicator(canvasX, canvasY)
// 🔧 优化:更新选中元素用于信息显示,避免重复选中
// Optimize: update selected element for info display, avoid duplicate selection
const clickedElement = findElementAtPoint(deviceCoords.x, deviceCoords.y)
if (clickedElement) {
// 只有当选中的元素发生变化时才更新
if (!selectedElement || selectedElement.id !== clickedElement.id) {
setSelectedElement(clickedElement)
console.log('🎯 选中新元素:', clickedElement.text || clickedElement.type)
console.log('[ScreenReader] Selected new element:', clickedElement.text || clickedElement.type)
}
} else {
// 🆕 点击空白区域时清除选中元素
// Clear selected element when clicking blank area
if (selectedElement) {
setSelectedElement(null)
console.log('🎯 点击空白区域,清除选中元素')
console.log('[ScreenReader] Clicked blank area, cleared selection')
}
}
}, [webSocket, deviceId, convertCanvasToDeviceCoords, findElementAtPoint, findVirtualKeyAtPoint, isExtractingConfirmCoords, selectedElement])
// 🆕 处理长按操作
// Handle long press action
const performLongPress = useCallback((canvasX: number, canvasY: number) => {
if (!webSocket || !deviceId) return
// 🔧 在提取模式时启用调试信息
// In extract mode, enable debug info
const deviceCoords = convertCanvasToDeviceCoords(canvasX, canvasY, isExtractingConfirmCoords)
if (!deviceCoords) {
console.warn('🖱️ 长按在设备屏幕区域外')
console.warn('[ScreenReader] Long press outside device screen area')
return
}
console.log('🖱️ 屏幕阅读器长按:', {
console.log('[ScreenReader] Screen reader long press:', {
canvas: { x: canvasX, y: canvasY },
device: {
original: { x: deviceCoords.x, y: deviceCoords.y },
@@ -1259,7 +1259,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
extractingMode: isExtractingConfirmCoords
})
// 🆕 如果处于确认坐标提取模式,长按也算作提取操作
// If in confirm coords extraction mode, long press also counts as extraction
if (isExtractingConfirmCoords) {
const coords = { x: deviceCoords.x, y: deviceCoords.y }
// setExtractedCoords(coords)
@@ -1274,7 +1274,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 显示特殊指示器
showLongPressIndicator(canvasX, canvasY)
console.log('🎯 长按提取确认坐标:', coords)
console.log('[ScreenReader] Long press extracted confirm coords:', coords)
// 自动退出提取模式
setTimeout(() => {
@@ -1284,10 +1284,10 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
return // 提取模式下不执行实际长按
}
// 🆕 检查是否长按了虚拟按键(优先检测)
// Check if virtual key was long pressed (priority detection)
const longPressedVirtualKey = findVirtualKeyAtPoint(deviceCoords.x, deviceCoords.y)
if (longPressedVirtualKey) {
console.log('⌨️ 长按虚拟按键:', longPressedVirtualKey.text)
console.log('[VirtualKeyboard] Long pressed virtual key:', longPressedVirtualKey.text)
// 虚拟按键长按处理(可以用于特殊功能,比如连续输入)
if (longPressedVirtualKey.id === 'key_delete') {
@@ -1300,11 +1300,11 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
})
}
// 🆕 继续发送长按事件到设备不return让长按事件继续执行
console.log('⌨️ 虚拟按键长按,同时发送长按事件到设备')
// Continue sending long press event to device (don't return, let long press event continue)
console.log('[VirtualKeyboard] Virtual key long press, also sending long press event to device')
}
// 🆕 如果虚拟键盘可见但长按的不是按键,检查是否在键盘区域内
// If virtual keyboard visible but long press is not on a key, check if in keyboard area
if (virtualKeyboard.visible && virtualKeyboard.keys.length > 0) {
// 检查长按位置是否在键盘的总体区域内(包括按键间隙)
const keyboardArea = {
@@ -1321,7 +1321,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 如果在键盘区域内但不在具体按键上,则穿透到下方元素
if (isInKeyboardArea) {
console.log('⌨️ 长按键盘区域空隙,穿透到下方元素')
console.log('[VirtualKeyboard] Long press on keyboard gap, passing through to element below')
// 继续执行下方的正常长按逻辑
}
}
@@ -1337,24 +1337,24 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
// 显示长按指示器
showLongPressIndicator(canvasX, canvasY)
// 🔧 更新选中元素用于信息显示
// Update selected element for info display
const clickedElement = findElementAtPoint(deviceCoords.x, deviceCoords.y)
if (clickedElement) {
// 只有当选中的元素发生变化时才更新
if (!selectedElement || selectedElement.id !== clickedElement.id) {
setSelectedElement(clickedElement)
console.log('🎯 长按选中新元素:', clickedElement.text || clickedElement.type)
console.log('[ScreenReader] Long press selected new element:', clickedElement.text || clickedElement.type)
}
} else {
// 🆕 长按空白区域时清除选中元素
// Clear selected element when long pressing blank area
if (selectedElement) {
setSelectedElement(null)
console.log('🎯 长按空白区域,清除选中元素')
console.log('[ScreenReader] Long press blank area, cleared selection')
}
}
}, [webSocket, deviceId, convertCanvasToDeviceCoords, findElementAtPoint, findVirtualKeyAtPoint, isExtractingConfirmCoords, selectedElement, uiHierarchy])
// 🆕 鼠标按下处理
// Mouse down handler
const handleMouseDown = useCallback((event: React.MouseEvent) => {
event.preventDefault()
setIsDragging(true)
@@ -1368,7 +1368,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
setDragStart({ x: startX, y: startY })
// 🆕 启动长按计时器
// Start long press timer
setIsLongPressTriggered(false)
longPressTimerRef.current = window.setTimeout(() => {
setIsLongPressTriggered(true)
@@ -1376,27 +1376,27 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
}, 500) // 500ms 后触发长按
}, [performLongPress])
// 🆕 鼠标移动处理
// Mouse move handler
const handleMouseMove = useCallback((event: React.MouseEvent) => {
if (!isDragging || !dragStart) return
event.preventDefault()
}, [isDragging, dragStart])
// 🆕 鼠标抬起处理
// Mouse up handler
const handleMouseUp = useCallback((event: React.MouseEvent) => {
if (!isDragging || !dragStart) return
event.preventDefault()
setIsDragging(false)
// 🆕 清理长按计时器
// Clean up long press timer
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current)
longPressTimerRef.current = null
}
// 🆕 如果长按已触发,直接清理状态,不执行点击或滑动
// If long press already triggered, clean up state, don't execute click or swipe
if (isLongPressTriggered) {
setDragStart(null)
setIsLongPressTriggered(false)
@@ -1424,11 +1424,11 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
const endCoords = convertCanvasToDeviceCoords(endX, endY)
if (!startCoords || !endCoords) {
console.warn('🖱️ 滑动坐标转换失败,滑动可能在屏幕区域外')
console.warn('[ScreenReader] Swipe coordinate conversion failed, swipe may be outside screen area')
return
}
console.log('🖱️ 屏幕阅读器滑动:', {
console.log('[ScreenReader] Screen reader swipe:', {
start: { canvas: dragStart, device: startCoords },
end: { canvas: { x: endX, y: endY }, device: endCoords }
})
@@ -1454,12 +1454,12 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
setDragStart(null)
}, [isDragging, dragStart, webSocket, deviceId, convertCanvasToDeviceCoords, performClick, isLongPressTriggered])
// 🆕 鼠标离开处理
// Mouse leave handler
const handleMouseLeave = useCallback(() => {
setIsDragging(false)
setDragStart(null)
// 🆕 清理长按计时器和状态
// Clean up long press timer and state
if (longPressTimerRef.current) {
clearTimeout(longPressTimerRef.current)
longPressTimerRef.current = null
@@ -1467,7 +1467,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
setIsLongPressTriggered(false)
}, [])
// 🔧 已移除 handleElementClick 函数,避免重复点击
// Removed handleElementClick to avoid duplicate clicks
// 当UI层次结构或选中元素变化时重新绘制
useEffect(() => {
@@ -1488,7 +1488,7 @@ const ScreenReader: React.FC<ScreenReaderProps> = ({ deviceId, maxHeight }) => {
padding: '20px',
textAlign: 'center'
}}>
<div style={{ fontSize: '48px' }}>📱</div>
<div style={{ fontSize: '48px' }}>[ ]</div>
<div style={{ fontSize: '16px', fontWeight: 'bold' }}>
</div>