Skip to content

Commit

Permalink
feat(CompositeDevice): Add direct write to dbus interface of Composit…
Browse files Browse the repository at this point in the history
…eDevices

- Adds new function, direct_write, to the Composite Device DBus interface. This allows a third party program to bypass the translation layers when responding to dbus input events.
- Completed all pathways for Capability::from_str().
  • Loading branch information
pastaq committed Apr 21, 2024
1 parent 59462e4 commit b9bd79e
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 2 deletions.
60 changes: 59 additions & 1 deletion src/input/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,26 @@ impl FromStr for Capability {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
let parts: Vec<&str> = s.split(":").collect();
let Some((part, parts)) = parts.split_first() else {
return Err(());
};
match *part {
"None" => Ok(Capability::None),
"NotImplemented" => Ok(Capability::NotImplemented),
"Sync" => Ok(Capability::Sync),
"Gamepad" => Ok(Capability::Gamepad(Gamepad::from_str(
parts.join(":").as_str(),
)?)),
"Keyboard" => Ok(Capability::Keyboard(Keyboard::from_str(
parts.join(":").as_str(),
)?)),
"Mouse" => Ok(Capability::Mouse(Mouse::from_str(
parts.join(":").as_str(),
)?)),
"DBus" => Ok(Capability::DBus(Action::from_str(
parts.join(":").as_str(),
)?)),
_ => Err(()),
}
}
Expand Down Expand Up @@ -173,6 +189,30 @@ impl fmt::Display for Gamepad {
}
}

impl FromStr for Gamepad {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(":").collect();
let Some((part, parts)) = parts.split_first() else {
return Err(());
};
match *part {
"Button" => Ok(Gamepad::Button(GamepadButton::from_str(
parts.join(":").as_str(),
)?)),
"Axis" => Ok(Gamepad::Axis(GamepadAxis::from_str(
parts.join(":").as_str(),
)?)),
"Trigger" => Ok(Gamepad::Trigger(GamepadTrigger::from_str(
parts.join(":").as_str(),
)?)),
"Accelerometer" => Ok(Gamepad::Accelerometer),
"Gyro" => Ok(Gamepad::Gyro),
_ => Err(()),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Mouse {
/// Represents (x, y) relative mouse motion
Expand All @@ -190,6 +230,24 @@ impl fmt::Display for Mouse {
}
}

impl FromStr for Mouse {
type Err = ();

fn from_str(s: &str) -> Result<Self, Self::Err> {
let parts: Vec<&str> = s.split(":").collect();
let Some((part, parts)) = parts.split_first() else {
return Err(());
};
match *part {
"Motion" => Ok(Mouse::Motion),
"Button" => Ok(Mouse::Button(MouseButton::from_str(
parts.join(":").as_str(),
)?)),
_ => Err(()),
}
}
}

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum MouseButton {
/// Left mouse button
Expand Down
66 changes: 65 additions & 1 deletion src/input/composite_device/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{
borrow::Borrow,
collections::{BTreeSet, HashMap, HashSet},
error::Error,
str::FromStr,
};

use evdev::InputEvent;
Expand All @@ -10,7 +11,11 @@ use tokio::{
task::JoinSet,
time::Duration,
};
use zbus::{fdo, Connection};
use zbus::{
fdo,
zvariant::{self, Value},
Connection,
};
use zbus_macros::dbus_interface;

use crate::{
Expand Down Expand Up @@ -132,6 +137,65 @@ impl DBusInterface {
Ok(())
}

/// Directly write to the composite device's target devices with the given event
fn direct_write(&self, event: String, value: zvariant::Value) -> fdo::Result<()> {
let cap = Capability::from_str(event.as_str()).map_err(|_| {
fdo::Error::Failed(format!(
"Failed to parse event string {event} into capability."
))
})?;

let val = match value {
zvariant::Value::Bool(v) => InputValue::Bool(v),
zvariant::Value::F64(v) => InputValue::Float(v),
zvariant::Value::Array(v) => match v.len() {
2 => {
let x_val = v.first().unwrap();
let y_val: &Value = v.get(1).unwrap().unwrap();
let x = f64::try_from(x_val).map_err(|_| {
fdo::Error::Failed("Failed to parse x value into float.".to_string())
})?;
let y = f64::try_from(y_val).map_err(|_| {
fdo::Error::Failed("Failed to parse y value into float.".to_string())
})?;
InputValue::Vector2 {
x: Some(x),
y: Some(y),
}
}
3 => {
let x_val = v.first().unwrap();
let y_val: &Value = v.get(1).unwrap().unwrap();
let z_val: &Value = v.get(2).unwrap().unwrap();
let x = f64::try_from(x_val).map_err(|_| {
fdo::Error::Failed("Failed to parse x value into float.".to_string())
})?;
let y = f64::try_from(y_val).map_err(|_| {
fdo::Error::Failed("Failed to parse y value into float.".to_string())
})?;
let z = f64::try_from(z_val).map_err(|_| {
fdo::Error::Failed("Failed to parse z value into float.".to_string())
})?;
InputValue::Vector3 {
x: Some(x),
y: Some(y),
z: Some(z),
}
}
_ => InputValue::None,
},
_ => InputValue::None,
};

let event = NativeEvent::new(cap, val);

self.tx
.send(Command::WriteEvent(event))
.map_err(|e| fdo::Error::Failed(e.to_string()))?;

Ok(())
}

/// List of capabilities that all source devices implement
#[dbus_interface(property)]
async fn capabilities(&self) -> fdo::Result<Vec<String>> {
Expand Down

0 comments on commit b9bd79e

Please sign in to comment.