Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
X11: Rewrite input handling in terms of XInput and XKB
This patch completes the port of the X11 backend from core input handling to XInput/XKB input handling. In this context the word 'core' refers to the core X11 protocol in contrast to protocol extensions such as XInput and XKB. XInput and XKB are very large protocols that extend X11 with features expected from modern desktop environments such as - Support for a rich set of input devices such as touchpads. - Support for multiple attached keyboards, mice, touchpads, tablets, etc. - Support for rich and interactive keyboard layouts. # Breaking Changes - This patch removes all processing of core input events in favor of XInput events. The legacy XIM input method protocol is based on filtering and injecting core input events. Therefore, this patch also removes support for XIM input methods. Applications are encouraged to switch to more modern IM protocols such as [IBus]. These protocols can be implemented in application space outside of winit. Note that modern toolskits such as QT5 and chromium do not support XIM. [IBus]: https://en.wikipedia.org/wiki/Intelligent_Input_Bus - This patch removes support for synthetic keyboard events. This feature cannot be implemented correctly: - XKB is a complex state machine where key presses and releases can perform a rich set of actions. For example: - Switching modifiers on and off. - Switching between keyboard layouts. - Moving the mouse cursor. These actions depend on the order the key are pressed and released. For example, if a key that switches layouts is released before a regular key, then the release of the regular key will produce different events than it would otherwise. - The winit API does not permit synthetic `ModifierChanged` events. As such, an application cannot distinguish between the user deliberately changing the active modifiers and synthetic changes. For example, consider an application that performs a drag-and-drop operation as long as the Shift modifier is active. Applications are encouraged to track the state of keys manually in a way that is suitable for their application. # New and Changed Features - Winit no longer tracks keyboard events if no winit window has the focus except that: - Raw keyboard events are still being tracked. A future patch might make this behavior optional. See rust-windowing#1634. - Changes to the keyboard layout are being tracked at all times. - The backend now has complete support for multiple seats. For each seat it tracks the modifier state and the focused window. In the case of `KeyboardInput` events, applications can distinguish multiple seats by tracking the value of the `device_id` field. In the case of `ModifierChanged` events, applications cannot distinguish different seats. A future patch might add a `device_id` field to `ModifierChanged` events. The following sequence of events is possible: 1. Key Press: Seat 1, Left Shift 2. Modifiers Changed: Shift 3. Key Press: Seat 2, Left Ctrl 4. Modifiers Changed: Ctrl 5. Key Press: Seat 1, KeyA, Text: "A" (due to active Shift) 6. Key Release: Seat 1, Left Shift 7. Modifiers Changed: None 8. Key Release: Seat 2, Left Ctrl 9. Modifiers Changed: None - Keyboard state and window events are now completely independent of device events. Applications can disable device events by modifying the winit source code (or in the future with a supported toggle) without incurring regressions in other areas. - Key release events no longer contain a value in the `text` and `text_with_all_modifiers` fields. - Key presses that are part of a compose sequence no longer contain a value in the `text` and `text_with_all_modifiers`. Applications that simply want to handle text input can therefore listen for key events and append the values of the `text` field to the input buffer without having to track any state. - The `logical_key` field of key events is no longer affected by compose sequences. This is in line with how browsers handle compose sequences. - Aborted compose sequences no longer produce any `text`. An aborted compose sequence is a sequence that was not completed correctly. For example, consider the following sequence of keysyms: 1. Multi_key 2. ( 3. c 4. ( `(` is not a valid continuation of the compose sequence starting with `[Multi_key, (, c]`. Therefore it aborts the sequence and no `text` is produced (not even for the final `(`). This is in line with existing practice on linux. - The `Dead` `Key` is now used exclusively for those keysyms that have `_dead_` in their name. This appears to be in line with how browsers handle dead keys. - The value of a `Dead` `Key` is in one of three categories: - If the dead key does not correspond to any particular diacritical mark, the value is `None`. For example, `dead_greek` (used to input Greek characters on a Latin keyboard). - If the dead key has a freestanding variant in unicode, the value is `Some(c)` with `c` being the freestanding character. For example, `dead_circumflex` has the value `Some('^')`. - Otherwise the value is `None`. For example, `dead_belowdot`. - `key_without_modifiers` now respects the effective XKB group. It only discards the state of modifiers. This is essential to correctly handle keyboard layouts in the GNOME desktop environment which uses XKB groups to switch between layouts. # Implementation Details - `EventProcessor` no longer uses any interior mutability. In cases where there were conflicting borrows, the code has been rewritten to use freestanding functions. - Keyboard state is now tracked exclusively by xkbcommon. The code that manually tracked some of this state has been removed. - The `xkb_state` module has been significantly simplified. The `process_key_event` function now computes all effects produced by a key press/release ahead of time. - Almost all XInput events also carry the current XKB state of its seat. We use this to track the state of modifiers eagerly and independently of keyboard events.
- Loading branch information