-
Notifications
You must be signed in to change notification settings - Fork 920
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
New keyboard API for Windows #1788
New keyboard API for Windows #1788
Conversation
I'm glad to see that you followed through on the implementation :) The goodMost buttons seem to work as expected. The bad
A lot of the special cases involving Ctrl are likely also triggered by Alt Graph. The ugly
(The missing Lastly(3), (4), (5) and (6) are probably very easy to fix, so those can probably be rectified immediately. (12) should also be more of an "isolated" bug. Here's my test program for reference. PS: Good lord, all of those
|
For better overview for non-Windows reviewers: API Changes/// Describes a keyboard input as a raw device event.
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct RawKeyEvent {
pub scancode: ScanCode,
pub physical_key: keyboard_types::Code,
pub state: keyboard_types::KeyState,
}
/// Describes a keyboard input targeting a window.
// TODO: Implement (de)serialization.
// (This struct cannot be serialized in its entirety because `ScanCode`
// contains platform dependent data so that value cannot be serialized)
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct KeyEvent {
pub scancode: ScanCode,
/// Represents the position of a key independent of the
/// currently active layout.
/// Conforms to https://www.w3.org/TR/uievents-code/
///
/// Note that `Fn` and `FnLock` key events are not emmited by `winit`.
/// These keys are usually handled at the hardware or at the OS level.
pub physical_key: keyboard_types::Code,
/// This value is affected by all modifiers except <kbd>Ctrl</kbd>.
///
/// This is suitable for text input in a GUI application.
///
/// Note that the `Unicode` variant may contain multiple characters.
/// For example on Windows when pressing <kbd>^</kbd> using
/// a US-International layout, this will be `Dead` for the first
/// keypress and will be `Unicode("^^")` for the second keypress.
/// It's important that this behaviour might be different on
/// other platforms. For example Linux systems may emit a
/// `Unicode("^")` on the second keypress.
///
/// ## Platform-specific
/// - **Web:** Dead keys might be reported as the real key instead
/// of `Dead` depending on the browser/OS.
pub logical_key: keyboard_types::Key,
pub location: keyboard_types::Location,
pub state: keyboard_types::KeyState,
pub repeat: bool,
pub(crate) platform_specific: platform_impl::KeyEventExtra,
}
/// Hardware-dependent keyboard scan code.
#[derive(Debug, Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
pub struct ScanCode(pub(crate) platform_impl::PlatformScanCode); and /// The window received a unicode character.
ReceivedCharacter(char), replaced by /// The user commited an IME string for this window.
///
/// This is a temporary API until #1497 gets completed. See:
/// https://github.com/rust-windowing/winit/issues/1497
ReceivedImeText(String), |
First of all, thanks for spearheading this work! I have to admit I didn't read/discovered the keyboard API thread so far, therefore, I'm quite confused on the difference between One thing which irks me a bit is allocating a new string for each character event. I assume in the future there might be need to dynamically enable/disable certain events (similar to #1634) |
|
What's the point of even exposing dead keys downstream and other compositing stuff? I think downstream shouldn't care about it and it's hardly platform specific, but we're trying to abstract things away? Allocating strings for each key press is also costly, and there's no reason to do so? Or is the goal to support multichar compose input? Also, location stuff is confusing, since I think everything will break on hardware dvorak or other layout, since you generally assume qwerty afaics? |
Saying that @maroider's statement on If keys like enter/escape/backspace don't emit the actual characters they send anymore, winit might as well just let downstream handle all the work themselves, that would be much easier at that point. I also agree with @kchibisov that allocation is just a bad idea. If an action leads to sending multiple characters, why not emit multiple characters? Windows emitting two |
Scancodes
There are two things called scancodes (at least on Windows): the code the keyboard itself uses to identify a key, and the code the OS sends to applications which also uniquely (well, mostly uniquely) identifies the key. The two used to be the same, IIRC, when PS/2 was the norm. The codes Windows sends to applications is still based on a set of PS/2 scancode values (set 2). I think that Linux may be basing its "keycodes" on "PS/2 scancode set 2", but don't quote me on that. Dead keys and allocating stringsI implore you all to read the "Dead keys" section of the W3C's "UI Events" specification with its accompanying examples (and despair). The other (and admittedly more important) half of the "Why must we use a full string?" equation is that the "UI Events" specification allows for "key" values to contain "0 or 1 non-control characters followed by 0 or more combining characters" (ref). Splitting these up into multiple events each delivering one The W3C's "Keyboard Event Viewer" is a useful tool here for testing what browsers actually implement. Control characters (including
|
Is there actually a reason to report dead keys and composestart...composeend? It's not really contorted to only report the final value. Maybe some apps might try to visualise dead chars during input but I haven't seen this.
If we have a maximum length, then we can use a |
None of the other things you've mentioned wouldn't work just as well by sending a
I don't see why winit's API should be restricted to the web APIs, when they're basically unmaintained and unused? Sending entire grapheme clusters with a single keyboard press rather than doing that through IME seems very strange to me. The examples for combining characters list one counter example first which does not contain any combining characters (why?) and the second one doesn't seem particularly useful.
It does.
Why is this a string again? Are desktop platforms expected to handle all input through |
Hence why I prefer software remapping. I think all major OSes have built-in support for Colemak and Dvorak now, so there's little reason people should resort to hardware remapping (except that custom software maps can still be a nuisance to set up). But the point is moot anyway because we can't do anything to help with hardware remapping even if we wanted to. |
Hardware remapping provides a much better and more consistent experience than having to constantly redo it in software every time. There's also not a single keyboard layout in the world that would match what I use. |
I've tried both. Software remapping is far more flexible. Go try my layouts. Sorry people, off-topic. |
Dead keys
I can vaguely recall some application or the other enabling superscript when I hit ^, but I can't for the life of me remember which one it was. Might have been Ctrl+^. Regardless of that, it should be of some use for "keybind customization" menus for applications with mnemonic shortcuts.
Yeah, calling it "contortions" was perhaps a bit of an exaggeration.
You are of course entirely correct, and I'm not opposed to moving it somewhere that makes more sense. Dead keys and the webIt is admittedly a bit of a shame that the W3C has decided to specify the dead-key behaviour that it has, but it's likely for the sake of simplifying Windows implementations. I did propose (in #753) having It would be nice if Do you have any thought on this, @pyfisch? Control characters
I'm not sure for which exact set of control characters it is you want to expose through
I feel like I should also state that I'm viewing this primarily from a gamedev angle, and a bit from a GUI / text editing angle.
|
Just to be clear, this is mostly a question of where you want to put it. But you must have a way for applications to handle text input. That includes all escape characters. Though as previously noted that might be in a desktop extension.
Just to be very clear on this: Unless you can easily make an application that runs both on the desktop and web with winit, there's zero point in having both in a single library. If we split the API in a web and a desktop way again and again, winit has clearly strayed from the goal to abstract over these platform differences begging the question if the goals it has still make sense. |
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.
A few comments, haven't looked into all the keyboard logic so far 👀
|
||
use crate::keyboard::KeyCode; | ||
|
||
pub trait KeyCodeExtScancode { |
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.
Could Scancode
be renamed with PhysicalKey
in this context?
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.
You mean you'd like it to be something like this?
pub trait KeyCodeExtPhysicalKey {
fn to_physical_key(self) -> Option<u32>;
fn from_physical_key(scancode: u32) -> KeyCode;
}
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.
Right, if we can get rid of scancode
in favor of physical_key
on the user facing api I think this would be very helpful
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.
I don't like this because if we go with this, then the term "physical_key" would be used for two different things.
physical_key
inKeyEvent
(andRawKeyEvent
) which is of typeKeyCode
and is a platfom agnostic value.physical_key
to refer to platform native physical key identifier such as theu16
scancodes on Windows and theu16
keyCode
on macOS
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.
An alternative name I could think of would be "native key id" as shown below. But I'm not sure what's wrong with "scancode". Is it that scancode is usualy used to refer toPS/2 scancodes, which are only used on Windows, but not on other platforms?
pub trait KeyCodeExtNativeKeyId {
fn to_native_key_id(self) -> Option<u32>;
fn from_native_key_id(native_key_id: u32) -> KeyCode;
}
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.
Thanks for explanation, it wasn't too clear right now the difference between physical key and scancode to me.
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.
But I'm not sure what's wrong with "scancode". Is it that scancode is usualy used to refer toPS/2 scancodes, which are only used on Windows, but not on other platforms?
It was a bit difficult to grasp the differences as we introduce new semantics while also keeping existing ones. It also says in the docs that they are kinda similar. But I'm fine with the current usage as well.
physical key (i.e. it's mostly synonymous with a scancode).
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.
Part of the problem is that scancode is an overloaded term. "Native key ID" seems a lot more neutral.
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.
I would be okay with changing this to "native key id". I'm wondering if this should be brought up at #753 to give a chance for others to object to it.
/// switches to this window BEFORE releasing it then releases the dead key. In this case | ||
/// the `ToUnicode` function will be called, incorrectly clearing the dead key state. Having | ||
/// an inccorect behaviour only in this case seems acceptable. | ||
prev_down_was_dead: bool, |
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.
reported by CI as never read
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.
Oh this was apparently left here from an earlier state when a completely different approach was used.
Co-authored-by: Markus Siglreithmaier <[email protected]>
…nto new-keyboard
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.
LGTM!
Only a few small annotations from my side. Examples worked fine and seems also detect anything flawlessly I throw at it (:
(didn't test IME parts)
Co-authored-by: Markus Siglreithmaier <[email protected]>
I'm glad you mentioned the IME because I just tested it again and of course it panicked :D My latest commit fixes that, and now it seems to work as expected again. As I mentioned elsewhere this should be regularly merged, not squashed. So if @msiglreith, you just give one more confirmation to the latest changes, then I'll merge this into the |
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.
thanks! feel free to move forward 🚀
I thought I can merge it normally but I can't, it says "Not enabled for this repository". @francesca64 or @vberger could you please enable merging without squashing? My understanding of git may be too limited here but if I'm not mistaken, then all other PRs that are based on this changeset (e.g. #1888 #1890) would have to be rebased on top of the squashed changes, which seems too tedious considering, it can be avoided. Alternatively if you don't want enable this, please merge this if the "Create a merge commit" is available to you. |
My Linux branch isn't rebased, it's based off of 42055e3 and a merge with f0474f2. EDIT: Had a quick chat with @ArturKovacs on Matrix. I can (probably) figure out how to deal with a squash & merge. |
@chrisduerr thanks, that's reassuring, and based on a quick local test, it does seem to be fine. As @maroider noted as well, squashing should be okay, so I'm doing that. |
Wow I can't believe it really happened. I know we still need to finish/get approved all the remaining platforms but this is a giant milestone and I can barely contain my excitement 😁 |
Indeed! Congratulations people on finally getting this merged into the testing branch! 🚀 |
* Introducing the new `KeyEvent` and renaming old stuff * Implemented physical_key on Windows * Ran cargo fmt * Progress with the keyboard's windows implementation * Add proper handling of dead keys * Add translation for non-printable virtual keys * Run `cargo fmt` * Fix for AltGraph not being reported * Synthesize key events when focus enters or leaves * Minor improvements * Remove obsolete API * Fix numlock and pause not being reported correctly * Ran `cargo fmt` * Fix numpad keys being reported incorrectly * Update examples * Ran `cargo fmt` * Add documentation for `ScanCode` * Add key binding example * Use consistent modifier key names rust-windowing#1343 * WONT COMPILE transitioning to new keyboard API * WONT COMPILE Implement new keyboard layout preparation * WONT COMPILE new keyboard API progress * Main compile errors fixed for keyboard * Fix bugs in new keyboard handling * Remove obsolete code * Fix examples * Ran `cargo fmt` * Fix build error with serde * Ran `cargo fmt` * Tweaks in the Windows keyboard implementation * Add `KeyCodeExtScancode` * Add `reset_dead_keys` * Improve the documentation for `Key` and `KeyCode` * Rename the meta key to super * Address feedback for the keyboard API * Fix for rustdoc Co-authored-by: Markus Røyset <[email protected]> * Improve documentation Co-authored-by: Markus Røyset <[email protected]> * Fix for arrow keys being reported as unidentified. And minor improvements * Fix media keys reporting Unidentified * Don't report text on key release events * Fix for NumLock being reported as Pause in raw input * Fix for strange behaviour around NumLock and Pause * Fix for NumLock being ineffective * Fix for location not being reported correctly * `RawKeyEvent`s now report repeat * Don't report text for synthetic key releases * Address feedback - Add the `Space` variant to the `to_text` function. - Mark `get_kbd_state` safe. - Change `[MaybeUninit<u8>; 256]` to `MaybeUninit<[u8; 256]>` * Filter `Unidentified` from PrtSc key device events * Don't report incorrect `RawKeyEvent` for shift + numpad * AltGraph is not reported again * Document Windows specific behaviour for shift+numpad * Fix typo * Dead keys now affect characters from logical_key * Prevent Pause and NumLock mappings in window events * Apply suggestions from code review Co-authored-by: Markus Røyset <[email protected]> * Ran `cargo fmt` * Add W3C license for `Key` and `KeyCode` * Extend documentation according to feedback * Ignore NumLock in `key_without_modifiers` * Remove unused `key_code_to_non_char_key` * Remove empty event.rs file * Use space for resetting dead keys * Fix reporting multiple graphemes in logical_key * Avoid incorrect synthetic keypress during setfocus * Fixed the AltGr keypress not being reported when the AltGr key is pressed and released in a very quick succession * Filter fake Ctrl events when pressing AltGr * Improve code quality * Remove `repeat` from `RawKeyEvent` * Allow fractional scroll in raw mouse events * Fix typo Co-authored-by: Markus Siglreithmaier <[email protected]> * Remove unused imports * Remove unused variable * Remove unnecessary `unwrap()` Co-authored-by: Markus Siglreithmaier <[email protected]> * Avoid using the deprecated `into_rgba()` * Fix IME crash Co-authored-by: Markus Røyset <[email protected]> Co-authored-by: Markus Siglreithmaier <[email protected]>
* Introducing the new `KeyEvent` and renaming old stuff * Implemented physical_key on Windows * Ran cargo fmt * Progress with the keyboard's windows implementation * Add proper handling of dead keys * Add translation for non-printable virtual keys * Run `cargo fmt` * Fix for AltGraph not being reported * Synthesize key events when focus enters or leaves * Minor improvements * Remove obsolete API * Fix numlock and pause not being reported correctly * Ran `cargo fmt` * Fix numpad keys being reported incorrectly * Update examples * Ran `cargo fmt` * Add documentation for `ScanCode` * Add key binding example * Use consistent modifier key names rust-windowing#1343 * WONT COMPILE transitioning to new keyboard API * WONT COMPILE Implement new keyboard layout preparation * WONT COMPILE new keyboard API progress * Main compile errors fixed for keyboard * Fix bugs in new keyboard handling * Remove obsolete code * Fix examples * Ran `cargo fmt` * Fix build error with serde * Ran `cargo fmt` * Tweaks in the Windows keyboard implementation * Add `KeyCodeExtScancode` * Add `reset_dead_keys` * Improve the documentation for `Key` and `KeyCode` * Rename the meta key to super * Address feedback for the keyboard API * Fix for rustdoc Co-authored-by: Markus Røyset <[email protected]> * Improve documentation Co-authored-by: Markus Røyset <[email protected]> * Fix for arrow keys being reported as unidentified. And minor improvements * Fix media keys reporting Unidentified * Don't report text on key release events * Fix for NumLock being reported as Pause in raw input * Fix for strange behaviour around NumLock and Pause * Fix for NumLock being ineffective * Fix for location not being reported correctly * `RawKeyEvent`s now report repeat * Don't report text for synthetic key releases * Address feedback - Add the `Space` variant to the `to_text` function. - Mark `get_kbd_state` safe. - Change `[MaybeUninit<u8>; 256]` to `MaybeUninit<[u8; 256]>` * Filter `Unidentified` from PrtSc key device events * Don't report incorrect `RawKeyEvent` for shift + numpad * AltGraph is not reported again * Document Windows specific behaviour for shift+numpad * Fix typo * Dead keys now affect characters from logical_key * Prevent Pause and NumLock mappings in window events * Apply suggestions from code review Co-authored-by: Markus Røyset <[email protected]> * Ran `cargo fmt` * Add W3C license for `Key` and `KeyCode` * Extend documentation according to feedback * Ignore NumLock in `key_without_modifiers` * Remove unused `key_code_to_non_char_key` * Remove empty event.rs file * Use space for resetting dead keys * Fix reporting multiple graphemes in logical_key * Avoid incorrect synthetic keypress during setfocus * Fixed the AltGr keypress not being reported when the AltGr key is pressed and released in a very quick succession * Filter fake Ctrl events when pressing AltGr * Improve code quality * Remove `repeat` from `RawKeyEvent` * Allow fractional scroll in raw mouse events * Fix typo Co-authored-by: Markus Siglreithmaier <[email protected]> * Remove unused imports * Remove unused variable * Remove unnecessary `unwrap()` Co-authored-by: Markus Siglreithmaier <[email protected]> * Avoid using the deprecated `into_rgba()` * Fix IME crash Co-authored-by: Markus Røyset <[email protected]> Co-authored-by: Markus Siglreithmaier <[email protected]> Fix the `drag_window` example
cargo fmt
has been run on this branchcargo doc
builds successfullyCHANGELOG.md
if knowledge of this change could be valuable to usersThis contains the Windows implementation of the keyboard API discussed at #753
Update
As of writing this the API implemented by this PR is as follows.
Click for the code
ReceivedCharacter(char)
was removed. Its functionality is now covered byKeyboardInput
andReceivedImeText
.