Rewild Your Web
web
browser
dweb
1// SPDX-License-Identifier: AGPL-3.0-or-later
2
3let shiftActive = false;
4let inputType = "text";
5let currentValue = "";
6
7// Check if the keyboard API is available
8const keyboardAvailable = typeof navigator.keyboard !== "undefined";
9if (keyboardAvailable) {
10 console.log("[Keyboard] navigator.keyboard API is available");
11} else {
12 console.warn(
13 "[Keyboard] navigator.keyboard API is NOT available - virtual keyboard will not function",
14 );
15}
16
17// Send a character to the active input via composition event
18function sendCharacter(char) {
19 if (!keyboardAvailable) {
20 return;
21 }
22 try {
23 navigator.keyboard.sendCompositionEvent({
24 state: "end",
25 data: char,
26 });
27 } catch (e) {
28 console.error("[Keyboard] Failed to send character:", e);
29 }
30}
31
32// Send a keyboard event (keydown + keyup) for special keys
33function sendKeyEvent(key, code) {
34 if (!keyboardAvailable) {
35 return;
36 }
37 try {
38 navigator.keyboard.sendKeyboardEvent({
39 state: "down",
40 key: key,
41 code: code || key,
42 });
43 navigator.keyboard.sendKeyboardEvent({
44 state: "up",
45 key: key,
46 code: code || key,
47 });
48 } catch (e) {
49 console.error("[Keyboard] Failed to send key event:", e);
50 }
51}
52
53// Listen for messages from parent to get input context
54window.addEventListener("message", (event) => {
55 if (event.data.type === "show") {
56 inputType = event.data.inputType || "text";
57 currentValue = event.data.currentValue || "";
58 console.log("[Keyboard] Input context received:", {
59 inputType,
60 currentValue,
61 });
62 // TODO: Adapt keyboard layout based on inputType (e.g., number pad for "number")
63 }
64});
65
66// Update key labels based on shift state
67function updateKeyLabels() {
68 document.querySelectorAll(".key[data-key]").forEach((key) => {
69 const keyValue = key.dataset.key;
70 if (keyValue.length === 1 && keyValue.match(/[a-z]/i)) {
71 key.textContent = shiftActive
72 ? keyValue.toUpperCase()
73 : keyValue.toLowerCase();
74 }
75 });
76
77 // Update shift button visual state
78 document.querySelectorAll(".shift").forEach((btn) => {
79 btn.classList.toggle("active", shiftActive);
80 });
81}
82
83// Handle key clicks
84document.querySelectorAll(".key").forEach((key) => {
85 key.addEventListener("click", (e) => {
86 e.preventDefault();
87
88 const action = key.dataset.action;
89 const keyValue = key.dataset.key;
90
91 if (action === "shift") {
92 shiftActive = !shiftActive;
93 updateKeyLabels();
94 console.log("[Keyboard] Shift toggled:", shiftActive);
95 } else if (action === "backspace") {
96 console.log("[Keyboard] Backspace pressed");
97 sendKeyEvent("Backspace", "Backspace");
98 } else if (action === "return") {
99 console.log("[Keyboard] Return pressed");
100 sendKeyEvent("Enter", "Enter");
101 } else if (action === "symbols") {
102 console.log("[Keyboard] Symbols mode requested");
103 // TODO: Switch to symbols keyboard layout
104 } else if (keyValue) {
105 let charToSend = keyValue;
106 if (shiftActive && keyValue.match(/[a-z]/i)) {
107 charToSend = keyValue.toUpperCase();
108 shiftActive = false; // Auto-release shift after typing
109 updateKeyLabels();
110 }
111 console.log("[Keyboard] Key pressed:", charToSend);
112 sendCharacter(charToSend);
113 }
114 });
115});
116
117// Initialize
118updateKeyLabels();