/** * Accessibility Mode UI - Touch Keyboard & STT Display */ class AccessibilityUI { constructor() { this.keyboardBuffer = ''; this.displayData = { history: [], keyboard_buffer: '' }; this.wsConnected = false; this.initializeElements(); this.attachEventListeners(); this.startPolling(); } initializeElements() { this.keyboardBufferEl = document.getElementById('keyboard-buffer'); this.transcriptDisplay = document.getElementById('transcript-display'); this.transcriptHistoryEl = null; this.sttStatusEl = document.getElementById('stt-status'); this.ttsStatusEl = document.getElementById('tts-status'); this.modeIndicatorEl = document.getElementById('mode-indicator'); // Keyboard buttons this.keyButtons = document.querySelectorAll('.key[data-char]'); this.backspaceBtn = document.getElementById('backspace-btn'); this.spaceBtn = document.getElementById('space-btn'); this.clearBtn = document.getElementById('clear-btn'); this.sendBtn = document.getElementById('send-btn'); } attachEventListeners() { // Character keys this.keyButtons.forEach(btn => { btn.addEventListener('click', () => this.inputCharacter(btn.dataset.char)); btn.addEventListener('touch start', (e) => e.preventDefault()); }); // Special keys this.backspaceBtn.addEventListener('click', () => this.backspace()); this.spaceBtn.addEventListener('click', () => this.inputCharacter(' ')); this.clearBtn.addEventListener('click', () => this.clearBuffer()); this.sendBtn.addEventListener('click', () => this.sendInput()); // Physical keyboard support document.addEventListener('keydown', (e) => this.handlePhysicalKey(e)); } inputCharacter(char) { this.keyboardBuffer += char.toUpperCase(); this.updateDisplay(); this.sendToROS('', false); // Update display on ROS } backspace() { this.keyboardBuffer = this.keyboardBuffer.slice(0, -1); this.updateDisplay(); this.sendToROS('', false); } clearBuffer() { this.keyboardBuffer = ''; this.updateDisplay(); this.sendToROS('[CLEAR]', false); } sendInput() { if (this.keyboardBuffer.trim()) { this.sendToROS('[SEND]', true); this.keyboardBuffer = ''; this.updateDisplay(); } } handlePhysicalKey(e) { if (e.target !== document.body) return; const char = e.key.toUpperCase(); if (e.key === 'Backspace') { e.preventDefault(); this.backspace(); } else if (e.key === 'Enter') { e.preventDefault(); this.sendInput(); } else if (char.match(/^[A-Z0-9 .,!?]$/)) { this.inputCharacter(char); } } updateDisplay() { this.keyboardBufferEl.textContent = this.keyboardBuffer || '(empty)'; this.renderTranscriptHistory(); } renderTranscriptHistory() { if (!this.displayData.history) return; let html = ''; this.displayData.history.forEach(entry => { const cls = entry.type === 'stt' ? 'transcript-stt' : 'transcript-keyboard'; const icon = entry.type === 'stt' ? '🎤' : '⌨️'; const text = entry.text || ''; html += `