New keyboard API for the web#1888
New keyboard API for the web#1888maroider wants to merge 13 commits intorust-windowing:new-keyboardfrom
Conversation
|
For the record: I'll test and properly review this once the merge conflicts are resolved. |
9e9b317 to
d7c9b81
Compare
|
Welp, I messed up the merge more times than I'd like to admit, but the merge conflicts should be resolved now. |
3391b55 to
16bb871
Compare
| pub fn key_text(event: &KeyboardEvent) -> Option<&'static str> { | ||
| let key = event.key(); | ||
| if let Key::Character(text) = Key::from_key_attribute_value(&key) { | ||
| // TODO: Fix unbounded leak | ||
| Some(Box::leak(String::from(text).into_boxed_str())) | ||
| } else { | ||
| None | ||
| } |
There was a problem hiding this comment.
The way I handled the leaked string, was by creating a global (lazy static) Mutex<HashSet<&'static str>>. I think the same approach is suitable here as well.
There was a problem hiding this comment.
I copied over what I used in the Linux PR, which is about what you described. I'm a bit uncertain of how mutexes work on WASM, but it seemed to run fine when I tested it.
There was a problem hiding this comment.
WebAssembly has instructions to block until a value in shared memory changes, which I believe is what mutexes use. Issue is, I'm pretty sure it causes an error if the main thread blocks, so we probably shouldn't use them here.
|
Furthermore, Space, Tab, and Enter emit |
This should be fixed now. What remains now is a single TODO comment as well as debugging the strange freezing. |
| match &key { | ||
| Key::Character(text) => Some(*text), | ||
| Key::Tab => Some("\t"), | ||
| Key::Enter => Some("\r"), | ||
| Key::Space => Some(" "), |
There was a problem hiding this comment.
Note that the Key has the to_text method which does pretty much this.
c75b536 to
2adcc7e
Compare
This is to appease `serde` for the time being.
As a direct result of this, `NativeKeyCode`, `Key`, `KeyCode` and `RawKeyEvent` no longer implement `Copy`.
2adcc7e to
2c7ba77
Compare
1ef0b49 to
54bb969
Compare
| "F33" => Key::F33, | ||
| "F34" => Key::F34, | ||
| "F35" => Key::F35, | ||
| string @ _ => Key::Character(string), |
There was a problem hiding this comment.
I don't think the @ _ is needed here.
| fn cached_string<S: AsRef<str>>(string: S) -> &'static str { | ||
| use std::collections::HashSet; | ||
| use std::sync::Mutex; | ||
|
|
||
| lazy_static::lazy_static! { | ||
| static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new()); | ||
| }; | ||
|
|
||
| let string = string.as_ref(); | ||
| let mut cache = STRING_CACHE.lock().unwrap(); | ||
| if let Some(string) = cache.get(string) { | ||
| *string | ||
| } else { | ||
| // borrowck couldn't quite figure out this one on its own | ||
| let string: &'static str = Box::leak(String::from(string).into_boxed_str()); | ||
| cache.insert(string); | ||
| string | ||
| } |
There was a problem hiding this comment.
What's the reason why we need an &'static str in the first place? It seems reasonable to me for KeyEvent and Key to contain owned strings instead and avoid this complexity.
| #[derive(Default)] | ||
| struct ModifiersShared(Rc<Cell<ModifiersState>>); | ||
|
|
||
| impl ModifiersShared { | ||
| fn set(&self, new: ModifiersState) { | ||
| self.0.set(new) | ||
| } | ||
|
|
||
| fn get(&self) -> ModifiersState { | ||
| self.0.get() | ||
| } | ||
| } | ||
|
|
||
| impl Clone for ModifiersShared { | ||
| fn clone(&self) -> Self { | ||
| Self(Rc::clone(&self.0)) | ||
| } | ||
| } |
There was a problem hiding this comment.
I think this could be replaced with type ModifiersShared = Rc<Cell<ModifiersState>> instead of having to declare a newtype.
| event.key().chars().next().unwrap() | ||
| // TODO: What should be done about `KeyboardEvent.isComposing`? | ||
|
|
||
| pub fn keyboard_modifiers(key: &Key<'_>) -> ModifiersState { |
There was a problem hiding this comment.
| pub fn keyboard_modifiers(key: &Key<'_>) -> ModifiersState { | |
| /// Returns the keyboard modifiers that changed with this keypress. | |
| /// | |
| /// For a pressed key, this is the keyboard modifiers that are newly pressed, | |
| /// and for a released key, this is the keyboard modifiers that are newly released. | |
| pub fn keyboard_modifiers(key: &Key<'_>) -> ModifiersState { |
Reading the code that was using this function, I assumed that this still had the old behaviour of returning the current state of the modifiers rather than the change to the modifiers. (It might also be a good idea to rename it to changed_modifiers or something.)
As a side-note, why was it changed to this in the first place? The old way of getting the current state seems easier to work with IMO.
| use std::sync::Mutex; | ||
|
|
||
| lazy_static::lazy_static! { | ||
| static ref STRING_CACHE: Mutex<HashSet<&'static str>> = Mutex::new(HashSet::new()); |
There was a problem hiding this comment.
The main thread isn't allowed to block on the web, so a Mutex probably shouldn't be used here. A thread_local! should work.
There was a problem hiding this comment.
To be fair, I don't think the event loop can be run outside of the main thread so this probably won't be a problem in practice, but that's even more of a reason to use a thread local.
| // pub fn codepoint(event: &KeyboardEvent) -> char { | ||
| // // `event.key()` always returns a non-empty `String`. Therefore, this should | ||
| // // never panic. | ||
| // // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key | ||
| // event.key().chars().next().unwrap() | ||
| // } |
There was a problem hiding this comment.
This should probably be removed.
|
Is there any update on this and how can we contribute if we need to ? |
cargo fmthas been run on this branchcargo docbuilds successfullyCHANGELOG.mdif knowledge of this change could be valuable to usersCreated or updated an example program if it would help users understand this functionalityThis implements #753 for WASM.
TODOs
stdwebbackend is worthwhile, since it's deprecated.Implement astdwebbackend if need be.TODOcomments in the code.