Skip to content

fix(ui): Fullscreen keyboard lock logic#535

Merged
ym merged 1 commit intojetkvm:devfrom
IDisposable:keyboard-lock
Jun 2, 2025
Merged

fix(ui): Fullscreen keyboard lock logic#535
ym merged 1 commit intojetkvm:devfrom
IDisposable:keyboard-lock

Conversation

@IDisposable
Copy link
Copy Markdown
Contributor

When the keyboard lock is supposed to be active (in full-screen mode), hitting the escape key (NOT long-pressing) should NOT dismiss the full-screen mode, and should send the Escape key through to the remote.

  • Added awaits to the browser calls that need to complete in order.
  • Cleaned up (mostly) duplicate code in the Absolute/Relative mouse handling.
  • Ensure we don't overrun any existing keyboard lock or pointer lock.
  • Release the keyboard lock when leaving full-screen.
  • Per standards, we need to acquire the keyboard and pointer locks before entering full-screen or the user may get multiple messages about exiting.
  • Fixed all the missing/excess React dependencies.
  • Moved the PointerLockBar up so it is visible.
  • Change PointerLockBar animations to ensure it is visible when needed.
  • Fixed readonly warnings.


interface OverlayContentProps {
children: React.ReactNode;
readonly children: React.ReactNode;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a warning in VS Code that all these properties should be declared readonly (which they should), so while I was in here I updated them. We need to do a sweep through the UI to get the rest... another PR will arrive for ONLY warning-fixes.

initial={{ y: 20, opacity: 0, zIndex: 0 }}
animate={{ opacity: 1, y: 0 }}
exit={{ y: 43, zIndex: 0 }}
className="flex w-full items-center justify-between bg-transparent"
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Animating the location just plain broke the layout and resulted in this button/action just being behind and invisible to the user. I couldn't get the thing centered the way I wanted, but in this form it animates into and out of visibility correctly. Also, setting the motion.div tobg-transparent helps ensure it doesn't look ugly.

exit={{ y: 43, zIndex: 0 }}
className="flex w-full items-center justify-between bg-transparent"
initial={{ opacity: 0, zIndex: 0 }}
animate={{ opacity: 1, zIndex: 20 }}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even though the div was supposed to be z-20, not animating to that destination left the div as z-index: 0 and thus invisible. Just changing this was NOT enough because it was still positioned all wonky relative to the action bar.

className="flex w-full items-center justify-between bg-transparent"
initial={{ opacity: 0, zIndex: 0 }}
animate={{ opacity: 1, zIndex: 20 }}
exit={{ opacity: 0, zIndex: 0 }}
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we fade in, we have to fade out :)

// Pointer lock and keyboard lock related
const isPointerLockPossible = window.location.protocol === "https:";

const isPointerLockPossible = window.location.protocol === "https:" || window.location.hostname === "localhost";
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also allowing pointer lock on "localhost" so we can test during development (this will not be an issue in deployed code)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I didn't realize that it could work on localhost. :-)

);

const videoKeyUpHandler = useCallback((e: KeyboardEvent) => {
if (!videoElm.current) return;
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cleaner to bail out so we don't need ?. below.


// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
window.clearKeys = () => sendKeyboardEvent([], []);
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not be polluting the global window namespace with this! I searched and found no references to clearKeys, so elided that line.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can probably use useRef or other methods to expose the API.@adamshiervani Any better idea?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you have a use-case, I can restore that line... but there are NO references to clearKeys anywhere else in the code-base

mouseWheelHandler,
videoKeyUpHandler,
],
[onVideoPlaying, videoKeyUpHandler],
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here and elsewhere, I deleted all the dependencies and let VSCode put back the ones really needed.

);

