pinnacle/src/input.rs

615 lines
22 KiB
Rust
Raw Normal View History

2023-08-01 18:06:35 +02:00
// SPDX-License-Identifier: GPL-3.0-or-later
2023-06-26 00:18:50 +02:00
2023-12-14 03:33:16 +01:00
pub mod libinput;
use std::{collections::HashMap, mem::Discriminant};
2023-07-25 01:59:05 +02:00
use crate::{
api::msg::{CallbackId, Modifier, MouseEdge, OutgoingMsg},
focus::FocusTarget,
2023-10-02 21:06:39 +02:00
state::WithState,
2023-07-25 01:59:05 +02:00
window::WindowElement,
};
use pinnacle_api_defs::pinnacle::input::{
libinput::v0alpha1::set_libinput_setting_request::Setting,
v0alpha1::{SetKeybindResponse, SetMousebindResponse},
};
use smithay::{
2023-12-14 03:33:16 +01:00
backend::input::{
AbsolutePositionEvent, Axis, AxisSource, ButtonState, Event, InputBackend, InputEvent,
KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent, PointerMotionEvent,
2023-08-08 17:55:06 +02:00
},
2023-08-06 03:49:39 +02:00
desktop::{layer_map_for_output, space::SpaceElement},
input::{
keyboard::{keysyms, FilterResult},
2023-09-15 09:50:42 +02:00
pointer::{AxisFrame, ButtonEvent, MotionEvent, RelativeMotionEvent},
},
2023-12-14 03:33:16 +01:00
reexports::input::{self, Led},
2023-06-10 03:29:17 +02:00
utils::{Logical, Point, SERIAL_COUNTER},
2023-09-10 11:49:31 +02:00
wayland::{seat::WaylandFocus, shell::wlr_layer},
};
use tokio::sync::mpsc::UnboundedSender;
2023-10-13 00:10:23 +02:00
use xkbcommon::xkb::Keysym;
2023-08-29 05:53:24 +02:00
use crate::state::State;
2023-12-14 03:33:16 +01:00
use self::libinput::LibinputSetting;
bitflags::bitflags! {
#[derive(Debug, Hash, Copy, Clone, PartialEq, Eq)]
pub struct ModifierMask: u8 {
const SHIFT = 1;
const CTRL = 1 << 1;
const ALT = 1 << 2;
const SUPER = 1 << 3;
}
}
#[derive(Default)]
pub struct InputState {
2023-06-18 04:02:58 +02:00
/// A hashmap of modifier keys and keycodes to callback IDs
pub keybinds: HashMap<(crate::api::msg::ModifierMask, Keysym), CallbackId>,
2023-06-18 04:02:58 +02:00
/// A hashmap of modifier keys and mouse button codes to callback IDs
pub mousebinds: HashMap<(crate::api::msg::ModifierMask, u32, MouseEdge), CallbackId>,
pub reload_keybind: Option<(crate::api::msg::ModifierMask, Keysym)>,
pub kill_keybind: Option<(crate::api::msg::ModifierMask, Keysym)>,
2023-12-17 04:20:29 +01:00
/// User defined libinput settings that will be applied
2023-09-29 01:46:08 +02:00
pub libinput_settings: Vec<LibinputSetting>,
2023-12-17 04:20:29 +01:00
/// All libinput devices that have been connected
2023-09-29 01:46:08 +02:00
pub libinput_devices: Vec<input::Device>,
pub grpc_keybinds:
HashMap<(ModifierMask, Keysym), UnboundedSender<Result<SetKeybindResponse, tonic::Status>>>,
pub grpc_mousebinds:
HashMap<(ModifierMask, u32), UnboundedSender<Result<SetMousebindResponse, tonic::Status>>>,
pub grpc_libinput_settings:
HashMap<Discriminant<Setting>, Box<dyn Fn(&mut input::Device) + Send>>,
}
impl std::fmt::Debug for InputState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InputState")
.field("keybinds", &self.keybinds)
.field("mousebinds", &self.mousebinds)
.field("reload_keybind", &self.reload_keybind)
.field("kill_keybind", &self.kill_keybind)
.field("libinput_settings", &self.libinput_settings)
.field("libinput_devices", &self.libinput_devices)
.field("grpc_keybinds", &self.grpc_keybinds)
.field("grpc_libinput_settings", &"...")
.finish()
}
2023-06-18 04:02:58 +02:00
}
impl InputState {
pub fn new() -> Self {
Default::default()
2023-06-18 04:02:58 +02:00
}
}
#[derive(Debug)]
enum KeyAction {
2023-12-17 04:20:29 +01:00
/// Call a callback from a config process
CallCallback(CallbackId),
CallGrpcCallback(UnboundedSender<Result<SetKeybindResponse, tonic::Status>>),
Quit,
SwitchVt(i32),
2023-08-16 00:26:17 +02:00
ReloadConfig,
}
2023-08-29 05:53:24 +02:00
impl State {
pub fn process_input_event<B: InputBackend>(&mut self, event: InputEvent<B>) {
match event {
// TODO: rest of input events
// InputEvent::DeviceAdded { device } => todo!(),
// InputEvent::DeviceRemoved { device } => todo!(),
InputEvent::Keyboard { event } => self.keyboard::<B>(event),
InputEvent::PointerMotion { event } => self.pointer_motion::<B>(event),
InputEvent::PointerMotionAbsolute { event } => self.pointer_motion_absolute::<B>(event),
InputEvent::PointerButton { event } => self.pointer_button::<B>(event),
InputEvent::PointerAxis { event } => self.pointer_axis::<B>(event),
_ => (),
}
}
2023-09-02 23:51:39 +02:00
/// Get the [`FocusTarget`] under `point`.
pub fn focus_target_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)>
where
P: Into<Point<f64, Logical>>,
{
2023-08-06 03:49:39 +02:00
let point: Point<f64, Logical> = point.into();
let output = self.space.outputs().find(|op| {
self.space
.output_geometry(op)
.expect("called output_geometry on unmapped output (this shouldn't happen here)")
.contains(point.to_i32_round())
})?;
let output_geo = self
.space
.output_geometry(output)
.expect("called output_geometry on unmapped output");
let layers = layer_map_for_output(output);
let top_fullscreen_window = self.focus_state.focus_stack.iter().rev().find(|win| {
win.with_state(|state| {
state.fullscreen_or_maximized.is_fullscreen()
&& output.with_state(|op_state| {
op_state
.focused_tags()
.any(|op_tag| state.tags.contains(op_tag))
})
})
});
2023-12-17 04:20:29 +01:00
if let Some(window) = top_fullscreen_window {
Some((FocusTarget::from(window.clone()), output_geo.loc))
} else if let (Some(layer), _) | (None, Some(layer)) = (
layers.layer_under(wlr_layer::Layer::Overlay, point),
layers.layer_under(wlr_layer::Layer::Top, point),
) {
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc))
} else if let Some(ret) = self
.space
.elements()
.rev()
.filter(|win| win.is_on_active_tag(self.space.outputs()))
.find_map(|win| {
let loc = self
.space
.element_location(win)
.expect("called elem loc on unmapped win")
- win.geometry().loc;
win.is_in_input_region(&(point - loc.to_f64()))
.then(|| (win.clone().into(), loc))
2023-08-06 03:49:39 +02:00
})
2023-12-17 04:20:29 +01:00
{
Some(ret)
} else if let (Some(layer), _) | (None, Some(layer)) = (
layers.layer_under(wlr_layer::Layer::Overlay, point),
layers.layer_under(wlr_layer::Layer::Top, point),
) {
let layer_loc = layers.layer_geometry(layer).expect("no layer geo").loc;
Some((FocusTarget::from(layer.clone()), output_geo.loc + layer_loc))
} else {
None
}
}
2023-08-08 17:55:06 +02:00
fn keyboard<I: InputBackend>(&mut self, event: I::KeyboardKeyEvent) {
let serial = SERIAL_COUNTER.next_serial();
let time = event.time_msec();
let press_state = event.state();
2023-08-16 00:26:17 +02:00
let reload_keybind = self.input_state.reload_keybind;
let kill_keybind = self.input_state.kill_keybind;
2023-09-29 02:10:36 +02:00
let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard");
2023-08-16 00:26:17 +02:00
2023-09-29 02:10:36 +02:00
let modifiers = keyboard.modifier_state();
2023-09-10 03:41:21 +02:00
2023-09-29 02:10:36 +02:00
let mut leds = Led::empty();
if modifiers.num_lock {
leds |= Led::NUMLOCK;
}
if modifiers.caps_lock {
leds |= Led::CAPSLOCK;
}
2023-09-10 03:41:21 +02:00
2023-09-29 02:10:36 +02:00
// FIXME: Leds only update once another key is pressed.
for device in self.input_state.libinput_devices.iter_mut() {
device.led_update(leds);
}
2023-09-10 03:41:21 +02:00
2023-09-29 02:10:36 +02:00
let action = keyboard.input(
self,
event.key_code(),
press_state,
serial,
time,
|state, modifiers, keysym| {
// tracing::debug!(keysym = ?keysym, raw_keysyms = ?keysym.raw_syms(), modified_syms = ?keysym.modified_syms());
2023-09-29 02:10:36 +02:00
if press_state == KeyState::Pressed {
let mut modifier_mask = Vec::<Modifier>::new();
if modifiers.alt {
modifier_mask.push(Modifier::Alt);
}
if modifiers.shift {
modifier_mask.push(Modifier::Shift);
}
if modifiers.ctrl {
modifier_mask.push(Modifier::Ctrl);
}
if modifiers.logo {
modifier_mask.push(Modifier::Super);
}
let modifier_mask = crate::api::msg::ModifierMask::from(modifier_mask);
let mut grpc_modifiers = ModifierMask::empty();
if modifiers.alt {
grpc_modifiers |= ModifierMask::ALT;
}
if modifiers.shift {
grpc_modifiers |= ModifierMask::SHIFT;
}
if modifiers.ctrl {
grpc_modifiers |= ModifierMask::CTRL;
}
if modifiers.logo {
grpc_modifiers |= ModifierMask::SUPER;
}
2023-09-29 02:10:36 +02:00
let raw_sym = keysym.raw_syms().iter().next();
let mod_sym = keysym.modified_sym();
if let (Some(sender), _) | (None, Some(sender)) = (
state
.input_state
.grpc_keybinds
.get(&(grpc_modifiers, mod_sym)),
raw_sym.and_then(|raw_sym| {
state
.input_state
.grpc_keybinds
.get(&(grpc_modifiers, *raw_sym))
}),
) {
return FilterResult::Intercept(KeyAction::CallGrpcCallback(
sender.clone(),
));
}
2023-09-29 02:10:36 +02:00
let cb_id_mod = state.input_state.keybinds.get(&(modifier_mask, mod_sym));
2023-12-17 04:20:29 +01:00
let cb_id_raw = raw_sym.and_then(|raw_sym| {
2023-09-29 02:10:36 +02:00
state.input_state.keybinds.get(&(modifier_mask, *raw_sym))
2023-12-17 04:20:29 +01:00
});
2023-09-29 02:10:36 +02:00
match (cb_id_mod, cb_id_raw) {
(Some(cb_id), _) | (None, Some(cb_id)) => {
return FilterResult::Intercept(KeyAction::CallCallback(*cb_id));
2023-08-08 17:55:06 +02:00
}
2023-09-29 02:10:36 +02:00
(None, None) => (),
}
2023-08-08 17:55:06 +02:00
2023-12-17 04:20:29 +01:00
if kill_keybind == Some((modifier_mask, mod_sym)) {
2023-09-29 02:10:36 +02:00
return FilterResult::Intercept(KeyAction::Quit);
2023-12-17 04:20:29 +01:00
} else if reload_keybind == Some((modifier_mask, mod_sym)) {
2023-09-29 02:10:36 +02:00
return FilterResult::Intercept(KeyAction::ReloadConfig);
} else if let mut vt @ keysyms::KEY_XF86Switch_VT_1
2023-10-13 00:10:23 +02:00
..=keysyms::KEY_XF86Switch_VT_12 = keysym.modified_sym().raw()
2023-09-29 02:10:36 +02:00
{
vt = vt - keysyms::KEY_XF86Switch_VT_1 + 1;
tracing::info!("Switching to vt {vt}");
return FilterResult::Intercept(KeyAction::SwitchVt(vt as i32));
2023-08-08 17:55:06 +02:00
}
2023-09-29 02:10:36 +02:00
}
2023-08-08 17:55:06 +02:00
2023-09-29 02:10:36 +02:00
FilterResult::Forward
},
);
2023-08-08 17:55:06 +02:00
match action {
Some(KeyAction::CallCallback(callback_id)) => {
if let Some(stream) = self.api_state.stream.as_ref() {
if let Err(err) = crate::api::send_to_client(
&mut stream.lock().expect("Could not lock stream mutex"),
&OutgoingMsg::CallCallback {
callback_id,
args: None,
},
) {
tracing::error!("error sending msg to client: {err}");
}
}
2023-08-08 17:55:06 +02:00
}
Some(KeyAction::CallGrpcCallback(sender)) => {
let _ = sender.send(Ok(SetKeybindResponse {}));
}
Some(KeyAction::SwitchVt(vt)) => {
2023-12-17 04:20:29 +01:00
self.switch_vt(vt);
2023-08-08 17:55:06 +02:00
}
Some(KeyAction::Quit) => {
2023-12-17 04:20:29 +01:00
tracing::info!("Quitting Pinnacle");
self.loop_signal.stop();
2023-08-08 17:55:06 +02:00
}
2023-08-16 00:26:17 +02:00
Some(KeyAction::ReloadConfig) => {
self.start_config(crate::config::get_config_dir())
2023-09-22 00:12:16 +02:00
.expect("failed to restart config");
2023-08-16 00:26:17 +02:00
}
2023-12-17 04:20:29 +01:00
None => (),
2023-08-08 17:55:06 +02:00
}
}
2023-06-10 03:29:17 +02:00
fn pointer_button<I: InputBackend>(&mut self, event: I::PointerButtonEvent) {
let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err
let keyboard = self.seat.get_keyboard().expect("Seat has no keyboard"); // FIXME: handle err
2023-06-10 03:29:17 +02:00
let serial = SERIAL_COUNTER.next_serial();
let button = event.button_code();
let button_state = event.state();
let pointer_loc = pointer.current_location();
2023-12-17 04:20:29 +01:00
let mouse_edge = match button_state {
2023-09-11 04:54:58 +02:00
ButtonState::Released => MouseEdge::Release,
ButtonState::Pressed => MouseEdge::Press,
};
let modifier_mask = crate::api::msg::ModifierMask::from(keyboard.modifier_state());
2023-09-11 04:54:58 +02:00
// If any mousebinds are detected, call the config's callback and return.
2023-12-17 04:20:29 +01:00
if let Some(&callback_id) =
self.input_state
.mousebinds
.get(&(modifier_mask, button, mouse_edge))
2023-09-11 04:54:58 +02:00
{
if let Some(stream) = self.api_state.stream.as_ref() {
crate::api::send_to_client(
&mut stream.lock().expect("failed to lock api stream"),
2023-09-11 04:54:58 +02:00
&OutgoingMsg::CallCallback {
callback_id,
args: None,
},
)
.expect("failed to call callback");
}
return;
}
2023-06-10 03:29:17 +02:00
// If the button was clicked, focus on the window below if exists, else
// unfocus on windows.
2023-12-17 04:20:29 +01:00
if button_state == ButtonState::Pressed {
if let Some((focus, _)) = self.focus_target_under(pointer_loc) {
2023-09-11 04:54:58 +02:00
// Move window to top of stack.
if let FocusTarget::Window(window) = &focus {
self.space.raise_element(window, true);
if let WindowElement::X11(surface) = &window {
2023-12-17 04:20:29 +01:00
self.xwm
.as_mut()
.expect("no xwm")
.raise_window(surface)
.expect("failed to raise x11 win");
surface
.set_activated(true)
.expect("failed to set x11 win to activated");
}
2023-09-11 04:54:58 +02:00
}
2023-07-29 04:38:12 +02:00
2023-09-11 04:54:58 +02:00
tracing::debug!("wl_surface focus is some? {}", focus.wl_surface().is_some());
2023-09-11 04:54:58 +02:00
// NOTE: *Do not* set keyboard focus to an override redirect window. This leads
// | to wonky things like right-click menus not correctly getting pointer
// | clicks or showing up at all.
2023-09-11 04:54:58 +02:00
// TODO: use update_keyboard_focus from anvil
2023-06-18 04:02:58 +02:00
if !matches!(
&focus,
FocusTarget::Window(WindowElement::X11OverrideRedirect(_))
) {
2023-09-11 04:54:58 +02:00
keyboard.set_focus(self, Some(focus.clone()), serial);
}
2023-09-11 04:54:58 +02:00
self.space.elements().for_each(|window| {
if let WindowElement::Wayland(window) = window {
window.toplevel().send_configure();
2023-08-08 00:23:09 +02:00
}
2023-09-11 04:54:58 +02:00
});
if let FocusTarget::Window(window) = &focus {
tracing::debug!("setting keyboard focus to {:?}", window.class());
2023-06-10 03:29:17 +02:00
}
} else {
2023-07-25 01:59:05 +02:00
self.space.elements().for_each(|window| match window {
WindowElement::Wayland(window) => {
window.set_activated(false);
window.toplevel().send_configure();
}
WindowElement::X11(surface) => {
surface
.set_activated(false)
.expect("failed to deactivate x11 win");
// INFO: do i need to configure this?
}
WindowElement::X11OverrideRedirect(_) => (),
_ => unreachable!(),
2023-06-10 03:29:17 +02:00
});
keyboard.set_focus(self, None, serial);
}
2023-06-10 03:29:17 +02:00
};
2023-06-10 03:29:17 +02:00
pointer.button(
self,
&ButtonEvent {
button,
state: button_state,
serial,
time: event.time_msec(),
},
);
2023-10-13 02:15:47 +02:00
pointer.frame(self);
2023-06-10 03:29:17 +02:00
}
fn pointer_axis<I: InputBackend>(&mut self, event: I::PointerAxisEvent) {
let source = event.source();
let horizontal_amount = event
.amount(Axis::Horizontal)
.unwrap_or_else(|| event.amount_v120(Axis::Horizontal).unwrap_or(0.0) * 3.0 / 120.);
2023-12-17 04:20:29 +01:00
let vertical_amount = event
2023-06-10 03:29:17 +02:00
.amount(Axis::Vertical)
.unwrap_or_else(|| event.amount_v120(Axis::Vertical).unwrap_or(0.0) * 3.0 / 120.);
let horizontal_amount_discrete = event.amount_v120(Axis::Horizontal);
let vertical_amount_discrete = event.amount_v120(Axis::Vertical);
2023-06-10 03:29:17 +02:00
let mut frame = AxisFrame::new(event.time_msec()).source(source);
2023-06-10 03:29:17 +02:00
if horizontal_amount != 0.0 {
frame = frame.value(Axis::Horizontal, horizontal_amount);
if let Some(discrete) = horizontal_amount_discrete {
frame = frame.v120(Axis::Horizontal, discrete as i32);
2023-06-10 03:29:17 +02:00
}
} else if source == AxisSource::Finger {
frame = frame.stop(Axis::Horizontal);
}
2023-06-10 03:29:17 +02:00
if vertical_amount != 0.0 {
frame = frame.value(Axis::Vertical, vertical_amount);
if let Some(discrete) = vertical_amount_discrete {
frame = frame.v120(Axis::Vertical, discrete as i32);
2023-06-10 03:29:17 +02:00
}
} else if source == AxisSource::Finger {
frame = frame.stop(Axis::Vertical);
}
2023-10-13 02:15:47 +02:00
let pointer = self.seat.get_pointer().expect("Seat has no pointer");
pointer.axis(self, frame);
pointer.frame(self);
2023-06-10 03:29:17 +02:00
}
2023-08-08 02:48:18 +02:00
2023-12-17 04:20:29 +01:00
/// Clamp pointer coordinates inside outputs.
///
/// This returns the nearest point inside an output.
2023-08-29 05:53:24 +02:00
fn clamp_coords(&self, pos: Point<f64, Logical>) -> Point<f64, Logical> {
if self.space.outputs().next().is_none() {
return pos;
}
2023-08-08 02:48:18 +02:00
2023-08-29 05:53:24 +02:00
let (pos_x, pos_y) = pos.into();
2023-08-08 02:48:18 +02:00
2023-08-29 05:53:24 +02:00
let nearest_points = self.space.outputs().map(|op| {
let size = self
.space
.output_geometry(op)
.expect("called output_geometry on unmapped output")
.size;
let loc = op.current_location();
let pos_x = pos_x.clamp(loc.x as f64, (loc.x + size.w) as f64);
let pos_y = pos_y.clamp(loc.y as f64, (loc.y + size.h) as f64);
(pos_x, pos_y)
});
let nearest_point = nearest_points.min_by(|(x1, y1), (x2, y2)| {
f64::total_cmp(
&((pos_x - x1).powi(2) + (pos_y - y1).powi(2)).sqrt(),
&((pos_x - x2).powi(2) + (pos_y - y2).powi(2)).sqrt(),
)
});
nearest_point.map(|point| point.into()).unwrap_or(pos)
2023-08-08 02:48:18 +02:00
}
2023-06-10 03:29:17 +02:00
fn pointer_motion_absolute<I: InputBackend>(&mut self, event: I::PointerMotionAbsoluteEvent) {
let Some(output) = self.space.outputs().next() else {
return;
};
2023-12-17 04:20:29 +01:00
let output_geo = self
.space
.output_geometry(output)
.expect("Output geometry doesn't exist");
2023-06-10 03:29:17 +02:00
let pointer_loc = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
let serial = SERIAL_COUNTER.next_serial();
let pointer = self.seat.get_pointer().expect("Seat has no pointer"); // FIXME: handle err
2023-06-10 03:29:17 +02:00
self.pointer_location = pointer_loc;
2023-06-25 00:39:40 +02:00
match self.focus_state.focused_output {
Some(_) => {
if let Some(output) = self
.space
.output_under(self.pointer_location)
.next()
.cloned()
{
self.focus_state.focused_output = Some(output);
}
}
None => {
self.focus_state.focused_output = self.space.outputs().next().cloned();
}
}
2023-06-10 03:29:17 +02:00
pointer.motion(
self,
self.focus_target_under(pointer_loc),
2023-06-10 03:29:17 +02:00
&MotionEvent {
location: pointer_loc,
serial,
time: event.time_msec(),
},
);
2023-10-13 02:15:47 +02:00
pointer.frame(self);
2023-06-10 03:29:17 +02:00
}
fn pointer_motion<I: InputBackend>(&mut self, event: I::PointerMotionEvent) {
let serial = SERIAL_COUNTER.next_serial();
self.pointer_location += event.delta();
// clamp to screen limits
// this event is never generated by winit
self.pointer_location = self.clamp_coords(self.pointer_location);
2023-06-25 00:39:40 +02:00
match self.focus_state.focused_output {
Some(_) => {
if let Some(output) = self
.space
.output_under(self.pointer_location)
.next()
.cloned()
{
self.focus_state.focused_output = Some(output);
}
}
None => {
self.focus_state.focused_output = self.space.outputs().next().cloned();
}
}
2023-06-10 03:29:17 +02:00
let surface_under = self.focus_target_under(self.pointer_location);
2023-10-15 09:27:41 +02:00
if let Some(pointer) = self.seat.get_pointer() {
pointer.motion(
2023-06-10 03:29:17 +02:00
self,
2023-09-15 09:50:42 +02:00
surface_under.clone(),
2023-06-10 03:29:17 +02:00
&MotionEvent {
location: self.pointer_location,
serial,
time: event.time_msec(),
},
);
2023-10-15 09:27:41 +02:00
pointer.relative_motion(
2023-09-15 09:50:42 +02:00
self,
surface_under,
&RelativeMotionEvent {
delta: event.delta(),
delta_unaccel: event.delta_unaccel(),
utime: event.time(),
},
2023-10-13 02:15:47 +02:00
);
2023-10-15 09:27:41 +02:00
pointer.frame(self);
self.schedule_render(
&self
.focus_state
.focused_output
.clone()
.expect("no focused output"),
);
2023-06-10 03:29:17 +02:00
}
}
}