Skip to content

Commit

Permalink
feat(MouseDevice): add event translation support for target mouse dev…
Browse files Browse the repository at this point in the history
…ices
  • Loading branch information
ShadowApex committed Apr 2, 2024
1 parent 0b424aa commit d31ee84
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 6 deletions.
2 changes: 1 addition & 1 deletion src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -971,7 +971,7 @@ impl CompositeDevice {
continue;
}

let event = NativeEvent::new(target_cap, value);
let event = NativeEvent::new_translated(source_cap.clone(), target_cap, value);
events.push(event);
}

Expand Down
51 changes: 49 additions & 2 deletions src/input/event/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,40 @@ use super::{evdev::EvdevEvent, value::InputValue};
/// A native event represents an InputPlumber event
#[derive(Debug, Clone)]
pub struct NativeEvent {
/// The capability of the input event. Target input devices that implement
/// this capability will be able to emit this event.
capability: Capability,
/// Optional source capability of the input event if this event was translated
/// from one type to another. This can allow downstream target input devices
/// to have different behavior for events that have been translated from one
/// type to another.
source_capability: Option<Capability>,
/// The value of the input event.
value: InputValue,
}

impl NativeEvent {
/// Returns a new [NativeEvent] with the given capability and value
pub fn new(capability: Capability, value: InputValue) -> NativeEvent {
NativeEvent { capability, value }
NativeEvent {
capability,
value,
source_capability: None,
}
}

/// Returns a new [NativeEvent] with the original un-translated source
/// capability, the translated capability, and value.
pub fn new_translated(
source_capability: Capability,
capability: Capability,
value: InputValue,
) -> NativeEvent {
NativeEvent {
capability,
source_capability: Some(source_capability),
value,
}
}

/// Returns the capability that this event implements
Expand All @@ -24,6 +51,22 @@ impl NativeEvent {
self.value.clone()
}

/// Returns true if this event is a translated event and has a source
/// capability defined.
pub fn is_translated(&self) -> bool {
self.source_capability.is_some()
}

/// Set the source capability of the event if this is a translated event
pub fn set_source_capability(&mut self, cap: Capability) {
self.source_capability = Some(cap);
}

/// Returns the source capability that this event was translated from
pub fn get_source_capability(&self) -> Option<Capability> {
self.source_capability.clone()
}

/// Returns whether or not the event is "pressed"
pub fn pressed(&self) -> bool {
self.value.pressed()
Expand All @@ -35,6 +78,10 @@ impl From<EvdevEvent> for NativeEvent {
fn from(item: EvdevEvent) -> Self {
let capability = item.as_capability();
let value = item.get_value();
NativeEvent { capability, value }
NativeEvent {
capability,
value,
source_capability: None,
}
}
}
37 changes: 36 additions & 1 deletion src/input/event/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ impl InputValue {
},
// Axis -> Mouse
Capability::Mouse(mouse) => match mouse {
Mouse::Motion => Err(TranslationError::NotImplemented),
Mouse::Motion => self
.translate_axis_to_mouse_motion(source_config, target_config),
Mouse::Button(_) => self.translate_axis_to_button(source_config),
},
// Axis -> Keyboard
Expand All @@ -151,6 +152,40 @@ impl InputValue {
}
}

/// Translate the axis value into mouse motion
fn translate_axis_to_mouse_motion(
&self,
source_config: &CapabilityConfig,
target_config: &CapabilityConfig,
) -> Result<InputValue, TranslationError> {
// Use provided mapping to determine mouse motion value
if let Some(mouse_config) = target_config.mouse.as_ref() {
if let Some(mouse_motion) = mouse_config.motion.as_ref() {
// Get the mouse speed in pixels-per-second
let speed_pps = mouse_motion.speed_pps.unwrap_or(800);

// If a direction is defined, map only the selected directions to
// the value.
if let Some(direction) = mouse_motion.direction.as_ref() {
todo!()
}
// If no direction is defined, map all axes to the mouse values
else {
todo!()
}
} else {
Err(TranslationError::InvalidTargetConfig(
"No mouse motion config to translate axis to mouse motion".to_string(),
))
}
//
} else {
Err(TranslationError::InvalidTargetConfig(
"No mouse config to translate axis to mouse motion".to_string(),
))
}
}

/// Translate the button value into an axis value based on the given config
fn translate_button_to_axis(
&self,
Expand Down
9 changes: 7 additions & 2 deletions src/input/target/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ use std::{collections::HashMap, error::Error};

use evdev::{
uinput::{VirtualDevice, VirtualDeviceBuilder},
AbsInfo, AbsoluteAxisCode, AttributeSet, InputEvent, RelativeAxisCode, SynchronizationCode,
SynchronizationEvent,
AbsInfo, AbsoluteAxisCode, AttributeSet, InputEvent, KeyCode, RelativeAxisCode,
SynchronizationCode, SynchronizationEvent,
};
use tokio::sync::{broadcast, mpsc};
use zbus::{fdo, Connection};
Expand Down Expand Up @@ -134,8 +134,13 @@ impl MouseDevice {

/// Create the virtual device to emulate
fn create_virtual_device(&self) -> Result<VirtualDevice, Box<dyn Error>> {
let mut buttons = AttributeSet::<KeyCode>::new();
buttons.insert(KeyCode::BTN_LEFT);
buttons.insert(KeyCode::BTN_RIGHT);
buttons.insert(KeyCode::BTN_MIDDLE);
let device = VirtualDeviceBuilder::new()?
.name("InputPlumber Mouse")
.with_keys(&buttons)?
.with_relative_axes(&AttributeSet::from_iter([
RelativeAxisCode::REL_X,
RelativeAxisCode::REL_Y,
Expand Down

0 comments on commit d31ee84

Please sign in to comment.