X11: Fix modifiers being reported after release (#1262)

* X11: Fix modifiers being reported after release

* Moves `ModifiersChanged` variant from `WindowEvent` to `DeviceEvent`

* Add CHANGELOG entry
This commit is contained in:
Murarth 2019-11-10 00:16:44 -07:00 committed by Hal Gentz
parent dba21c06ed
commit c66784995d
6 changed files with 110 additions and 114 deletions

View file

@ -1,6 +1,7 @@
# Unreleased # Unreleased
- On macOS, fix application termination on `ControlFlow::Exit` - On macOS, fix application termination on `ControlFlow::Exit`
- On X11, fix key modifiers being incorrectly reported.
# 0.20.0 Alpha 4 (2019-10-18) # 0.20.0 Alpha 4 (2019-10-18)

View file

@ -134,10 +134,6 @@ pub enum WindowEvent {
input: KeyboardInput, input: KeyboardInput,
}, },
/// Keyboard modifiers have changed
#[doc(hidden)]
ModifiersChanged { modifiers: ModifiersState },
/// The cursor has moved on the window. /// The cursor has moved on the window.
CursorMoved { CursorMoved {
device_id: DeviceId, device_id: DeviceId,
@ -266,7 +262,15 @@ pub enum DeviceEvent {
button: ButtonId, button: ButtonId,
state: ElementState, state: ElementState,
}, },
Key(KeyboardInput), Key(KeyboardInput),
/// Keyboard modifiers have changed
#[doc(hidden)]
ModifiersChanged {
modifiers: ModifiersState,
},
Text { Text {
codepoint: char, codepoint: char,
}, },

View file

@ -54,6 +54,10 @@ impl<T> WindowEventsSink<T> {
} }
} }
pub fn send_event(&mut self, evt: crate::event::Event<T>) {
self.buffer.push_back(evt);
}
pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) { pub fn send_window_event(&mut self, evt: crate::event::WindowEvent, wid: WindowId) {
self.buffer.push_back(crate::event::Event::WindowEvent { self.buffer.push_back(crate::event::Event::WindowEvent {
event: evt, event: evt,
@ -240,9 +244,7 @@ pub struct EventLoop<T: 'static> {
// Utility for grabbing the cursor and changing visibility // Utility for grabbing the cursor and changing visibility
_user_source: ::calloop::Source<::calloop::channel::Channel<T>>, _user_source: ::calloop::Source<::calloop::channel::Channel<T>>,
user_sender: ::calloop::channel::Sender<T>, user_sender: ::calloop::channel::Sender<T>,
_kbd_source: ::calloop::Source< _kbd_source: ::calloop::Source<::calloop::channel::Channel<crate::event::Event<()>>>,
::calloop::channel::Channel<(crate::event::WindowEvent, super::WindowId)>,
>,
window_target: RootELW<T>, window_target: RootELW<T>,
} }
@ -296,13 +298,14 @@ impl<T: 'static> EventLoop<T> {
let inner_loop = ::calloop::EventLoop::new().unwrap(); let inner_loop = ::calloop::EventLoop::new().unwrap();
let (kbd_sender, kbd_channel) = ::calloop::channel::channel(); let (kbd_sender, kbd_channel) = ::calloop::channel::channel::<crate::event::Event<()>>();
let kbd_sink = sink.clone(); let kbd_sink = sink.clone();
let kbd_source = inner_loop let kbd_source = inner_loop
.handle() .handle()
.insert_source(kbd_channel, move |evt, &mut ()| { .insert_source(kbd_channel, move |evt, &mut ()| {
if let ::calloop::channel::Event::Msg((evt, wid)) = evt { if let ::calloop::channel::Event::Msg(evt) = evt {
kbd_sink.lock().unwrap().send_window_event(evt, wid); let evt = evt.map_nonuser_event().ok().unwrap();
kbd_sink.lock().unwrap().send_event(evt);
} }
}) })
.unwrap(); .unwrap();
@ -726,7 +729,7 @@ struct SeatManager<T: 'static> {
sink: Arc<Mutex<WindowEventsSink<T>>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>, seats: Arc<Mutex<Vec<(u32, wl_seat::WlSeat)>>>,
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, kbd_sender: ::calloop::channel::Sender<crate::event::Event<()>>,
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>, relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,
pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>, pointer_constraints_proxy: Arc<Mutex<Option<ZwpPointerConstraintsV1>>>,
cursor_manager: Arc<Mutex<CursorManager>>, cursor_manager: Arc<Mutex<CursorManager>>,
@ -771,7 +774,7 @@ impl<T: 'static> SeatManager<T> {
struct SeatData<T> { struct SeatData<T> {
sink: Arc<Mutex<WindowEventsSink<T>>>, sink: Arc<Mutex<WindowEventsSink<T>>>,
store: Arc<Mutex<WindowStore>>, store: Arc<Mutex<WindowStore>>,
kbd_sender: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, kbd_sender: ::calloop::channel::Sender<crate::event::Event<()>>,
pointer: Option<wl_pointer::WlPointer>, pointer: Option<wl_pointer::WlPointer>,
relative_pointer: Option<ZwpRelativePointerV1>, relative_pointer: Option<ZwpRelativePointerV1>,
relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>, relative_pointer_manager_proxy: Rc<RefCell<Option<ZwpRelativePointerManagerV1>>>,

View file

@ -8,11 +8,13 @@ use smithay_client_toolkit::{
reexports::client::protocol::{wl_keyboard, wl_seat}, 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( pub fn init_keyboard(
seat: &wl_seat::WlSeat, seat: &wl_seat::WlSeat,
sink: ::calloop::channel::Sender<(crate::event::WindowEvent, super::WindowId)>, sink: ::calloop::channel::Sender<crate::event::Event<()>>,
modifiers_tracker: Arc<Mutex<ModifiersState>>, modifiers_tracker: Arc<Mutex<ModifiersState>>,
) -> wl_keyboard::WlKeyboard { ) -> wl_keyboard::WlKeyboard {
// { variables to be captured by the closures // { variables to be captured by the closures
@ -29,12 +31,22 @@ pub fn init_keyboard(
match evt { match evt {
KbEvent::Enter { surface, .. } => { KbEvent::Enter { surface, .. } => {
let wid = make_wid(&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); *target.lock().unwrap() = Some(wid);
} }
KbEvent::Leave { surface, .. } => { KbEvent::Leave { surface, .. } => {
let wid = make_wid(&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; *target.lock().unwrap() = None;
} }
KbEvent::Key { KbEvent::Key {
@ -52,11 +64,10 @@ pub fn init_keyboard(
}; };
let vkcode = key_to_vkey(rawkey, keysym); let vkcode = key_to_vkey(rawkey, keysym);
my_sink my_sink
.send(( .send(Event::WindowEvent {
WindowEvent::KeyboardInput { window_id: mk_root_wid(wid),
device_id: crate::event::DeviceId( event: WindowEvent::KeyboardInput {
crate::platform_impl::DeviceId::Wayland(DeviceId), device_id: device_id(),
),
input: KeyboardInput { input: KeyboardInput {
state, state,
scancode: rawkey, scancode: rawkey,
@ -64,8 +75,7 @@ pub fn init_keyboard(
modifiers: modifiers_tracker.lock().unwrap().clone(), modifiers: modifiers_tracker.lock().unwrap().clone(),
}, },
}, },
wid, })
))
.unwrap(); .unwrap();
// send char event only on key press, not release // send char event only on key press, not release
if let ElementState::Released = state { if let ElementState::Released = state {
@ -74,7 +84,10 @@ pub fn init_keyboard(
if let Some(txt) = utf8 { if let Some(txt) = utf8 {
for chr in txt.chars() { for chr in txt.chars() {
my_sink my_sink
.send((WindowEvent::ReceivedCharacter(chr), wid)) .send(Event::WindowEvent {
window_id: mk_root_wid(wid),
event: WindowEvent::ReceivedCharacter(chr),
})
.unwrap(); .unwrap();
} }
} }
@ -88,11 +101,12 @@ pub fn init_keyboard(
*modifiers_tracker.lock().unwrap() = modifiers; *modifiers_tracker.lock().unwrap() = modifiers;
if let Some(wid) = *target.lock().unwrap() { my_sink
my_sink .send(Event::DeviceEvent {
.send((WindowEvent::ModifiersChanged { modifiers }, wid)) device_id: device_id(),
.unwrap(); event: DeviceEvent::ModifiersChanged { modifiers },
} })
.unwrap();
} }
} }
}, },
@ -101,11 +115,10 @@ pub fn init_keyboard(
let state = ElementState::Pressed; let state = ElementState::Pressed;
let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym); let vkcode = key_to_vkey(repeat_event.rawkey, repeat_event.keysym);
repeat_sink repeat_sink
.send(( .send(Event::WindowEvent {
WindowEvent::KeyboardInput { window_id: mk_root_wid(wid),
device_id: crate::event::DeviceId( event: WindowEvent::KeyboardInput {
crate::platform_impl::DeviceId::Wayland(DeviceId), device_id: device_id(),
),
input: KeyboardInput { input: KeyboardInput {
state, state,
scancode: repeat_event.rawkey, scancode: repeat_event.rawkey,
@ -113,13 +126,15 @@ pub fn init_keyboard(
modifiers: my_modifiers.lock().unwrap().clone(), modifiers: my_modifiers.lock().unwrap().clone(),
}, },
}, },
wid, })
))
.unwrap(); .unwrap();
if let Some(txt) = repeat_event.utf8 { if let Some(txt) = repeat_event.utf8 {
for chr in txt.chars() { for chr in txt.chars() {
repeat_sink repeat_sink
.send((WindowEvent::ReceivedCharacter(chr), wid)) .send(Event::WindowEvent {
window_id: mk_root_wid(wid),
event: WindowEvent::ReceivedCharacter(chr),
})
.unwrap(); .unwrap();
} }
} }
@ -147,12 +162,22 @@ pub fn init_keyboard(
move |evt, _| match evt { move |evt, _| match evt {
wl_keyboard::Event::Enter { surface, .. } => { wl_keyboard::Event::Enter { surface, .. } => {
let wid = make_wid(&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); target = Some(wid);
} }
wl_keyboard::Event::Leave { surface, .. } => { wl_keyboard::Event::Leave { surface, .. } => {
let wid = make_wid(&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; target = None;
} }
wl_keyboard::Event::Key { key, state, .. } => { wl_keyboard::Event::Key { key, state, .. } => {
@ -163,11 +188,10 @@ pub fn init_keyboard(
_ => unreachable!(), _ => unreachable!(),
}; };
my_sink my_sink
.send(( .send(Event::WindowEvent {
WindowEvent::KeyboardInput { window_id: mk_root_wid(wid),
device_id: crate::event::DeviceId( event: WindowEvent::KeyboardInput {
crate::platform_impl::DeviceId::Wayland(DeviceId), device_id: device_id(),
),
input: KeyboardInput { input: KeyboardInput {
state, state,
scancode: key, scancode: key,
@ -175,8 +199,7 @@ pub fn init_keyboard(
modifiers: ModifiersState::default(), modifiers: ModifiersState::default(),
}, },
}, },
wid, })
))
.unwrap(); .unwrap();
} }
} }
@ -386,3 +409,11 @@ impl From<keyboard::ModifiersState> 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))
}

View file

@ -25,7 +25,6 @@ pub(super) struct EventProcessor<T: 'static> {
pub(super) target: Rc<RootELW<T>>, pub(super) target: Rc<RootELW<T>>,
pub(super) mod_keymap: ModifierKeymap, pub(super) mod_keymap: ModifierKeymap,
pub(super) device_mod_state: ModifierKeyState, pub(super) device_mod_state: ModifierKeyState,
pub(super) window_mod_state: ModifierKeyState,
} }
impl<T: 'static> EventProcessor<T> { impl<T: 'static> EventProcessor<T> {
@ -131,7 +130,6 @@ impl<T: 'static> EventProcessor<T> {
self.mod_keymap.reset_from_x_connection(&wt.xconn); self.mod_keymap.reset_from_x_connection(&wt.xconn);
self.device_mod_state.update(&self.mod_keymap); self.device_mod_state.update(&self.mod_keymap);
self.window_mod_state.update(&self.mod_keymap);
} }
} }
@ -547,7 +545,7 @@ impl<T: 'static> EventProcessor<T> {
}; };
let virtual_keycode = events::keysym_to_element(keysym as c_uint); 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 { callback(Event::WindowEvent {
window_id, window_id,
@ -561,27 +559,6 @@ impl<T: 'static> EventProcessor<T> {
}, },
}, },
}); });
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 { if state == Pressed {
@ -894,21 +871,6 @@ impl<T: 'static> EventProcessor<T> {
event: Focused(true), 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, // The deviceid for this event is for a keyboard instead of a pointer,
// so we have to do a little extra work. // so we have to do a little extra work.
let pointer_id = self let pointer_id = self
@ -941,21 +903,6 @@ impl<T: 'static> EventProcessor<T> {
.unfocus(xev.event) .unfocus(xev.event)
.expect("Failed to unfocus input context"); .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 { callback(Event::WindowEvent {
window_id: mkwid(xev.event), window_id: mkwid(xev.event),
event: Focused(false), event: Focused(false),
@ -1068,7 +1015,7 @@ impl<T: 'static> EventProcessor<T> {
_ => unreachable!(), _ => unreachable!(),
}; };
let device_id = xev.sourceid; let device_id = mkdid(xev.sourceid);
let keycode = xev.detail; let keycode = xev.detail;
if keycode < 8 { if keycode < 8 {
return; return;
@ -1088,6 +1035,18 @@ impl<T: 'static> EventProcessor<T> {
let virtual_keycode = events::keysym_to_element(keysym as c_uint); 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) = if let Some(modifier) =
self.mod_keymap.get_modifier(keycode as ffi::KeyCode) self.mod_keymap.get_modifier(keycode as ffi::KeyCode)
{ {
@ -1096,19 +1055,18 @@ impl<T: 'static> EventProcessor<T> {
keycode as ffi::KeyCode, keycode as ffi::KeyCode,
modifier, 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 => { ffi::XI_HierarchyChanged => {

View file

@ -192,7 +192,6 @@ impl<T: 'static> EventLoop<T> {
xi2ext, xi2ext,
mod_keymap, mod_keymap,
device_mod_state: Default::default(), device_mod_state: Default::default(),
window_mod_state: Default::default(),
}; };
// Register for device hotplug events // Register for device hotplug events