-
Notifications
You must be signed in to change notification settings - Fork 893
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
X11: Sync key press/release with window focus #1296
Conversation
* When a window loses focus, key release events are issued for all pressed keys * When a window gains focus, key press events are issued for all pressed keys * Adds `is_synthetic` field to `WindowEvent` variant `KeyboardInput` to indicate that these events are synthetic. * Adds `is_synthetic: false` to `WindowEvent::KeyboardInput` events issued on all other platforms
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.
So, under i3wm there are some unfortunate focus issues that make this operate in an unexpected manner.
It's hard to spot, but becomes more obvious while testing this PR as it leads to the synthetic key events to get repeated.
For context, the window is on workspace 5 and my terminal on workspace 4. Logo-5
moves your focus to workspace 5, Logo-4
moves it to workspace 4.
More precisely, when Logo-<num>
is pressed, ALL windows lose focus, the cursor is moved onto the appropriate workstation and the window that will become focused is highlighted.
The window that will become focused, however, only gains it's focus when the <num>
key is released. Releasing the Logo
key has no effect.
Here we have the window in focus. We hold Logo
then 4
. We receive two focus lost events. Upon releasing the 4
we receive a third. This is likely just i3wm being janky and reporting multiple focus lost events to the client that just lost focus- once when it sends it to all clients, and twice for some odd reason to the specific client that lost focus.
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167648, tv_nsec: 411933429 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 125, state: Pressed, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } }) }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: ModifiersChanged { modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Pressed, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: false } }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167653, tv_nsec: 272226669 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 5, state: Pressed, virtual_keycode: Some(Key4), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 5, state: Released, virtual_keycode: Some(Key4), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Released, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: Focused(false) }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167654, tv_nsec: 194180513 }, requested_resume: None })
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 5, state: Released, virtual_keycode: Some(Key4), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Released, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: Focused(false) }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167654, tv_nsec: 201562658 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 5, state: Released, virtual_keycode: Some(Key4), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Released, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: Focused(false) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorLeft { device_id: DeviceId(X(DeviceId(2))) } }
EventsCleared
However, consider the following: when the window is regaining focus, we receive two focus gained events- one before the <num>
key is released and one after. The first focus event actually arrives before the window has gained focus! I tested the behavior out in some other applications: firefox seams to recognize that they have not gained focus, but riot-desktop, keepassxc, file-roller, and xfce4-terminal do not.
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167884, tv_nsec: 50759782 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 125, state: Pressed, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167886, tv_nsec: 682480255 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 6, state: Pressed, virtual_keycode: Some(Key5), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167889, tv_nsec: 258764883 }, requested_resume: None })
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167889, tv_nsec: 267693397 }, requested_resume: None })
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: Focused(true) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: -919.3846153846155, y: 488.3076923076923 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 6, state: Pressed, virtual_keycode: Some(Key5), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Pressed, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167889, tv_nsec: 270401893 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 6, state: Released, virtual_keycode: Some(Key5), modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: Focused(true) }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: -919.3846153846155, y: 488.3076923076923 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Pressed, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }, is_synthetic: true } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorEntered { device_id: DeviceId(X(DeviceId(2))) } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: 884.3076923076924, y: 475.3846153846154 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: LogicalPosition { x: 884.3076923076924, y: 475.3846153846154 }, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 0, value: 2880.0 } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: AxisMotion { device_id: DeviceId(X(DeviceId(2))), axis: 1, value: 539.0 } }
EventsCleared
NewEvents(WaitCancelled { start: Instant { tv_sec: 2167894, tv_nsec: 276126253 }, requested_resume: None })
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: Key(KeyboardInput { scancode: 125, state: Released, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: true } }) }
DeviceEvent { device_id: DeviceId(X(DeviceId(10))), event: ModifiersChanged { modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } } }
WindowEvent { window_id: WindowId(X(WindowId(71303169))), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), input: KeyboardInput { scancode: 125, state: Released, virtual_keycode: None, modifiers: ModifiersState { shift: false, ctrl: false, alt: false, logo: false } }, is_synthetic: false } }
EventsCleared
Anyways, as it stands, these synthetic errors are getting duplicated multiple times. I'll leave it up to you to decide if that's okay.
@goddessfreya If there are no further issues with this PR, can I get an explicit approval? |
rust-windowing generates synthetic key press and release events to try and work around issues with keys being pressed and held while window focus is lost, see rust-windowing/winit#1296 However the Ubuntu workspace keyboard shortcut (and others) is causing synthetic Pressed events, without the corresponding Release event. Ignoring synthetic key pressed events, in addition to the existing behaviour of releasing all keys when window focus is lost (feenkcom/gtoolkit#423) resolves the issue. Fixes: feenkcom/gtoolkit#1178
Metacello new baseline: 'GToolkit'; repository: 'github://feenkcom/gtoolkit:v0.7.1088/src'; load All commits (inlcuding upstream repositories) since last build: feenkcom/gtoolkit-glutin@55656e by Alistair Grant Ignore synthetic key Pressed events rust-windowing generates synthetic key press and release events to try and work around issues with keys being pressed and held while window focus is lost, see rust-windowing/winit#1296 However the Ubuntu workspace keyboard shortcut (and others) is causing synthetic Pressed events, without the corresponding Release event. Ignoring synthetic key pressed events, in addition to the existing behaviour of releasing all keys when window focus is lost (#423) resolves the issue. Fixes: #1178
is_synthetic
field toWindowEvent
variantKeyboardInput
to indicate that these events are synthetic.
is_synthetic: false
toWindowEvent::KeyboardInput
events issuedon all other platforms
Addresses #1272 (but doesn't close, as that issue affects other platforms).
cargo fmt
has been run on this branchcargo doc
builds successfullyCHANGELOG.md
if knowledge of this change could be valuable to users