Inject synthetic keyup events to recover from macOS swallowing them while a Meta key is held#7
Conversation
…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.
|
@lxpollitt , thank you for the new batch of improvements for joric. I might struggle to find time to properly test these fixes before the end of next week, but after that I should have some time to properly check things over for each fix. Keep the fixes coming in. I think its great that someone else is contributing to this project. - Btw, in one of my other projects (a very similar one called jvic), I added a TeaVM build target, which is another web based option. The build and running code is a lot faster for the teavm version vs the gwt version. Doing solely that appears to have fixed some of the audio glitches I had on the web version of jvic, so it might be that joric would benefit from a teavm build target as well as the default for web. I am thinking about doing that at some point, also potentially using OPFS for persistence of disk writes (which I have also recently added to jvic). |
|
@lanceewing no rush. None of them are urgent, and I definitely don't want you to feel its overly onerous on you as the primary maintainer. Get to them whenever is good for you. This particular one used to catch me out quite frequently given I'm primarily a macOS users. (And I only realised when I was digging into the issue for this PR that I could cancel the stuck key by pressing it again. So it was a genuine pain point for me. Then I ended thinking I really should look into why the desktop version hung for me on macOS so I could at least say I've tested with that for my changes. Then once I got that working, that lead me to take a quick look into the audio on desktop on macOS. So ended up being a longer journey and more PRs than I initially had in mind - but hopefully it is useful for others to have these fixes too.) Love the project overall by the way. The web hosted emulator is absolutely great for me sharing games with friends that I'm resurrecting that I wrote way back in 1983! |
This PR addresses macOS swallowing keyup events while a Meta (CMD) key is held.
Problem
On macOS, the OS swallows keyup events for non-modifier keys whose keyup would land while a Meta (CMD) key is held. This is a long-standing macOS behaviour is inherited by Safari, Chrome, and Firefox. This results in the key becoming "stuck" down, until it is next pressed and released. So for example, if the user types CMD-X into the Oric BASIC command line, then X becomes stuck held down, generating auto-repeat X characters indefinitely until the user next presses and releases X. (And because of Oric's keyboard scanning behaviour, pressing any other key does not cancel the auto-repeat / stuck key. You have to press the X itself.)
Fix
Added a DOM-level keydown/keyup listener via JSNI to
GwtKeyboardMatrix. It tracks which non-Meta keycodes have received a keydown but not yet a keyup. On the transition from CMD-held → CMD-released, it dispatches synthetic DOM keyup events for those tracked keys. The synthetic events flow through libGDX's normal listener path (it doesn't know they're synthetic) and clear the stuckpressedKeys[]entries.Scope
GLFW_KEY_LEFT/RIGHT_SUPERtoKeys.SYM, so I think it doesn't have the samepressedKeys[]gate problem. But note I've not been able to test this first hand because the desktop version doesn't currently run for me on my Mac. (I may investigate this problem another time.)useCapture=trueso it runs before libGDX's own listener (which usesuseCapture=false).Testing
I've confirmed the fix behaves as expected for me using both Safari and Chrome on macOS. I haven't been able to verity Windows and Linux behaves as expected as I don't have easy access to a Windows or Linux desktops. I think the code is pretty safe but it would be good to verify on at least one other OS to be sure before merging.