+
+ Click to access all hotkeys
+
+
+
+
+
+
+
diff --git a/client/web/src/main.ts b/client/web/src/main.ts
index c1cb0f2b..4b83aaef 100644
--- a/client/web/src/main.ts
+++ b/client/web/src/main.ts
@@ -1,9 +1,11 @@
import { createApp } from "vue";
+import { fullscreenModeChanged } from "@/utilities/fullscreen";
import { handleKeyUp, handleKeyDown } from "@/utilities/input";
import App from "./App.vue";
// Bind global browser events
document.addEventListener("contextmenu", (e) => e.preventDefault());
+document.addEventListener("fullscreenchange", () => fullscreenModeChanged());
window.addEventListener("keyup", (e: KeyboardEvent) => handleKeyUp(e));
window.addEventListener("keydown", (e: KeyboardEvent) => handleKeyDown(e));
diff --git a/client/web/src/utilities/fullscreen.ts b/client/web/src/utilities/fullscreen.ts
new file mode 100644
index 00000000..744e0a7b
--- /dev/null
+++ b/client/web/src/utilities/fullscreen.ts
@@ -0,0 +1,37 @@
+import { reactive, readonly } from "vue";
+
+const state = reactive({
+ windowFullscreen: false,
+ keyboardLocked: false,
+});
+
+export function fullscreenModeChanged() {
+ state.windowFullscreen = Boolean(document.fullscreenElement);
+ if (!state.windowFullscreen) state.keyboardLocked = false;
+}
+
+export function keyboardLockApiSupported(): boolean {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ return "keyboard" in navigator && "lock" in (navigator as any).keyboard;
+}
+
+export async function enterFullscreen() {
+ await document.documentElement.requestFullscreen();
+
+ if (keyboardLockApiSupported()) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ await (navigator as any).keyboard.lock(["ControlLeft", "ControlRight"]);
+ state.keyboardLocked = true;
+ }
+}
+
+export async function exitFullscreen() {
+ await document.exitFullscreen();
+}
+
+export async function toggleFullscreen() {
+ if (state.windowFullscreen) await exitFullscreen();
+ else await enterFullscreen();
+}
+
+export default readonly(state);
diff --git a/client/web/src/utilities/input.ts b/client/web/src/utilities/input.ts
index b6954985..eacb6189 100644
--- a/client/web/src/utilities/input.ts
+++ b/client/web/src/utilities/input.ts
@@ -1,3 +1,5 @@
+import { toggleFullscreen } from "@/utilities/fullscreen";
+
const wasm = import("@/../wasm/pkg");
export function shouldRedirectKeyboardEventToBackend(e: KeyboardEvent): boolean {
@@ -6,7 +8,11 @@ export function shouldRedirectKeyboardEventToBackend(e: KeyboardEvent): boolean
if (target.nodeName === "INPUT" || target.nodeName === "TEXTAREA" || target.isContentEditable) return false;
// Don't redirect a fullscreen request
- if (e.key.toLowerCase() === "f11") return false;
+ if (e.key.toLowerCase() === "f11" && e.type === "keydown" && !e.repeat) {
+ e.preventDefault();
+ toggleFullscreen();
+ return false;
+ }
// Don't redirect a reload request
if (e.key.toLowerCase() === "f5") return false;