Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 155 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,17 @@ serde_yaml = "0.9.34"
tabled = { version = "0.18.0", features = ["ansi"] }
thiserror = "1.0.69"
tokio = { version = "1.43.0", features = ["full"] }
tokio-tungstenite = { version = "0.26.2" }
udev = { version = "0.9.3", features = ["mio"] }
uhid-virt = "0.0.8"
virtual-usb = { git = "https://github.com/ShadowBlip/virtual-usb-rs.git", rev = "4bca5c6fb9f2b63944a286854405e3e7e0b5d259" }
xdg = "2.5.2"
zbus = { version = "5.5.0", default-features = false, features = ["tokio"] }
zbus_macros = "5.5.0"

#[features]
#networking = ["dep:tokio-tungstenite"]

[profile.release]
debug = false
strip = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ and translate their input to a variety of virtual device formats.
- [x] Emulate mouse, keyboard, and gamepad inputs
- [x] Intercept and route input over DBus for overlay interface control
- [x] Input mapping profiles to translate source input into the desired target input
- [ ] Route input over the network
- [x] Route input over the network

## Install

Expand Down
36 changes: 36 additions & 0 deletions rootfs/usr/share/inputplumber/devices/80-websockets.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# yaml-language-server: $schema=https://raw.githubusercontent.com/ShadowBlip/InputPlumber/main/rootfs/usr/share/inputplumber/schema/composite_device_v1.json
# Schema version number
version: 1

# The type of configuration schema
kind: CompositeDevice

# Name of the composite device mapping
name: Websockets

# Maximum number of source devices per CompositeDevice.
maximum_sources: 1

# Only use this profile if *any* of the given matches matches. If this list is
# empty, then the source devices will *always* be checked.
# /sys/class/dmi/id/product_name
matches: []

# One or more source devices to combine into a single virtual device. The events
# from these devices will be watched and translated according to the key map.
source_devices:
- group: gamepad
websocket:
address: "0.0.0.0"
port: 12907

# Optional configuration for the composite device
options:
# If true, InputPlumber will automatically try to manage the input device. If
# this is false, InputPlumber will not try to manage the device unless an
# external service enables management of the device. Defaults to 'false'
auto_manage: true

# The target input device(s) to emulate by default
target_devices:
- xbox-elite
20 changes: 20 additions & 0 deletions src/cli/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use zbus::Connection;
use crate::cli::get_managed_objects;
use crate::dbus::interface::composite_device::CompositeDeviceInterfaceProxy;
use crate::dbus::interface::manager::ManagerInterfaceProxy;
use crate::dbus::interface::target::websocket::TargetWebsocketInterfaceProxy;
use crate::dbus::interface::target::TargetInterfaceProxy;
use crate::input::target::TargetDeviceTypeId;

Expand Down Expand Up @@ -42,6 +43,11 @@ pub enum DeviceCommand {
},
/// Test input menu
Test,
/// Connect this input device to a remote instance of InputPlumber
Connect {
/// URL of the remote instance of InputPlumber (e.g. "ws://192.168.0.100:12901")
url: String,
},
}

#[derive(Subcommand, Debug, Clone)]
Expand Down Expand Up @@ -286,6 +292,20 @@ pub async fn handle_device(
return Err(e.to_string().into());
}
}
DeviceCommand::Connect { url } => {
device
.set_target_devices(vec!["websocket".to_string()])
.await?;
let target_devices = device.target_devices().await?;
for path in target_devices {
let websocket = TargetWebsocketInterfaceProxy::builder(&conn)
.path(path)?
.build()
.await?;
websocket.connect(url.clone()).await?;
println!("Successfully connected to: {url}");
}
}
}

Ok(())
Expand Down
Loading