anvil: Add tablet support

This commit is contained in:
Poly 2021-06-30 16:58:59 +02:00
parent 90a62aeae7
commit c557adc6a6
2 changed files with 141 additions and 2 deletions

View File

@ -8,13 +8,15 @@ use crate::AnvilState;
use smithay::{
backend::input::{
self, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent, PointerAxisEvent,
PointerButtonEvent,
self, Device, DeviceCapability, Event, InputBackend, InputEvent, KeyState, KeyboardKeyEvent,
PointerAxisEvent, PointerButtonEvent, ProximityState, TabletToolButtonEvent, TabletToolEvent,
TabletToolProximityEvent, TabletToolTipEvent, TabletToolTipState,
},
reexports::wayland_server::protocol::wl_pointer,
wayland::{
output::Mode,
seat::{keysyms as xkb, AxisFrame, Keysym, ModifiersState},
tablet_manager::TabletSeatTrait,
SERIAL_COUNTER as SCOUNTER,
},
};
@ -238,6 +240,27 @@ impl AnvilState<UdevData> {
InputEvent::PointerMotion { event, .. } => self.on_pointer_move::<B>(event),
InputEvent::PointerButton { event, .. } => self.on_pointer_button::<B>(event),
InputEvent::PointerAxis { event, .. } => self.on_pointer_axis::<B>(event),
InputEvent::TabletToolAxis { event, .. } => self.on_tablet_tool_axis::<B>(event),
InputEvent::TabletToolProximity { event, .. } => self.on_tablet_tool_proximity::<B>(event),
InputEvent::TabletToolTip { event, .. } => self.on_tablet_tool_tip::<B>(event),
InputEvent::TabletToolButton { event, .. } => self.on_tablet_button::<B>(event),
InputEvent::DeviceAdded { device } => {
if device.has_capability(DeviceCapability::TabletTool) {
self.seat.tablet_seat().add_tablet(&device.into());
}
}
InputEvent::DeviceRemoved { device } => {
if device.has_capability(DeviceCapability::TabletTool) {
let tablet_seat = self.seat.tablet_seat();
tablet_seat.remove_tablet(&device.into());
// If there are no tablets in seat we can remove all tools
if tablet_seat.count_tablets() == 0 {
tablet_seat.clear_tools();
}
}
}
_ => {
// other events are not handled in anvil (yet)
}
@ -259,6 +282,111 @@ impl AnvilState<UdevData> {
.motion(self.pointer_location, under, serial, evt.time());
}
fn on_tablet_tool_axis<B: InputBackend>(&mut self, evt: B::TabletToolAxisEvent) {
if let Some(out) = self.backend_data.output_map.first() {
self.pointer_location = evt.position_transformed(out.size);
let under = self.window_map.borrow().get_surface_under(self.pointer_location);
let tablet = self.seat.tablet_seat().get_tablet(&evt.device().into());
let tool = self.seat.tablet_seat().get_tool(&evt.tool());
if let (Some(tablet), Some(tool)) = (tablet, tool) {
if evt.pressure_has_changed() {
tool.pressure(evt.pressure());
}
if evt.distance_has_changed() {
tool.distance(evt.distance());
}
if evt.tilt_has_changed() {
tool.tilt(evt.tilt());
}
if evt.slider_has_changed() {
tool.slider_position(evt.slider_position());
}
if evt.rotation_has_changed() {
tool.rotation(evt.rotation());
}
if evt.wheel_has_changed() {
tool.wheel(evt.wheel_delta(), evt.wheel_delta_discrete());
}
tool.motion(
self.pointer_location,
under,
&tablet,
SCOUNTER.next_serial(),
evt.time(),
);
}
}
}
fn on_tablet_tool_proximity<B: InputBackend>(&mut self, evt: B::TabletToolProximityEvent) {
if let Some(out) = self.backend_data.output_map.first() {
let tool = evt.tool();
self.seat.tablet_seat().add_tool(&tool);
self.pointer_location = evt.position_transformed(out.size);
let under = self.window_map.borrow().get_surface_under(self.pointer_location);
let tablet = self.seat.tablet_seat().get_tablet(&evt.device().into());
let tool = self.seat.tablet_seat().get_tool(&tool);
if let (Some(under), Some(tablet), Some(tool)) = (under, tablet, tool) {
match evt.state() {
ProximityState::In => tool.proximity_in(
self.pointer_location,
under,
&tablet,
SCOUNTER.next_serial(),
evt.time(),
),
ProximityState::Out => tool.proximity_out(evt.time()),
}
}
}
}
fn on_tablet_tool_tip<B: InputBackend>(&mut self, evt: B::TabletToolTipEvent) {
let tool = self.seat.tablet_seat().get_tool(&evt.tool());
if let Some(tool) = tool {
match evt.tip_state() {
TabletToolTipState::Down => {
tool.tip_down(SCOUNTER.next_serial(), evt.time());
// change the keyboard focus unless the pointer is grabbed
if !self.pointer.is_grabbed() {
let under = self
.window_map
.borrow_mut()
.get_surface_and_bring_to_top(self.pointer_location);
let serial = SCOUNTER.next_serial();
self.keyboard
.set_focus(under.as_ref().map(|&(ref s, _)| s), serial);
}
}
TabletToolTipState::Up => {
tool.tip_up(evt.time());
}
}
}
}
fn on_tablet_button<B: InputBackend>(&mut self, evt: B::TabletToolButtonEvent) {
let tool = self.seat.tablet_seat().get_tool(&evt.tool());
if let Some(tool) = tool {
tool.button(
evt.button(),
evt.button_state(),
SCOUNTER.next_serial(),
evt.time(),
);
}
}
fn clamp_coords(&self, pos: (f64, f64)) -> (f64, f64) {
if self.output_map.borrow().is_empty() {
return pos;

View File

@ -16,6 +16,7 @@ use smithay::{
data_device::{default_action_chooser, init_data_device, set_data_device_focus, DataDeviceEvent},
seat::{CursorImageStatus, KeyboardHandle, PointerHandle, Seat, XkbConfig},
shm::init_shm_global,
tablet_manager::{init_tablet_manager_global, TabletSeatTrait},
},
};
@ -41,6 +42,7 @@ pub struct AnvilState<BackendData> {
pub pointer_location: (f64, f64),
pub cursor_status: Arc<Mutex<CursorImageStatus>>,
pub seat_name: String,
pub seat: Seat,
pub start_time: std::time::Instant,
// things we must keep alive
#[cfg(feature = "xwayland")]
@ -121,6 +123,14 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
*cursor_status2.lock().unwrap() = new_status
});
init_tablet_manager_global(&mut display.borrow_mut());
let cursor_status3 = cursor_status.clone();
seat.tablet_seat().on_cursor_surface(move |_tool, new_status| {
// TODO: tablet tools should have their own cursors
*cursor_status3.lock().unwrap() = new_status;
});
let keyboard = seat
.add_keyboard(XkbConfig::default(), 200, 25, |seat, focus| {
set_data_device_focus(seat, focus.and_then(|s| s.as_ref().client()))
@ -159,6 +169,7 @@ impl<BackendData: Backend + 'static> AnvilState<BackendData> {
cursor_status,
pointer_location: (0.0, 0.0),
seat_name,
seat,
start_time: std::time::Instant::now(),
#[cfg(feature = "xwayland")]
xwayland,