Skip to content
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

core: Key input overhaul #19616

Merged
merged 5 commits into from
Mar 2, 2025
Merged

core: Key input overhaul #19616

merged 5 commits into from
Mar 2, 2025

Conversation

kjarosh
Copy link
Member

@kjarosh kjarosh commented Feb 24, 2025

The main goal of this refactor is to unify key input across all platforms and move all Flash Player related behaviors to core in order to get rid of differences across platforms and minimize bugs.

Instead of providing KeyCodes in PlayerEvents, frontends now provide KeyDescriptors, which describe the pressed key on a high level. Then, Ruffle core does all necessary mappings to KeyCodes (and key location).

Additionally, this PR implements support for KeyboardEvent.keyLocation.

CC @evilpie

@kjarosh kjarosh added A-input Area: Input handling T-compat Type: Compatibility with Flash Player input Issues relating to user input in Flash content waiting-on-review Waiting on review from a Ruffle team member labels Feb 24, 2025
return Some(KeyCode::from_code(char.to_ascii_uppercase() as u32));
fn alpha_to_logical(ch: &str) -> LogicalKey {
// TODO What if we get multiple chars?
if let Some(ch) = ch.chars().last() {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Didn't we use the first character before?

Copy link
Member Author

Choose a reason for hiding this comment

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

@kjarosh kjarosh force-pushed the key-code-mapping branch from f7d47e2 to fa35648 Compare March 1, 2025 14:51
"F23" => KeyCode::F23,
"F24" => KeyCode::F24,
_ => KeyCode::UNKNOWN,
"Backquote" => PhysicalKey::Backquote,
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just curious: I tried to figure out where this order comes from and I think it's based on the code in e.g. https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_code_values#code_values_on_windows. So why is the first not Escape?

Copy link
Member Author

Choose a reason for hiding this comment

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

Oh I had no reason to use Windows-specific docs :D The order is based on the spec: https://w3c.github.io/uievents-code/#code-value-tables

First it's categorized by section, then by the key's physical location, the order should be the same as in the PhysicalKey enum (you can see the sections there).

@evilpie
Copy link
Collaborator

evilpie commented Mar 1, 2025

It is probably interesting to mention that this adds not yet used support for mapping physical keys to Flash's virtual key code.

Copy link
Collaborator

@evilpie evilpie left a comment

Choose a reason for hiding this comment

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

Great work.

I feel like If we we also used winit as an abstraction for key handling on the web we could probably unify a lot of the code between desktop and web.

@kjarosh
Copy link
Member Author

kjarosh commented Mar 1, 2025

I feel like If we we also used winit as an abstraction for key handling on the web we could probably unify a lot of the code between desktop and web.

That is very true. Web and winit have compatible interfaces (winit basically uses the web interface in Rust), but as long as we don't use winit on web, we have to duplicate this interface :/

@kjarosh kjarosh force-pushed the key-code-mapping branch 2 times, most recently from 01e5c5e to c16dea4 Compare March 2, 2025 19:57
@kjarosh kjarosh removed the waiting-on-review Waiting on review from a Ruffle team member label Mar 2, 2025
@kjarosh kjarosh force-pushed the key-code-mapping branch from c16dea4 to 2a15cdf Compare March 2, 2025 21:37
kjarosh added 5 commits March 2, 2025 22:37
The main goal of this refactor is to unify key input across all
platforms and move all Flash Player related behaviors to core in order
to get rid of differences across platforms and minimize bugs.

Instead of providing KeyCodes in PlayerEvents, frontends now provide
KeyDescriptors, which describe the pressed key on a high level.
Then, Ruffle core does all necessary mappings to KeyCodes
(and key location in the future).

This also adds (not yet used) physical key mapping in Ruffle.
This test verifies key input mapping on an 80% keyboard.
This test verifies key input mapping on a numpad.
This test verifies the behavior of keyLocation in key events.
@kjarosh kjarosh force-pushed the key-code-mapping branch from 2a15cdf to b593080 Compare March 2, 2025 21:38
@kjarosh kjarosh merged commit 9891184 into ruffle-rs:master Mar 2, 2025
22 checks passed
@kjarosh kjarosh deleted the key-code-mapping branch March 2, 2025 22:11
Comment on lines +832 to +837
#[derive(Debug, Clone, Copy)]
pub struct KeyDescriptor {
pub physical_key: PhysicalKey,
pub logical_key: LogicalKey,
pub key_location: KeyLocation,
}
Copy link
Member

Choose a reason for hiding this comment

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

Any suggestions on how to jam the contents of this neat struct (especially LogicalKey) all the way across this pipeline? 😵‍💫

https://github.com/ruffle-rs/ruffle-android/blob/main/app/src/main/res/layout/keyboard.xml#L121-L127
https://github.com/ruffle-rs/ruffle-android/blob/main/app/src/main/java/rs/ruffle/PlayerActivity.kt#L179-L188
https://github.com/ruffle-rs/ruffle-android/blob/main/app/src/main/java/rs/ruffle/PlayerActivity.kt#L97-L98
https://github.com/ruffle-rs/ruffle-android/blob/main/src/lib.rs#L487-L523
https://github.com/ruffle-rs/ruffle-android/blob/main/src/lib.rs#L400-L421

Or maybe I should leave all the XML/Kotlin parts operating on "softkeyboard scancodes" of a made-up layout, and translate it all in the Rust part? But that creates an uncomfy tie (or gap, depending on how you look at it) between how and where the layout is defined (including the button text), and what it "means" for the Ruffle player...

Copy link
Member Author

Choose a reason for hiding this comment

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

IMO when it comes to a simple, custom keyboard, you should use an approach similar to one used in tests, where each key has an identifier and is mapped into PhysicalKey/LogicalKey/KeyLocation. For more advanced keyboards I would expect all 3 fields to come from the virtual keyboard.

Maybe we can explore the idea of using the system keyboard on Android?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe we can explore the idea of using the system keyboard on Android?

I don't think we can get separate down/up events from that, nor can it handle pressing multiple keys at the same time...

Copy link
Member

Choose a reason for hiding this comment

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

For pure text entry, sure, it would be great, but not for playing games, and such.

Copy link
Member

Choose a reason for hiding this comment

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

(The same mechanisms could/should trigger hiding our handmade keyboard and bringing up the system one as currently used for the same purpose on web IMO.)

Copy link
Member

@torokati44 torokati44 Mar 3, 2025

Choose a reason for hiding this comment

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

Bur yeah, making each key have a proper identifier in its tag attribute, and carrying that string all the way into Rust, then dispatching on it there (turning it into a KeyIdentifier) sounds doable. But passing strings through the JNI FFI boundary is just so much more inconvenient than simple scalar values IIRC... 😩 Sure it's not impossible, just less nice...

Copy link
Member Author

Choose a reason for hiding this comment

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

You can always map it in Java and pass numerical values down. Not sure if that would require code duplication or not

Copy link
Member

Choose a reason for hiding this comment

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

Yeah but that would just require more messing around with encoding different (sometimes optional) info about all the keys into numbers and then those into Rust enumerants... This way it would be in one place at least.

Copy link
Member

Choose a reason for hiding this comment

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

Well, it would still require separating the methods to pass in the key events coming from our handmade virtual keyboard (with the string identifiers), and those coming from an actual physical keyboard connected say via Bluetooth (or USB or adb/scrcpy or whatever), in the form of an Android KeyEvent. Oh well, this isn't a big deal either I guess...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-input Area: Input handling input Issues relating to user input in Flash content newsworthy T-compat Type: Compatibility with Flash Player
Projects
None yet
4 participants