Rework keyboard handler

This commit is contained in:
Victor Berger 2017-09-21 19:28:59 +02:00
parent c5048fea71
commit 2850def0f4
2 changed files with 58 additions and 39 deletions

View File

@ -5,7 +5,7 @@ authors = ["Victor Berger <victor.berger@thalesgroup.com>"]
license = "MIT" license = "MIT"
[dependencies] [dependencies]
wayland-server = "0.10.1" wayland-server = "0.10.2"
nix = "0.7.0" nix = "0.7.0"
xkbcommon = "0.2.1" xkbcommon = "0.2.1"
tempfile = "2.1.5" tempfile = "2.1.5"
@ -20,7 +20,7 @@ glium = { version = "0.17.1", optional = true, default-features = false }
input = { version = "0.2.0", optional = true } input = { version = "0.2.0", optional = true }
clippy = { version = "*", optional = true } clippy = { version = "*", optional = true }
rental = "0.4.11" rental = "0.4.11"
wayland-protocols = { version = "0.10.1", features = ["unstable_protocols", "server"] } wayland-protocols = { version = "0.10.2", features = ["unstable_protocols", "server"] }
image = "0.15.0" image = "0.15.0"
error-chain = "0.11.0" error-chain = "0.11.0"

View File

@ -74,7 +74,8 @@ impl ModifiersState {
} }
struct KbdInternal { struct KbdInternal {
focus: Option<(wl_surface::WlSurface, wl_keyboard::WlKeyboard)>, known_kbds: Vec<wl_keyboard::WlKeyboard>,
focus: Option<wl_surface::WlSurface>,
pressed_keys: Vec<u32>, pressed_keys: Vec<u32>,
mods_state: ModifiersState, mods_state: ModifiersState,
keymap: xkb::Keymap, keymap: xkb::Keymap,
@ -102,6 +103,7 @@ impl KbdInternal {
).ok_or(())?; ).ok_or(())?;
let state = xkb::State::new(&keymap); let state = xkb::State::new(&keymap);
Ok(KbdInternal { Ok(KbdInternal {
known_kbds: Vec::new(),
focus: None, focus: None,
pressed_keys: Vec::new(), pressed_keys: Vec::new(),
mods_state: ModifiersState::new(), mods_state: ModifiersState::new(),
@ -152,6 +154,18 @@ impl KbdInternal {
}; };
serialized.into() serialized.into()
} }
fn with_focused_kbds<F>(&self, mut f: F)
where F: FnMut(&wl_keyboard::WlKeyboard, &wl_surface::WlSurface)
{
if let Some(ref surface) = self.focus {
for kbd in &self.known_kbds {
if kbd.same_client_as(surface) {
f(kbd, surface);
}
}
}
}
} }
/// Errors that can be encountered when creating a keyboard handler /// Errors that can be encountered when creating a keyboard handler
@ -227,7 +241,7 @@ impl KbdHandle {
/// keyboard handler. It will internally track the state of the keymap. /// keyboard handler. It will internally track the state of the keymap.
/// ///
/// The `filter` argument is expected to be a closure which will peek at the generated input /// The `filter` argument is expected to be a closure which will peek at the generated input
/// as interpreted by the keymap befor it is forwarded to the focused client. If this closure /// as interpreted by the keymap before it is forwarded to the focused client. If this closure
/// returns false, the input will not be sent to the client. This mechanism can be used to /// returns false, the input will not be sent to the client. This mechanism can be used to
/// implement compositor-level key bindings for example. /// implement compositor-level key bindings for example.
/// ///
@ -254,16 +268,22 @@ impl KbdHandle {
} }
// forward to client if no keybinding is triggered // forward to client if no keybinding is triggered
if let Some((_, ref kbd)) = guard.focus { let modifiers = if mods_changed {
if mods_changed { Some(guard.serialize_modifiers())
let (dep, la, lo, gr) = guard.serialize_modifiers(); } else {
kbd.modifiers(serial, dep, la, lo, gr); None
} };
let wl_state = match state { let wl_state = match state {
KeyState::Pressed => wl_keyboard::KeyState::Pressed, KeyState::Pressed => wl_keyboard::KeyState::Pressed,
KeyState::Released => wl_keyboard::KeyState::Released, KeyState::Released => wl_keyboard::KeyState::Released,
}; };
guard.with_focused_kbds(|kbd, _| {
if let Some((dep, la, lo, gr)) = modifiers {
kbd.modifiers(serial, dep, la, lo, gr);
}
kbd.key(serial, 0, keycode, wl_state); kbd.key(serial, 0, keycode, wl_state);
});
if guard.focus.is_some() {
trace!(self.arc.logger, "Input forwarded to client"); trace!(self.arc.logger, "Input forwarded to client");
} else { } else {
trace!(self.arc.logger, "No client currently focused"); trace!(self.arc.logger, "No client currently focused");
@ -274,51 +294,50 @@ impl KbdHandle {
/// ///
/// Any previous focus will be sent a `wl_keyboard::leave` event, and if the new focus /// Any previous focus will be sent a `wl_keyboard::leave` event, and if the new focus
/// is not `None`, a `wl_keyboard::enter` event will be sent. /// is not `None`, a `wl_keyboard::enter` event will be sent.
pub fn set_focus(&self, focus: Option<(wl_surface::WlSurface, wl_keyboard::WlKeyboard)>, serial: u32) { pub fn set_focus(&self, focus: Option<wl_surface::WlSurface>, serial: u32) {
// TODO: check surface and keyboard are from the same client
let mut guard = self.arc.internal.lock().unwrap(); let mut guard = self.arc.internal.lock().unwrap();
// remove current focus // unset old focus
let old_kbd = if let Some((old_surface, old_kbd)) = guard.focus.take() { guard.with_focused_kbds(|kbd, s| {
if old_surface.status() != Liveness::Dead { kbd.leave(serial, s);
old_kbd.leave(serial, &old_surface); });
}
Some(old_kbd)
} else {
None
};
// set new focus // set new focus
if let Some((surface, kbd)) = focus { guard.focus = focus;
if surface.status() != Liveness::Dead {
// send new mods status if client instance changed
match old_kbd {
Some(ref okbd) if okbd.equals(&kbd) => {}
_ => {
let (dep, la, lo, gr) = guard.serialize_modifiers(); let (dep, la, lo, gr) = guard.serialize_modifiers();
let keys = guard.serialize_pressed_keys();
guard.with_focused_kbds(|kbd, s| {
kbd.modifiers(serial, dep, la, lo, gr); kbd.modifiers(serial, dep, la, lo, gr);
} kbd.enter(serial, s, keys.clone());
} });
// send enter event if guard.focus.is_some() {
kbd.enter(serial, &surface, guard.serialize_pressed_keys());
}
guard.focus = Some((surface, kbd));
trace!(self.arc.logger, "Focus set to new surface"); trace!(self.arc.logger, "Focus set to new surface");
} else { } else {
trace!(self.arc.logger, "Focus unset"); trace!(self.arc.logger, "Focus unset");
} }
} }
/// Send the keymap to this keyboard /// Register a new keyboard to this handler
///
/// The keymap will automatically be sent to it
/// ///
/// This should be done first, before anything else is done with this keyboard. /// This should be done first, before anything else is done with this keyboard.
pub fn send_keymap(&self, kbd: &wl_keyboard::WlKeyboard) { pub fn new_kbd(&self, kbd: wl_keyboard::WlKeyboard) {
trace!(self.arc.logger, "Sending keymap to client"); trace!(self.arc.logger, "Sending keymap to client");
kbd.keymap( kbd.keymap(
wl_keyboard::KeymapFormat::XkbV1, wl_keyboard::KeymapFormat::XkbV1,
self.arc.keymap_file.as_raw_fd(), self.arc.keymap_file.as_raw_fd(),
self.arc.keymap_len, self.arc.keymap_len,
); );
let mut guard = self.arc.internal.lock().unwrap();
guard.known_kbds.push(kbd);
}
/// Performs an internal cleanup of known kbds
///
/// Drops any wl_keyboard that is no longer alive
pub fn cleanup_old_kbds(&self) {
let mut guard = self.arc.internal.lock().unwrap();
guard.known_kbds.retain(|kbd| kbd.status() != Liveness::Dead);
} }
} }