Rework keyboard handler
This commit is contained in:
parent
c5048fea71
commit
2850def0f4
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
let wl_state = match state {
|
||||||
|
KeyState::Pressed => wl_keyboard::KeyState::Pressed,
|
||||||
|
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.modifiers(serial, dep, la, lo, gr);
|
||||||
}
|
}
|
||||||
let wl_state = match state {
|
|
||||||
KeyState::Pressed => wl_keyboard::KeyState::Pressed,
|
|
||||||
KeyState::Released => wl_keyboard::KeyState::Released,
|
|
||||||
};
|
|
||||||
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 {
|
let (dep, la, lo, gr) = guard.serialize_modifiers();
|
||||||
// send new mods status if client instance changed
|
let keys = guard.serialize_pressed_keys();
|
||||||
match old_kbd {
|
guard.with_focused_kbds(|kbd, s| {
|
||||||
Some(ref okbd) if okbd.equals(&kbd) => {}
|
kbd.modifiers(serial, dep, la, lo, gr);
|
||||||
_ => {
|
kbd.enter(serial, s, keys.clone());
|
||||||
let (dep, la, lo, gr) = guard.serialize_modifiers();
|
});
|
||||||
kbd.modifiers(serial, dep, la, lo, gr);
|
if guard.focus.is_some() {
|
||||||
}
|
|
||||||
}
|
|
||||||
// send enter event
|
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue