diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dc52443..5f2d3741 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - On macOS, fix application termination on `ControlFlow::Exit` +- On X11, fix key modifiers being incorrectly reported. # 0.20.0 Alpha 4 (2019-10-18) diff --git a/src/event.rs b/src/event.rs index d5548908..a6aa9bd0 100644 --- a/src/event.rs +++ b/src/event.rs @@ -134,10 +134,6 @@ pub enum WindowEvent { input: KeyboardInput, }, - /// Keyboard modifiers have changed - #[doc(hidden)] - ModifiersChanged { modifiers: ModifiersState }, - /// The cursor has moved on the window. CursorMoved { device_id: DeviceId, @@ -266,7 +262,15 @@ pub enum DeviceEvent { button: ButtonId, state: ElementState, }, + Key(KeyboardInput), + + /// Keyboard modifiers have changed + #[doc(hidden)] + ModifiersChanged { + modifiers: ModifiersState, + }, + Text { codepoint: char, }, diff --git a/src/platform_impl/linux/wayland/event_loop.rs b/src/platform_impl/linux/wayland/event_loop.rs index 3e04137e..146dcb37 100644 --- a/src/platform_impl/linux/wayland/event_loop.rs +++ b/src/platform_impl/linux/wayland/event_loop.rs @@ -54,6 +54,10 @@ impl WindowEventsSink { } } + pub fn send_event(&mut self, evt: crate::event::Event) { + self.buffer.push_back(evt); + } + pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) { self.buffer.push_back(crate::event::Event::WindowEvent { event: evt, @@ -240,9 +244,7 @@ pub struct EventLoop { // Utility for grabbing the cursor and changing visibility _user_source: ::calloop::Source<::calloop::channel::Channel>, user_sender: ::calloop::channel::Sender, - _kbd_source: ::calloop::Source< - ::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>, - >, + _kbd_source: ::calloop::Source<::calloop::channel::Channel>>, window_target: RootELW, } @@ -296,13 +298,14 @@ impl EventLoop { let inner_loop = ::calloop::EventLoop::new().unwrap(); - let (kbd_sender, kbd_channel) = ::calloop::channel::channel(); + let (kbd_sender, kbd_channel) = ::calloop::channel::channel::>(); let kbd_sink = sink.clone(); let kbd_source = inner_loop .handle() .insert_source(kbd_channel, move |evt, &mut ()| { - if let ::calloop::channel::Event::Msg((evt, wid)) = evt { - kbd_sink.lock().unwrap().send_window_event(evt, wid); + if let ::calloop::channel::Event::Msg(evt) = evt { + let evt = evt.map_nonuser_event().ok().unwrap(); + kbd_sink.lock().unwrap().send_event(evt); } }) .unwrap(); @@ -726,7 +729,7 @@ struct SeatManager { sink: Arc>>, store: Arc>, seats: Arc>>, - kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, + kbd_sender: ::calloop::channel::Sender>, relative_pointer_manager_proxy: Rc>>, pointer_constraints_proxy: Arc>>, cursor_manager: Arc>, @@ -771,7 +774,7 @@ impl SeatManager { struct SeatData { sink: Arc>>, store: Arc>, - kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, + kbd_sender: ::calloop::channel::Sender>, pointer: Option, relative_pointer: Option, relative_pointer_manager_proxy: Rc>>, diff --git a/src/platform_impl/linux/wayland/keyboard.rs b/src/platform_impl/linux/wayland/keyboard.rs index 4a236691..1b46f81f 100644 --- a/src/platform_impl/linux/wayland/keyboard.rs +++ b/src/platform_impl/linux/wayland/keyboard.rs @@ -8,11 +8,13 @@ use smithay_client_toolkit::{ reexports::client::protocol::{wl_keyboard, wl_seat}, }; -use crate::event::{ElementState, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent}; +use crate::event::{ + DeviceEvent, ElementState, Event, KeyboardInput, ModifiersState, VirtualKeyCode, WindowEvent, +}; pub fn init_keyboard( seat: &wl_seat::WlSeat, - sink: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, + sink: ::calloop::channel::Sender>, modifiers_tracker: Arc>, ) -> wl_keyboard::WlKeyboard { // { variables to be captured by the closures @@ -29,12 +31,22 @@ pub fn init_keyboard( match evt { KbEvent::Enter { surface, .. } => { let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); + my_sink + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::Focused(true), + }) + .unwrap(); *target.lock().unwrap() = Some(wid); } KbEvent::Leave { surface, .. } => { let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); + my_sink + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::Focused(false), + }) + .unwrap(); *target.lock().unwrap() = None; } KbEvent::Key { @@ -52,11 +64,10 @@ pub fn init_keyboard( }; let vkcode = key_to_vkey(rawkey, keysym); my_sink - .send(( - WindowEvent::KeyboardInput { - device_id: crate::event::DeviceId( - crate::platform_impl::DeviceId::Wayland(DeviceId), - ), + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::KeyboardInput { + device_id: device_id(), input: KeyboardInput { state, scancode: rawkey, @@ -64,8 +75,7 @@ pub fn init_keyboard( modifiers: modifiers_tracker.lock().unwrap().clone(), }, }, - wid, - )) + }) .unwrap(); // send char event only on key press, not release if let ElementState::Released = state { @@ -74,7 +84,10 @@ pub fn init_keyboard( if let Some(txt) = utf8 { for chr in txt.chars() { my_sink - .send((WindowEvent::ReceivedCharacter(chr), wid)) + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::ReceivedCharacter(chr), + }) .unwrap(); } } @@ -88,11 +101,12 @@ pub fn init_keyboard( *modifiers_tracker.lock().unwrap() = modifiers; - if let Some(wid) = *target.lock().unwrap() { - my_sink - .send((WindowEvent::ModifiersChanged { modifiers }, wid)) - .unwrap(); - } + my_sink + .send(Event::DeviceEvent { + device_id: device_id(), + event: DeviceEvent::ModifiersChanged { modifiers }, + }) + .unwrap(); } } }, @@ -101,11 +115,10 @@ pub fn init_keyboard( let state = ElementState::Pressed; let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym); repeat_sink - .send(( - WindowEvent::KeyboardInput { - device_id: crate::event::DeviceId( - crate::platform_impl::DeviceId::Wayland(DeviceId), - ), + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::KeyboardInput { + device_id: device_id(), input: KeyboardInput { state, scancode: repeat_event.rawkey, @@ -113,13 +126,15 @@ pub fn init_keyboard( modifiers: my_modifiers.lock().unwrap().clone(), }, }, - wid, - )) + }) .unwrap(); if let Some(txt) = repeat_event.utf8 { for chr in txt.chars() { repeat_sink - .send((WindowEvent::ReceivedCharacter(chr), wid)) + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::ReceivedCharacter(chr), + }) .unwrap(); } } @@ -147,12 +162,22 @@ pub fn init_keyboard( move |evt, _| match evt { wl_keyboard::Event::Enter { surface, .. } => { let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(true), wid)).unwrap(); + my_sink + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::Focused(true), + }) + .unwrap(); target = Some(wid); } wl_keyboard::Event::Leave { surface, .. } => { let wid = make_wid(&surface); - my_sink.send((WindowEvent::Focused(false), wid)).unwrap(); + my_sink + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::Focused(false), + }) + .unwrap(); target = None; } wl_keyboard::Event::Key { key, state, .. } => { @@ -163,11 +188,10 @@ pub fn init_keyboard( _ => unreachable!(), }; my_sink - .send(( - WindowEvent::KeyboardInput { - device_id: crate::event::DeviceId( - crate::platform_impl::DeviceId::Wayland(DeviceId), - ), + .send(Event::WindowEvent { + window_id: mk_root_wid(wid), + event: WindowEvent::KeyboardInput { + device_id: device_id(), input: KeyboardInput { state, scancode: key, @@ -175,8 +199,7 @@ pub fn init_keyboard( modifiers: ModifiersState::default(), }, }, - wid, - )) + }) .unwrap(); } } @@ -386,3 +409,11 @@ impl From for ModifiersState { } } } + +fn device_id() -> crate::event::DeviceId { + crate::event::DeviceId(crate::platform_impl::DeviceId::Wayland(DeviceId)) +} + +fn mk_root_wid(wid: crate::platform_impl::wayland::WindowId) -> crate::window::WindowId { + crate::window::WindowId(crate::platform_impl::WindowId::Wayland(wid)) +} diff --git a/src/platform_impl/linux/x11/event_processor.rs b/src/platform_impl/linux/x11/event_processor.rs index 3ca469df..53178ebf 100644 --- a/src/platform_impl/linux/x11/event_processor.rs +++ b/src/platform_impl/linux/x11/event_processor.rs @@ -25,7 +25,6 @@ pub(super) struct EventProcessor { pub(super) target: Rc>, pub(super) mod_keymap: ModifierKeymap, pub(super) device_mod_state: ModifierKeyState, - pub(super) window_mod_state: ModifierKeyState, } impl EventProcessor { @@ -131,7 +130,6 @@ impl EventProcessor { self.mod_keymap.reset_from_x_connection(&wt.xconn); self.device_mod_state.update(&self.mod_keymap); - self.window_mod_state.update(&self.mod_keymap); } } @@ -547,7 +545,7 @@ impl EventProcessor { }; let virtual_keycode = events::keysym_to_element(keysym as c_uint); - let modifiers = self.window_mod_state.modifiers(); + let modifiers = self.device_mod_state.modifiers(); callback(Event::WindowEvent { window_id, @@ -561,27 +559,6 @@ impl EventProcessor { }, }, }); - - if let Some(modifier) = - self.mod_keymap.get_modifier(xkev.keycode as ffi::KeyCode) - { - self.window_mod_state.key_event( - state, - xkev.keycode as ffi::KeyCode, - modifier, - ); - - let new_modifiers = self.window_mod_state.modifiers(); - - if modifiers != new_modifiers { - callback(Event::WindowEvent { - window_id, - event: WindowEvent::ModifiersChanged { - modifiers: new_modifiers, - }, - }); - } - } } if state == Pressed { @@ -894,21 +871,6 @@ impl EventProcessor { event: Focused(true), }); - // When focus is gained, send any existing modifiers - // to the window in a ModifiersChanged event. This is - // done to compensate for modifier keys that may be - // changed while a window is out of focus. - if !self.device_mod_state.is_empty() { - self.window_mod_state = self.device_mod_state.clone(); - - let modifiers = self.window_mod_state.modifiers(); - - callback(Event::WindowEvent { - window_id, - event: WindowEvent::ModifiersChanged { modifiers }, - }); - } - // The deviceid for this event is for a keyboard instead of a pointer, // so we have to do a little extra work. let pointer_id = self @@ -941,21 +903,6 @@ impl EventProcessor { .unfocus(xev.event) .expect("Failed to unfocus input context"); - // When focus is lost, send a ModifiersChanged event - // containing no modifiers set. This is done to compensate - // for modifier keys that may be changed while a window - // is out of focus. - if !self.window_mod_state.is_empty() { - self.window_mod_state.clear(); - - callback(Event::WindowEvent { - window_id: mkwid(xev.event), - event: WindowEvent::ModifiersChanged { - modifiers: ModifiersState::default(), - }, - }); - } - callback(Event::WindowEvent { window_id: mkwid(xev.event), event: Focused(false), @@ -1068,7 +1015,7 @@ impl EventProcessor { _ => unreachable!(), }; - let device_id = xev.sourceid; + let device_id = mkdid(xev.sourceid); let keycode = xev.detail; if keycode < 8 { return; @@ -1088,6 +1035,18 @@ impl EventProcessor { let virtual_keycode = events::keysym_to_element(keysym as c_uint); + let modifiers = self.device_mod_state.modifiers(); + + callback(Event::DeviceEvent { + device_id, + event: DeviceEvent::Key(KeyboardInput { + scancode, + virtual_keycode, + state, + modifiers, + }), + }); + if let Some(modifier) = self.mod_keymap.get_modifier(keycode as ffi::KeyCode) { @@ -1096,19 +1055,18 @@ impl EventProcessor { keycode as ffi::KeyCode, modifier, ); + + let new_modifiers = self.device_mod_state.modifiers(); + + if modifiers != new_modifiers { + callback(Event::DeviceEvent { + device_id, + event: DeviceEvent::ModifiersChanged { + modifiers: new_modifiers, + }, + }); + } } - - let modifiers = self.device_mod_state.modifiers(); - - callback(Event::DeviceEvent { - device_id: mkdid(device_id), - event: DeviceEvent::Key(KeyboardInput { - scancode, - virtual_keycode, - state, - modifiers, - }), - }); } ffi::XI_HierarchyChanged => { diff --git a/src/platform_impl/linux/x11/mod.rs b/src/platform_impl/linux/x11/mod.rs index 5b283e68..90f09cfb 100644 --- a/src/platform_impl/linux/x11/mod.rs +++ b/src/platform_impl/linux/x11/mod.rs @@ -192,7 +192,6 @@ impl EventLoop { xi2ext, mod_keymap, device_mod_state: Default::default(), - window_mod_state: Default::default(), }; // Register for device hotplug events