aboutsummaryrefslogtreecommitdiff
path: root/src/input.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/input.rs')
-rw-r--r--src/input.rs100
1 files changed, 80 insertions, 20 deletions
diff --git a/src/input.rs b/src/input.rs
index 063d321c..a86045bd 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -1,3 +1,4 @@
+use std::any::Any;
use std::collections::HashSet;
use smithay::backend::input::{
@@ -14,7 +15,8 @@ use smithay::input::pointer::{
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, RelativeMotionEvent,
};
-use smithay::utils::SERIAL_COUNTER;
+use smithay::reexports::input;
+use smithay::utils::{Logical, Point, SERIAL_COUNTER};
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
use crate::config::{Action, Binds, LayoutAction, Modifiers};
@@ -28,8 +30,16 @@ pub enum CompositorMod {
Alt,
}
+#[derive(Debug, Clone, Copy, PartialEq)]
+pub struct TabletData {
+ pub aspect_ratio: f64,
+}
+
impl State {
- pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>) {
+ pub fn process_input_event<I: InputBackend>(&mut self, event: InputEvent<I>)
+ where
+ I::Device: 'static, // Needed for downcasting.
+ {
let _span = tracy_client::span!("process_input_event");
// A bit of a hack, but animation end runs some logic (i.e. workspace clean-up) and it
@@ -582,14 +592,10 @@ impl State {
pointer.frame(self);
}
InputEvent::TabletToolAxis { event, .. } => {
- let Some(output) = self.niri.output_for_tablet() else {
+ let Some(pos) = self.compute_tablet_position(&event) else {
return;
};
- let output_geo = self.niri.global_space.output_geometry(output).unwrap();
-
- let pos = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
-
let serial = SERIAL_COUNTER.next_serial();
let pointer = self.niri.seat.get_pointer().unwrap();
@@ -671,14 +677,10 @@ impl State {
}
}
InputEvent::TabletToolProximity { event, .. } => {
- let Some(output) = self.niri.output_for_tablet() else {
+ let Some(pos) = self.compute_tablet_position(&event) else {
return;
};
- let output_geo = self.niri.global_space.output_geometry(output).unwrap();
-
- let pos = event.position_transformed(output_geo.size) + output_geo.loc.to_f64();
-
let serial = SERIAL_COUNTER.next_serial();
let pointer = self.niri.seat.get_pointer().unwrap();
@@ -927,17 +929,75 @@ impl State {
}
pub fn process_libinput_event(&mut self, event: &mut InputEvent<LibinputInputBackend>) {
- if let InputEvent::DeviceAdded { device } = event {
- // According to Mutter code, this setting is specific to touchpads.
- let is_touchpad = device.config_tap_finger_count() > 0;
- if is_touchpad {
- let c = &self.niri.config.borrow().input.touchpad;
- let _ = device.config_tap_set_enabled(c.tap);
- let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
- let _ = device.config_accel_set_speed(c.accel_speed);
+ match event {
+ InputEvent::DeviceAdded { device } => {
+ // According to Mutter code, this setting is specific to touchpads.
+ let is_touchpad = device.config_tap_finger_count() > 0;
+ if is_touchpad {
+ let c = &self.niri.config.borrow().input.touchpad;
+ let _ = device.config_tap_set_enabled(c.tap);
+ let _ = device.config_scroll_set_natural_scroll_enabled(c.natural_scroll);
+ let _ = device.config_accel_set_speed(c.accel_speed);
+ }
+
+ if device.has_capability(smithay::reexports::input::DeviceCapability::TabletTool) {
+ match device.size() {
+ Some((w, h)) => {
+ self.niri.tablets.insert(
+ device.clone(),
+ TabletData {
+ aspect_ratio: w / h,
+ },
+ );
+ }
+ None => {
+ warn!("tablet tool device has no size");
+ }
+ }
+ }
+ }
+ InputEvent::DeviceRemoved { device } => {
+ self.niri.tablets.remove(device);
}
+ _ => (),
}
}
+
+ fn compute_tablet_position<I: InputBackend>(
+ &mut self,
+ event: &(impl Event<I> + TabletToolEvent<I>),
+ ) -> Option<Point<f64, Logical>>
+ where
+ I::Device: 'static,
+ {
+ let output = self.niri.output_for_tablet()?;
+ let output_geo = self.niri.global_space.output_geometry(output).unwrap();
+
+ let mut pos = event.position_transformed(output_geo.size);
+ pos.x /= output_geo.size.w as f64;
+ pos.y /= output_geo.size.h as f64;
+
+ let device = event.device();
+ if let Some(device) = (&device as &dyn Any).downcast_ref::<input::Device>() {
+ if let Some(data) = self.niri.tablets.get(device) {
+ // This code does the same thing as mutter with "keep aspect ratio" enabled.
+ let output_aspect_ratio = output_geo.size.w as f64 / output_geo.size.h as f64;
+ let ratio = data.aspect_ratio / output_aspect_ratio;
+
+ if ratio > 1. {
+ pos.x *= ratio;
+ } else {
+ pos.y /= ratio;
+ }
+ }
+ };
+
+ pos.x *= output_geo.size.w as f64;
+ pos.y *= output_geo.size.h as f64;
+ pos.x = pos.x.clamp(0.0, output_geo.size.w as f64 - 1.);
+ pos.y = pos.y.clamp(0.0, output_geo.size.h as f64 - 1.);
+ Some(pos + output_geo.loc.to_f64())
+ }
}
/// Check whether the key should be intercepted and mark intercepted