1use pinnacle_api_defs::pinnacle::input::{
8 self,
9 v1::{
10 set_device_libinput_setting_request::Setting, set_device_map_target_request::Target,
11 GetDeviceCapabilitiesRequest, GetDeviceInfoRequest, GetDeviceTypeRequest,
12 GetDevicesRequest, SetDeviceLibinputSettingRequest, SetDeviceMapTargetRequest,
13 },
14};
15
16use crate::{client::Client, output::OutputHandle, signal::InputSignal, util::Rect, BlockOnTokio};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
20pub enum AccelProfile {
21 Flat,
25 Adaptive,
29}
30
31impl From<AccelProfile> for input::v1::AccelProfile {
32 fn from(value: AccelProfile) -> Self {
33 match value {
34 AccelProfile::Flat => input::v1::AccelProfile::Flat,
35 AccelProfile::Adaptive => input::v1::AccelProfile::Adaptive,
36 }
37 }
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43pub enum ClickMethod {
44 ButtonAreas,
46 Clickfinger,
48}
49
50impl From<ClickMethod> for input::v1::ClickMethod {
51 fn from(value: ClickMethod) -> Self {
52 match value {
53 ClickMethod::ButtonAreas => input::v1::ClickMethod::ButtonAreas,
54 ClickMethod::Clickfinger => input::v1::ClickMethod::ClickFinger,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
61pub enum ScrollMethod {
62 NoScroll,
66 TwoFinger,
68 Edge,
70 OnButtonDown,
72}
73
74impl From<ScrollMethod> for input::v1::ScrollMethod {
75 fn from(value: ScrollMethod) -> Self {
76 match value {
77 ScrollMethod::NoScroll => input::v1::ScrollMethod::NoScroll,
78 ScrollMethod::TwoFinger => input::v1::ScrollMethod::TwoFinger,
79 ScrollMethod::Edge => input::v1::ScrollMethod::Edge,
80 ScrollMethod::OnButtonDown => input::v1::ScrollMethod::OnButtonDown,
81 }
82 }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
87pub enum TapButtonMap {
88 LeftRightMiddle,
90 LeftMiddleRight,
92}
93
94impl From<TapButtonMap> for input::v1::TapButtonMap {
95 fn from(value: TapButtonMap) -> Self {
96 match value {
97 TapButtonMap::LeftRightMiddle => input::v1::TapButtonMap::LeftRightMiddle,
98 TapButtonMap::LeftMiddleRight => input::v1::TapButtonMap::LeftMiddleRight,
99 }
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
105pub enum SendEventsMode {
106 Enabled,
108 Disabled,
110 DisabledOnExternalMouse,
112}
113
114impl From<SendEventsMode> for input::v1::SendEventsMode {
115 fn from(value: SendEventsMode) -> Self {
116 match value {
117 SendEventsMode::Enabled => input::v1::SendEventsMode::Enabled,
118 SendEventsMode::Disabled => input::v1::SendEventsMode::Disabled,
119 SendEventsMode::DisabledOnExternalMouse => {
120 input::v1::SendEventsMode::DisabledOnExternalMouse
121 }
122 }
123 }
124}
125
126bitflags::bitflags! {
127 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
129 pub struct Capability: u16 {
130 const KEYBOARD = 1;
132 const POINTER = 1 << 1;
134 const TOUCH = 1 << 2;
136 const TABLET_TOOL = 1 << 3;
138 const TABLET_PAD = 1 << 4;
140 const GESTURE = 1 << 5;
142 const SWITCH = 1 << 6;
144 }
145}
146
147#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
154pub enum DeviceType {
155 #[default]
157 Unknown,
158 Touchpad,
160 Trackball,
162 Trackpoint,
164 Mouse,
166 Tablet,
168 Keyboard,
170 Switch,
172}
173
174impl DeviceType {
175 #[must_use]
179 pub fn is_unknown(&self) -> bool {
180 matches!(self, Self::Unknown)
181 }
182
183 #[must_use]
187 pub fn is_touchpad(&self) -> bool {
188 matches!(self, Self::Touchpad)
189 }
190
191 #[must_use]
195 pub fn is_trackball(&self) -> bool {
196 matches!(self, Self::Trackball)
197 }
198
199 #[must_use]
203 pub fn is_trackpoint(&self) -> bool {
204 matches!(self, Self::Trackpoint)
205 }
206
207 #[must_use]
211 pub fn is_mouse(&self) -> bool {
212 matches!(self, Self::Mouse)
213 }
214
215 #[must_use]
219 pub fn is_tablet(&self) -> bool {
220 matches!(self, Self::Tablet)
221 }
222
223 #[must_use]
227 pub fn is_keyboard(&self) -> bool {
228 matches!(self, Self::Keyboard)
229 }
230
231 #[must_use]
235 pub fn is_switch(&self) -> bool {
236 matches!(self, Self::Switch)
237 }
238}
239
240impl From<input::v1::DeviceType> for DeviceType {
241 fn from(value: input::v1::DeviceType) -> Self {
242 match value {
243 input::v1::DeviceType::Unspecified => DeviceType::Unknown,
244 input::v1::DeviceType::Touchpad => DeviceType::Touchpad,
245 input::v1::DeviceType::Trackball => DeviceType::Trackball,
246 input::v1::DeviceType::Trackpoint => DeviceType::Trackpoint,
247 input::v1::DeviceType::Mouse => DeviceType::Mouse,
248 input::v1::DeviceType::Tablet => DeviceType::Tablet,
249 input::v1::DeviceType::Keyboard => DeviceType::Keyboard,
250 input::v1::DeviceType::Switch => DeviceType::Switch,
251 }
252 }
253}
254
255#[derive(Clone, PartialEq, Eq, Hash, Debug)]
257pub struct DeviceHandle {
258 pub(crate) sysname: String,
259}
260
261impl DeviceHandle {
262 pub fn capabilities(&self) -> Capability {
264 self.capabilities_async().block_on_tokio()
265 }
266
267 pub async fn capabilities_async(&self) -> Capability {
269 let caps = Client::input()
270 .get_device_capabilities(GetDeviceCapabilitiesRequest {
271 device_sysname: self.sysname.clone(),
272 })
273 .await
274 .unwrap()
275 .into_inner();
276
277 let mut capability = Capability::default();
278
279 if caps.keyboard {
280 capability |= Capability::KEYBOARD;
281 }
282 if caps.pointer {
283 capability |= Capability::POINTER;
284 }
285 if caps.touch {
286 capability |= Capability::TOUCH;
287 }
288 if caps.tablet_tool {
289 capability |= Capability::TABLET_TOOL;
290 }
291 if caps.tablet_pad {
292 capability |= Capability::TABLET_PAD;
293 }
294 if caps.gesture {
295 capability |= Capability::GESTURE;
296 }
297 if caps.switch {
298 capability |= Capability::SWITCH;
299 }
300
301 capability
302 }
303
304 pub fn name(&self) -> String {
306 self.name_async().block_on_tokio()
307 }
308
309 pub async fn name_async(&self) -> String {
311 Client::input()
312 .get_device_info(GetDeviceInfoRequest {
313 device_sysname: self.sysname.clone(),
314 })
315 .await
316 .unwrap()
317 .into_inner()
318 .name
319 }
320
321 pub fn product_id(&self) -> u32 {
323 self.product_id_async().block_on_tokio()
324 }
325
326 pub async fn product_id_async(&self) -> u32 {
328 Client::input()
329 .get_device_info(GetDeviceInfoRequest {
330 device_sysname: self.sysname.clone(),
331 })
332 .await
333 .unwrap()
334 .into_inner()
335 .product_id
336 }
337
338 pub fn vendor_id(&self) -> u32 {
340 self.vendor_id_async().block_on_tokio()
341 }
342
343 pub async fn vendor_id_async(&self) -> u32 {
345 Client::input()
346 .get_device_info(GetDeviceInfoRequest {
347 device_sysname: self.sysname.clone(),
348 })
349 .await
350 .unwrap()
351 .into_inner()
352 .vendor_id
353 }
354
355 pub fn device_type(&self) -> DeviceType {
357 self.device_type_async().block_on_tokio()
358 }
359
360 pub async fn device_type_async(&self) -> DeviceType {
362 Client::input()
363 .get_device_type(GetDeviceTypeRequest {
364 device_sysname: self.sysname.clone(),
365 })
366 .await
367 .unwrap()
368 .into_inner()
369 .device_type()
370 .into()
371 }
372
373 pub fn map_to_output(&self, output: &OutputHandle) {
383 Client::input()
384 .set_device_map_target(SetDeviceMapTargetRequest {
385 device_sysname: self.sysname.clone(),
386 target: Some(Target::OutputName(output.name())),
387 })
388 .block_on_tokio()
389 .unwrap();
390 }
391
392 pub fn map_to_region(&self, region: Rect) {
404 Client::input()
405 .set_device_map_target(SetDeviceMapTargetRequest {
406 device_sysname: self.sysname.clone(),
407 target: Some(Target::Region(region.into())),
408 })
409 .block_on_tokio()
410 .unwrap();
411 }
412
413 pub fn set_accel_profile(&self, accel_profile: AccelProfile) {
415 Client::input()
416 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
417 device_sysname: self.sysname.clone(),
418 setting: Some(Setting::AccelProfile(
419 input::v1::AccelProfile::from(accel_profile).into(),
420 )),
421 })
422 .block_on_tokio()
423 .unwrap();
424 }
425
426 pub fn set_accel_speed(&self, accel_speed: f64) {
428 Client::input()
429 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
430 device_sysname: self.sysname.clone(),
431 setting: Some(Setting::AccelSpeed(accel_speed)),
432 })
433 .block_on_tokio()
434 .unwrap();
435 }
436
437 pub fn set_calibration_matrix(&self, calibration_matrix: [f32; 6]) {
439 Client::input()
440 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
441 device_sysname: self.sysname.clone(),
442 setting: Some(Setting::CalibrationMatrix(input::v1::CalibrationMatrix {
443 matrix: calibration_matrix.to_vec(),
444 })),
445 })
446 .block_on_tokio()
447 .unwrap();
448 }
449
450 pub fn set_click_method(&self, click_method: ClickMethod) {
452 Client::input()
453 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
454 device_sysname: self.sysname.clone(),
455 setting: Some(Setting::ClickMethod(
456 input::v1::ClickMethod::from(click_method).into(),
457 )),
458 })
459 .block_on_tokio()
460 .unwrap();
461 }
462
463 pub fn set_disable_while_typing(&self, disable_while_typing: bool) {
465 Client::input()
466 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
467 device_sysname: self.sysname.clone(),
468 setting: Some(Setting::DisableWhileTyping(disable_while_typing)),
469 })
470 .block_on_tokio()
471 .unwrap();
472 }
473
474 pub fn set_left_handed(&self, left_handed: bool) {
476 Client::input()
477 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
478 device_sysname: self.sysname.clone(),
479 setting: Some(Setting::LeftHanded(left_handed)),
480 })
481 .block_on_tokio()
482 .unwrap();
483 }
484
485 pub fn set_middle_emulation(&self, middle_emulation: bool) {
487 Client::input()
488 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
489 device_sysname: self.sysname.clone(),
490 setting: Some(Setting::MiddleEmulation(middle_emulation)),
491 })
492 .block_on_tokio()
493 .unwrap();
494 }
495
496 pub fn set_rotation_angle(&self, rotation_angle: u32) {
498 Client::input()
499 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
500 device_sysname: self.sysname.clone(),
501 setting: Some(Setting::RotationAngle(rotation_angle)),
502 })
503 .block_on_tokio()
504 .unwrap();
505 }
506
507 pub fn set_scroll_button(&self, scroll_button: u32) {
509 Client::input()
510 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
511 device_sysname: self.sysname.clone(),
512 setting: Some(Setting::ScrollButton(scroll_button)),
513 })
514 .block_on_tokio()
515 .unwrap();
516 }
517
518 pub fn set_scroll_button_lock(&self, scroll_button_lock: bool) {
520 Client::input()
521 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
522 device_sysname: self.sysname.clone(),
523 setting: Some(Setting::ScrollButtonLock(scroll_button_lock)),
524 })
525 .block_on_tokio()
526 .unwrap();
527 }
528
529 pub fn set_scroll_method(&self, scroll_method: ScrollMethod) {
531 Client::input()
532 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
533 device_sysname: self.sysname.clone(),
534 setting: Some(Setting::ScrollMethod(
535 input::v1::ScrollMethod::from(scroll_method).into(),
536 )),
537 })
538 .block_on_tokio()
539 .unwrap();
540 }
541
542 pub fn set_natural_scroll(&self, natural_scroll: bool) {
544 Client::input()
545 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
546 device_sysname: self.sysname.clone(),
547 setting: Some(Setting::NaturalScroll(natural_scroll)),
548 })
549 .block_on_tokio()
550 .unwrap();
551 }
552
553 pub fn set_tap_button_map(&self, tap_button_map: TapButtonMap) {
555 Client::input()
556 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
557 device_sysname: self.sysname.clone(),
558 setting: Some(Setting::TapButtonMap(
559 input::v1::TapButtonMap::from(tap_button_map).into(),
560 )),
561 })
562 .block_on_tokio()
563 .unwrap();
564 }
565
566 pub fn set_tap_drag(&self, tap_drag: bool) {
568 Client::input()
569 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
570 device_sysname: self.sysname.clone(),
571 setting: Some(Setting::TapDrag(tap_drag)),
572 })
573 .block_on_tokio()
574 .unwrap();
575 }
576
577 pub fn set_tap_drag_lock(&self, tap_drag_lock: bool) {
579 Client::input()
580 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
581 device_sysname: self.sysname.clone(),
582 setting: Some(Setting::TapDragLock(tap_drag_lock)),
583 })
584 .block_on_tokio()
585 .unwrap();
586 }
587
588 pub fn set_tap(&self, tap: bool) {
590 Client::input()
591 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
592 device_sysname: self.sysname.clone(),
593 setting: Some(Setting::Tap(tap)),
594 })
595 .block_on_tokio()
596 .unwrap();
597 }
598
599 pub fn set_send_events_mode(&self, send_events_mode: SendEventsMode) {
601 Client::input()
602 .set_device_libinput_setting(SetDeviceLibinputSettingRequest {
603 device_sysname: self.sysname.clone(),
604 setting: Some(Setting::SendEventsMode(
605 input::v1::SendEventsMode::from(send_events_mode).into(),
606 )),
607 })
608 .block_on_tokio()
609 .unwrap();
610 }
611}
612
613pub fn get_devices() -> impl Iterator<Item = DeviceHandle> {
615 Client::input()
616 .get_devices(GetDevicesRequest {})
617 .block_on_tokio()
618 .unwrap()
619 .into_inner()
620 .device_sysnames
621 .into_iter()
622 .map(|sysname| DeviceHandle { sysname })
623}
624
625pub fn for_each_device<F: FnMut(&DeviceHandle) + Send + 'static>(mut for_all: F) {
633 for device in get_devices() {
634 for_all(&device);
635 }
636
637 super::connect_signal(InputSignal::DeviceAdded(Box::new(for_all)));
638}