add the keyboardgrab and rename GrabStartData
to PointerGrabStartData
This commit is contained in:
parent
8edcdf5cd0
commit
070dc78c11
|
@ -13,6 +13,7 @@
|
||||||
- `PointerButtonEvent::button` now returns an `Option<MouseButton>`.
|
- `PointerButtonEvent::button` now returns an `Option<MouseButton>`.
|
||||||
- `MouseButton` is now non-exhaustive.
|
- `MouseButton` is now non-exhaustive.
|
||||||
- Remove `Other` and add `Forward` and `Back` variants to `MouseButton`. Use the new `PointerButtonEvent::button_code` in place of `Other`.
|
- Remove `Other` and add `Forward` and `Back` variants to `MouseButton`. Use the new `PointerButtonEvent::button_code` in place of `Other`.
|
||||||
|
- `GrabStartData` has been renamed to `PointerGrabStartData`
|
||||||
|
|
||||||
#### Backends
|
#### Backends
|
||||||
|
|
||||||
|
@ -49,6 +50,7 @@
|
||||||
- Support for `xdg_wm_base` protocol version 3
|
- Support for `xdg_wm_base` protocol version 3
|
||||||
- Added the option to initialize the dmabuf global with a client filter
|
- Added the option to initialize the dmabuf global with a client filter
|
||||||
- `wayland::output::Output` now has user data attached to it and more functions to query its properties
|
- `wayland::output::Output` now has user data attached to it and more functions to query its properties
|
||||||
|
- Added a `KeyboardGrab` similar to the existing `PointerGrab`
|
||||||
|
|
||||||
#### Backends
|
#### Backends
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ use smithay::{
|
||||||
compositor_init, is_sync_subsurface, with_states, with_surface_tree_upward, BufferAssignment,
|
compositor_init, is_sync_subsurface, with_states, with_surface_tree_upward, BufferAssignment,
|
||||||
SurfaceAttributes, TraversalAction,
|
SurfaceAttributes, TraversalAction,
|
||||||
},
|
},
|
||||||
seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
|
seat::{AxisFrame, PointerGrab, PointerGrabStartData, PointerInnerHandle, Seat},
|
||||||
shell::{
|
shell::{
|
||||||
legacy::{wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind},
|
legacy::{wl_shell_init, ShellRequest, ShellState as WlShellState, ShellSurfaceKind},
|
||||||
wlr_layer::{LayerShellRequest, LayerSurfaceAttributes},
|
wlr_layer::{LayerShellRequest, LayerSurfaceAttributes},
|
||||||
|
@ -39,7 +39,7 @@ use crate::{
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MoveSurfaceGrab {
|
struct MoveSurfaceGrab {
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
window_map: Rc<RefCell<WindowMap>>,
|
window_map: Rc<RefCell<WindowMap>>,
|
||||||
toplevel: SurfaceKind,
|
toplevel: SurfaceKind,
|
||||||
initial_window_location: Point<i32, Logical>,
|
initial_window_location: Point<i32, Logical>,
|
||||||
|
@ -82,7 +82,7 @@ impl PointerGrab for MoveSurfaceGrab {
|
||||||
handle.axis(details)
|
handle.axis(details)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_data(&self) -> &GrabStartData {
|
fn start_data(&self) -> &PointerGrabStartData {
|
||||||
&self.start_data
|
&self.start_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ impl From<ResizeEdge> for xdg_toplevel::ResizeEdge {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ResizeSurfaceGrab {
|
struct ResizeSurfaceGrab {
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
toplevel: SurfaceKind,
|
toplevel: SurfaceKind,
|
||||||
edges: ResizeEdge,
|
edges: ResizeEdge,
|
||||||
initial_window_size: Size<i32, Logical>,
|
initial_window_size: Size<i32, Logical>,
|
||||||
|
@ -280,7 +280,7 @@ impl PointerGrab for ResizeSurfaceGrab {
|
||||||
handle.axis(details)
|
handle.axis(details)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_data(&self) -> &GrabStartData {
|
fn start_data(&self) -> &PointerGrabStartData {
|
||||||
&self.start_data
|
&self.start_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ use wayland_server::{
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
wayland::{
|
wayland::{
|
||||||
seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
|
seat::{AxisFrame, PointerGrab, PointerGrabStartData, PointerInnerHandle, Seat},
|
||||||
Serial,
|
Serial,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -16,7 +16,7 @@ use crate::{
|
||||||
use super::{with_source_metadata, DataDeviceData, SeatData};
|
use super::{with_source_metadata, DataDeviceData, SeatData};
|
||||||
|
|
||||||
pub(crate) struct DnDGrab {
|
pub(crate) struct DnDGrab {
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
data_source: Option<wl_data_source::WlDataSource>,
|
data_source: Option<wl_data_source::WlDataSource>,
|
||||||
current_focus: Option<wl_surface::WlSurface>,
|
current_focus: Option<wl_surface::WlSurface>,
|
||||||
pending_offers: Vec<wl_data_offer::WlDataOffer>,
|
pending_offers: Vec<wl_data_offer::WlDataOffer>,
|
||||||
|
@ -29,7 +29,7 @@ pub(crate) struct DnDGrab {
|
||||||
|
|
||||||
impl DnDGrab {
|
impl DnDGrab {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
source: Option<wl_data_source::WlDataSource>,
|
source: Option<wl_data_source::WlDataSource>,
|
||||||
origin: wl_surface::WlSurface,
|
origin: wl_surface::WlSurface,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
|
@ -222,7 +222,7 @@ impl PointerGrab for DnDGrab {
|
||||||
handle.axis(details);
|
handle.axis(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_data(&self) -> &GrabStartData {
|
fn start_data(&self) -> &PointerGrabStartData {
|
||||||
&self.start_data
|
&self.start_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ use slog::{debug, error, o};
|
||||||
|
|
||||||
use crate::wayland::{
|
use crate::wayland::{
|
||||||
compositor,
|
compositor,
|
||||||
seat::{GrabStartData, Seat},
|
seat::{PointerGrabStartData, Seat},
|
||||||
Serial,
|
Serial,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -335,7 +335,7 @@ pub fn set_data_device_selection(seat: &Seat, mime_types: Vec<String>) {
|
||||||
pub fn start_dnd<C>(
|
pub fn start_dnd<C>(
|
||||||
seat: &Seat,
|
seat: &Seat,
|
||||||
serial: Serial,
|
serial: Serial,
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
metadata: SourceMetadata,
|
metadata: SourceMetadata,
|
||||||
callback: C,
|
callback: C,
|
||||||
) where
|
) where
|
||||||
|
|
|
@ -8,7 +8,7 @@ use wayland_server::{
|
||||||
use crate::{
|
use crate::{
|
||||||
utils::{Logical, Point},
|
utils::{Logical, Point},
|
||||||
wayland::{
|
wayland::{
|
||||||
seat::{AxisFrame, GrabStartData, PointerGrab, PointerInnerHandle, Seat},
|
seat::{AxisFrame, PointerGrab, PointerGrabStartData, PointerInnerHandle, Seat},
|
||||||
Serial,
|
Serial,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@ pub enum ServerDndEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct ServerDnDGrab<C: 'static> {
|
pub(crate) struct ServerDnDGrab<C: 'static> {
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
metadata: super::SourceMetadata,
|
metadata: super::SourceMetadata,
|
||||||
current_focus: Option<wl_surface::WlSurface>,
|
current_focus: Option<wl_surface::WlSurface>,
|
||||||
pending_offers: Vec<wl_data_offer::WlDataOffer>,
|
pending_offers: Vec<wl_data_offer::WlDataOffer>,
|
||||||
|
@ -53,7 +53,7 @@ pub(crate) struct ServerDnDGrab<C: 'static> {
|
||||||
|
|
||||||
impl<C: 'static> ServerDnDGrab<C> {
|
impl<C: 'static> ServerDnDGrab<C> {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
start_data: GrabStartData,
|
start_data: PointerGrabStartData,
|
||||||
metadata: super::SourceMetadata,
|
metadata: super::SourceMetadata,
|
||||||
seat: Seat,
|
seat: Seat,
|
||||||
callback: Rc<RefCell<C>>,
|
callback: Rc<RefCell<C>>,
|
||||||
|
@ -222,7 +222,7 @@ where
|
||||||
handle.axis(details);
|
handle.axis(details);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_data(&self) -> &GrabStartData {
|
fn start_data(&self) -> &PointerGrabStartData {
|
||||||
&self.start_data
|
&self.start_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,9 +86,16 @@ pub struct XkbConfig<'a> {
|
||||||
pub options: Option<String>,
|
pub options: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum GrabStatus {
|
||||||
|
None,
|
||||||
|
Active(Serial, Box<dyn KeyboardGrab>),
|
||||||
|
Borrowed,
|
||||||
|
}
|
||||||
|
|
||||||
struct KbdInternal {
|
struct KbdInternal {
|
||||||
known_kbds: Vec<WlKeyboard>,
|
known_kbds: Vec<WlKeyboard>,
|
||||||
focus: Option<WlSurface>,
|
focus: Option<WlSurface>,
|
||||||
|
pending_focus: Option<WlSurface>,
|
||||||
pressed_keys: Vec<u32>,
|
pressed_keys: Vec<u32>,
|
||||||
mods_state: ModifiersState,
|
mods_state: ModifiersState,
|
||||||
keymap: xkb::Keymap,
|
keymap: xkb::Keymap,
|
||||||
|
@ -96,6 +103,7 @@ struct KbdInternal {
|
||||||
repeat_rate: i32,
|
repeat_rate: i32,
|
||||||
repeat_delay: i32,
|
repeat_delay: i32,
|
||||||
focus_hook: Box<dyn FnMut(Option<&WlSurface>)>,
|
focus_hook: Box<dyn FnMut(Option<&WlSurface>)>,
|
||||||
|
grab: GrabStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
// focus_hook does not implement debug, so we have to impl Debug manually
|
// focus_hook does not implement debug, so we have to impl Debug manually
|
||||||
|
@ -147,6 +155,7 @@ impl KbdInternal {
|
||||||
Ok(KbdInternal {
|
Ok(KbdInternal {
|
||||||
known_kbds: Vec::new(),
|
known_kbds: Vec::new(),
|
||||||
focus: None,
|
focus: None,
|
||||||
|
pending_focus: None,
|
||||||
pressed_keys: Vec::new(),
|
pressed_keys: Vec::new(),
|
||||||
mods_state: ModifiersState::default(),
|
mods_state: ModifiersState::default(),
|
||||||
keymap,
|
keymap,
|
||||||
|
@ -154,6 +163,7 @@ impl KbdInternal {
|
||||||
repeat_rate,
|
repeat_rate,
|
||||||
repeat_delay,
|
repeat_delay,
|
||||||
focus_hook,
|
focus_hook,
|
||||||
|
grab: GrabStatus::None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,6 +225,35 @@ impl KbdInternal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_grab<F>(&mut self, f: F, logger: ::slog::Logger)
|
||||||
|
where
|
||||||
|
F: FnOnce(KeyboardInnerHandle<'_>, &mut dyn KeyboardGrab),
|
||||||
|
{
|
||||||
|
let mut grab = ::std::mem::replace(&mut self.grab, GrabStatus::Borrowed);
|
||||||
|
match grab {
|
||||||
|
GrabStatus::Borrowed => panic!("Accessed a keyboard grab from within a keyboard grab access."),
|
||||||
|
GrabStatus::Active(_, ref mut handler) => {
|
||||||
|
// If this grab is associated with a surface that is no longer alive, discard it
|
||||||
|
if let Some(ref surface) = handler.start_data().focus {
|
||||||
|
if !surface.as_ref().is_alive() {
|
||||||
|
self.grab = GrabStatus::None;
|
||||||
|
f(KeyboardInnerHandle { inner: self, logger }, &mut DefaultGrab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
f(KeyboardInnerHandle { inner: self, logger }, &mut **handler);
|
||||||
|
}
|
||||||
|
GrabStatus::None => {
|
||||||
|
f(KeyboardInnerHandle { inner: self, logger }, &mut DefaultGrab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let GrabStatus::Borrowed = self.grab {
|
||||||
|
// the grab has not been ended nor replaced, put it back in place
|
||||||
|
self.grab = grab;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors that can be encountered when creating a keyboard handler
|
/// Errors that can be encountered when creating a keyboard handler
|
||||||
|
@ -320,6 +359,47 @@ pub enum FilterResult<T> {
|
||||||
Intercept(T),
|
Intercept(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Data about the event that started the grab.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct GrabStartData {
|
||||||
|
/// The focused surface, if any, at the start of the grab.
|
||||||
|
pub focus: Option<WlSurface>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A trait to implement a keyboard grab
|
||||||
|
///
|
||||||
|
/// In some context, it is necessary to temporarily change the behavior of the keyboard. This is
|
||||||
|
/// typically known as a keyboard grab. A example would be, during a popup grab the keyboard focus
|
||||||
|
/// will not be changed and stay on the grabbed popup.
|
||||||
|
///
|
||||||
|
/// This trait is the interface to intercept regular keyboard events and change them as needed, its
|
||||||
|
/// interface mimics the [`KeyboardHandle`] interface.
|
||||||
|
///
|
||||||
|
/// If your logic decides that the grab should end, both [`KeyboardInnerHandle`] and [`KeyboardHandle`] have
|
||||||
|
/// a method to change it.
|
||||||
|
///
|
||||||
|
/// When your grab ends (either as you requested it or if it was forcefully cancelled by the server),
|
||||||
|
/// the struct implementing this trait will be dropped. As such you should put clean-up logic in the destructor,
|
||||||
|
/// rather than trying to guess when the grab will end.
|
||||||
|
pub trait KeyboardGrab {
|
||||||
|
/// An input was reported
|
||||||
|
fn input(
|
||||||
|
&mut self,
|
||||||
|
handle: &mut KeyboardInnerHandle<'_>,
|
||||||
|
keycode: u32,
|
||||||
|
key_state: WlKeyState,
|
||||||
|
modifiers: Option<(u32, u32, u32, u32)>,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// A focus change was requested
|
||||||
|
fn set_focus(&mut self, handle: &mut KeyboardInnerHandle<'_>, focus: Option<&WlSurface>, serial: Serial);
|
||||||
|
|
||||||
|
/// The data about the event that started the grab.
|
||||||
|
fn start_data(&self) -> &GrabStartData;
|
||||||
|
}
|
||||||
|
|
||||||
/// An handle to a keyboard handler
|
/// An handle to a keyboard handler
|
||||||
///
|
///
|
||||||
/// It can be cloned and all clones manipulate the same internal state.
|
/// It can be cloned and all clones manipulate the same internal state.
|
||||||
|
@ -337,6 +417,42 @@ pub struct KeyboardHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl KeyboardHandle {
|
impl KeyboardHandle {
|
||||||
|
/// Change the current grab on this keyboard to the provided grab
|
||||||
|
///
|
||||||
|
/// Overwrites any current grab.
|
||||||
|
pub fn set_grab<G: KeyboardGrab + 'static>(&self, grab: G, serial: Serial) {
|
||||||
|
self.arc.internal.borrow_mut().grab = GrabStatus::Active(serial, Box::new(grab));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove any current grab on this keyboard, resetting it to the default behavior
|
||||||
|
pub fn unset_grab(&self) {
|
||||||
|
self.arc.internal.borrow_mut().grab = GrabStatus::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this keyboard is currently grabbed with this serial
|
||||||
|
pub fn has_grab(&self, serial: Serial) -> bool {
|
||||||
|
let guard = self.arc.internal.borrow_mut();
|
||||||
|
match guard.grab {
|
||||||
|
GrabStatus::Active(s, _) => s == serial,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Check if this keyboard is currently being grabbed
|
||||||
|
pub fn is_grabbed(&self) -> bool {
|
||||||
|
let guard = self.arc.internal.borrow_mut();
|
||||||
|
!matches!(guard.grab, GrabStatus::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the start data for the grab, if any.
|
||||||
|
pub fn grab_start_data(&self) -> Option<GrabStartData> {
|
||||||
|
let guard = self.arc.internal.borrow();
|
||||||
|
match &guard.grab {
|
||||||
|
GrabStatus::Active(_, g) => Some(g.start_data().clone()),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Handle a keystroke
|
/// Handle a keystroke
|
||||||
///
|
///
|
||||||
/// All keystrokes from the input backend should be fed _in order_ to this method of the
|
/// All keystrokes from the input backend should be fed _in order_ to this method of the
|
||||||
|
@ -392,14 +508,12 @@ impl KeyboardHandle {
|
||||||
KeyState::Pressed => WlKeyState::Pressed,
|
KeyState::Pressed => WlKeyState::Pressed,
|
||||||
KeyState::Released => WlKeyState::Released,
|
KeyState::Released => WlKeyState::Released,
|
||||||
};
|
};
|
||||||
guard.with_focused_kbds(|kbd, _| {
|
guard.with_grab(
|
||||||
// key event must be sent before modifers event for libxkbcommon
|
move |mut handle, grab| {
|
||||||
// to process them correctly
|
grab.input(&mut handle, keycode, wl_state, modifiers, serial, time);
|
||||||
kbd.key(serial.into(), time, keycode, wl_state);
|
},
|
||||||
if let Some((dep, la, lo, gr)) = modifiers {
|
self.arc.logger.clone(),
|
||||||
kbd.modifiers(serial.into(), dep, la, lo, gr);
|
);
|
||||||
}
|
|
||||||
});
|
|
||||||
if guard.focus.is_some() {
|
if guard.focus.is_some() {
|
||||||
trace!(self.arc.logger, "Input forwarded to client");
|
trace!(self.arc.logger, "Input forwarded to client");
|
||||||
} else {
|
} else {
|
||||||
|
@ -417,44 +531,13 @@ impl KeyboardHandle {
|
||||||
/// a [`wl_keyboard::Event::Enter`](wayland_server::protocol::wl_keyboard::Event::Enter) event will be sent.
|
/// a [`wl_keyboard::Event::Enter`](wayland_server::protocol::wl_keyboard::Event::Enter) event will be sent.
|
||||||
pub fn set_focus(&self, focus: Option<&WlSurface>, serial: Serial) {
|
pub fn set_focus(&self, focus: Option<&WlSurface>, serial: Serial) {
|
||||||
let mut guard = self.arc.internal.borrow_mut();
|
let mut guard = self.arc.internal.borrow_mut();
|
||||||
|
guard.pending_focus = focus.cloned();
|
||||||
let same = guard
|
guard.with_grab(
|
||||||
.focus
|
move |mut handle, grab| {
|
||||||
.as_ref()
|
grab.set_focus(&mut handle, focus, serial);
|
||||||
.and_then(|f| focus.map(|s| s.as_ref().equals(f.as_ref())))
|
},
|
||||||
.unwrap_or(false);
|
self.arc.logger.clone(),
|
||||||
|
);
|
||||||
if !same {
|
|
||||||
// unset old focus
|
|
||||||
guard.with_focused_kbds(|kbd, s| {
|
|
||||||
kbd.leave(serial.into(), s);
|
|
||||||
});
|
|
||||||
|
|
||||||
// set new focus
|
|
||||||
guard.focus = focus.cloned();
|
|
||||||
let (dep, la, lo, gr) = guard.serialize_modifiers();
|
|
||||||
let keys = guard.serialize_pressed_keys();
|
|
||||||
guard.with_focused_kbds(|kbd, surface| {
|
|
||||||
kbd.enter(serial.into(), surface, keys.clone());
|
|
||||||
// Modifiers must be send after enter event.
|
|
||||||
kbd.modifiers(serial.into(), dep, la, lo, gr);
|
|
||||||
});
|
|
||||||
{
|
|
||||||
let KbdInternal {
|
|
||||||
ref focus,
|
|
||||||
ref mut focus_hook,
|
|
||||||
..
|
|
||||||
} = *guard;
|
|
||||||
focus_hook(focus.as_ref());
|
|
||||||
}
|
|
||||||
if guard.focus.is_some() {
|
|
||||||
trace!(self.arc.logger, "Focus set to new surface");
|
|
||||||
} else {
|
|
||||||
trace!(self.arc.logger, "Focus unset");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
trace!(self.arc.logger, "Focus unchanged");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if given client currently has keyboard focus
|
/// Check if given client currently has keyboard focus
|
||||||
|
@ -543,3 +626,129 @@ pub(crate) fn implement_keyboard(keyboard: Main<WlKeyboard>, handle: Option<&Key
|
||||||
|
|
||||||
keyboard.deref().clone()
|
keyboard.deref().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// This inner handle is accessed from inside a keyboard grab logic, and directly
|
||||||
|
/// sends event to the client
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct KeyboardInnerHandle<'a> {
|
||||||
|
inner: &'a mut KbdInternal,
|
||||||
|
logger: ::slog::Logger,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> KeyboardInnerHandle<'a> {
|
||||||
|
/// Change the current grab on this keyboard to the provided grab
|
||||||
|
///
|
||||||
|
/// Overwrites any current grab.
|
||||||
|
pub fn set_grab<G: KeyboardGrab + 'static>(&mut self, serial: Serial, grab: G) {
|
||||||
|
self.inner.grab = GrabStatus::Active(serial, Box::new(grab));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove any current grab on this keyboard, resetting it to the default behavior
|
||||||
|
///
|
||||||
|
/// This will also restore the focus of the underlying keyboard if restore_focus
|
||||||
|
/// is [`true`]
|
||||||
|
pub fn unset_grab(&mut self, serial: Serial, restore_focus: bool) {
|
||||||
|
self.inner.grab = GrabStatus::None;
|
||||||
|
// restore the focus
|
||||||
|
if restore_focus {
|
||||||
|
let focus = self.inner.pending_focus.clone();
|
||||||
|
self.set_focus(focus.as_ref(), serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Access the current focus of this keyboard
|
||||||
|
pub fn current_focus(&self) -> Option<&WlSurface> {
|
||||||
|
self.inner.focus.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send the input to the focused keyboards
|
||||||
|
pub fn input(
|
||||||
|
&mut self,
|
||||||
|
keycode: u32,
|
||||||
|
key_state: WlKeyState,
|
||||||
|
modifiers: Option<(u32, u32, u32, u32)>,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
self.inner.with_focused_kbds(|kbd, _| {
|
||||||
|
// key event must be sent before modifers event for libxkbcommon
|
||||||
|
// to process them correctly
|
||||||
|
kbd.key(serial.into(), time, keycode, key_state);
|
||||||
|
if let Some((dep, la, lo, gr)) = modifiers {
|
||||||
|
kbd.modifiers(serial.into(), dep, la, lo, gr);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the current focus of this keyboard
|
||||||
|
///
|
||||||
|
/// If the new focus is different from the previous one, any previous focus
|
||||||
|
/// will be sent a [`wl_keyboard::Event::Leave`](wayland_server::protocol::wl_keyboard::Event::Leave)
|
||||||
|
/// event, and if the new focus is not `None`,
|
||||||
|
/// a [`wl_keyboard::Event::Enter`](wayland_server::protocol::wl_keyboard::Event::Enter) event will be sent.
|
||||||
|
pub fn set_focus(&mut self, focus: Option<&WlSurface>, serial: Serial) {
|
||||||
|
let same = self
|
||||||
|
.inner
|
||||||
|
.focus
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|f| focus.map(|s| s.as_ref().equals(f.as_ref())))
|
||||||
|
.unwrap_or(false);
|
||||||
|
|
||||||
|
if !same {
|
||||||
|
// unset old focus
|
||||||
|
self.inner.with_focused_kbds(|kbd, s| {
|
||||||
|
kbd.leave(serial.into(), s);
|
||||||
|
});
|
||||||
|
|
||||||
|
// set new focus
|
||||||
|
self.inner.focus = focus.cloned();
|
||||||
|
let (dep, la, lo, gr) = self.inner.serialize_modifiers();
|
||||||
|
let keys = self.inner.serialize_pressed_keys();
|
||||||
|
self.inner.with_focused_kbds(|kbd, surface| {
|
||||||
|
kbd.enter(serial.into(), surface, keys.clone());
|
||||||
|
// Modifiers must be send after enter event.
|
||||||
|
kbd.modifiers(serial.into(), dep, la, lo, gr);
|
||||||
|
});
|
||||||
|
{
|
||||||
|
let KbdInternal {
|
||||||
|
ref focus,
|
||||||
|
ref mut focus_hook,
|
||||||
|
..
|
||||||
|
} = *self.inner;
|
||||||
|
focus_hook(focus.as_ref());
|
||||||
|
}
|
||||||
|
if self.inner.focus.is_some() {
|
||||||
|
trace!(self.logger, "Focus set to new surface");
|
||||||
|
} else {
|
||||||
|
trace!(self.logger, "Focus unset");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
trace!(self.logger, "Focus unchanged");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The default grab, the behavior when no particular grab is in progress
|
||||||
|
struct DefaultGrab;
|
||||||
|
|
||||||
|
impl KeyboardGrab for DefaultGrab {
|
||||||
|
fn input(
|
||||||
|
&mut self,
|
||||||
|
handle: &mut KeyboardInnerHandle<'_>,
|
||||||
|
keycode: u32,
|
||||||
|
key_state: WlKeyState,
|
||||||
|
modifiers: Option<(u32, u32, u32, u32)>,
|
||||||
|
serial: Serial,
|
||||||
|
time: u32,
|
||||||
|
) {
|
||||||
|
handle.input(keycode, key_state, modifiers, serial, time)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_focus(&mut self, handle: &mut KeyboardInnerHandle<'_>, focus: Option<&WlSurface>, serial: Serial) {
|
||||||
|
handle.set_focus(focus, serial)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_data(&self) -> &GrabStartData {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -41,12 +41,12 @@ mod pointer;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
keyboard::{
|
keyboard::{
|
||||||
keysyms, Error as KeyboardError, FilterResult, KeyboardHandle, Keysym, KeysymHandle, ModifiersState,
|
keysyms, Error as KeyboardError, FilterResult, GrabStartData as KeyboardGrabStartData, KeyboardGrab,
|
||||||
XkbConfig,
|
KeyboardHandle, KeyboardInnerHandle, Keysym, KeysymHandle, ModifiersState, XkbConfig,
|
||||||
},
|
},
|
||||||
pointer::{
|
pointer::{
|
||||||
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData, PointerGrab, PointerHandle,
|
AxisFrame, CursorImageAttributes, CursorImageStatus, GrabStartData as PointerGrabStartData,
|
||||||
PointerInnerHandle,
|
PointerGrab, PointerHandle, PointerInnerHandle,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue