mirror of
https://github.com/niri-wm/niri.git
synced 2026-06-23 02:05:33 +07:00
input: add basic touch support
This commit is contained in:
committed by
Ivan Molodetskikh
parent
5ac350d51c
commit
719697179f
+132
-6
@@ -8,7 +8,7 @@ use smithay::backend::input::{
|
||||
GestureBeginEvent, GestureEndEvent, GesturePinchUpdateEvent as _, GestureSwipeUpdateEvent as _,
|
||||
InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent, PointerButtonEvent,
|
||||
PointerMotionEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
|
||||
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState,
|
||||
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState, TouchEvent,
|
||||
};
|
||||
use smithay::backend::libinput::LibinputInputBackend;
|
||||
use smithay::input::keyboard::{keysyms, FilterResult, Keysym, ModifiersState};
|
||||
@@ -17,6 +17,7 @@ use smithay::input::pointer::{
|
||||
GesturePinchBeginEvent, GesturePinchEndEvent, GesturePinchUpdateEvent, GestureSwipeBeginEvent,
|
||||
GestureSwipeEndEvent, GestureSwipeUpdateEvent, MotionEvent, RelativeMotionEvent,
|
||||
};
|
||||
use smithay::input::touch::{DownEvent, MotionEvent as TouchMotionEvent, UpEvent};
|
||||
use smithay::utils::{Logical, Point, SERIAL_COUNTER};
|
||||
use smithay::wayland::pointer_constraints::{with_pointer_constraint, PointerConstraint};
|
||||
use smithay::wayland::tablet_manager::{TabletDescriptor, TabletSeatTrait};
|
||||
@@ -101,11 +102,11 @@ impl State {
|
||||
GesturePinchEnd { event } => self.on_gesture_pinch_end::<I>(event),
|
||||
GestureHoldBegin { event } => self.on_gesture_hold_begin::<I>(event),
|
||||
GestureHoldEnd { event } => self.on_gesture_hold_end::<I>(event),
|
||||
TouchDown { .. } => (),
|
||||
TouchMotion { .. } => (),
|
||||
TouchUp { .. } => (),
|
||||
TouchCancel { .. } => (),
|
||||
TouchFrame { .. } => (),
|
||||
TouchDown { event } => self.on_touch_down::<I>(event),
|
||||
TouchMotion { event } => self.on_touch_motion::<I>(event),
|
||||
TouchUp { event } => self.on_touch_up::<I>(event),
|
||||
TouchCancel { event } => self.on_touch_cancel::<I>(event),
|
||||
TouchFrame { event } => self.on_touch_frame::<I>(event),
|
||||
SwitchToggle { .. } => (),
|
||||
Special(_) => (),
|
||||
}
|
||||
@@ -154,9 +155,14 @@ impl State {
|
||||
}
|
||||
}
|
||||
|
||||
if device.has_capability(input::DeviceCapability::Touch) {
|
||||
self.niri.touch.insert(device.clone());
|
||||
}
|
||||
|
||||
apply_libinput_settings(&self.niri.config.borrow().input, device);
|
||||
}
|
||||
InputEvent::DeviceRemoved { device } => {
|
||||
self.niri.touch.remove(device);
|
||||
self.niri.tablets.remove(device);
|
||||
self.niri.devices.remove(device);
|
||||
}
|
||||
@@ -171,6 +177,9 @@ impl State {
|
||||
let desc = TabletDescriptor::from(&device);
|
||||
tablet_seat.add_tablet::<Self>(&self.niri.display_handle, &desc);
|
||||
}
|
||||
if device.has_capability(DeviceCapability::Touch) && self.niri.seat.get_touch().is_none() {
|
||||
self.niri.seat.add_touch();
|
||||
}
|
||||
}
|
||||
|
||||
fn on_device_removed(&mut self, device: impl Device) {
|
||||
@@ -185,6 +194,9 @@ impl State {
|
||||
tablet_seat.clear_tools();
|
||||
}
|
||||
}
|
||||
if device.has_capability(DeviceCapability::Touch) && self.niri.touch.is_empty() {
|
||||
self.niri.seat.remove_touch();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes the cursor position for the tablet event.
|
||||
@@ -283,6 +295,10 @@ impl State {
|
||||
return;
|
||||
}
|
||||
|
||||
if let Some(touch) = self.niri.seat.get_touch() {
|
||||
touch.cancel(self);
|
||||
}
|
||||
|
||||
match action {
|
||||
Action::Quit(skip_confirmation) => {
|
||||
if !skip_confirmation {
|
||||
@@ -1354,6 +1370,116 @@ impl State {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Computes the cursor position for the touch event.
|
||||
///
|
||||
/// This function handles the touch output mapping, as well as coordinate transform
|
||||
fn compute_touch_location<I: InputBackend, E: AbsolutePositionEvent<I>>(
|
||||
&self,
|
||||
evt: &E,
|
||||
) -> Option<Point<f64, Logical>> {
|
||||
let output = self.niri.output_for_touch()?;
|
||||
let output_geo = self.niri.global_space.output_geometry(output).unwrap();
|
||||
let transform = output.current_transform();
|
||||
let size = transform.invert().transform_size(output_geo.size);
|
||||
Some(
|
||||
transform.transform_point_in(evt.position_transformed(size), &size.to_f64())
|
||||
+ output_geo.loc.to_f64(),
|
||||
)
|
||||
}
|
||||
|
||||
fn on_touch_down<I: InputBackend>(&mut self, evt: I::TouchDownEvent) {
|
||||
let Some(handle) = self.niri.seat.get_touch() else {
|
||||
return;
|
||||
};
|
||||
let Some(touch_location) = self.compute_touch_location(&evt) else {
|
||||
return;
|
||||
};
|
||||
|
||||
if !handle.is_grabbed() {
|
||||
let output_under_touch = self
|
||||
.niri
|
||||
.global_space
|
||||
.output_under(touch_location)
|
||||
.next()
|
||||
.cloned();
|
||||
if let Some(window) = self.niri.window_under(touch_location) {
|
||||
let window = window.clone();
|
||||
self.niri.layout.activate_window(&window);
|
||||
|
||||
// FIXME: granular.
|
||||
self.niri.queue_redraw_all();
|
||||
} else if let Some(output) = output_under_touch {
|
||||
self.niri.layout.activate_output(&output);
|
||||
|
||||
// FIXME: granular.
|
||||
self.niri.queue_redraw_all();
|
||||
};
|
||||
};
|
||||
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
let under = self
|
||||
.niri
|
||||
.surface_under_and_global_space(touch_location)
|
||||
.map(|under| under.surface);
|
||||
handle.down(
|
||||
self,
|
||||
under,
|
||||
&DownEvent {
|
||||
slot: evt.slot(),
|
||||
location: touch_location,
|
||||
serial,
|
||||
time: evt.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
fn on_touch_up<I: InputBackend>(&mut self, evt: I::TouchUpEvent) {
|
||||
let Some(handle) = self.niri.seat.get_touch() else {
|
||||
return;
|
||||
};
|
||||
let serial = SERIAL_COUNTER.next_serial();
|
||||
handle.up(
|
||||
self,
|
||||
&UpEvent {
|
||||
slot: evt.slot(),
|
||||
serial,
|
||||
time: evt.time_msec(),
|
||||
},
|
||||
)
|
||||
}
|
||||
fn on_touch_motion<I: InputBackend>(&mut self, evt: I::TouchMotionEvent) {
|
||||
let Some(handle) = self.niri.seat.get_touch() else {
|
||||
return;
|
||||
};
|
||||
let Some(touch_location) = self.compute_touch_location(&evt) else {
|
||||
return;
|
||||
};
|
||||
let under = self
|
||||
.niri
|
||||
.surface_under_and_global_space(touch_location)
|
||||
.map(|under| under.surface);
|
||||
handle.motion(
|
||||
self,
|
||||
under,
|
||||
&TouchMotionEvent {
|
||||
slot: evt.slot(),
|
||||
location: touch_location,
|
||||
time: evt.time_msec(),
|
||||
},
|
||||
);
|
||||
}
|
||||
fn on_touch_frame<I: InputBackend>(&mut self, _evt: I::TouchFrameEvent) {
|
||||
let Some(handle) = self.niri.seat.get_touch() else {
|
||||
return;
|
||||
};
|
||||
handle.frame(self);
|
||||
}
|
||||
fn on_touch_cancel<I: InputBackend>(&mut self, _evt: I::TouchCancelEvent) {
|
||||
let Some(handle) = self.niri.seat.get_touch() else {
|
||||
return;
|
||||
};
|
||||
handle.cancel(self);
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether the key should be intercepted and mark intercepted
|
||||
|
||||
+14
@@ -144,6 +144,7 @@ pub struct Niri {
|
||||
|
||||
pub devices: HashSet<input::Device>,
|
||||
pub tablets: HashMap<input::Device, TabletData>,
|
||||
pub touch: HashSet<input::Device>,
|
||||
|
||||
// Smithay state.
|
||||
pub compositor_state: CompositorState,
|
||||
@@ -702,6 +703,10 @@ impl State {
|
||||
self.niri.reposition_outputs(None);
|
||||
|
||||
self.backend.on_output_config_changed(&mut self.niri);
|
||||
|
||||
if let Some(touch) = self.niri.seat.get_touch() {
|
||||
touch.cancel(self);
|
||||
}
|
||||
}
|
||||
|
||||
// Can't really update xdg-decoration settings since we have to hide the globals for CSD
|
||||
@@ -1002,6 +1007,7 @@ impl Niri {
|
||||
|
||||
devices: HashSet::new(),
|
||||
tablets: HashMap::new(),
|
||||
touch: HashSet::new(),
|
||||
|
||||
compositor_state,
|
||||
xdg_shell_state,
|
||||
@@ -1602,6 +1608,14 @@ impl Niri {
|
||||
.or_else(|| self.global_space.outputs().next())
|
||||
}
|
||||
|
||||
pub fn output_for_touch(&self) -> Option<&Output> {
|
||||
let config = self.config.borrow();
|
||||
let map_to_output = config.input.touch.map_to_output.as_ref();
|
||||
map_to_output
|
||||
.and_then(|name| self.output_by_name.get(name))
|
||||
.or_else(|| self.global_space.outputs().next())
|
||||
}
|
||||
|
||||
pub fn output_for_root(&self, root: &WlSurface) -> Option<&Output> {
|
||||
// Check the main layout.
|
||||
let win_out = self.layout.find_window_and_output(root);
|
||||
|
||||
Reference in New Issue
Block a user