Skip to content

feat: add configurable ignore_keys setting to filter key events#2047

Open
tjasko wants to merge 1 commit into
novnc:masterfrom
tjasko:feat/ignore-keyboard-keys
Open

feat: add configurable ignore_keys setting to filter key events#2047
tjasko wants to merge 1 commit into
novnc:masterfrom
tjasko:feat/ignore-keyboard-keys

Conversation

@tjasko

@tjasko tjasko commented Mar 28, 2026

Copy link
Copy Markdown

Overview

Introduce a new ignore_keys setting that allows users to prevent specific keyboard inputs from being forwarded to the remote VNC host while still allowing the browser/client to handle them locally.

This addresses common UX issues where browser-level shortcuts (e.g. Escape to exit fullscreen or F11 for fullscreen toggle) are also sent to the VM, potentially interrupting workflows or triggering unintended actions.

Key behavior:

  • Keys listed in ignore_keys are handled locally & not sent to the VM
  • Default value is to not ignore any key events
  • Supports comma-separated input with whitespace tolerance
  • Accepts aliases (e.g. "esc", "ctrl", "cmd") mapped to canonical codes
  • Matching is case-insensitive and normalized

Implementation details:

  • Centralized supported keys via supportedIgnoreKeys
  • Added normalizeIgnoreKey() to map aliases to canonical codes
  • Introduced wrapRfbSendKey() to intercept and filter outgoing key events
  • Simplified keyEvent() to delegate to rfb.sendKey
  • Added validation for user input with visual feedback on invalid entries
  • Added dynamic tooltip and placeholder generation from supported key list

UI changes:

  • Added ignore_keys input to settings panel
  • Added tooltip with supported key examples
  • Added inline validation styling for invalid entries

Tests:

  • Added coverage for shouldIgnoreKey() including aliases, normalization, whitespace handling, and edge cases
  • Added tests for wrapped sendKey behavior to ensure filtering works
  • Updated keyEvent() tests to reflect pass-through behavior
  • Added validation and helper function tests

This change improves usability when interacting with fullscreen mode and other browser-level shortcuts, while remaining backward compatible.

Introduce a new `ignore_keys` setting that allows users to prevent
specific keyboard inputs from being forwarded to the remote VNC host
while still allowing the browser/client to handle them locally.

This addresses common UX issues where browser-level shortcuts (e.g.
Escape to exit fullscreen or F11 for fullscreen toggle) are also sent
to the VM, potentially interrupting workflows or triggering unintended
actions.

Key behavior:
- Keys listed in `ignore_keys` are handled locally & not sent to the VM
- Default value is to not ignore any key events
- Supports comma-separated input with whitespace tolerance
- Accepts aliases (e.g. "esc", "ctrl", "cmd") mapped to canonical codes
- Matching is case-insensitive and normalized

Implementation details:
- Centralized supported keys via `supportedIgnoreKeys`
- Added `normalizeIgnoreKey()` to map aliases to canonical codes
- Introduced `wrapRfbSendKey()` to intercept and filter outgoing key
  events
- Simplified `keyEvent()` to delegate to `rfb.sendKey`
- Added validation for user input with visual feedback on invalid
  entries
- Added dynamic tooltip and placeholder generation from supported
  key list

UI changes:
- Added `ignore_keys` input to settings panel
- Added tooltip with supported key examples
- Added inline validation styling for invalid entries

Tests:
- Added coverage for `shouldIgnoreKey()` including aliases,
  normalization, whitespace handling, and edge cases
- Added tests for wrapped `sendKey` behavior to ensure filtering works
- Updated `keyEvent()` tests to reflect pass-through behavior
- Added validation and helper function tests

This change improves usability when interacting with fullscreen mode
and other browser-level shortcuts, while remaining backward compatible.

@samhed samhed left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thank you for contributing! I think this could be a useful feature in some cases.

I tested it in Chrome 145 on Fedora 43. Functionally, it works as advertised.

The code needs some work though, see the comments.

Comment thread app/styles/base.css

#noVNC_setting_ignore_keys.noVNC_invalid,
#noVNC_setting_ignore_keys.noVNC_invalid:focus {
border-color: var(--novnc-red);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't see why we need our own color for this, regular "red" looks fine.

Comment thread app/ui.js
}
} else {
ctrl.value = value;
ctrl.value = value ?? '';

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is this?

Comment thread app/ui.js
UI.rfb.sendKey(keysym, code, down);
},

wrapRfbSendKey() {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

filterIgnoredKeys() ?

Comment thread app/ui.js
UI.addSettingChangeHandler('reconnect_delay');
UI.addSettingChangeHandler('ignore_keys');
const input = document.getElementById('noVNC_setting_ignore_keys');
if (input && !input.dataset.validationBound) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why have you added this validationBound attribute? I can't see any reason for why these two handlers need such a guard if no others do.

We should probably get rid of the "if" and the variable as well and follow the style of the other handlers.

Comment thread app/ui.js
const ctrl = document.getElementById('noVNC_setting_' + name);
// Update cookie and form control setting. If value is not set, then
// updates from control to current cookie setting.
saveSetting(nameOrEvent) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The changes to this function makes no sense to me - saveSetting() doesn't ever seem to be called with an event?

Comment thread vnc.html
</label>
</li>
<li><hr></li>
<li class="noVNC_setting">

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Most users won't need this, I think it fits best under the "advanced" section of the settings.

Comment thread vnc.html
<div class="noVNC_setting_with_help">
<label for="noVNC_setting_ignore_keys">Ignored Keys:</label>

<button id="noVNC_ignore_keys_help_button" type="button">?</button>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This large circled question mark doesn't fit the rest of our interface. I'd also like to avoid infrastructure for tooltips.

Couldn't we simply use the html "title" attribute to get almost the same? (With &#013; we can have line breaks in the title attribute.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants