-
-
Notifications
You must be signed in to change notification settings - Fork 574
[web export] Fix Safari Arrow keys in HTML export/webapp #2838
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
… key events with KeyboardEvent.location === 3 (numpad) to location: 0 on WebKit in capture phase\n- Prevent page scrolling on Arrow keys while canvas is focused\n- Ensure canvas is focusable (tabindex=0) and focused on start\n\nThis addresses Safari/WebKit misclassification of physical Arrow keys so games receive directional input correctly.
|
The PR looks too big for such a small thing to me, but I'm not a web dev :) |
|
100% fair. What's funny is I've been a web guy for 15 years and I don't really grok what's going on here either. I will try and engage my brain and take a closer look myself in a while, instead of babysitting AI like a fool. |
|
So I would agree that the code is a little verbose perhaps, but it does do the right thing. The issue is that Safari (at least on my MacBook Air M4) process the arrow keys on the built-in keyboard as being part of the numpad, which sets the key location to 4 (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/location). However some part of TIC-80 further down the stack does not consume the events with this location. The 'easiest' solution for me was to add this shim, which essentially watches for the arrow key input on safari and remaps its location from 3 (numpad) to 0 (standard location). The shim itself is maybe a little verbose but in my eyes it does the right thing and it's relatively well encapsulated. It's also gated for WebKit so it shouldn't affect other browsers, just Safari and Safari-related (Orion for instance). (function(){
const ua = navigator.userAgent || '';
const isWebKit = /AppleWebKit/i.test(ua);
if (!isWebKit) return;
const synthesizeArrowWithLocation0 = (orig) => {
try {
const ev = new KeyboardEvent(orig.type, {
key: orig.key,
code: orig.code,
location: 0,
repeat: orig.repeat,
ctrlKey: orig.ctrlKey,
shiftKey: orig.shiftKey,
altKey: orig.altKey,
metaKey: orig.metaKey,
bubbles: true,
cancelable: true,
});
Object.defineProperty(ev, 'which', { get: () => orig.which });
Object.defineProperty(ev, 'keyCode', { get: () => orig.keyCode });
return ev;
} catch { return null; }
};
const remapArrowLocationCapture = (e) => {
const isArrow = (e.key && e.key.startsWith('Arrow')) || (e.code && e.code.startsWith('Arrow'));
if (!isArrow) return;
if (e.location === 3) {
const syn = synthesizeArrowWithLocation0(e);
if (syn) {
e.stopImmediatePropagation();
e.preventDefault();
(e.target || document.getElementById('canvas')).dispatchEvent(syn);
}
}
};
['keydown','keyup'].forEach(t => document.addEventListener(t, remapArrowLocationCapture, true));
})();It's in a closure so we don't pollute the global scope. Essentially we just add two event listeners on the document, for keydown and keyup. That listener checks if it's an arrow key, and if so, checks if the location is 3 (numpad). If so, it synthesises a new event with the correct location and kills the existing one with stopImmediatePropagation and preventDefault. Then it dispatches the synthesised one. We can't just do There is a second part to this that prevents scrolling when the canvas is focused, but I guess that should be removed for this PR - more of a nice-to-have. |
|
And a final note: The semicolons needed adding because otherwise the closure creates a syntax error: Anyway, I wanted to say a really big thank you for TIC-80. I paid for the Pro version the other day on Itch. I did most of a degree in game development but got sidetracked along the way and haven't written a game in over a decade. After discovering TIC-80 I've written 2 in a week. I really love it, so thank you very much! |
nesbox
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, lets try the PR
thank you for the help
|
I guess the other solution is to enable the base system to accept arrow keys from the numpad as well. Tbh that's probably cleaner but I wouldn't know where the processing is for it. Anyway, thanks for accepting and thanks for TIC-80! ❤️ |
Safari/WebKit sometimes reports physical Arrow keys with KeyboardEvent.location === 3 (numpad). The Emscripten input glue ignores those for directional input, so arrows don't work in Safari.
This PR adds a small, WebKit-scoped capture-phase shim to remap Arrow key events with location 3 to location 0, prevents page scrolling on Arrow keys while the canvas is focused, and ensures the canvas is focusable and focused on start.
Changes:
Tested locally in Safari: arrows now reach the game.
The preceding text and the patch written by Claude, but the fix does work.