-
Notifications
You must be signed in to change notification settings - Fork 892
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
Add keyboard modifiers to input event #112
Conversation
I have no clue what to do with modifiers. When it comes to windowing, there are tons of concepts that have existed in the 90s and that are now considered obsolete. I'm not sure whether keyboard modifiers are one of them. I don't really see why Ctrl/Alt/Shift should be treated in a special way. I'm not buying the "unnecessary work for the user" argument, because that could always be solved by adding some utility struct that tracks the state of the keyboard. The concern about alt+tabbing is justified, but it's maybe just a bug that can be solved in another way? Usually when I don't know whether something is "modern" I look at what wayland does, because they are the only modern windowing system. |
I think ease of use for the API user is important. For a low-level component such as the Wayland protocol it makes sense to just send the key events. As a user of API providing cross-platform window creation and input handling it doesn't make sense if every program needs to have a state machine to track modifier keys. |
I'm not sure what you mean by Wayland not having a concept of modifiers. Looking at the protocol, there's a Windowing APIs on each platform provide access to the current modifiers when a key is pressed. It seems that you would prefer to ignore the data provided by the windowing system and try to reconstruct it ourselves from a series of key presses. But, there's evidence that the latter doesn't work in all situations. It seems that the only correct option is to somehow provide the modifier data from the windowing system. If the only problem was ergonomics, I would agree with you about providing a sort of state tracking type that user's could opt into. |
Ease of use can be done in another way than giving out modifiers. If all windowing APIs give you modifiers, then I think there's probably a good reason and winit should give them as well. So I guess I'm ok with the change. Anyway, back to the PR:
|
As I see it there is no reliable way to write an application that uses Ctrl-, Alt- etc keyboard shortcuts using the current API. Example keyboard event APIs:
The other APIs also provides the string representation of the key if it is a printable character. This allows the API user to do any type of complex keyboard event handling from this single event. I will add that too while we are making this API breaking change. I agree that bitflags is not necessary, performance is not an issue here. I only did X11 since I wanted to get the API itself reviewed first. I'll do the Wayland and Windows implementations, but I don't have access to MacOS so I can't implement that. @jwilm What are your thoughts? |
Tomaka just mentioned in the parent comment that providing the modifiers is fine; I'm not sure what you're arguing for in the first half of your comment.
I've got a commit with this as well, but I'm not convinced passing the printable character in the event is the right solution because it would require a
If you had asked me about this before opening the PR, I would have pointed out that there is a Cocoa implementation as well. The Wayland and Windows APIs are definitely unimplemented, though.
This is your call. if mods == SHIFT | CONTROL Which is, in my opinion, more ergonomic than a struct. if mods == Mods::new().shift().control() It also ends up being more code for Glutin to maintain.
Sorry about this. One of the reasons I hadn't opened a PR yet was specifically because it wasn't yet implemented on all platforms. Alacritty aims to support X11, Wayland, macOS, and Windows; we definitely want to implement these APIs on all platforms. |
Definitely struct. |
I don't understand your insistence on a struct. It's going to end up as 4 bytes wide versus 1. The bitflags seem more ergonomic. It's less code for glutin/winit to maintain. Bitflags are a standard thing in the Rust ecosystem so users will immediately be familiar with them. You even said yourself that the struct is less optimal. So far in this discussion, there has not been one point in favor of using a struct other than it being your preference. Yet, you insist on the struct as the solution here. |
Example struct implementation:
Doesn't seem too bad. I'm a C++ expert, not a rust expert, so I couldn't say what is the cleanest most idiomatic way. Considering memory and performance is irrelevant in this case. Only usage ergonomics and rust best practices are relevant. |
I disagree that bitfields are standard in Rust and that people are familiar with them. In the end I think it should be the job of the Rust compiler to optimize a struct made of four bools into a bitfield. Eventually in a few years we'll not only be optimal but also idiomatic. |
I can appreciate that argument.
Agreed
This part is a bummer, but you've made a solid case for the struct. Thanks for explaining your position. |
This can never happen for the same reasons no C++ compiler will ever do this: you can take the address of the bool field, thus it must be addressable (and be at least a byte big). A struct of bools will never magically become a bitfield through compiler optimizations. |
Being able to take the address of a bool field is arguably not very useful. I can totally imagine this being changed in the future if you put some kind of |
I refactored the code use a struct instead and added implementations for win32 and macos. I couldn't find a machine which can run Wayland (Mesa EGL issues) so I gave up on implementing for wayland. @tomaka Unless you have additional concerns, this is ready to merge now. Remember to bump the major version since this breaks API compatibility. |
Is it useful or not is entirely irrelevant; it exist in the language and thus needs to work so you won't see the optimization you're imagining. I'd put the chances of a |
@Valloric It's the same constraint C++ has on bools, they have to be addressable. We're talking about keyboard events here. Saving some bits or allocations is irrelevant. |
Exactly my point.
I have no horse in this race; I only wanted to dispel the fantasy that the struct-of-bools will magically become more compact now or in the future. It won't. |
We are controlling the language. The language is not something mystical that doesn't obey the laws of nature. It's totally something that can be adjusted as long as backward compatibility is preserved. |
src/events.rs
Outdated
@@ -312,3 +312,11 @@ pub enum VirtualKeyCode { | |||
WebStop, | |||
Yen, | |||
} | |||
|
|||
#[derive(Default, Debug, Clone, Copy)] | |||
pub struct Mods { |
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.
This needs some documentation. Not everybody knows what a modifier is.
Also the fields should be 4-spaces indented, not 2.
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.
Should I just call it KeyboardModifiers?
src/events.rs
Outdated
pub shift: bool, | ||
pub ctrl: bool, | ||
pub alt: bool, | ||
pub supr: 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.
I don't even know what supr
is?
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.
It is probably the Super key aka. the Windows key.
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 looked into this and super key seems to be the most common platform neutral name for the windows / command key. Super is reserved so I named it supr.
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.
Shame that super
is a reserved keyword. I find supr
quite a confusing name...
an other common name for this key (in linux world at least) is mod4
(alt
is also mod1
, I don't know what are 2 and 3), but I don't think it's a clear name either...
super_
would do the work, but is ugly ... I'm out of ideas here... At least it needs to be clearly documented what key it represents (telling in the docs that it is the "windows key" on most keyboards)
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.
Other possible name: internally, xkbcommon calls it the "logo key", which is actually a pretty accurate name
src/platform/macos/mod.rs
Outdated
@@ -525,9 +526,9 @@ impl Window { | |||
|
|||
unsafe fn modifier_event(event: id, keymask: appkit::NSEventModifierFlags, key: events::VirtualKeyCode, key_pressed: bool) -> Option<Event> { | |||
if !key_pressed && NSEvent::modifierFlags(event).contains(keymask) { | |||
return Some(Event::KeyboardInput(ElementState::Pressed, NSEvent::keyCode(event) as u8, Some(key))); | |||
return Some(Event::KeyboardInput(ElementState::Pressed, NSEvent::keyCode(event) as u8, Some(key), Mods::default())); |
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'm not sure if Mods::default()
here is an expected behavior.
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're right, it would not be consistent with x11 and Windows behavior
src/api/wayland/keyboard.rs
Outdated
@@ -35,7 +37,7 @@ impl wayland_kbd::Handler for KbdHandler { | |||
}; | |||
let vkcode = key_to_vkey(rawkey, keysym); | |||
let mut guard = eviter.lock().unwrap(); | |||
guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode)); | |||
guard.push_back(Event::KeyboardInput(state, rawkey as u8, vkcode, Mods::default())); |
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.
Please at least add a TODO if you can't implement on wayland.
Some things I'm not sure about:
|
Yes the modifier is the union of all keys with the same name as currently implemented. Yes on x11 and win32 the ctrl press event has the ctrl modifier. |
Regarding wayland, this requires some work on I suggest you focus on merging that, and I'll make a PR later to add it. Just add a big |
I'm not sure if this matters, but on my keyboard the right alt is "Alt Gr" and not the regular "Alt" |
Regarding wayland, I've just released wayland_kbd-0.7 which provides the modifiers state to the events handlers, with this updating the wayland backend should be completely straightforward: https://docs.rs/wayland-kbd/0.7.0/wayland_kbd/struct.ModifiersState.html Note that I kept "shift" and "caps lock" separated, this might need some merge logic. |
Code review comments fixed. Rebased to master. |
@tomaka Comments? |
Please add a |
src/platform/macos/events_loop.rs
Outdated
} | ||
|
||
ev_mods | ||
} |
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.
Not really important, but this whole function body could just be:
let flags = unsafe { NSEvent::modifierFlags(event) };
ModifiersState {
shift: flags.contains(appkit::NSShiftKeyMask),
ctrl: flags.contains(appkit::NSControlKeyMask),
alt: flags.contains(appkit::NSAlternateKeyMask),
logo: flags.contains(appkit::NSCommandKeyMask),
}
Making applications track modifier keys results in unnecessary work for consumers, it's error prone, and it turns out to have unavoidable bugs. For example, alt-tabbing with x11 results in the alt modifier state getting stuck. To resolve these problems, this patch adds a Mods value to the keyboard input event. Based on this patch: jwilm/glutin@d287fa9
@tomaka added the TODO comments and simplified macOS implemention as suggested by @mitchmindtree |
Can we merge this if all is good? I'd like to build on it for the remake of the wayland backend to the new design. |
Check for libEGL.dll This would allow rendering through Angle, then capturing and analyzing the WR results on Windows using powerful tools (like RenderDoc, GPU PerfStudio, PIX, NSight, etc). Upstream PR: rust-windowing/glutin#846 <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/glutin/112) <!-- Reviewable:end -->
…ctive-post-mul Add Perspective::post_mul
Making applications track modifier keys results in unnecessary work for
consumers, it's error prone, and it turns out to have unavoidable bugs.
For example, alt-tabbing with x11 results in the alt modifier state
getting stuck.
To resolve these problems, this patch adds a Mods value to the keyboard
input event.
Based on this patch: jwilm/glutin@d287fa9
This PR resolves issues #77 and #108