code.pyret.org
code.pyret.org copied to clipboard
key events
This comes as no surprise to anyone, but I've been knee-deep in it with WeScheme for the last few days so I figured I might as well file a report. This is based on the Pyret program found at https://code.pyret.org/editor#share=0BzzMl1BJlJDkeFFTUVhURk1rd0E&v=v0.5r1428
- Caps lock is ignored (CapsLock+k -> k, instead of K)
- Shift modifier is ignored (Shift+k -> k, instead of K)
- Alt/Opt modifier is ignored (Alt-c -> c, instead of ç)
I don't know how much of the old jsBigBang code Pyret inherited, but here's the issue: the only way to get modifier keys (shift, alt, etc) is to listen for keydown events, and the only [easy] way to get the modified character (ç) is to listen for keypress events.
I briefly attempted to reconstruct the typed character solely from the keydown event, but that got complicated fast. For WeScheme, I instead signed up the key-event handler for both down and press, and then had it sift through some conditions to know when to ignore one and listen for the other. It feels like a bit of a fragile solution, but I don't expect anyone to re-assign the extended ASCII character set anytime soon. :)
Hope this is helpful!
Wait, if I do:
document.body.addEventListener("keypress", function(e) { console.log(e); })
And type "Shift-K", I get an object with:
altKey: false
shiftKey: true
metaKey: false
ctrlKey: false
So some of these are certainly present.
If I type Option-[ (for curly quote on a Mac), I get:
altKey: true
shiftKey: false
...
keyIdentifier: "U+005B" // unfortunately, thats [, not “, as we might hope
I think that the modifier keys are reasonably cross-browser (Caps Lock isn't considered a modifier key). I think getting option-based input via OSX is probably best done by hiding a text area and focusing that, then reading the input out of it after an "input" event, rather than rebuilding the modifier logic ourselves.
(NB: This is all in Chromium, but CPO does Ctrl-S and Ctrl-Enter for save/run this way, and it works across all the major browsers).
Huh? keypress isn't fired if you just hit a modifier key.
Agreed. I didn't realize part of the goal was to fire key events for standalone modifier keys; I thought you were just saying it was hard to get the modifier information period. I take it you want to support a key event that fires "Shift" and having Shift+a show up as "A" for the key? Or is there another reason keydown rather than keypress is necessary?
If we want to preserve compatibility with DrRacket's on-key handler, we need to use keydown.
Small poke. Seems relevant in light of https://groups.google.com/forum/#!topic/pyret-discuss/lEDVirNisRI
One of the teachers at the physics workshop had asked whether we had key-down vs. key-up events.
Per the thread on pyret-discuss:
The best proposed solution is to add another kind of key event (call it
on-key-detailedfor now) that is provided with much more information thanon-key. The goal, of course, is to keepon-keysimple, while providing the richer functionality.
Regardless of the more detailed function, on-key could still reflect weather shift is used, and produce "K" when you type "shift-k". I believe this is standard behavior: in OpenGL you get the capitalized key, and in JavaScript you get both the capitalized and lowercase key.
I'd suggest something like on-raw-key, and try to expose something similar to the JS Key Event. This would have the advantage of making the library more friendly to folks coming from JS-land, and free us from having to design a different API for "detailed" key events by piggybacking on the one that already exists.
Concrete proposal:
on-raw-key is a handler that expects a function with the following signature:
state :: a, key :: RawKeyEvent -> a
Where a is the reactor state and RawKeyEvent is a datatype:
data RawKeyEvent:
| raw-key-event(key :: String, type :: RawKeyEventType, caps :: Boolean, shift :: Boolean, alt :: Boolean, command :: Boolean, control :: Boolean)
end
data RawKeyEventType:
| up
| down
| press
end
Feel free to point out missing things in the above definition.
How does this interact with on-key handlers? Which happens first? Do we call both on-key and on-raw-key for sustained keypresses? Or do we make it a well-formedness error to have both kinds of key handlers?
Proposal:
It's a well-formedness error to have both. on-key should desugar into a use of on-raw-key.
I like this. Can you say more about what key is? For example, could it be ç? Any printable character? What about non-printable key combos, such as "Ctrl-Shift"?
We've discussed this a bunch this morning while resolving https://github.com/brownplt/code.pyret.org/pull/167/files
It seems like the .key field on the keydown event has all the properties needed for this. Browsers have (since this issue was opened) converged on support for this in the last few years, so I think this can be much more straightforward.
To answer the direct, most recent question, if a user typed "Alt-Shift Y" on OSX (which produces Á on my laptop), there would be three calls to the reactor's on-key handler:
- One containing the key
"alt" - One containing the key
"shift" - One containing the key
"Á"
Since students already (implicitly) learn to filter out keys in games to not crash if expressions, I think it's fine to have them filter out modifier keys.
Of course, we should also add on-raw-key, this discussion just addresses what the value provided to on-key is.
(CC @blerner @ds26gte )
(Docs: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key and https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values)
Just a note that @jpolitz has been working on this inside the on-raw-key branch. See #262
It looks like PR #262 may have come almost all the way to implementing this. Is it stuck in PR purgatory, or did it get implemented elsewhere?
@jpolitz I know you have a PR for this. I'm guessing it's gone stale? Could this be something for an undergrad to clean up?
@jpolitz did this PR ever get merged?