Skip to content

Treat Sym/Meta+key as a no-op on the emulated keyboard matrix#8

Open
lxpollitt wants to merge 2 commits into
lanceewing:masterfrom
lxpollitt:pr2-suppress-cmd-no-op
Open

Treat Sym/Meta+key as a no-op on the emulated keyboard matrix#8
lxpollitt wants to merge 2 commits into
lanceewing:masterfrom
lxpollitt:pr2-suppress-cmd-no-op

Conversation

@lxpollitt
Copy link
Copy Markdown
Contributor

This PR builds on #7 (the Meta related synthetic keyup fix) and assumes it lands first. It adds keyboard matrix-level suppression of Sym/Meta+key combinations, so they don't leak into the emulated Oric keyboard at all.

Problem

The Oric had no Sym/Meta key (CMD on Mac, Windows key on Windows, Super key on Linux, Sym on Android), and Sym/Meta+key combinations are conventionally OS or application shortcuts on every modern platform, so the user almost certainly didn't intend them as Oric input. Before this PR, pressing e.g. CMD+A in the Oric BASIC command line produced a stray "A" character input in the Oric. (And without #7 in place, that key would get stuck down and auto-repeat indefinitely in the case of macOS.)

Fix

Added a symPressed flag to KeyboardMatrix plus a setSymPressed(boolean) entry point. While symPressed is true, non-Sym/non-Meta keyDown events return early without setting any matrix bit, so the chord never produces Oric input.

The flag is updated from two sources:

  • lwjgl3 desktop: keyDown(Keys.SYM) / keyUp(Keys.SYM). The desktop backend correctly translates GLFW_KEY_LEFT/RIGHT_SUPER into Keys.SYM, so these paths fire naturally.
  • GWT/web: the existing DOM-level listener from Inject synthetic keyup events to recover from macOS swallowing them while a Meta key is held #7 was extended to also read event.metaKey directly and funnel it through setSymPressed. Necessary because libGDX's GWT backend maps the Meta key to Keys.UNKNOWN (a long-standing FIXME in DefaultGwtInput.java), so the keyDown(Keys.SYM) path never fires in the browser. The listener uses useCapture=true so symPressed is updated before libGDX's bubble-phase listener delivers the would-be-suppressed key.

The need for these two paths does slightly increase the complexity of the code in this area. I've tried to comment the code as clearly as I can to ease understanding and future maintainability, and overall it doesn't feel hugely complex. But equally it's not a "critical" bug fix and could be lived with as is if preferred.

Note on the continued need for #7

The synthesised keyup that #7 generates on Meta-key release is still required even with this PR's matrix-level suppression in place. Otherwise a sequence such as the following would get stuck on macOS: press and hold A; press and hold CMD; release A; release CMD -> results in A remaining stuck down.

Scope

  • All platforms benefit: desktop (Mac/Win/Linux), web, and Android.
  • On Android, Keys.SYM historically corresponded to the Symbol key on hardware QWERTY keyboards (HTC G1, Motorola Droid era) rather than a Meta-style modifier. Treating it the same way here seems logical: pressing Sym+A would otherwise produce a stray "A" on the Oric, just like CMD+A on Mac did. See the field comment in KeyboardMatrix.java for more.

Testing

I've confirmed the fix behaves as expected for me using both Safari and Chrome on macOS. I haven't been able to verify Windows/Linux/desktop first-hand (desktop doesn't currently run for me on my Mac, and I don't have easy access to Windows/Linux desktop). The code is pretty straightforward but it would be good to verify on at least one other OS to be sure before merging on both web and desktop.

lxpollitt added 2 commits June 6, 2026 15:59
…hile a Meta key is held

macOS suppresses keyUp events for non-modifier keys whose keyUp would
occur while a Meta (CMD) key is held - an OS-level behaviour inherited
by Chrome, Safari and Firefox.

GwtKeyboardMatrix's UI-thread constructor now installs a DOM-level
keydown/keyup listener (capture phase, so it runs before libGDX's own
document-level bubble-phase listener). The listener tracks which non-
Meta keys have unreleased keydowns and, on Meta release, dispatches a
synthetic keyup event for each. The synthetic events flow through
libGDX's normal keyup handler and clear its internal pressedKeys[]
state.
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.

1 participant