I am trying to create a simple HTML file that I can use to make one half of my 32:9 widescreen dark (e.g. while watching a video).
I have created this document that works pretty well:
<!DOCTYPE html>
<html>
<head>
<title> </title>
<meta charset="utf-8">
<style>
* { background-color: black; height: 100%; margin: 0; padding: 0; }
.no-cursor { cursor: none; }
</style>
<script type="text/javascript">
const MOTION_TIMEOUT = 500;
const FREEZE_TIMEOUT = 1000;
const NO_CURSOR_CLASS = "no-cursor";
var motionTimer, unfreezeTimer, hidden, frozen;
function tryOpenFullscreen(elem) {
let requestFullscreen = elem.requestFullscreen || elem.mozRequestFullScreen || elem.webkitRequestFullscreen || elem.msRequestFullscreen;
if (requestFullscreen) {
try {
requestFullscreen.call(elem);
} catch (error) {
console.error("Failed to open fullscreen", error);
}
} else {
console.error("Fullscreen not supported");
}
}
function mouseNotMoved() {
window.clearTimeout(motionTimer);
hide();
}
function mouseMoved() {
if (!frozen) {
window.clearTimeout(motionTimer);
show();
motionTimer = window.setTimeout(mouseNotMoved, MOTION_TIMEOUT);
}
}
function isInFullscreen() {
const element = document.fullscreenElement || document.webkitFullscreenElement || document.msFullscreenElement;
return element !== undefined && element !== null;
}
function toggleFullscreen() {
// Toggling fullscreen will trigger mousemove event,
// so we need to freeze the cursor motion detection for a short time
window.clearTimeout(unfreezeTimer);
freeze();
unfreezeTimer = window.setTimeout(unfreeze, FREEZE_TIMEOUT);
if (isInFullscreen()) {
document.exitFullscreen();
} else {
tryOpenFullscreen(document.body);
}
}
function keyPress(event) {
if (event.key === "Escape") {
// Exit fullscreen when pressing Escape
if (isInFullscreen()) {
toggleFullscreen();
}
} else if (event.key === "f") {
toggleFullscreen();
} else if (event.key === "F11") {
// Prevent browser from going fullscreen by pressing F11
// Using F11 to exit fullscreen is allowed
if (!isInFullscreen()) {
event.preventDefault();
toggleFullscreen();
}
}
}
function hide() {
document.body.classList.add(NO_CURSOR_CLASS);
hidden = true;
}
function show() {
document.body.classList.remove(NO_CURSOR_CLASS);
hidden = false;
}
function freeze() {
frozen = true;
}
function unfreeze() {
frozen = false;
}
function init() {
hidden = true;
frozen = false;
document.body.addEventListener("mousemove", mouseMoved);
document.body.addEventListener("dblclick", toggleFullscreen);
window.addEventListener("keydown", keyPress);
motionTimer = window.setTimeout(mouseNotMoved, MOTION_TIMEOUT);
}
window.addEventListener("load", init);
</script>
</head>
<body>
</body>
</html>
It's basically a blank black page with some setTimeout code to hide the cursor when that doesn't move for a bit. And to make the whole screen black, I have a method toggleFullscreen that determines whether it needs to request or exit the fullscreen, and then calls uses the available requestFullscreen method on the document.body element, or document.exitFullscreen().
toggleFullscreen is called either as the dblclick event handler, or from within an event handler for the keydown event if the F key was pressed. All this works absolutely fine, I can press F as often as I want to toggle back and forth.
But now I'm having trouble with adding the last "feature": The default F11 fullscreen mode will reveal a flyout navigation bar when the mouse moves to the top screen border, which is unwanted behavior for my purposes. Hence I would like to use my own toggleFullscreen for entering. As suggested here I am calling event.preventDefault() first, and then toggleFullscreen.
But here it becomes strange: entering fullscreen this way works, but not if I just left fullscreen with F11:
- I can intercept the first
F11keypress, prevent the browser fullscreen, and go into DOM fullscreen instead. - I also intercept the second
F11, but let it exit fullscreen by native means, which works just fine, too. - When I press
F11for the third time,requestFullscreenthrows an error "Fullscreen request denied".
The error comes with a warning "Request for full-screen was denied because Element.mozRequestFullScreen() was not called from inside a short running user-generated event handler." This question talks about this error, but I'm not having a 1-second problem I think - the code should take mere milliseconds to get to the request.
What puzzles me is that the keydown event handler should tick all the boxes for "short running user-generated event handler" (event.isTrusted is true for the F11 event that will cause the throw).
I did some testing and found that requesting fullscreen through F11 fails if and only if the previous user-generated event was "exit fullscreen through F11":
My keydown event handler
- works indefinitely when using only
Fto enter and exit - works indefinitely when using
F11to enter butFto exit - doesn't work when using
Fto enter andF11to exit and thenF11to enter again - works indefinitely using just
F11to enter and exit when I click once before usingF11to enter
I've tried using document.focus() and document.click() in an attempt to mimic the effect of the mouse click, but to no avail. I also tried using preventDefault + toggleFullscreen for F11 enter and exit, but that doesn't make a difference, either.
The document works in Edge and Chrome, but as Firefox is my default browser, I'd like to fix it for this.