// 键盘输入处理类 class KeyboardInputHandler { constructor() { this.onCommand = null; // 命令回调函数 this.commandHistory = []; this.maxHistorySize = 20; this.isPanelCollapsed = false; this.isActive = false; // 面板激活状态 // 拖拽相关属性 this.isDragging = false; this.dragOffset = { x: 0, y: 0 }; this.currentPosition = { x: null, y: null }; this.init(); } init() { this.setupEventListeners(); this.updatePanel(); this.setActiveState(false); // 初始为非激活状态 this.setPanelCollapsed(true); // 默认折叠面板 console.log('键盘输入处理器已初始化'); } setupEventListeners() { // 输入框事件 const commandInput = document.getElementById('commandInput'); const sendBtn = document.getElementById('sendCommandBtn'); const toggleBtn = document.getElementById('toggleKeyboardPanel'); if (commandInput) { // 回车发送命令 commandInput.addEventListener('keydown', (e) => { if (e.key === 'Enter') { e.preventDefault(); this.sendCommand(); } }); // 历史记录导航(上下键) commandInput.addEventListener('keydown', (e) => { if (e.key === 'ArrowUp') { e.preventDefault(); this.navigateHistory(-1); } else if (e.key === 'ArrowDown') { e.preventDefault(); this.navigateHistory(1); } }); } // 发送按钮 if (sendBtn) { sendBtn.addEventListener('click', () => { this.sendCommand(); }); } // 面板折叠按钮 if (toggleBtn) { toggleBtn.addEventListener('click', () => { this.togglePanel(); }); } // 快捷指令按钮 const quickCmdBtns = document.querySelectorAll('.quick-cmd'); quickCmdBtns.forEach(btn => { btn.addEventListener('click', () => { const command = btn.getAttribute('data-command'); if (command) { this.executeCommand(command); } }); }); // 全局键盘快捷键 document.addEventListener('keydown', (e) => { this.handleGlobalShortcuts(e); }); // 历史记录点击事件 this.setupHistoryListener(); // 拖拽功能 this.setupDragFunctionality(); } setupHistoryListener() { const historyList = document.getElementById('commandHistory'); if (historyList) { historyList.addEventListener('click', (e) => { if (e.target.classList.contains('history-item') || e.target.parentElement.classList.contains('history-item')) { const historyItem = e.target.classList.contains('history-item') ? e.target : e.target.parentElement; const command = historyItem.querySelector('.history-command').textContent; if (command) { this.fillInputWithCommand(command); } } }); } } handleGlobalShortcuts(e) { // F9 由 main.js 处理,这里不再处理 // if (e.key === 'F9') { // e.preventDefault(); // this.toggleActiveState(); // return; // } // 只在面板激活且没有焦点在输入框时处理全局快捷键 if (!this.isActive || document.activeElement.tagName === 'INPUT') { return; } // Ctrl/Cmd + K 聚焦到输入框 if ((e.ctrlKey || e.metaKey) && e.key === 'k') { e.preventDefault(); this.focusInput(); } // Ctrl/Cmd + ` 切换面板 if ((e.ctrlKey || e.metaKey) && e.key === '`') { e.preventDefault(); this.togglePanel(); } // ESC 清空输入框、取消激活或折叠面板 if (e.key === 'Escape') { const input = document.getElementById('commandInput'); if (input && input.value) { input.value = ''; input.blur(); } else if (this.isActive) { this.setActiveState(false); } else { this.togglePanel(); } } // 数字键快速命令(1-6) - 仅在激活状态下工作 if (this.isActive && e.key >= '1' && e.key <= '6') { const quickCommands = [ 'cook cook cook pot', // 1 'stop stop stop pot', // 2 'apple', // 3 'banana', // 4 'pizza', // 5 'cake' // 6 ]; const commandIndex = parseInt(e.key) - 1; if (commandIndex < quickCommands.length) { e.preventDefault(); this.executeCommand(quickCommands[commandIndex]); } } } sendCommand() { const input = document.getElementById('commandInput'); if (!input || !this.isActive) return; const command = input.value.trim(); if (!command) return; this.executeCommand(command); input.value = ''; } executeCommand(command) { // 添加到历史记录 this.addToHistory(command); // 显示调试信息 console.log(`[键盘输入] 执行命令: "${command}"`); // 触发命令回调 if (this.onCommand) { this.onCommand(command); } // 更新界面 this.updatePanel(); this.showCommandFeedback(command); } addToHistory(command) { // 避免重复的连续命令 if (this.commandHistory.length > 0 && this.commandHistory[this.commandHistory.length - 1].command === command) { return; } const historyItem = { command: command, timestamp: new Date().toLocaleTimeString(), fullTimestamp: Date.now() }; this.commandHistory.push(historyItem); // 限制历史记录大小 if (this.commandHistory.length > this.maxHistorySize) { this.commandHistory.shift(); } this.updateHistoryDisplay(); } navigateHistory(direction) { // 实现历史记录导航功能 const input = document.getElementById('commandInput'); if (!input || this.commandHistory.length === 0) return; if (!this.historyIndex) { this.historyIndex = this.commandHistory.length; } this.historyIndex += direction; if (this.historyIndex < 0) { this.historyIndex = 0; } else if (this.historyIndex >= this.commandHistory.length) { this.historyIndex = this.commandHistory.length; input.value = ''; return; } input.value = this.commandHistory[this.historyIndex].command; } fillInputWithCommand(command) { const input = document.getElementById('commandInput'); if (input) { input.value = command; input.focus(); } } updateHistoryDisplay() { const historyList = document.getElementById('commandHistory'); if (!historyList) return; if (this.commandHistory.length === 0) { historyList.innerHTML = '
暂无命令历史
'; return; } const historyHTML = this.commandHistory .slice(-10) // 只显示最近10条 .reverse() .map(item => `
${this.escapeHtml(item.command)} ${item.timestamp}
`).join(''); historyList.innerHTML = historyHTML; } showCommandFeedback(command) { // 创建命令反馈动画 const panel = document.getElementById('keyboardInputPanel'); if (!panel) return; // 添加闪烁效果 panel.style.borderColor = '#ff6b6b'; setTimeout(() => { panel.style.borderColor = '#4ecdc4'; }, 200); // 在面板标题旁显示最后执行的命令 const header = panel.querySelector('.input-header h4'); if (header) { const originalText = header.textContent; header.textContent = `🎮 执行: ${command}`; header.style.color = '#ff6b6b'; setTimeout(() => { header.textContent = originalText; header.style.color = 'white'; }, 1500); } } togglePanel() { this.setPanelCollapsed(!this.isPanelCollapsed); } setPanelCollapsed(collapsed) { const panel = document.getElementById('keyboardInputPanel'); const content = document.getElementById('keyboardInputContent'); const toggleBtn = document.getElementById('toggleKeyboardPanel'); if (!panel || !content || !toggleBtn) return; this.isPanelCollapsed = collapsed; if (this.isPanelCollapsed) { // 完全隐藏面板 panel.style.display = 'none'; panel.classList.add('collapsed'); } else { // 显示面板 panel.style.display = 'block'; panel.classList.remove('collapsed'); content.style.display = 'block'; toggleBtn.textContent = '⌨️'; toggleBtn.title = '折叠键盘输入面板'; } console.log(`键盘输入面板${this.isPanelCollapsed ? '已隐藏' : '已显示'}`); } focusInput() { const input = document.getElementById('commandInput'); if (input) { // 如果面板未激活,先激活 if (!this.isActive) { this.setActiveState(true); } // 如果面板是折叠的,先展开 if (this.isPanelCollapsed) { this.setPanelCollapsed(false); } setTimeout(() => { input.focus(); }, 100); } } updatePanel() { this.updateHistoryDisplay(); // 更新快捷指令状态 const quickCmdBtns = document.querySelectorAll('.quick-cmd'); quickCmdBtns.forEach(btn => { btn.addEventListener('mouseenter', () => { const command = btn.getAttribute('data-command'); btn.title = `点击执行: ${command}`; }); }); } // 工具方法 escapeHtml(text) { const div = document.createElement('div'); div.textContent = text; return div.innerHTML; } // 设置面板激活状态 setActiveState(active) { console.log(`setActiveState called with: ${active}`); this.isActive = active; const panel = document.getElementById('keyboardInputPanel'); if (!panel) { console.log('keyboardInputPanel not found!'); return; } panel.classList.remove('active', 'inactive'); if (active) { panel.classList.add('active'); console.log('Panel activated - adding active class'); this.showActivationIndicator('面板已激活 - 可以输入命令'); } else { panel.classList.add('inactive'); console.log('Panel deactivated - adding inactive class'); this.showActivationIndicator('面板未激活 - 按F9激活'); } console.log(`键盘输入面板${active ? '已激活' : '已取消激活'}`); console.log('Panel classes:', panel.className); } // 切换面板激活状态 toggleActiveState() { console.log('toggleActiveState called, current state:', this.isActive); this.setActiveState(!this.isActive); console.log('toggleActiveState completed, new state:', this.isActive); } // 显示激活状态指示器 showActivationIndicator(message) { // 移除之前的指示器 const existingIndicator = document.querySelector('.activation-indicator'); if (existingIndicator) { existingIndicator.remove(); } // 创建新的指示器 const indicator = document.createElement('div'); indicator.className = 'activation-indicator'; indicator.textContent = message; indicator.style.cssText = ` position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: ${this.isActive ? '#4ecdc4' : '#6c757d'}; color: white; padding: 15px 25px; border-radius: 25px; font-family: 'Comic Neue', cursive; font-weight: bold; font-size: 16px; z-index: 15000; box-shadow: 0 8px 32px rgba(0,0,0,0.3); animation: activationPulse 0.5s ease-out; `; document.body.appendChild(indicator); // 自动移除 setTimeout(() => { if (indicator.parentNode) { indicator.style.animation = 'activationFadeOut 0.3s ease-out forwards'; setTimeout(() => { if (indicator.parentNode) { indicator.parentNode.removeChild(indicator); } }, 300); } }, 2000); } // 获取统计信息 getStats() { return { totalCommands: this.commandHistory.length, isCollapsed: this.isPanelCollapsed, isActive: this.isActive, lastCommand: this.commandHistory.length > 0 ? this.commandHistory[this.commandHistory.length - 1].command : null }; } // 清空历史记录 clearHistory() { this.commandHistory = []; this.updateHistoryDisplay(); console.log('命令历史已清空'); } // 导出历史记录 exportHistory() { const data = { exported: new Date().toISOString(), commands: this.commandHistory }; const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `magicpot-commands-${Date.now()}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); console.log('命令历史已导出'); } // 获取命令提示 getCommandSuggestions(input) { const suggestions = [ 'cook cook cook pot', 'stop stop stop pot', 'apple', 'banana', 'orange', 'strawberry', 'watermelon', 'grape', 'pizza', 'burger', 'bread', 'rice', 'noodles', 'cake', 'cookie', 'cheese', 'fish', 'chicken', 'carrot', 'tomato', 'corn', 'broccoli' ]; if (!input) return suggestions.slice(0, 5); const filtered = suggestions.filter(cmd => cmd.toLowerCase().includes(input.toLowerCase()) ); return filtered.slice(0, 8); } // 设置拖拽功能 setupDragFunctionality() { const panel = document.getElementById('keyboardInputPanel'); const header = panel?.querySelector('.input-header'); if (!panel || !header) return; // 鼠标按下开始拖拽 header.addEventListener('mousedown', (e) => { if (!this.isActive) return; // 只有激活状态下才能拖拽 this.isDragging = true; panel.classList.add('dragging'); const rect = panel.getBoundingClientRect(); this.dragOffset.x = e.clientX - rect.left; this.dragOffset.y = e.clientY - rect.top; // 记录当前位置 this.currentPosition.x = rect.left; this.currentPosition.y = rect.top; e.preventDefault(); }); // 全局鼠标移动事件 document.addEventListener('mousemove', (e) => { if (!this.isDragging) return; e.preventDefault(); // 计算新位置 let newX = e.clientX - this.dragOffset.x; let newY = e.clientY - this.dragOffset.y; // 边界检查 const rect = panel.getBoundingClientRect(); const maxX = window.innerWidth - rect.width; const maxY = window.innerHeight - rect.height; newX = Math.max(0, Math.min(newX, maxX)); newY = Math.max(0, Math.min(newY, maxY)); // 应用新位置 panel.style.left = newX + 'px'; panel.style.top = newY + 'px'; panel.style.right = 'auto'; panel.style.bottom = 'auto'; this.currentPosition.x = newX; this.currentPosition.y = newY; }); // 全局鼠标松开事件 document.addEventListener('mouseup', (e) => { if (!this.isDragging) return; this.isDragging = false; panel.classList.remove('dragging'); // 保存位置到localStorage this.savePosition(); }); // 加载保存的位置 this.loadPosition(); } // 保存面板位置 savePosition() { if (this.currentPosition.x !== null && this.currentPosition.y !== null) { const position = { x: this.currentPosition.x, y: this.currentPosition.y }; localStorage.setItem('keyboardPanelPosition', JSON.stringify(position)); } } // 加载保存的位置 loadPosition() { const panel = document.getElementById('keyboardInputPanel'); if (!panel) return; try { const savedPosition = localStorage.getItem('keyboardPanelPosition'); if (savedPosition) { const position = JSON.parse(savedPosition); // 检查位置是否在屏幕范围内 const rect = panel.getBoundingClientRect(); const maxX = window.innerWidth - rect.width; const maxY = window.innerHeight - rect.height; if (position.x >= 0 && position.x <= maxX && position.y >= 0 && position.y <= maxY) { panel.style.left = position.x + 'px'; panel.style.top = position.y + 'px'; panel.style.right = 'auto'; panel.style.bottom = 'auto'; this.currentPosition.x = position.x; this.currentPosition.y = position.y; } } } catch (error) { console.warn('加载面板位置失败:', error); } } // 重置面板位置到右下角 resetPosition() { const panel = document.getElementById('keyboardInputPanel'); if (!panel) return; panel.style.left = 'auto'; panel.style.top = 'auto'; panel.style.right = '20px'; panel.style.bottom = '20px'; this.currentPosition.x = null; this.currentPosition.y = null; // 清除保存的位置 localStorage.removeItem('keyboardPanelPosition'); console.log('面板位置已重置到右下角'); } } // 添加快捷键提示样式 const keyboardStyle = document.createElement('style'); keyboardStyle.textContent = ` .keyboard-shortcuts-hint { position: absolute; bottom: 5px; left: 50%; transform: translateX(-50%); background: rgba(0, 0, 0, 0.8); color: white; padding: 5px 10px; border-radius: 10px; font-size: 0.7em; white-space: nowrap; opacity: 0; transition: opacity 0.3s ease; pointer-events: none; font-family: 'Comic Neue', cursive; } .keyboard-input-panel:hover .keyboard-shortcuts-hint { opacity: 1; } .command-input:focus + .keyboard-shortcuts-hint { opacity: 1; } @keyframes activationPulse { 0% { opacity: 0; transform: translate(-50%, -50%) scale(0.8); } 50% { transform: translate(-50%, -50%) scale(1.1); } 100% { opacity: 1; transform: translate(-50%, -50%) scale(1); } } @keyframes activationFadeOut { from { opacity: 1; transform: translate(-50%, -50%) scale(1); } to { opacity: 0; transform: translate(-50%, -50%) scale(0.9); } } `; document.head.appendChild(keyboardStyle);