class KeyboardController { constructor(connection) { this.connection = connection; this.container = null; this.layouts = { default: [ ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"], ["q", "w", "e", "r", "t", "y", "u", "i", "o", "p"], ["a", "s", "d", "f", "g", "h", "j", "k", "l"], ["🄰", "z", "x", "c", "v", "b", "n", "m", ".", "⌦"], ["🔢", " ", "↵"] ], uppercase: [ ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"], ["A", "S", "D", "F", "G", "H", "J", "K", "L"], ["🅰", "Z", "X", "C", "V", "B", "N", "M", ",", "⌦"], ["🔢", " ", "↵"] ], symbols: [ ["!", "@", "#", "$", "%", "^", "&", "*", "(", ")"], ["[", "]", "{", "}", ";", ":", "'", "\"", ",", "<"], [".", ">", "-", "_", "=", "+", "/", "?", "\\"], ["🄰", "|", "`", "~", "⌦"], ["🔤", " ", "↵"] ] } } _sendKeyPress(l) { this.connection.sendMessage("k", [l]); } makeKeyboardForLayout(layout) { queueMicrotask(() => { while (this.container.firstChild) { this.container.removeChild(this.container.lastChild); } const rowsParent = document.createElement("div"); rowsParent.classList.add("Keyboard-rows"); const rowsFragment = document.createDocumentFragment(); for (let row = 0; row < layout.length; row++) { const rowElement = document.createElement("div"); rowElement.classList.add("Keyboard-row"); for (let col = 0; col < layout[row].length; col++) { const key = layout[row][col]; const colElement = document.createElement("button"); colElement.classList.add("Keyboard-button"); colElement.innerText = key; colElement.addEventListener("click", () => { this.handleKeypress(key); }); rowElement.appendChild(colElement); } rowsFragment.appendChild(rowElement); } rowsParent.appendChild(rowsFragment); this.container.appendChild(rowsParent); }); } handleKeypress(key) { switch (key) { case "🄰": { this.makeKeyboardForLayout(this.layouts.uppercase); break; } case "🅰": { this.makeKeyboardForLayout(this.layouts.default); break; } case "🔢": { this.makeKeyboardForLayout(this.layouts.symbols); break; } case "🔤": { this.makeKeyboardForLayout(this.layouts.default); break; } case " ": { this._sendKeyPress("{space}"); break; } case "⌦": { this._sendKeyPress("{backspace}"); break; } case "↵": { this._sendKeyPress("{ent}"); break; } default: { this._sendKeyPress(key); break; } } } mountOn(element) { if (this.container) return; // Already mounted; this.container = document.createElement("div"); this.container.classList.add("Keyboard"); element.appendChild(this.container); this.makeKeyboardForLayout(this.layouts.default); } unmount() { if (!this.container) return; // Not mounted - don't do anything this.container.parentElement.removeChild(this.container); this.container = null; } } export default KeyboardController;