wayland: implement wl_touch
Co-authored-by: Julian Orth <ju.orth@gmail.com>
This commit is contained in:
parent
905e2dd7ba
commit
681c1ad033
35 changed files with 1071 additions and 52 deletions
|
|
@ -141,7 +141,7 @@ Jay supports the following wayland protocols:
|
|||
| ext_session_lock_manager_v1 | 1 | Yes |
|
||||
| ext_transient_seat_manager_v1 | 1[^ts_rejected] | Yes |
|
||||
| org_kde_kwin_server_decoration_manager | 1 | |
|
||||
| wl_compositor | 6[^no_touch] | |
|
||||
| wl_compositor | 6 | |
|
||||
| wl_data_device_manager | 3 | |
|
||||
| wl_drm | 2 | |
|
||||
| wl_output | 4 | |
|
||||
|
|
@ -179,12 +179,5 @@ Jay supports the following wayland protocols:
|
|||
| zxdg_decoration_manager_v1 | 1 | |
|
||||
| zxdg_output_manager_v1 | 3 | |
|
||||
|
||||
[^no_touch]: Touch input is not supported.
|
||||
[^lsaccess]: Sandboxes can restrict access to this protocol.
|
||||
[^ts_rejected]: Seat creation is always rejected.
|
||||
|
||||
## Missing Features
|
||||
|
||||
The following features are currently not supported but might get implemented in the future:
|
||||
|
||||
- Touch support.
|
||||
|
|
|
|||
|
|
@ -897,6 +897,10 @@ impl Client {
|
|||
self.send(&ClientMessage::SetTransformMatrix { device, matrix })
|
||||
}
|
||||
|
||||
pub fn set_calibration_matrix(&self, device: InputDevice, matrix: [[f32; 3]; 2]) {
|
||||
self.send(&ClientMessage::SetCalibrationMatrix { device, matrix })
|
||||
}
|
||||
|
||||
pub fn set_px_per_wheel_scroll(&self, device: InputDevice, px: f64) {
|
||||
self.send(&ClientMessage::SetPxPerWheelScroll { device, px })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -502,6 +502,10 @@ pub enum ClientMessage<'a> {
|
|||
connector: Option<Connector>,
|
||||
mode: TearingMode,
|
||||
},
|
||||
SetCalibrationMatrix {
|
||||
device: InputDevice,
|
||||
matrix: [[f32; 3]; 2],
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
|
|
|
|||
|
|
@ -80,6 +80,13 @@ impl InputDevice {
|
|||
get!().set_transform_matrix(self, matrix);
|
||||
}
|
||||
|
||||
/// Sets the calibration matrix of the device.
|
||||
///
|
||||
/// This corresponds to the libinput setting of the same name.
|
||||
pub fn set_calibration_matrix(self, matrix: [[f32; 3]; 2]) {
|
||||
get!().set_calibration_matrix(self, matrix);
|
||||
}
|
||||
|
||||
/// Returns the name of the device.
|
||||
pub fn name(self) -> String {
|
||||
get!(String::new()).device_name(self)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
- Add fine-grained damage tracking.
|
||||
- Add support for adaptive sync.
|
||||
- Add support for tearing.
|
||||
- Add support for touch input.
|
||||
|
||||
# 1.4.0 (2024-07-07)
|
||||
|
||||
|
|
|
|||
|
|
@ -167,6 +167,12 @@ pub trait InputDevice {
|
|||
None
|
||||
}
|
||||
fn set_transform_matrix(&self, matrix: TransformMatrix);
|
||||
fn calibration_matrix(&self) -> Option<[[f32; 3]; 2]> {
|
||||
None
|
||||
}
|
||||
fn set_calibration_matrix(&self, m: [[f32; 3]; 2]) {
|
||||
let _ = m;
|
||||
}
|
||||
fn name(&self) -> Rc<String>;
|
||||
fn dev_t(&self) -> Option<c::dev_t> {
|
||||
None
|
||||
|
|
@ -392,6 +398,27 @@ pub enum InputEvent {
|
|||
source: Option<TabletStripEventSource>,
|
||||
position: Option<f64>,
|
||||
},
|
||||
TouchDown {
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x_normed: Fixed,
|
||||
y_normed: Fixed,
|
||||
},
|
||||
TouchUp {
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
},
|
||||
TouchMotion {
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x_normed: Fixed,
|
||||
y_normed: Fixed,
|
||||
},
|
||||
TouchCancel {
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
},
|
||||
TouchFrame,
|
||||
}
|
||||
|
||||
pub enum DrmEvent {
|
||||
|
|
|
|||
|
|
@ -376,6 +376,7 @@ struct InputDeviceProperties {
|
|||
drag_enabled: Cell<Option<bool>>,
|
||||
drag_lock_enabled: Cell<Option<bool>>,
|
||||
natural_scrolling_enabled: Cell<Option<bool>>,
|
||||
calibration_matrix: Cell<Option<[[f32; 3]; 2]>>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
@ -436,6 +437,9 @@ impl MetalInputDevice {
|
|||
if let Some(enabled) = self.desired.natural_scrolling_enabled.get() {
|
||||
self.set_natural_scrolling_enabled(enabled);
|
||||
}
|
||||
if let Some(lh) = self.desired.calibration_matrix.get() {
|
||||
self.set_calibration_matrix(lh);
|
||||
}
|
||||
self.fetch_effective();
|
||||
}
|
||||
|
||||
|
|
@ -465,6 +469,11 @@ impl MetalInputDevice {
|
|||
.natural_scrolling_enabled
|
||||
.set(Some(device.natural_scrolling_enabled()));
|
||||
}
|
||||
if device.has_calibration_matrix() {
|
||||
self.effective
|
||||
.calibration_matrix
|
||||
.set(Some(device.get_calibration_matrix()));
|
||||
}
|
||||
}
|
||||
|
||||
fn pre_pause(&self) {
|
||||
|
|
@ -721,6 +730,22 @@ impl InputDevice for MetalInputDevice {
|
|||
groups,
|
||||
}))
|
||||
}
|
||||
|
||||
fn calibration_matrix(&self) -> Option<[[f32; 3]; 2]> {
|
||||
self.effective.calibration_matrix.get()
|
||||
}
|
||||
|
||||
fn set_calibration_matrix(&self, m: [[f32; 3]; 2]) {
|
||||
self.desired.calibration_matrix.set(Some(m));
|
||||
if let Some(dev) = self.inputdev.get() {
|
||||
if dev.device().has_calibration_matrix() {
|
||||
dev.device().set_calibration_matrix(m);
|
||||
self.effective
|
||||
.calibration_matrix
|
||||
.set(Some(dev.device().get_calibration_matrix()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MetalInputDevice {
|
||||
|
|
|
|||
|
|
@ -121,6 +121,11 @@ impl MetalBackend {
|
|||
c::LIBINPUT_EVENT_TABLET_PAD_BUTTON => self.handle_tablet_pad_button(event),
|
||||
c::LIBINPUT_EVENT_TABLET_PAD_RING => self.handle_tablet_pad_ring(event),
|
||||
c::LIBINPUT_EVENT_TABLET_PAD_STRIP => self.handle_tablet_pad_strip(event),
|
||||
c::LIBINPUT_EVENT_TOUCH_DOWN => self.handle_touch_down(event),
|
||||
c::LIBINPUT_EVENT_TOUCH_UP => self.handle_touch_up(event),
|
||||
c::LIBINPUT_EVENT_TOUCH_MOTION => self.handle_touch_motion(event),
|
||||
c::LIBINPUT_EVENT_TOUCH_CANCEL => self.handle_touch_cancel(event),
|
||||
c::LIBINPUT_EVENT_TOUCH_FRAME => self.handle_touch_frame(event),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -539,4 +544,45 @@ impl MetalBackend {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_touch_down(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let (event, dev) = unpack!(self, event, touch_event);
|
||||
dev.event(InputEvent::TouchDown {
|
||||
time_usec: event.time_usec(),
|
||||
id: event.seat_slot(),
|
||||
x_normed: Fixed::from_f64(event.x_transformed(1)),
|
||||
y_normed: Fixed::from_f64(event.y_transformed(1)),
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_touch_up(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let (event, dev) = unpack!(self, event, touch_event);
|
||||
dev.event(InputEvent::TouchUp {
|
||||
time_usec: event.time_usec(),
|
||||
id: event.seat_slot(),
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_touch_motion(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let (event, dev) = unpack!(self, event, touch_event);
|
||||
dev.event(InputEvent::TouchMotion {
|
||||
time_usec: event.time_usec(),
|
||||
id: event.seat_slot(),
|
||||
x_normed: Fixed::from_f64(event.x_transformed(1)),
|
||||
y_normed: Fixed::from_f64(event.y_transformed(1)),
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_touch_cancel(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let (event, dev) = unpack!(self, event, touch_event);
|
||||
dev.event(InputEvent::TouchCancel {
|
||||
time_usec: event.time_usec(),
|
||||
id: event.seat_slot(),
|
||||
})
|
||||
}
|
||||
|
||||
fn handle_touch_frame(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let (_, dev) = unpack!(self, event, touch_event);
|
||||
dev.event(InputEvent::TouchFrame)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,6 +131,8 @@ pub enum DeviceCommand {
|
|||
MapToOutput(MapToOutputArgs),
|
||||
/// Removes the mapping from this device to an output.
|
||||
RemoveMapping,
|
||||
/// Set the calibration matrix.
|
||||
SetCalibrationMatrix(SetCalibrationMatrixArgs),
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Debug, Clone)]
|
||||
|
|
@ -200,6 +202,16 @@ pub struct SetTransformMatrixArgs {
|
|||
pub m22: f64,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Clone)]
|
||||
pub struct SetCalibrationMatrixArgs {
|
||||
pub m00: f32,
|
||||
pub m01: f32,
|
||||
pub m02: f32,
|
||||
pub m10: f32,
|
||||
pub m11: f32,
|
||||
pub m12: f32,
|
||||
}
|
||||
|
||||
#[derive(Args, Debug, Clone)]
|
||||
pub struct MapToOutputArgs {
|
||||
/// The output to map to.
|
||||
|
|
@ -272,6 +284,7 @@ struct InputDevice {
|
|||
pub px_per_wheel_scroll: Option<f64>,
|
||||
pub transform_matrix: Option<[[f64; 2]; 2]>,
|
||||
pub output: Option<String>,
|
||||
pub calibration_matrix: Option<[[f32; 3]; 2]>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
|
@ -595,6 +608,21 @@ impl Input {
|
|||
output: None,
|
||||
});
|
||||
}
|
||||
DeviceCommand::SetCalibrationMatrix(a) => {
|
||||
self.handle_error(input, |e| {
|
||||
eprintln!("Could not modify the calibration matrix: {}", e);
|
||||
});
|
||||
tc.send(jay_input::SetCalibrationMatrix {
|
||||
self_id: input,
|
||||
id: args.device,
|
||||
m00: a.m00,
|
||||
m01: a.m01,
|
||||
m02: a.m02,
|
||||
m10: a.m10,
|
||||
m11: a.m11,
|
||||
m12: a.m12,
|
||||
});
|
||||
}
|
||||
}
|
||||
tc.round_trip().await;
|
||||
}
|
||||
|
|
@ -728,6 +756,9 @@ impl Input {
|
|||
if let Some(v) = &device.output {
|
||||
println!("{prefix} mapped to output: {}", v);
|
||||
}
|
||||
if let Some(v) = &device.calibration_matrix {
|
||||
println!("{prefix} calibration matrix: {:?}", v);
|
||||
}
|
||||
}
|
||||
|
||||
async fn get(self: &Rc<Self>, input: JayInputId) -> Data {
|
||||
|
|
@ -792,6 +823,7 @@ impl Input {
|
|||
px_per_wheel_scroll: is_pointer.then_some(msg.px_per_wheel_scroll),
|
||||
transform_matrix: uapi::pod_read(msg.transform_matrix).ok(),
|
||||
output: None,
|
||||
calibration_matrix: None,
|
||||
});
|
||||
});
|
||||
jay_input::InputDeviceOutput::handle(tc, input, data.clone(), |data, msg| {
|
||||
|
|
@ -800,6 +832,13 @@ impl Input {
|
|||
last.output = Some(msg.output.to_string());
|
||||
}
|
||||
});
|
||||
jay_input::CalibrationMatrix::handle(tc, input, data.clone(), |data, msg| {
|
||||
let mut data = data.borrow_mut();
|
||||
if let Some(last) = data.input_device.last_mut() {
|
||||
last.calibration_matrix =
|
||||
Some([[msg.m00, msg.m01, msg.m02], [msg.m10, msg.m11, msg.m12]]);
|
||||
}
|
||||
});
|
||||
tc.round_trip().await;
|
||||
let x = data.borrow_mut().clone();
|
||||
x
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ use {
|
|||
TabletPadStripSource, TabletPadStripStop, TabletToolButton, TabletToolDistance,
|
||||
TabletToolDown, TabletToolFrame, TabletToolMotion, TabletToolPressure,
|
||||
TabletToolProximityIn, TabletToolProximityOut, TabletToolRotation,
|
||||
TabletToolSlider, TabletToolTilt, TabletToolUp, TabletToolWheel,
|
||||
TabletToolSlider, TabletToolTilt, TabletToolUp, TabletToolWheel, TouchCancel,
|
||||
TouchDown, TouchMotion, TouchUp,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
@ -583,6 +584,54 @@ async fn run(seat_test: Rc<SeatTest>) {
|
|||
}
|
||||
println!();
|
||||
});
|
||||
let st = seat_test.clone();
|
||||
TouchDown::handle(tc, se, (), move |_, ev| {
|
||||
if all || ev.seat == seat {
|
||||
if all {
|
||||
print!("Seat: {}, ", st.name(ev.seat));
|
||||
}
|
||||
println!(
|
||||
"Time: {:.4}, Touch: {}, Down: {}x{}",
|
||||
time(ev.time_usec),
|
||||
ev.id,
|
||||
ev.x,
|
||||
ev.y
|
||||
);
|
||||
}
|
||||
});
|
||||
let st = seat_test.clone();
|
||||
TouchUp::handle(tc, se, (), move |_, ev| {
|
||||
if all || ev.seat == seat {
|
||||
if all {
|
||||
print!("Seat: {}, ", st.name(ev.seat));
|
||||
}
|
||||
println!("Time: {:.4}, Touch: {}, Up", time(ev.time_usec), ev.id);
|
||||
}
|
||||
});
|
||||
let st = seat_test.clone();
|
||||
TouchMotion::handle(tc, se, (), move |_, ev| {
|
||||
if all || ev.seat == seat {
|
||||
if all {
|
||||
print!("Seat: {}, ", st.name(ev.seat));
|
||||
}
|
||||
println!(
|
||||
"Time: {:.4}, Touch: {} Motion: {}x{}",
|
||||
time(ev.time_usec),
|
||||
ev.id,
|
||||
ev.x,
|
||||
ev.y
|
||||
);
|
||||
}
|
||||
});
|
||||
let st = seat_test.clone();
|
||||
TouchCancel::handle(tc, se, (), move |_, ev| {
|
||||
if all || ev.seat == seat {
|
||||
if all {
|
||||
print!("Seat: {}, ", st.name(ev.seat));
|
||||
}
|
||||
println!("Time: {:.4}, Touch: {}, Cancel", time(ev.time_usec), ev.id);
|
||||
}
|
||||
});
|
||||
pending::<()>().await;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -689,6 +689,16 @@ impl ConfigProxyHandler {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_set_calibration_matrix(
|
||||
&self,
|
||||
device: InputDevice,
|
||||
matrix: [[f32; 3]; 2],
|
||||
) -> Result<(), CphError> {
|
||||
let dev = self.get_device_handler_data(device)?;
|
||||
dev.device.set_calibration_matrix(matrix);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn handle_get_workspace(&self, name: &str) {
|
||||
let name = Rc::new(name.to_owned());
|
||||
let ws = match self.workspaces_by_name.get(&name) {
|
||||
|
|
@ -1897,6 +1907,9 @@ impl ConfigProxyHandler {
|
|||
ClientMessage::SetTearingMode { connector, mode } => self
|
||||
.handle_set_tearing_mode(connector, mode)
|
||||
.wrn("set_tearing_mode")?,
|
||||
ClientMessage::SetCalibrationMatrix { device, matrix } => self
|
||||
.handle_set_calibration_matrix(device, matrix)
|
||||
.wrn("set_calibration_matrix")?,
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ impl Global for JayCompositorGlobal {
|
|||
}
|
||||
|
||||
fn version(&self) -> u32 {
|
||||
3
|
||||
4
|
||||
}
|
||||
|
||||
fn required_caps(&self) -> ClientCaps {
|
||||
|
|
@ -336,7 +336,7 @@ impl JayCompositorRequestHandler for JayCompositor {
|
|||
}
|
||||
|
||||
fn get_input(&self, req: GetInput, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
let sc = Rc::new(JayInput::new(req.id, &self.client));
|
||||
let sc = Rc::new(JayInput::new(req.id, &self.client, self.version));
|
||||
track!(self.client, sc);
|
||||
self.client.add_client_obj(&sc)?;
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -24,14 +24,18 @@ pub struct JayInput {
|
|||
pub id: JayInputId,
|
||||
pub client: Rc<Client>,
|
||||
pub tracker: Tracker<Self>,
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
const CALIBRATION_MATRIX_SINCE: Version = Version(4);
|
||||
|
||||
impl JayInput {
|
||||
pub fn new(id: JayInputId, client: &Rc<Client>) -> Self {
|
||||
pub fn new(id: JayInputId, client: &Rc<Client>, version: Version) -> Self {
|
||||
Self {
|
||||
id,
|
||||
client: client.clone(),
|
||||
tracker: Default::default(),
|
||||
version,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,6 +142,19 @@ impl JayInput {
|
|||
});
|
||||
}
|
||||
}
|
||||
if self.version >= CALIBRATION_MATRIX_SINCE {
|
||||
if let Some(m) = dev.calibration_matrix() {
|
||||
self.client.event(CalibrationMatrix {
|
||||
self_id: self.id,
|
||||
m00: m[0][0],
|
||||
m01: m[0][1],
|
||||
m02: m[0][2],
|
||||
m10: m[1][0],
|
||||
m11: m[1][1],
|
||||
m12: m[1][2],
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn device(&self, id: u32) -> Result<Rc<DeviceHandlerData>, JayInputError> {
|
||||
|
|
@ -424,11 +441,24 @@ impl JayInputRequestHandler for JayInput {
|
|||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
fn set_calibration_matrix(
|
||||
&self,
|
||||
req: SetCalibrationMatrix,
|
||||
_slf: &Rc<Self>,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.or_error(|| {
|
||||
let dev = self.device(req.id)?;
|
||||
dev.device
|
||||
.set_calibration_matrix([[req.m00, req.m01, req.m02], [req.m10, req.m11, req.m12]]);
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
object_base! {
|
||||
self = JayInput;
|
||||
version = Version(1);
|
||||
version = self.version;
|
||||
}
|
||||
|
||||
impl Object for JayInput {}
|
||||
|
|
|
|||
|
|
@ -468,6 +468,46 @@ impl JaySeatEvents {
|
|||
ring,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_touch_down(&self, seat: SeatId, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
self.client.event(TouchDown {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_touch_up(&self, seat: SeatId, time_usec: u64, id: i32) {
|
||||
self.client.event(TouchUp {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
id,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_touch_motion(&self, seat: SeatId, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
self.client.event(TouchMotion {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn send_touch_cancel(&self, seat: SeatId, time_usec: u64, id: i32) {
|
||||
self.client.event(TouchCancel {
|
||||
self_id: self.id,
|
||||
seat: seat.raw(),
|
||||
time_usec,
|
||||
id,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl JaySeatEventsRequestHandler for JaySeatEvents {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ mod kb_owner;
|
|||
mod pointer_owner;
|
||||
pub mod tablet;
|
||||
pub mod text_input;
|
||||
mod touch_owner;
|
||||
pub mod wl_keyboard;
|
||||
pub mod wl_pointer;
|
||||
pub mod wl_touch;
|
||||
|
|
@ -52,6 +53,7 @@ use {
|
|||
zwp_input_method_keyboard_grab_v2::ZwpInputMethodKeyboardGrabV2,
|
||||
zwp_input_method_v2::ZwpInputMethodV2, zwp_text_input_v3::ZwpTextInputV3,
|
||||
},
|
||||
touch_owner::TouchOwnerHolder,
|
||||
wl_keyboard::{WlKeyboard, WlKeyboardError, REPEAT_INFO_SINCE},
|
||||
wl_pointer::WlPointer,
|
||||
wl_touch::WlTouch,
|
||||
|
|
@ -79,7 +81,7 @@ use {
|
|||
},
|
||||
wire::{
|
||||
wl_seat::*, ExtIdleNotificationV1Id, WlDataDeviceId, WlKeyboardId, WlPointerId,
|
||||
WlSeatId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||
WlSeatId, WlTouchId, ZwlrDataControlDeviceV1Id, ZwpPrimarySelectionDeviceV1Id,
|
||||
ZwpRelativePointerV1Id, ZwpTextInputV3Id,
|
||||
},
|
||||
xkbcommon::{DynKeyboardState, KeyboardState, KeymapId, XkbKeymap, XkbState},
|
||||
|
|
@ -103,7 +105,6 @@ pub use {
|
|||
|
||||
pub const POINTER: u32 = 1;
|
||||
const KEYBOARD: u32 = 2;
|
||||
#[allow(dead_code)]
|
||||
const TOUCH: u32 = 4;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
|
@ -142,6 +143,8 @@ pub struct WlSeatGlobal {
|
|||
name: GlobalName,
|
||||
state: Rc<State>,
|
||||
seat_name: String,
|
||||
capabilities: Cell<u32>,
|
||||
num_touch_devices: NumCell<u32>,
|
||||
pos_time_usec: Cell<u64>,
|
||||
pointer_stack: RefCell<Vec<Rc<dyn Node>>>,
|
||||
pointer_stack_modified: Cell<bool>,
|
||||
|
|
@ -173,6 +176,7 @@ pub struct WlSeatGlobal {
|
|||
pointer_owner: PointerOwnerHolder,
|
||||
kb_owner: KbOwnerHolder,
|
||||
gesture_owner: GestureOwnerHolder,
|
||||
touch_owner: TouchOwnerHolder,
|
||||
dropped_dnd: RefCell<Option<DroppedDnd>>,
|
||||
shortcuts: RefCell<AHashMap<u32, SmallMap<u32, u32, 2>>>,
|
||||
queue_link: RefCell<Option<LinkedNode<Rc<Self>>>>,
|
||||
|
|
@ -213,6 +217,8 @@ impl WlSeatGlobal {
|
|||
name,
|
||||
state: state.clone(),
|
||||
seat_name: seat_name.to_string(),
|
||||
capabilities: Cell::new(0),
|
||||
num_touch_devices: Default::default(),
|
||||
pos_time_usec: Cell::new(0),
|
||||
pointer_stack: RefCell::new(vec![]),
|
||||
pointer_stack_modified: Cell::new(false),
|
||||
|
|
@ -237,6 +243,7 @@ impl WlSeatGlobal {
|
|||
pointer_owner: Default::default(),
|
||||
kb_owner: Default::default(),
|
||||
gesture_owner: Default::default(),
|
||||
touch_owner: Default::default(),
|
||||
dropped_dnd: RefCell::new(None),
|
||||
shortcuts: Default::default(),
|
||||
queue_link: Default::default(),
|
||||
|
|
@ -269,9 +276,24 @@ impl WlSeatGlobal {
|
|||
}
|
||||
});
|
||||
slf.tree_changed_handler.set(Some(future));
|
||||
slf.update_capabilities();
|
||||
slf
|
||||
}
|
||||
|
||||
fn update_capabilities(&self) {
|
||||
let mut caps = POINTER | KEYBOARD;
|
||||
if self.num_touch_devices.get() > 0 {
|
||||
caps |= TOUCH;
|
||||
}
|
||||
if self.capabilities.replace(caps) != caps {
|
||||
for client in self.bindings.borrow().values() {
|
||||
for seat in client.values() {
|
||||
seat.send_capabilities();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keymap(&self) -> Rc<XkbKeymap> {
|
||||
self.seat_kb_map.get()
|
||||
}
|
||||
|
|
@ -852,6 +874,7 @@ impl WlSeatGlobal {
|
|||
self.primary_selection.set(None);
|
||||
self.pointer_owner.clear();
|
||||
self.kb_owner.clear();
|
||||
self.touch_owner.clear();
|
||||
*self.dropped_dnd.borrow_mut() = None;
|
||||
self.queue_link.take();
|
||||
self.tree_changed_handler.set(None);
|
||||
|
|
@ -888,6 +911,7 @@ impl WlSeatGlobal {
|
|||
pointers: Default::default(),
|
||||
relative_pointers: Default::default(),
|
||||
keyboards: Default::default(),
|
||||
touches: Default::default(),
|
||||
version,
|
||||
tracker: Default::default(),
|
||||
});
|
||||
|
|
@ -994,6 +1018,7 @@ pub struct WlSeat {
|
|||
pointers: CopyHashMap<WlPointerId, Rc<WlPointer>>,
|
||||
relative_pointers: CopyHashMap<ZwpRelativePointerV1Id, Rc<ZwpRelativePointerV1>>,
|
||||
keyboards: CopyHashMap<WlKeyboardId, Rc<WlKeyboard>>,
|
||||
touches: CopyHashMap<WlTouchId, Rc<WlTouch>>,
|
||||
version: Version,
|
||||
tracker: Tracker<Self>,
|
||||
}
|
||||
|
|
@ -1004,7 +1029,7 @@ impl WlSeat {
|
|||
fn send_capabilities(self: &Rc<Self>) {
|
||||
self.client.event(Capabilities {
|
||||
self_id: self.id,
|
||||
capabilities: POINTER | KEYBOARD,
|
||||
capabilities: self.global.capabilities.get(),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -1059,6 +1084,7 @@ impl WlSeatRequestHandler for WlSeat {
|
|||
let p = Rc::new(WlTouch::new(req.id, slf));
|
||||
track!(self.client, p);
|
||||
self.client.add_client_obj(&p)?;
|
||||
self.touches.set(req.id, p);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1096,6 +1122,7 @@ impl Object for WlSeat {
|
|||
self.pointers.clear();
|
||||
self.relative_pointers.clear();
|
||||
self.keyboards.clear();
|
||||
self.touches.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1146,6 +1173,10 @@ impl DeviceHandlerData {
|
|||
if let Some(info) = &self.tablet_pad_init {
|
||||
old.tablet_remove_tablet_pad(info.id);
|
||||
}
|
||||
if self.is_touch {
|
||||
old.num_touch_devices.fetch_sub(1);
|
||||
old.update_capabilities();
|
||||
}
|
||||
}
|
||||
self.update_xkb_state();
|
||||
if let Some(seat) = &seat {
|
||||
|
|
@ -1155,6 +1186,10 @@ impl DeviceHandlerData {
|
|||
if let Some(info) = &self.tablet_pad_init {
|
||||
seat.tablet_add_tablet_pad(self.device.id(), info);
|
||||
}
|
||||
if self.is_touch {
|
||||
seat.num_touch_devices.fetch_add(1);
|
||||
seat.update_capabilities();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ use {
|
|||
AXIS_STOP_SINCE_VERSION, AXIS_VALUE120_SINCE_VERSION, IDENTICAL, INVERTED,
|
||||
POINTER_FRAME_SINCE_VERSION, WHEEL_TILT, WHEEL_TILT_SINCE_VERSION,
|
||||
},
|
||||
wl_touch::WlTouch,
|
||||
zwp_pointer_constraints_v1::{ConstraintType, SeatConstraintStatus},
|
||||
zwp_relative_pointer_v1::ZwpRelativePointerV1,
|
||||
Dnd, SeatId, WlSeat, WlSeatGlobal, CHANGE_CURSOR_MOVED, CHANGE_TREE,
|
||||
|
|
@ -31,6 +32,7 @@ use {
|
|||
wl_surface::{xdg_surface::xdg_popup::XdgPopup, WlSurface},
|
||||
},
|
||||
object::Version,
|
||||
rect::Rect,
|
||||
state::DeviceHandlerData,
|
||||
tree::{Direction, Node, ToplevelNode},
|
||||
utils::{bitflags::BitflagsExt, hash_map_ext::HashMapExt, smallmap::SmallMap},
|
||||
|
|
@ -54,6 +56,7 @@ pub struct NodeSeatState {
|
|||
pointer_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
kb_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
gesture_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
touch_foci: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
pointer_grabs: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
dnd_targets: SmallMap<SeatId, Rc<WlSeatGlobal>, 1>,
|
||||
tablet_pad_foci: SmallMap<TabletPadId, Rc<TabletPad>, 1>,
|
||||
|
|
@ -111,6 +114,14 @@ impl NodeSeatState {
|
|||
self.tablet_tool_foci.remove(&tool.id);
|
||||
}
|
||||
|
||||
pub(super) fn touch_begin(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.touch_foci.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
||||
pub(super) fn touch_end(&self, seat: &WlSeatGlobal) {
|
||||
self.touch_foci.remove(&seat.id);
|
||||
}
|
||||
|
||||
pub(super) fn add_dnd_target(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.dnd_targets.insert(seat.id, seat.clone());
|
||||
}
|
||||
|
|
@ -184,6 +195,9 @@ impl NodeSeatState {
|
|||
while let Some((_, pad)) = self.tablet_pad_foci.pop() {
|
||||
pad.pad_owner.focus_root(&pad);
|
||||
}
|
||||
while let Some((_, seat)) = self.touch_foci.pop() {
|
||||
seat.touch_owner.cancel(&seat);
|
||||
}
|
||||
self.release_kb_focus2(focus_last);
|
||||
}
|
||||
|
||||
|
|
@ -230,7 +244,11 @@ impl WlSeatGlobal {
|
|||
| InputEvent::TabletPadButton { time_usec, .. }
|
||||
| InputEvent::TabletPadModeSwitch { time_usec, .. }
|
||||
| InputEvent::TabletPadRing { time_usec, .. }
|
||||
| InputEvent::TabletPadStrip { time_usec, .. } => {
|
||||
| InputEvent::TabletPadStrip { time_usec, .. }
|
||||
| InputEvent::TouchDown { time_usec, .. }
|
||||
| InputEvent::TouchUp { time_usec, .. }
|
||||
| InputEvent::TouchMotion { time_usec, .. }
|
||||
| InputEvent::TouchCancel { time_usec, .. } => {
|
||||
self.last_input_usec.set(time_usec);
|
||||
if self.idle_notifications.is_not_empty() {
|
||||
for notification in self.idle_notifications.lock().drain_values() {
|
||||
|
|
@ -243,7 +261,8 @@ impl WlSeatGlobal {
|
|||
| InputEvent::AxisStop { .. }
|
||||
| InputEvent::Axis120 { .. }
|
||||
| InputEvent::TabletToolAdded { .. }
|
||||
| InputEvent::TabletToolRemoved { .. } => {}
|
||||
| InputEvent::TabletToolRemoved { .. }
|
||||
| InputEvent::TouchFrame => {}
|
||||
}
|
||||
match event {
|
||||
InputEvent::ConnectorPosition { .. }
|
||||
|
|
@ -274,6 +293,11 @@ impl WlSeatGlobal {
|
|||
InputEvent::TabletPadModeSwitch { .. } => {}
|
||||
InputEvent::TabletPadRing { .. } => {}
|
||||
InputEvent::TabletPadStrip { .. } => {}
|
||||
InputEvent::TouchDown { .. } => {}
|
||||
InputEvent::TouchUp { .. } => {}
|
||||
InputEvent::TouchMotion { .. } => {}
|
||||
InputEvent::TouchCancel { .. } => {}
|
||||
InputEvent::TouchFrame => {}
|
||||
}
|
||||
match event {
|
||||
InputEvent::Key {
|
||||
|
|
@ -407,6 +431,21 @@ impl WlSeatGlobal {
|
|||
source,
|
||||
position,
|
||||
} => self.tablet_event_pad_strip(pad, strip, source, position, time_usec),
|
||||
InputEvent::TouchDown {
|
||||
time_usec,
|
||||
id,
|
||||
x_normed,
|
||||
y_normed,
|
||||
} => self.touch_down(time_usec, id, dev.get_rect(&self.state), x_normed, y_normed),
|
||||
InputEvent::TouchUp { time_usec, id } => self.touch_up(time_usec, id),
|
||||
InputEvent::TouchMotion {
|
||||
time_usec,
|
||||
id,
|
||||
x_normed,
|
||||
y_normed,
|
||||
} => self.touch_motion(time_usec, id, dev.get_rect(&self.state), x_normed, y_normed),
|
||||
InputEvent::TouchCancel { time_usec, id } => self.touch_cancel(time_usec, id),
|
||||
InputEvent::TouchFrame => self.touch_frame(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -613,6 +652,58 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
fn touch_down(
|
||||
self: &Rc<Self>,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
rect: Rect,
|
||||
x_normed: Fixed,
|
||||
y_normed: Fixed,
|
||||
) {
|
||||
self.cursor_group().deactivate();
|
||||
let x = Fixed::from_f64(rect.x1() as f64 + rect.width() as f64 * x_normed.to_f64());
|
||||
let y = Fixed::from_f64(rect.y1() as f64 + rect.height() as f64 * y_normed.to_f64());
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_touch_down(self.id, time_usec, id, x, y);
|
||||
});
|
||||
self.touch_owner.down(self, time_usec, id, x, y);
|
||||
}
|
||||
|
||||
fn touch_up(self: &Rc<Self>, time_usec: u64, id: i32) {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_touch_up(self.id, time_usec, id);
|
||||
});
|
||||
self.touch_owner.up(self, time_usec, id);
|
||||
}
|
||||
|
||||
fn touch_motion(
|
||||
self: &Rc<Self>,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
rect: Rect,
|
||||
x_normed: Fixed,
|
||||
y_normed: Fixed,
|
||||
) {
|
||||
self.cursor_group().deactivate();
|
||||
let x = Fixed::from_f64(rect.x1() as f64 + rect.width() as f64 * x_normed.to_f64());
|
||||
let y = Fixed::from_f64(rect.y1() as f64 + rect.height() as f64 * y_normed.to_f64());
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_touch_motion(self.id, time_usec, id, x, y);
|
||||
});
|
||||
self.touch_owner.motion(self, time_usec, id, x, y);
|
||||
}
|
||||
|
||||
fn touch_cancel(self: &Rc<Self>, time_usec: u64, id: i32) {
|
||||
self.state.for_each_seat_tester(|t| {
|
||||
t.send_touch_cancel(self.id, time_usec, id);
|
||||
});
|
||||
self.touch_owner.cancel(self);
|
||||
}
|
||||
|
||||
fn touch_frame(self: &Rc<Self>) {
|
||||
self.touch_owner.frame(self);
|
||||
}
|
||||
|
||||
pub(super) fn key_event<F>(
|
||||
self: &Rc<Self>,
|
||||
time_usec: u64,
|
||||
|
|
@ -744,7 +835,7 @@ impl WlSeatGlobal {
|
|||
self.kb_owner.set_kb_node(self, node);
|
||||
}
|
||||
|
||||
fn for_each_seat<C>(&self, ver: Version, client: ClientId, mut f: C)
|
||||
pub(super) fn for_each_seat<C>(&self, ver: Version, client: ClientId, mut f: C)
|
||||
where
|
||||
C: FnMut(&Rc<WlSeat>),
|
||||
{
|
||||
|
|
@ -794,6 +885,18 @@ impl WlSeatGlobal {
|
|||
})
|
||||
}
|
||||
|
||||
fn for_each_touch<C>(&self, ver: Version, client: ClientId, mut f: C)
|
||||
where
|
||||
C: FnMut(&Rc<WlTouch>),
|
||||
{
|
||||
self.for_each_seat(ver, client, |seat| {
|
||||
let touches = seat.touches.lock();
|
||||
for touch in touches.values() {
|
||||
f(touch);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn for_each_data_device<C>(&self, ver: Version, client: ClientId, mut f: C)
|
||||
where
|
||||
C: FnMut(&Rc<WlDataDevice>),
|
||||
|
|
@ -869,6 +972,16 @@ impl WlSeatGlobal {
|
|||
// client.flush();
|
||||
}
|
||||
|
||||
pub fn surface_touch_event<F>(&self, ver: Version, surface: &WlSurface, mut f: F)
|
||||
where
|
||||
F: FnMut(&Rc<WlTouch>),
|
||||
{
|
||||
let client = &surface.client;
|
||||
self.for_each_touch(ver, client.id, |p| {
|
||||
f(p);
|
||||
});
|
||||
}
|
||||
|
||||
fn cursor_moved(self: &Rc<Self>, time_usec: u64) {
|
||||
self.pos_time_usec.set(time_usec);
|
||||
self.changes.or_assign(CHANGE_CURSOR_MOVED);
|
||||
|
|
@ -1133,6 +1246,53 @@ impl WlSeatGlobal {
|
|||
}
|
||||
}
|
||||
|
||||
// Touch callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn touch_down_surface(
|
||||
self: &Rc<Self>,
|
||||
surface: &WlSurface,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
let serial = surface.client.next_serial();
|
||||
let time = (time_usec / 1000) as _;
|
||||
self.surface_touch_event(Version::ALL, surface, |t| {
|
||||
t.send_down(serial, time, surface.id, id, x, y)
|
||||
});
|
||||
if let Some(node) = surface.get_focus_node(self.id) {
|
||||
self.focus_node(node);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn touch_up_surface(&self, surface: &WlSurface, time_usec: u64, id: i32) {
|
||||
let serial = surface.client.next_serial();
|
||||
let time = (time_usec / 1000) as _;
|
||||
self.surface_touch_event(Version::ALL, surface, |t| t.send_up(serial, time, id))
|
||||
}
|
||||
|
||||
pub fn touch_motion_surface(
|
||||
&self,
|
||||
surface: &WlSurface,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
let time = (time_usec / 1000) as _;
|
||||
self.surface_touch_event(Version::ALL, surface, |t| t.send_motion(time, id, x, y));
|
||||
}
|
||||
|
||||
pub fn touch_frame_surface(&self, surface: &WlSurface) {
|
||||
self.surface_touch_event(Version::ALL, surface, |t| t.send_frame())
|
||||
}
|
||||
|
||||
pub fn touch_cancel_surface(&self, surface: &WlSurface) {
|
||||
self.surface_touch_event(Version::ALL, surface, |t| t.send_cancel())
|
||||
}
|
||||
}
|
||||
|
||||
// Dnd callbacks
|
||||
impl WlSeatGlobal {
|
||||
pub fn dnd_surface_leave(&self, surface: &WlSurface, dnd: &Dnd) {
|
||||
|
|
|
|||
167
src/ifs/wl_seat/touch_owner.rs
Normal file
167
src/ifs/wl_seat/touch_owner.rs
Normal file
|
|
@ -0,0 +1,167 @@
|
|||
use {
|
||||
crate::{
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::WlSeatGlobal,
|
||||
tree::{FindTreeUsecase, FoundNode, Node},
|
||||
utils::{clonecell::CloneCell, smallmap::SmallMap},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub struct TouchOwnerHolder {
|
||||
default: Rc<DefaultTouchOwner>,
|
||||
owner: CloneCell<Rc<dyn TouchOwner>>,
|
||||
}
|
||||
|
||||
impl Default for TouchOwnerHolder {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
default: Rc::new(DefaultTouchOwner),
|
||||
owner: CloneCell::new(Rc::new(DefaultTouchOwner)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchOwnerHolder {
|
||||
pub fn down(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
self.owner.get().down(seat, time_usec, id, x, y)
|
||||
}
|
||||
|
||||
pub fn up(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
|
||||
self.owner.get().up(seat, time_usec, id)
|
||||
}
|
||||
|
||||
pub fn motion(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
self.owner.get().motion(seat, time_usec, id, x, y)
|
||||
}
|
||||
|
||||
pub fn frame(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.owner.get().frame(seat)
|
||||
}
|
||||
|
||||
pub fn cancel(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.owner.get().cancel(seat)
|
||||
}
|
||||
|
||||
pub fn clear(&self) {
|
||||
self.set_default_owner();
|
||||
}
|
||||
|
||||
fn set_default_owner(&self) {
|
||||
self.owner.set(self.default.clone());
|
||||
}
|
||||
}
|
||||
|
||||
struct DefaultTouchOwner;
|
||||
|
||||
struct GrabTouchOwner {
|
||||
node: Rc<dyn Node>,
|
||||
down_ids: SmallMap<i32, (), 10>,
|
||||
}
|
||||
|
||||
trait TouchOwner {
|
||||
fn down(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed);
|
||||
fn up(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32);
|
||||
fn motion(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed);
|
||||
fn frame(&self, seat: &Rc<WlSeatGlobal>);
|
||||
fn cancel(&self, seat: &Rc<WlSeatGlobal>);
|
||||
}
|
||||
|
||||
impl TouchOwner for DefaultTouchOwner {
|
||||
fn down(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
let mut found_tree = seat.found_tree.borrow_mut();
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
found_tree.push(FoundNode {
|
||||
node: seat.state.root.clone(),
|
||||
x: x_int,
|
||||
y: y_int,
|
||||
});
|
||||
seat.state
|
||||
.root
|
||||
.node_find_tree_at(x_int, y_int, &mut found_tree, FindTreeUsecase::None);
|
||||
let node = found_tree.pop();
|
||||
found_tree.clear();
|
||||
drop(found_tree);
|
||||
if let Some(node) = node {
|
||||
node.node.node_seat_state().touch_begin(seat);
|
||||
let owner = Rc::new(GrabTouchOwner {
|
||||
node: node.node,
|
||||
down_ids: Default::default(),
|
||||
});
|
||||
seat.touch_owner.owner.set(owner.clone());
|
||||
owner.down(seat, time_usec, id, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
fn up(&self, _seat: &Rc<WlSeatGlobal>, _time_usec: u64, _id: i32) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn motion(&self, _seat: &Rc<WlSeatGlobal>, _time_usec: u64, _id: i32, _x: Fixed, _y: Fixed) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn frame(&self, _seat: &Rc<WlSeatGlobal>) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
fn cancel(&self, _seat: &Rc<WlSeatGlobal>) {
|
||||
// nothing
|
||||
}
|
||||
}
|
||||
|
||||
impl GrabTouchOwner {
|
||||
fn translate(&self, x: Fixed, y: Fixed) -> (Fixed, Fixed) {
|
||||
let x_int = x.round_down();
|
||||
let y_int = y.round_down();
|
||||
let (x_int, y_int) = self.node.node_absolute_position().translate(x_int, y_int);
|
||||
(x.apply_fract(x_int), y.apply_fract(y_int))
|
||||
}
|
||||
|
||||
fn revert_to_default(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.node.node_seat_state().touch_end(seat);
|
||||
seat.touch_owner.set_default_owner();
|
||||
}
|
||||
}
|
||||
|
||||
impl TouchOwner for GrabTouchOwner {
|
||||
fn down(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
if self.down_ids.insert(id, ()).is_some() {
|
||||
return;
|
||||
}
|
||||
let (x, y) = self.translate(x, y);
|
||||
self.node
|
||||
.clone()
|
||||
.node_on_touch_down(seat, time_usec, id, x, y);
|
||||
}
|
||||
|
||||
fn up(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
|
||||
if self.down_ids.remove(&id).is_none() {
|
||||
return;
|
||||
}
|
||||
self.node.clone().node_on_touch_up(seat, time_usec, id);
|
||||
}
|
||||
|
||||
fn motion(&self, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32, x: Fixed, y: Fixed) {
|
||||
if !self.down_ids.contains(&id) {
|
||||
return;
|
||||
}
|
||||
let (x, y) = self.translate(x, y);
|
||||
self.node
|
||||
.clone()
|
||||
.node_on_touch_motion(seat, time_usec, id, x, y);
|
||||
}
|
||||
|
||||
fn frame(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.node.node_on_touch_frame(seat);
|
||||
if self.down_ids.is_empty() {
|
||||
self.revert_to_default(seat);
|
||||
}
|
||||
}
|
||||
|
||||
fn cancel(&self, seat: &Rc<WlSeatGlobal>) {
|
||||
self.node.node_on_touch_cancel(seat);
|
||||
self.revert_to_default(seat);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +1,20 @@
|
|||
use {
|
||||
crate::{
|
||||
client::ClientError,
|
||||
fixed::Fixed,
|
||||
ifs::wl_seat::WlSeat,
|
||||
leaks::Tracker,
|
||||
object::Object,
|
||||
wire::{wl_touch::*, WlTouchId},
|
||||
object::{Object, Version},
|
||||
wire::{wl_touch::*, WlSurfaceId, WlTouchId},
|
||||
},
|
||||
std::rc::Rc,
|
||||
thiserror::Error,
|
||||
};
|
||||
|
||||
#[allow(dead_code)]
|
||||
const DOWN: u32 = 0;
|
||||
pub const SHAPE_SINCE_VERSION: Version = Version(6);
|
||||
#[allow(dead_code)]
|
||||
const UP: u32 = 1;
|
||||
#[allow(dead_code)]
|
||||
const MOTION: u32 = 2;
|
||||
#[allow(dead_code)]
|
||||
const FRAME: u32 = 3;
|
||||
#[allow(dead_code)]
|
||||
const CANCEL: u32 = 4;
|
||||
#[allow(dead_code)]
|
||||
const SHAPE: u32 = 5;
|
||||
#[allow(dead_code)]
|
||||
const ORIENTATION: u32 = 6;
|
||||
pub const ORIENTATION_DIRECTION_SINCE_VERSION: Version = Version(6);
|
||||
|
||||
pub struct WlTouch {
|
||||
id: WlTouchId,
|
||||
|
|
@ -39,12 +30,79 @@ impl WlTouch {
|
|||
tracker: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_down(
|
||||
&self,
|
||||
serial: u32,
|
||||
time: u32,
|
||||
surface: WlSurfaceId,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
self.seat.client.event(Down {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
time,
|
||||
surface,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send_up(&self, serial: u32, time: u32, id: i32) {
|
||||
self.seat.client.event(Up {
|
||||
self_id: self.id,
|
||||
serial,
|
||||
time,
|
||||
id,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send_motion(&self, time: u32, id: i32, x: Fixed, y: Fixed) {
|
||||
self.seat.client.event(Motion {
|
||||
self_id: self.id,
|
||||
time,
|
||||
id,
|
||||
x,
|
||||
y,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn send_frame(&self) {
|
||||
self.seat.client.event(Frame { self_id: self.id })
|
||||
}
|
||||
|
||||
pub fn send_cancel(&self) {
|
||||
self.seat.client.event(Cancel { self_id: self.id })
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn send_shape(&self, id: i32, major: Fixed, minor: Fixed) {
|
||||
self.seat.client.event(Shape {
|
||||
self_id: self.id,
|
||||
id,
|
||||
major,
|
||||
minor,
|
||||
})
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn send_orientation(&self, id: i32, orientation: Fixed) {
|
||||
self.seat.client.event(Orientation {
|
||||
self_id: self.id,
|
||||
id,
|
||||
orientation,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl WlTouchRequestHandler for WlTouch {
|
||||
type Error = WlTouchError;
|
||||
|
||||
fn release(&self, _req: Release, _slf: &Rc<Self>) -> Result<(), Self::Error> {
|
||||
self.seat.touches.remove(&self.id);
|
||||
self.seat.client.remove_obj(self)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1643,6 +1643,40 @@ impl Node for WlSurface {
|
|||
seat.mods_surface(self, kb_state);
|
||||
}
|
||||
|
||||
fn node_on_touch_down(
|
||||
self: Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
seat.touch_down_surface(&self, time_usec, id, x, y)
|
||||
}
|
||||
|
||||
fn node_on_touch_up(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
|
||||
seat.touch_up_surface(&self, time_usec, id)
|
||||
}
|
||||
|
||||
fn node_on_touch_motion(
|
||||
self: Rc<Self>,
|
||||
seat: &WlSeatGlobal,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
seat.touch_motion_surface(&self, time_usec, id, x, y)
|
||||
}
|
||||
|
||||
fn node_on_touch_frame(&self, seat: &WlSeatGlobal) {
|
||||
seat.touch_frame_surface(&self)
|
||||
}
|
||||
|
||||
fn node_on_touch_cancel(&self, seat: &WlSeatGlobal) {
|
||||
seat.touch_cancel_surface(&self)
|
||||
}
|
||||
|
||||
fn node_on_button(
|
||||
self: Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@ use {
|
|||
libinput_device, libinput_device_config_accel_get_profile,
|
||||
libinput_device_config_accel_get_speed, libinput_device_config_accel_is_available,
|
||||
libinput_device_config_accel_set_profile, libinput_device_config_accel_set_speed,
|
||||
libinput_device_config_left_handed_get,
|
||||
libinput_device_config_calibration_get_matrix,
|
||||
libinput_device_config_calibration_has_matrix,
|
||||
libinput_device_config_calibration_set_matrix, libinput_device_config_left_handed_get,
|
||||
libinput_device_config_left_handed_is_available,
|
||||
libinput_device_config_left_handed_set,
|
||||
libinput_device_config_scroll_get_natural_scroll_enabled,
|
||||
|
|
@ -265,6 +267,25 @@ impl<'a> LibInputDevice<'a> {
|
|||
_phantom: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_calibration_matrix(&self) -> bool {
|
||||
unsafe { libinput_device_config_calibration_has_matrix(self.dev) != 0 }
|
||||
}
|
||||
|
||||
pub fn set_calibration_matrix(&self, m: [[f32; 3]; 2]) {
|
||||
let m = [m[0][0], m[0][1], m[0][2], m[1][0], m[1][1], m[1][2]];
|
||||
unsafe {
|
||||
libinput_device_config_calibration_set_matrix(self.dev, &m);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_calibration_matrix(&self) -> [[f32; 3]; 2] {
|
||||
let mut m = [0.0; 6];
|
||||
unsafe {
|
||||
libinput_device_config_calibration_get_matrix(self.dev, &mut m);
|
||||
}
|
||||
[[m[0], m[1], m[2]], [m[3], m[4], m[5]]]
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LibInputDeviceGroup<'a> {
|
||||
|
|
|
|||
|
|
@ -16,17 +16,17 @@ use {
|
|||
libinput_event_get_gesture_event, libinput_event_get_keyboard_event,
|
||||
libinput_event_get_pointer_event, libinput_event_get_switch_event,
|
||||
libinput_event_get_tablet_pad_event, libinput_event_get_tablet_tool_event,
|
||||
libinput_event_get_type, libinput_event_keyboard, libinput_event_keyboard_get_key,
|
||||
libinput_event_keyboard_get_key_state, libinput_event_keyboard_get_time_usec,
|
||||
libinput_event_pointer, libinput_event_pointer_get_button,
|
||||
libinput_event_pointer_get_button_state, libinput_event_pointer_get_dx,
|
||||
libinput_event_pointer_get_dx_unaccelerated, libinput_event_pointer_get_dy,
|
||||
libinput_event_pointer_get_dy_unaccelerated, libinput_event_pointer_get_scroll_value,
|
||||
libinput_event_pointer_get_scroll_value_v120, libinput_event_pointer_get_time_usec,
|
||||
libinput_event_pointer_has_axis, libinput_event_switch,
|
||||
libinput_event_switch_get_switch, libinput_event_switch_get_switch_state,
|
||||
libinput_event_switch_get_time_usec, libinput_event_tablet_pad,
|
||||
libinput_event_tablet_pad_get_button_number,
|
||||
libinput_event_get_touch_event, libinput_event_get_type, libinput_event_keyboard,
|
||||
libinput_event_keyboard_get_key, libinput_event_keyboard_get_key_state,
|
||||
libinput_event_keyboard_get_time_usec, libinput_event_pointer,
|
||||
libinput_event_pointer_get_button, libinput_event_pointer_get_button_state,
|
||||
libinput_event_pointer_get_dx, libinput_event_pointer_get_dx_unaccelerated,
|
||||
libinput_event_pointer_get_dy, libinput_event_pointer_get_dy_unaccelerated,
|
||||
libinput_event_pointer_get_scroll_value, libinput_event_pointer_get_scroll_value_v120,
|
||||
libinput_event_pointer_get_time_usec, libinput_event_pointer_has_axis,
|
||||
libinput_event_switch, libinput_event_switch_get_switch,
|
||||
libinput_event_switch_get_switch_state, libinput_event_switch_get_time_usec,
|
||||
libinput_event_tablet_pad, libinput_event_tablet_pad_get_button_number,
|
||||
libinput_event_tablet_pad_get_button_state, libinput_event_tablet_pad_get_mode,
|
||||
libinput_event_tablet_pad_get_mode_group, libinput_event_tablet_pad_get_ring_number,
|
||||
libinput_event_tablet_pad_get_ring_position, libinput_event_tablet_pad_get_ring_source,
|
||||
|
|
@ -40,10 +40,12 @@ use {
|
|||
libinput_event_tablet_tool_get_tool,
|
||||
libinput_event_tablet_tool_get_wheel_delta_discrete,
|
||||
libinput_event_tablet_tool_get_x_transformed,
|
||||
libinput_event_tablet_tool_get_y_transformed, libinput_tablet_tool,
|
||||
libinput_tablet_tool_get_serial, libinput_tablet_tool_get_tool_id,
|
||||
libinput_tablet_tool_get_type, libinput_tablet_tool_get_user_data,
|
||||
libinput_tablet_tool_set_user_data,
|
||||
libinput_event_tablet_tool_get_y_transformed, libinput_event_touch,
|
||||
libinput_event_touch_get_seat_slot, libinput_event_touch_get_time_usec,
|
||||
libinput_event_touch_get_x_transformed, libinput_event_touch_get_y_transformed,
|
||||
libinput_tablet_tool, libinput_tablet_tool_get_serial,
|
||||
libinput_tablet_tool_get_tool_id, libinput_tablet_tool_get_type,
|
||||
libinput_tablet_tool_get_user_data, libinput_tablet_tool_set_user_data,
|
||||
},
|
||||
},
|
||||
std::marker::PhantomData,
|
||||
|
|
@ -89,6 +91,11 @@ pub struct LibInputTabletTool<'a> {
|
|||
pub(super) _phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
pub struct LibInputEventTouch<'a> {
|
||||
pub(super) event: *mut libinput_event_touch,
|
||||
pub(super) _phantom: PhantomData<&'a ()>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for LibInputEvent<'a> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
|
|
@ -155,6 +162,11 @@ impl<'a> LibInputEvent<'a> {
|
|||
LibInputEventTabletPad,
|
||||
libinput_event_get_tablet_pad_event
|
||||
);
|
||||
converter!(
|
||||
touch_event,
|
||||
LibInputEventTouch,
|
||||
libinput_event_get_touch_event
|
||||
);
|
||||
}
|
||||
|
||||
impl<'a> LibInputEventKeyboard<'a> {
|
||||
|
|
@ -467,3 +479,29 @@ impl<'a> LibInputEventTabletPad<'a> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LibInputEventTouch<'a> {
|
||||
pub fn seat_slot(&self) -> i32 {
|
||||
unsafe { libinput_event_touch_get_seat_slot(self.event) }
|
||||
}
|
||||
|
||||
// pub fn x(&self) -> f64 {
|
||||
// unsafe { libinput_event_touch_get_x(self.event) }
|
||||
// }
|
||||
//
|
||||
// pub fn y(&self) -> f64 {
|
||||
// unsafe { libinput_event_touch_get_y(self.event) }
|
||||
// }
|
||||
|
||||
pub fn x_transformed(&self, width: u32) -> f64 {
|
||||
unsafe { libinput_event_touch_get_x_transformed(self.event, width) }
|
||||
}
|
||||
|
||||
pub fn y_transformed(&self, height: u32) -> f64 {
|
||||
unsafe { libinput_event_touch_get_y_transformed(self.event, height) }
|
||||
}
|
||||
|
||||
pub fn time_usec(&self) -> u64 {
|
||||
unsafe { libinput_event_touch_get_time_usec(self.event) }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ pub struct libinput_tablet_pad_mode_group(u8);
|
|||
pub struct libinput_tablet_tool(u8);
|
||||
// #[repr(transparent)]
|
||||
// pub struct libinput_tablet_pad(u8);
|
||||
#[repr(transparent)]
|
||||
pub struct libinput_event_touch(u8);
|
||||
|
||||
#[link(name = "input")]
|
||||
extern "C" {
|
||||
|
|
@ -357,6 +359,29 @@ extern "C" {
|
|||
// group: *mut libinput_tablet_pad_mode_group,
|
||||
// button: c::c_uint,
|
||||
// ) -> c::c_int;
|
||||
|
||||
pub fn libinput_event_get_touch_event(event: *mut libinput_event) -> *mut libinput_event_touch;
|
||||
pub fn libinput_event_touch_get_seat_slot(event: *mut libinput_event_touch) -> i32;
|
||||
pub fn libinput_event_touch_get_time_usec(event: *mut libinput_event_touch) -> u64;
|
||||
// pub fn libinput_event_touch_get_x(event: *mut libinput_event_touch) -> f64;
|
||||
pub fn libinput_event_touch_get_x_transformed(
|
||||
event: *mut libinput_event_touch,
|
||||
width: u32,
|
||||
) -> f64;
|
||||
// pub fn libinput_event_touch_get_y(event: *mut libinput_event_touch) -> f64;
|
||||
pub fn libinput_event_touch_get_y_transformed(
|
||||
event: *mut libinput_event_touch,
|
||||
height: u32,
|
||||
) -> f64;
|
||||
pub fn libinput_device_config_calibration_has_matrix(device: *mut libinput_device) -> c::c_int;
|
||||
pub fn libinput_device_config_calibration_set_matrix(
|
||||
device: *mut libinput_device,
|
||||
matrix: *const [f32; 6],
|
||||
) -> libinput_config_status;
|
||||
pub fn libinput_device_config_calibration_get_matrix(
|
||||
device: *mut libinput_device,
|
||||
matrix: *mut [f32; 6],
|
||||
) -> c::c_int;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
|
|
|
|||
|
|
@ -278,6 +278,7 @@ pub struct DeviceHandlerData {
|
|||
pub output: CloneCell<Option<Rc<OutputGlobalOpt>>>,
|
||||
pub tablet_init: Option<Box<TabletInit>>,
|
||||
pub tablet_pad_init: Option<Box<TabletPadInit>>,
|
||||
pub is_touch: bool,
|
||||
}
|
||||
|
||||
pub struct ConnectorData {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::{
|
||||
backend::InputDevice,
|
||||
backend::{InputDevice, InputDeviceCapability},
|
||||
ifs::wl_seat::PX_PER_SCROLL,
|
||||
state::{DeviceHandlerData, InputDeviceData, State},
|
||||
tasks::udev_utils::{udev_props, UdevProps},
|
||||
|
|
@ -26,6 +26,7 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
|
|||
output: Default::default(),
|
||||
tablet_init: dev.tablet_info(),
|
||||
tablet_pad_init: dev.tablet_pad_info(),
|
||||
is_touch: dev.has_capability(InputDeviceCapability::Touch),
|
||||
});
|
||||
let ae = Rc::new(AsyncEvent::default());
|
||||
let oh = DeviceHandler {
|
||||
|
|
|
|||
|
|
@ -330,7 +330,7 @@ impl ToolClient {
|
|||
self_id: s.registry,
|
||||
name: s.jay_compositor.0,
|
||||
interface: JayCompositor.name(),
|
||||
version: s.jay_compositor.1.min(3),
|
||||
version: s.jay_compositor.1.min(4),
|
||||
id: id.into(),
|
||||
});
|
||||
self.jay_compositor.set(Some(id));
|
||||
|
|
|
|||
44
src/tree.rs
44
src/tree.rs
|
|
@ -200,6 +200,50 @@ pub trait Node: 'static {
|
|||
let _ = kb_state;
|
||||
}
|
||||
|
||||
fn node_on_touch_down(
|
||||
self: Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
let _ = seat;
|
||||
let _ = time_usec;
|
||||
let _ = id;
|
||||
let _ = x;
|
||||
let _ = y;
|
||||
}
|
||||
|
||||
fn node_on_touch_up(self: Rc<Self>, seat: &Rc<WlSeatGlobal>, time_usec: u64, id: i32) {
|
||||
let _ = seat;
|
||||
let _ = time_usec;
|
||||
let _ = id;
|
||||
}
|
||||
|
||||
fn node_on_touch_motion(
|
||||
self: Rc<Self>,
|
||||
seat: &WlSeatGlobal,
|
||||
time_usec: u64,
|
||||
id: i32,
|
||||
x: Fixed,
|
||||
y: Fixed,
|
||||
) {
|
||||
let _ = seat;
|
||||
let _ = time_usec;
|
||||
let _ = id;
|
||||
let _ = x;
|
||||
let _ = y;
|
||||
}
|
||||
|
||||
fn node_on_touch_frame(&self, seat: &WlSeatGlobal) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn node_on_touch_cancel(&self, seat: &WlSeatGlobal) {
|
||||
let _ = seat;
|
||||
}
|
||||
|
||||
fn node_on_button(
|
||||
self: Rc<Self>,
|
||||
seat: &Rc<WlSeatGlobal>,
|
||||
|
|
|
|||
|
|
@ -250,6 +250,7 @@ pub struct Input {
|
|||
pub keymap: Option<ConfigKeymap>,
|
||||
pub switch_actions: AHashMap<SwitchEvent, Action>,
|
||||
pub output: Option<Option<OutputMatch>>,
|
||||
pub calibration_matrix: Option<[[f32; 3]; 2]>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
|
|
|||
|
|
@ -40,6 +40,12 @@ pub enum InputParserError {
|
|||
TwoColumns,
|
||||
#[error("Transform matrix entries must be floats")]
|
||||
Float,
|
||||
#[error("Calibration matrix must have exactly two rows")]
|
||||
CaliTwoRows,
|
||||
#[error("Calibration matrix must have exactly three columns")]
|
||||
CaliThreeColumns,
|
||||
#[error("Calibration matrix entries must be floats")]
|
||||
CaliFloat,
|
||||
}
|
||||
|
||||
pub struct InputParser<'a> {
|
||||
|
|
@ -80,6 +86,7 @@ impl<'a> Parser for InputParser<'a> {
|
|||
on_converted_to_tablet_val,
|
||||
output_val,
|
||||
remove_mapping,
|
||||
calibration_matrix,
|
||||
),
|
||||
) = ext.extract((
|
||||
(
|
||||
|
|
@ -103,6 +110,7 @@ impl<'a> Parser for InputParser<'a> {
|
|||
opt(val("on-converted-to-tablet")),
|
||||
opt(val("output")),
|
||||
recover(opt(bol("remove-mapping"))),
|
||||
recover(opt(val("calibration-matrix"))),
|
||||
),
|
||||
))?;
|
||||
let accel_profile = match accel_profile {
|
||||
|
|
@ -214,6 +222,16 @@ impl<'a> Parser for InputParser<'a> {
|
|||
output = Some(None);
|
||||
}
|
||||
}
|
||||
let calibration_matrix = match calibration_matrix {
|
||||
None => None,
|
||||
Some(matrix) => match matrix.parse(&mut CalibrationMatrixParser) {
|
||||
Ok(v) => Some(v),
|
||||
Err(e) => {
|
||||
log::warn!("Could not parse calibration matrix: {}", self.cx.error(e));
|
||||
None
|
||||
}
|
||||
},
|
||||
};
|
||||
Ok(Input {
|
||||
tag: tag.despan_into(),
|
||||
match_: match_val.parse_map(&mut InputMatchParser(self.cx))?,
|
||||
|
|
@ -229,6 +247,7 @@ impl<'a> Parser for InputParser<'a> {
|
|||
keymap,
|
||||
switch_actions,
|
||||
output,
|
||||
calibration_matrix,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -311,3 +330,45 @@ impl Parser for TransformMatrixRowParser {
|
|||
Ok([extract(&array[0])?, extract(&array[1])?])
|
||||
}
|
||||
}
|
||||
|
||||
struct CalibrationMatrixParser;
|
||||
|
||||
impl Parser for CalibrationMatrixParser {
|
||||
type Value = [[f32; 3]; 2];
|
||||
type Error = InputParserError;
|
||||
const EXPECTED: &'static [DataType] = &[DataType::Array];
|
||||
|
||||
fn parse_array(&mut self, span: Span, array: &[Spanned<Value>]) -> ParseResult<Self> {
|
||||
if array.len() != 2 {
|
||||
return Err(InputParserError::CaliTwoRows.spanned(span));
|
||||
}
|
||||
Ok([
|
||||
array[0].parse(&mut CalibrationMatrixRowParser)?,
|
||||
array[1].parse(&mut CalibrationMatrixRowParser)?,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
struct CalibrationMatrixRowParser;
|
||||
|
||||
impl Parser for CalibrationMatrixRowParser {
|
||||
type Value = [f32; 3];
|
||||
type Error = InputParserError;
|
||||
const EXPECTED: &'static [DataType] = &[DataType::Array];
|
||||
|
||||
fn parse_array(&mut self, span: Span, array: &[Spanned<Value>]) -> ParseResult<Self> {
|
||||
if array.len() != 3 {
|
||||
return Err(InputParserError::CaliThreeColumns.spanned(span));
|
||||
}
|
||||
let extract = |v: &Spanned<Value>| match v.value {
|
||||
Value::Float(f) => Ok(f as f32),
|
||||
Value::Integer(f) => Ok(f as _),
|
||||
_ => Err(InputParserError::CaliFloat.spanned(v.span)),
|
||||
};
|
||||
Ok([
|
||||
extract(&array[0])?,
|
||||
extract(&array[1])?,
|
||||
extract(&array[2])?,
|
||||
])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -437,6 +437,9 @@ impl Input {
|
|||
c.remove_mapping();
|
||||
}
|
||||
}
|
||||
if let Some(v) = self.calibration_matrix {
|
||||
c.set_calibration_matrix(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -861,6 +861,18 @@
|
|||
"remove-mapping": {
|
||||
"type": "boolean",
|
||||
"description": "Removes the mapping of from this device to an output.\n\nThis should only be used within `configure-input` actions.\n\n- Example:\n\n ```toml\n [shortcuts]\n alt-x = { type = \"configure-input\", input = { match.tag = \"wacom\", remove-mapping = true } }\n\n [[inputs]]\n tag = \"wacom\"\n match.name = \"Wacom Bamboo Comic 2FG Pen\"\n output.connector = \"DP-1\"\n ```\n"
|
||||
},
|
||||
"calibration-matrix": {
|
||||
"type": "array",
|
||||
"description": "The calibration matrix of the device. This matrix should be 2x3.\n\nSee the libinput documentation for more details.\n\n- Example: To flip the device 90 degrees:\n\n ```toml\n [[inputs]]\n calibration-matrix = [[0, 1, 0], [-1, 0, 1]]\n ```\n",
|
||||
"items": {
|
||||
"type": "array",
|
||||
"description": "",
|
||||
"items": {
|
||||
"type": "number",
|
||||
"description": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
|
|
|||
|
|
@ -1768,6 +1768,21 @@ The table has the following fields:
|
|||
|
||||
The value of this field should be a boolean.
|
||||
|
||||
- `calibration-matrix` (optional):
|
||||
|
||||
The calibration matrix of the device. This matrix should be 2x3.
|
||||
|
||||
See the libinput documentation for more details.
|
||||
|
||||
- Example: To flip the device 90 degrees:
|
||||
|
||||
```toml
|
||||
[[inputs]]
|
||||
calibration-matrix = [[0, 1, 0], [-1, 0, 1]]
|
||||
```
|
||||
|
||||
The value of this field should be an array of arrays of numbers.
|
||||
|
||||
|
||||
<a name="types-InputMatch"></a>
|
||||
### `InputMatch`
|
||||
|
|
|
|||
|
|
@ -1328,6 +1328,24 @@ Input:
|
|||
match.name = "Wacom Bamboo Comic 2FG Pen"
|
||||
output.connector = "DP-1"
|
||||
```
|
||||
calibration-matrix:
|
||||
kind: array
|
||||
items:
|
||||
kind: array
|
||||
items:
|
||||
kind: number
|
||||
required: false
|
||||
description: |
|
||||
The calibration matrix of the device. This matrix should be 2x3.
|
||||
|
||||
See the libinput documentation for more details.
|
||||
|
||||
- Example: To flip the device 90 degrees:
|
||||
|
||||
```toml
|
||||
[[inputs]]
|
||||
calibration-matrix = [[0, 1, 0], [-1, 0, 1]]
|
||||
```
|
||||
|
||||
|
||||
AccelProfile:
|
||||
|
|
|
|||
|
|
@ -114,6 +114,16 @@ request map_to_output {
|
|||
output: optstr,
|
||||
}
|
||||
|
||||
request set_calibration_matrix (since = 4) {
|
||||
id: u32,
|
||||
m00: pod(f32),
|
||||
m01: pod(f32),
|
||||
m02: pod(f32),
|
||||
m10: pod(f32),
|
||||
m11: pod(f32),
|
||||
m12: pod(f32),
|
||||
}
|
||||
|
||||
# events
|
||||
|
||||
event seat {
|
||||
|
|
@ -158,3 +168,12 @@ event input_device_output {
|
|||
id: u32,
|
||||
output: str,
|
||||
}
|
||||
|
||||
event calibration_matrix (since = 4) {
|
||||
m00: pod(f32),
|
||||
m01: pod(f32),
|
||||
m02: pod(f32),
|
||||
m10: pod(f32),
|
||||
m11: pod(f32),
|
||||
m12: pod(f32),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -239,3 +239,31 @@ event tablet_pad_ring_frame {
|
|||
input_device: u32,
|
||||
ring: u32,
|
||||
}
|
||||
|
||||
event touch_down {
|
||||
seat: u32,
|
||||
time_usec: pod(u64),
|
||||
id: i32,
|
||||
x: fixed,
|
||||
y: fixed,
|
||||
}
|
||||
|
||||
event touch_up {
|
||||
seat: u32,
|
||||
time_usec: pod(u64),
|
||||
id: i32,
|
||||
}
|
||||
|
||||
event touch_motion {
|
||||
seat: u32,
|
||||
time_usec: pod(u64),
|
||||
id: i32,
|
||||
x: fixed,
|
||||
y: fixed,
|
||||
}
|
||||
|
||||
event touch_cancel {
|
||||
seat: u32,
|
||||
time_usec: pod(u64),
|
||||
id: i32,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ event up {
|
|||
|
||||
event motion {
|
||||
time: u32,
|
||||
id: u32,
|
||||
id: i32,
|
||||
x: fixed,
|
||||
y: fixed,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue