Skip to content

Commit

Permalink
input: add basic touch support
Browse files Browse the repository at this point in the history
  • Loading branch information
cmeissl committed Feb 24, 2024
1 parent c471617 commit 00932a7
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 6 deletions.
15 changes: 15 additions & 0 deletions niri-config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ pub struct Input {
pub trackpoint: Trackpoint,
#[knuffel(child, default)]
pub tablet: Tablet,
#[knuffel(child, default)]
pub touch: Touch,
#[knuffel(child)]
pub disable_power_key_handling: bool,
}
Expand Down Expand Up @@ -201,6 +203,12 @@ pub struct Tablet {
pub map_to_output: Option<String>,
}

#[derive(knuffel::Decode, Debug, Default, PartialEq)]
pub struct Touch {
#[knuffel(child, unwrap(argument))]
pub map_to_output: Option<String>,
}

#[derive(knuffel::Decode, Debug, Clone, PartialEq)]
pub struct Output {
#[knuffel(child)]
Expand Down Expand Up @@ -1005,6 +1013,10 @@ mod tests {
map-to-output "eDP-1"
}
touch {
map-to-output "eDP-1"
}
disable-power-key-handling
}
Expand Down Expand Up @@ -1136,6 +1148,9 @@ mod tests {
tablet: Tablet {
map_to_output: Some("eDP-1".to_owned()),
},
touch: Touch {
map_to_output: Some("eDP-1".to_owned()),
},
disable_power_key_handling: true,
},
outputs: vec![Output {
Expand Down
7 changes: 7 additions & 0 deletions resources/default-config.kdl
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ input {
map-to-output "eDP-1"
}

touch {
// Set the name of the output (see below) which touch input will map to.
// If this is unset or the output doesn't exist, touch input maps to one of the
// existing outputs.
map-to-output "eDP-1"
}

// By default, niri will take over the power button to make it sleep
// instead of power off.
// Uncomment this if you would like to configure the power button elsewhere
Expand Down
108 changes: 102 additions & 6 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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};
Expand Down Expand Up @@ -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(_) => (),
}
Expand Down Expand Up @@ -171,6 +172,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) {
Expand Down Expand Up @@ -283,6 +287,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 {
Expand Down Expand Up @@ -1354,6 +1362,94 @@ 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;
};
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
Expand Down
12 changes: 12 additions & 0 deletions src/niri.rs
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,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
Expand Down Expand Up @@ -1602,6 +1606,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);
Expand Down

0 comments on commit 00932a7

Please sign in to comment.