// Setup Absolute Mouse Events
// Setup Mouse Events
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Merged the (nearly) duplicate handling for relative vs. absolute mouse handling.

);
} else {
// Reset the mouse position when the window is blurred or the document is hidden
window.addEventListener("blur", resetMousePosition, { signal });
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suspect we should be doing this in both cases, but wasn't sure how to confirm that, so I left it only on absolute mouse mode.

@IDisposable
Copy link
Copy Markdown
Contributor Author

Ready for you @ym @adamshiervani

@IDisposable IDisposable marked this pull request as draft May 28, 2025 01:38
@IDisposable IDisposable marked this pull request as ready for review May 28, 2025 01:38
@IDisposable
Copy link
Copy Markdown
Contributor Author

Before this change, on entering full screen you get the message To exit full screen, press Esc and if you hit an Escape key it will leave full screen mode.
Before

After this change, on entering full screen you get the message To exit full screen, press and hold Esc and if you hit an Escape key it will NOT leave full screen mode.
After

When the keyboard lock is supposed to be active (in full-screen mode), hitting the escape key (NOT long-pressing) should NOT dismiss the full-screen mode, and should send the Escape key through to the remote.

- Added awaits to the browser calls that need to complete in order.
- Cleaned up (mostly) duplicate code in the Absolute/Relative mouse handling
- Ensure we don't overrun any existing keyboard lock or pointer lock
- Release the keyboard lock when leaving full-screen
- Per standards, we need to acquire the keyboard and pointer locks before entering full-screen or the user may get multiple messages about exiting.
- Fixed all the missing/excess React dependencies.
- Moved the pointer lock bar up so it is visible.
- Somewhere along the way, the prompt to click the video when in relative-mouse-mode stopped being visible, restored it's visibility
- Fixed all the "should be readonly" warnings.
@adrianmeraz
Copy link
Copy Markdown
Contributor

Looks great, looking forward to being able to using escape on my remote machines (which I do all the time by accident)

@ym ym merged commit f4bb47c into jetkvm:dev Jun 2, 2025
2 checks passed
@IDisposable IDisposable deleted the keyboard-lock branch June 3, 2025 01:20

const checkNavigatorPermissions = useCallback(async (permissionName: string) => {
const name = permissionName as PermissionName;
const { state } = await navigator.permissions.query({ name });
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will throw an error in browsers that do understand a permission, e.g. Firefox, causing the fullscreen button to not do anything. See: https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query

Thrown if retrieving the PermissionDescriptor information failed in some way, or the permission doesn't exist or is unsupported by the user agent.

Screenshot 2025-06-19 at 22 11 23

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use anything but Chrome and Edge, so thanks for finding this. I can wrap that with a check.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in #631

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't use anything but Chrome and Edge, so thanks for finding this. I can wrap that with a check.

Unfortunately it is still necessary to do cross-browser and cross-device testing in the world of web development today. I can recommend caniuse.com.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PR #631 submitted

IDisposable added a commit to IDisposable/kvm that referenced this pull request Jun 19, 2025
Per jetkvm#535 (comment) we need to handle Firefox/Mozilla browsers not having these pointer-lock or keyboard-lock permissions checks. Also might as well not throw if something goes wrong when trying to check permissions or apply for locks.
@adrianmeraz
Copy link
Copy Markdown
Contributor

@IDisposable Did this really get merged into the latest update? I don't see the changes, doesn't required a long press ESC

@IDisposable
Copy link
Copy Markdown
Contributor Author

IDisposable commented Jun 25, 2025

It can only do a keyboard lock if you're hitting it in HTTPS, so enable that or use app.jetkvm.com to access the JetKVM

@amatriain
Copy link
Copy Markdown

Still not working for me with Firefox on arch linux. App version 0.4.5, System version 0.2.5. Accessing jetKVM through the LAN, not cloud, with HTTPS mode enabled, using the self-signed cert option.

@literallylara
Copy link
Copy Markdown

@amatriain Keyboard locking is in experimental state and not currently suppported by Firefox, see: https://caniuse.com/mdn-api_keyboard_lock

ym pushed a commit to ym/jetkvm-kvm that referenced this pull request Sep 26, 2025
When the keyboard lock is supposed to be active (in full-screen mode), hitting the escape key (NOT long-pressing) should NOT dismiss the full-screen mode, and should send the Escape key through to the remote.

- Added awaits to the browser calls that need to complete in order.
- Cleaned up (mostly) duplicate code in the Absolute/Relative mouse handling
- Ensure we don't overrun any existing keyboard lock or pointer lock
- Release the keyboard lock when leaving full-screen
- Per standards, we need to acquire the keyboard and pointer locks before entering full-screen or the user may get multiple messages about exiting.
- Fixed all the missing/excess React dependencies.
- Moved the pointer lock bar up so it is visible.
- Somewhere along the way, the prompt to click the video when in relative-mouse-mode stopped being visible, restored it's visibility
- Fixed all the "should be readonly" warnings.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants