initial commit
This commit is contained in:
commit
9744166dca
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
/target
|
203
Cargo.lock
generated
Normal file
203
Cargo.lock
generated
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "autocfg"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitflags"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bitvec"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
|
||||||
|
dependencies = [
|
||||||
|
"funty",
|
||||||
|
"radium",
|
||||||
|
"tap",
|
||||||
|
"wyz",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "byteorder"
|
||||||
|
version = "1.4.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cc"
|
||||||
|
version = "1.0.73"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "evdev"
|
||||||
|
version = "0.11.5"
|
||||||
|
dependencies = [
|
||||||
|
"bitvec",
|
||||||
|
"libc",
|
||||||
|
"nix 0.23.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "funty"
|
||||||
|
version = "2.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "libc"
|
||||||
|
version = "0.2.126"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memoffset"
|
||||||
|
version = "0.6.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.23.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f866317acbd3a240710c63f065ffb1e4fd466259045ccb504130b7f668f35c6"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cc",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.24.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "195cdbc1741b8134346d515b3a56a1c94b0912758009cfd53f99ea0f57b065fc"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"memoffset",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.40"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.20"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "radium"
|
||||||
|
version = "0.7.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "remote-evdev"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"byteorder",
|
||||||
|
"evdev",
|
||||||
|
"nix 0.24.2",
|
||||||
|
"ron",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ron"
|
||||||
|
version = "0.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "88073939a61e5b7680558e6be56b419e208420c2adb92be54921fa6b72283f1a"
|
||||||
|
dependencies = [
|
||||||
|
"base64",
|
||||||
|
"bitflags",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.139"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0171ebb889e45aa68b44aee0859b3eede84c6f5f5c228e6f140c0b2a0a46cad6"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.139"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dc1d3230c1de7932af58ad8ffbe1d784bd55efd5a9d84ac24f69c72d83543dfb"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "1.0.98"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tap"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wyz"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "30b31594f29d27036c383b53b59ed3476874d518f0efb151b27a4c275141390e"
|
||||||
|
dependencies = [
|
||||||
|
"tap",
|
||||||
|
]
|
15
Cargo.toml
Normal file
15
Cargo.toml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[package]
|
||||||
|
name = "remote-evdev"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
evdev = "0.11.4"
|
||||||
|
ron = "*"
|
||||||
|
byteorder = "1.4.3"
|
||||||
|
nix = "0.24.2"
|
||||||
|
|
||||||
|
[patch.crates-io]
|
||||||
|
evdev = { path = "evdev" }
|
92
src/config.rs
Normal file
92
src/config.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
pub struct DeviceInfo {
|
||||||
|
pub path: String,
|
||||||
|
pub device_type: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NetConfig {
|
||||||
|
pub is_server: bool,
|
||||||
|
pub is_host: bool,
|
||||||
|
pub port: i32,
|
||||||
|
pub ip_address: String
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_config() -> (NetConfig, Vec<DeviceInfo>) {
|
||||||
|
let args: Vec<String> = env::args().collect();
|
||||||
|
|
||||||
|
let mut context = "";
|
||||||
|
let mut cfg = NetConfig {
|
||||||
|
is_server: false,
|
||||||
|
is_host: true,
|
||||||
|
port: 64654,
|
||||||
|
ip_address: String::from("auto")
|
||||||
|
};
|
||||||
|
let mut devices_info = Vec::new();
|
||||||
|
for i in &args[1..] {
|
||||||
|
match i.as_str() {
|
||||||
|
"-s" | "--server" => cfg.is_server = true,
|
||||||
|
"-c" | "--client" => cfg.is_server = false,
|
||||||
|
"-h" | "--host" => cfg.is_host = true,
|
||||||
|
"-g" | "--guest" => cfg.is_host = false,
|
||||||
|
"-p" | "--port" => context = "port",
|
||||||
|
"-a" | "--ip-address" => context = "ip_address",
|
||||||
|
"-d" | "--device" => {
|
||||||
|
context = "device";
|
||||||
|
devices_info.push(DeviceInfo {
|
||||||
|
path: String::from(""),
|
||||||
|
device_type: String::from("other")
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"--id" => context = "device_id",
|
||||||
|
"--path" => context = "device_path",
|
||||||
|
"--event" => context = "device_event",
|
||||||
|
"--full-path" => context = "device_full_path",
|
||||||
|
"--type" => context = "device_type",
|
||||||
|
&_ => {
|
||||||
|
if context.starts_with("device") {
|
||||||
|
let (key, tmp) = match context {
|
||||||
|
"device_id" => ("path", "/dev/input/by-id/"),
|
||||||
|
"device_path" => ("path", "/dev/input/by-path/"),
|
||||||
|
"device_event" => ("path", "/dev/input/"),
|
||||||
|
"device_full_path" => ("path", ""),
|
||||||
|
"device_type" => {
|
||||||
|
match i.as_str() {
|
||||||
|
"pointer" | "keyboard" => ("type", ""),
|
||||||
|
&_ => panic!("Invalid device type {}!", i.as_str())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
&_ => panic!("Unknown context!")
|
||||||
|
};
|
||||||
|
let mut value = tmp.to_owned();
|
||||||
|
let mut device_info = devices_info.last_mut().unwrap();
|
||||||
|
if key == "path" {
|
||||||
|
value = format!("{}{}", value, i);
|
||||||
|
if !Path::new(value.as_str()).exists() {
|
||||||
|
panic!("Path {} does not exist!", value)
|
||||||
|
}
|
||||||
|
device_info.path = value;
|
||||||
|
} else if key == "type" {
|
||||||
|
device_info.device_type = key.to_owned();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
match context {
|
||||||
|
"port" => {
|
||||||
|
match i.parse::<i32>() {
|
||||||
|
Ok(num) => cfg.port = num,
|
||||||
|
Err(_) => panic!("Invalid port value!")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ip_address" => cfg.ip_address = i.to_owned(),
|
||||||
|
&_ => panic!("Invalid context!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.ip_address == "auto" {
|
||||||
|
panic!("Not implemented yet!")
|
||||||
|
}
|
||||||
|
return (cfg, devices_info);
|
||||||
|
}
|
21
src/epoll_struct.rs
Normal file
21
src/epoll_struct.rs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
|
|
||||||
|
pub struct Epoll(RawFd);
|
||||||
|
|
||||||
|
impl Epoll {
|
||||||
|
pub(crate) fn new(fd: RawFd) -> Self {
|
||||||
|
Epoll(fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for Epoll {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Epoll {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
let _ = nix::unistd::close(self.0);
|
||||||
|
}
|
||||||
|
}
|
55
src/handle_client/handle_guest.rs
Normal file
55
src/handle_client/handle_guest.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use std::io::prelude::*;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use byteorder::{BigEndian, ReadBytesExt};
|
||||||
|
use evdev::{
|
||||||
|
InputEvent,
|
||||||
|
uinput::VirtualDevice
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
manage_device::deserialize::{
|
||||||
|
deserialize_device::build_virtual_device,
|
||||||
|
deserialize_input_event
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn receive_device(mut stream: &TcpStream) -> std::io::Result<Option<VirtualDevice>> {
|
||||||
|
let buf_size = stream.read_u64::<BigEndian>()?;
|
||||||
|
if buf_size == 0 {
|
||||||
|
return Ok(None)
|
||||||
|
};
|
||||||
|
let mut buf = vec![0; buf_size as usize];
|
||||||
|
stream.read_exact(&mut buf)?;
|
||||||
|
let data = String::from_utf8(buf).expect("Couldn't decode utf8");
|
||||||
|
Ok(Some(build_virtual_device(data)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receive_input_event(mut stream: &TcpStream) -> std::io::Result<(usize, InputEvent)> {
|
||||||
|
Ok(
|
||||||
|
(
|
||||||
|
stream.read_u64::<BigEndian>()? as usize,
|
||||||
|
deserialize_input_event(
|
||||||
|
(
|
||||||
|
stream.read_u16::<BigEndian>()?,
|
||||||
|
stream.read_u16::<BigEndian>()?,
|
||||||
|
stream.read_i32::<BigEndian>()?
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_client(stream: TcpStream) -> std::io::Result<()>{
|
||||||
|
let mut devices = Vec::new();
|
||||||
|
while let Some(device) = receive_device(&stream)? {
|
||||||
|
devices.push(device);
|
||||||
|
}
|
||||||
|
loop {
|
||||||
|
let (device_id, input_event) = receive_input_event(&stream)?;
|
||||||
|
if device_id as u64 == u32::MAX as u64 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
devices[device_id].emit_raw(&[input_event]).expect("Couldn't emit input event");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
81
src/handle_client/handle_host/device_collection.rs
Normal file
81
src/handle_client/handle_host/device_collection.rs
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
use evdev::{Device, InputEvent};
|
||||||
|
|
||||||
|
use crate::manage_device::set_unblocking;
|
||||||
|
|
||||||
|
pub struct FetchDevicesEventsSynced<'a> {
|
||||||
|
collection: &'a mut DeviceCollection
|
||||||
|
}
|
||||||
|
|
||||||
|
impl <'a>Iterator for FetchDevicesEventsSynced<'a> {
|
||||||
|
|
||||||
|
type Item = Vec<(usize, InputEvent)>;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
let mut events = Vec::new();
|
||||||
|
for device_id in 0..self.collection.len() {
|
||||||
|
match self.collection[device_id].fetch_events() {
|
||||||
|
Ok(events_fetch) => {
|
||||||
|
for event in events_fetch {
|
||||||
|
events.push((device_id, event))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(events)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct DeviceCollection {
|
||||||
|
pub devices: Vec<Device>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceCollection {
|
||||||
|
pub fn new() -> DeviceCollection {
|
||||||
|
DeviceCollection {
|
||||||
|
devices: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, mut device: Device) {
|
||||||
|
set_unblocking(&mut device);
|
||||||
|
device.grab().expect("Couldn't grab device!");
|
||||||
|
self.devices.push(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&mut self) -> usize {
|
||||||
|
self.devices.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fetch_events(&mut self) -> FetchDevicesEventsSynced {
|
||||||
|
FetchDevicesEventsSynced {collection: self}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoIterator for DeviceCollection {
|
||||||
|
type Item = Device;
|
||||||
|
type IntoIter = std::vec::IntoIter<Self::Item>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.devices.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Index<usize> for DeviceCollection {
|
||||||
|
type Output = Device;
|
||||||
|
|
||||||
|
fn index(&self, index: usize) -> &Self::Output {
|
||||||
|
&self.devices[index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::IndexMut<usize> for DeviceCollection {
|
||||||
|
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||||
|
&mut self.devices[index]
|
||||||
|
}
|
||||||
|
}
|
62
src/handle_client/handle_host/mod.rs
Normal file
62
src/handle_client/handle_host/mod.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use std::io::prelude::*;
|
||||||
|
use std::net::TcpStream;
|
||||||
|
use evdev::{
|
||||||
|
Device,
|
||||||
|
InputEvent
|
||||||
|
};
|
||||||
|
use byteorder::{BigEndian, WriteBytesExt};
|
||||||
|
|
||||||
|
mod device_collection;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::DeviceInfo,
|
||||||
|
manage_device::serialize::{
|
||||||
|
serialize_device::serialize,
|
||||||
|
serialize_input_event
|
||||||
|
},
|
||||||
|
handle_client::handle_host::device_collection::DeviceCollection
|
||||||
|
};
|
||||||
|
|
||||||
|
fn send_device(mut stream: &TcpStream, device: &mut Device) -> std::io::Result<()>{
|
||||||
|
let buf = serialize(&device);
|
||||||
|
let buf_len = buf.as_bytes().len() as u64;
|
||||||
|
stream.write_u64::<BigEndian>(buf_len)?;
|
||||||
|
stream.write(buf.as_bytes())?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_input_event(mut stream: &TcpStream, device_id: usize, input_event: InputEvent) -> std::io::Result<()> {
|
||||||
|
let data = serialize_input_event(input_event);
|
||||||
|
stream.write_u64::<BigEndian>(device_id as u64)?;
|
||||||
|
stream.write_u16::<BigEndian>(data.0)?;
|
||||||
|
stream.write_u16::<BigEndian>(data.1)?;
|
||||||
|
stream.write_i32::<BigEndian>(data.2)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_client(mut stream: TcpStream, devices_info: &Vec<DeviceInfo>) -> std::io::Result<()>{
|
||||||
|
let mut collection = DeviceCollection::new();
|
||||||
|
for device_info in devices_info {
|
||||||
|
match Device::open(&device_info.path) {
|
||||||
|
Ok(device) => collection.push(device),
|
||||||
|
Err(_) => panic!("Couldn't open device {}", device_info.path)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for device in collection.devices.iter_mut() {
|
||||||
|
send_device(&stream, device)?;
|
||||||
|
}
|
||||||
|
stream.write_u64::<BigEndian>(0)?;
|
||||||
|
for events in collection.fetch_events() {
|
||||||
|
for (device_id, event) in events {
|
||||||
|
send_input_event(&stream, device_id, event)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stream.write_u64::<BigEndian>(u32::MAX as u64)?;
|
||||||
|
stream.write_u16::<BigEndian>(0)?;
|
||||||
|
stream.write_u16::<BigEndian>(0)?;
|
||||||
|
stream.write_i32::<BigEndian>(0)?;
|
||||||
|
for device in collection.devices.iter_mut() {
|
||||||
|
device.ungrab().expect("Couldn't ungrab device {}!");
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
14
src/handle_client/mod.rs
Normal file
14
src/handle_client/mod.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
use std::net::TcpStream;
|
||||||
|
|
||||||
|
mod handle_host;
|
||||||
|
mod handle_guest;
|
||||||
|
|
||||||
|
use crate::config::{NetConfig, DeviceInfo};
|
||||||
|
|
||||||
|
pub fn handle_client(stream: TcpStream, cfg: &NetConfig, devices_info: &Vec<DeviceInfo>) {
|
||||||
|
if cfg.is_host {
|
||||||
|
crate::handle_client::handle_host::handle_client(stream, devices_info).expect("Couldn't write to stream")
|
||||||
|
} else {
|
||||||
|
crate::handle_client::handle_guest::handle_client(stream).expect("Couldn't read from stream")
|
||||||
|
}
|
||||||
|
}
|
24
src/main.rs
Normal file
24
src/main.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#![feature(generic_associated_types)]
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod epoll_struct;
|
||||||
|
mod streams;
|
||||||
|
mod handle_client;
|
||||||
|
mod manage_device;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
config::{
|
||||||
|
get_config,
|
||||||
|
},
|
||||||
|
streams::get_streams,
|
||||||
|
handle_client::handle_client,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let (cfg, devices_info) = get_config();
|
||||||
|
let ip = format!("{}:{}", cfg.ip_address, cfg.port);
|
||||||
|
for stream in get_streams(cfg.is_server, ip) {
|
||||||
|
handle_client(stream, &cfg, &devices_info);
|
||||||
|
}
|
||||||
|
}
|
94
src/manage_device/deserialize/deserialize_device.rs
Normal file
94
src/manage_device/deserialize/deserialize_device.rs
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
use std::ops::DerefMut;
|
||||||
|
use ron::de::from_str;
|
||||||
|
use evdev::{
|
||||||
|
Key,
|
||||||
|
InputId,
|
||||||
|
SwitchType,
|
||||||
|
RelativeAxisType,
|
||||||
|
BusType,
|
||||||
|
AttributeSet,
|
||||||
|
AttributeSetRef,
|
||||||
|
uinput::{
|
||||||
|
VirtualDevice,
|
||||||
|
VirtualDeviceBuilder
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
fn deserialize_name(data: &str) -> String {
|
||||||
|
from_str(data).expect("Couldn't deserialize name!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_input_id(data: &str) -> InputId {
|
||||||
|
let vals: [u16; 4] = from_str(data).expect("Couldn't deserialize InputId!");
|
||||||
|
InputId::new(BusType(vals[0]), vals[1], vals[2], vals[3])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_supported_keys(data: &str, keys: &mut AttributeSetRef<Key>) {
|
||||||
|
let vals: Vec<u16> = from_str(data).expect("Couldn't deserialize supported keys!");
|
||||||
|
for key in vals.iter().map(|x| Key(*x)) {
|
||||||
|
keys.insert(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_supported_relative_axes(data: &str, relative_axes: &mut AttributeSetRef<RelativeAxisType>) -> Result<(), &'static str> {
|
||||||
|
match from_str::<Option<Vec<u16>>>(data).expect("Couldn't deserialize relative axes") {
|
||||||
|
Some(vals) => {
|
||||||
|
for rel_axes_type in vals.iter().map(|x| RelativeAxisType(*x)) {
|
||||||
|
relative_axes.insert(rel_axes_type);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
None => Err("No relative axes support"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize_supported_switches(data: &str, switches: &mut AttributeSetRef<SwitchType>) -> Result<(), &'static str> {
|
||||||
|
match from_str::<Option<Vec<u16>>>(data).expect("Couldn't deserialize relative axes") {
|
||||||
|
Some(vals) => {
|
||||||
|
for switch_type in vals.iter().map(|x| SwitchType(*x)) {
|
||||||
|
switches.insert(switch_type);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
None => Err("No switch support"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(
|
||||||
|
data: String,
|
||||||
|
keys: &mut AttributeSetRef<Key>,
|
||||||
|
relative_axes: &mut AttributeSetRef<RelativeAxisType>,
|
||||||
|
switches: &mut AttributeSetRef<SwitchType>
|
||||||
|
) -> (String, InputId, Result<(), &'static str>, Result<(), &'static str>) {
|
||||||
|
let de_data: [String; 5] = from_str(data.as_str()).expect("Couldn't deserialize device!");
|
||||||
|
let name = deserialize_name(de_data[0].as_str());
|
||||||
|
let input_id = deserialize_input_id(de_data[1].as_str());
|
||||||
|
deserialize_supported_keys(de_data[2].as_str(), keys);
|
||||||
|
(
|
||||||
|
name,
|
||||||
|
input_id,
|
||||||
|
deserialize_supported_relative_axes(de_data[3].as_str(), relative_axes),
|
||||||
|
deserialize_supported_switches(de_data[4].as_str(), switches)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_virtual_device(data: String) -> VirtualDevice {
|
||||||
|
let mut keys: AttributeSet<Key> = AttributeSet::new();
|
||||||
|
let mut relative_axes: AttributeSet<RelativeAxisType> = AttributeSet::new();
|
||||||
|
let mut switches: AttributeSet<SwitchType> = AttributeSet::new();
|
||||||
|
let (name, input_id, relative_axes_support, switch_support) = deserialize(data, keys.deref_mut(), relative_axes.deref_mut(), switches.deref_mut());
|
||||||
|
let mut uinput_builder = VirtualDeviceBuilder::new().expect("Couldn't create new virtual device builder!")
|
||||||
|
.name(name.as_str())
|
||||||
|
.input_id(input_id)
|
||||||
|
.with_keys(keys.deref_mut()).expect("Couldn't build virtual device with keys!");
|
||||||
|
match relative_axes_support {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(_) => uinput_builder = uinput_builder.with_relative_axes(relative_axes.deref_mut()).expect("Couldn't build virtual device with relative axes!")
|
||||||
|
}
|
||||||
|
match switch_support {
|
||||||
|
Ok(_) => {},
|
||||||
|
Err(_) => uinput_builder = uinput_builder.with_switches(switches.deref_mut()).expect("Couldn't build virtual device with switches!")
|
||||||
|
}
|
||||||
|
uinput_builder.build().expect("Couldn't build virtual device!")
|
||||||
|
}
|
10
src/manage_device/deserialize/mod.rs
Normal file
10
src/manage_device/deserialize/mod.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
use evdev::{
|
||||||
|
InputEvent,
|
||||||
|
EventType
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod deserialize_device;
|
||||||
|
|
||||||
|
pub fn deserialize_input_event(data: (u16, u16, i32)) -> InputEvent {
|
||||||
|
InputEvent::new(EventType(data.0), data.1, data.2)
|
||||||
|
}
|
35
src/manage_device/mod.rs
Normal file
35
src/manage_device/mod.rs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
use std::os::unix::io::AsRawFd;
|
||||||
|
use evdev::Device;
|
||||||
|
use nix::{
|
||||||
|
fcntl::{FcntlArg, OFlag},
|
||||||
|
sys::epoll,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod serialize;
|
||||||
|
pub mod deserialize;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
epoll_struct::Epoll,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn set_unblocking(device: &mut Device) {
|
||||||
|
let raw_fd = device.as_raw_fd();
|
||||||
|
// Set nonblocking
|
||||||
|
nix::fcntl::fcntl(raw_fd, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("Couldn't set nonblocking!");
|
||||||
|
|
||||||
|
//Create epoll handle and attach raw_fd
|
||||||
|
let epoll_fd = Epoll::new(epoll::epoll_create1(
|
||||||
|
epoll::EpollCreateFlags::EPOLL_CLOEXEC,
|
||||||
|
).expect("Couldn't create epoll handle!"));
|
||||||
|
let mut event = epoll::EpollEvent::new(epoll::EpollFlags::EPOLLIN, 0);
|
||||||
|
epoll::epoll_ctl(
|
||||||
|
epoll_fd.as_raw_fd(),
|
||||||
|
epoll::EpollOp::EpollCtlAdd,
|
||||||
|
raw_fd,
|
||||||
|
Some(&mut event),
|
||||||
|
).expect("Couldn't attach raw_fd to epoll!");
|
||||||
|
|
||||||
|
// We don't care about these, but the kernel wants to fill them.
|
||||||
|
let _events = [epoll::EpollEvent::empty(); 2];
|
||||||
|
|
||||||
|
}
|
7
src/manage_device/serialize/mod.rs
Normal file
7
src/manage_device/serialize/mod.rs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
use evdev::InputEvent;
|
||||||
|
|
||||||
|
pub mod serialize_device;
|
||||||
|
|
||||||
|
pub fn serialize_input_event(event: InputEvent) -> (u16, u16, i32) {
|
||||||
|
(event.event_type().0, event.code(), event.value())
|
||||||
|
}
|
60
src/manage_device/serialize/serialize_device.rs
Normal file
60
src/manage_device/serialize/serialize_device.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use ron::ser::to_string;
|
||||||
|
use evdev::Device;
|
||||||
|
|
||||||
|
fn serialize_name(device: &Device) -> String {
|
||||||
|
to_string(
|
||||||
|
device.name().unwrap()
|
||||||
|
).expect("Error serializing name!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_input_id(device: &Device) -> String {
|
||||||
|
let input_id = device.input_id();
|
||||||
|
to_string(
|
||||||
|
&[
|
||||||
|
input_id.bus_type().0,
|
||||||
|
input_id.vendor(),
|
||||||
|
input_id.product(),
|
||||||
|
input_id.version()
|
||||||
|
]
|
||||||
|
).expect("Error serializing InputId!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_supported_keys(device: &Device) -> String {
|
||||||
|
to_string(
|
||||||
|
&device.supported_keys().unwrap().iter().map(|x| x.0).collect::<Vec<u16>>()
|
||||||
|
).expect("Error serializing supported_keys!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_supported_relative_axes(device: &Device) -> String {
|
||||||
|
to_string::<Option<Vec<u16>>>(
|
||||||
|
&match device.supported_relative_axes() {
|
||||||
|
Some(relative_axes) => Some(
|
||||||
|
relative_axes.iter().map(|x| x.0).collect::<Vec<u16>>()
|
||||||
|
),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
).expect("Error serializing supported_relative_axes!")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_supported_switches(device: &Device) -> String {
|
||||||
|
to_string::<Option<Vec<u16>>>(
|
||||||
|
&match device.supported_switches() {
|
||||||
|
Some(switches) => Some(
|
||||||
|
switches.iter().map(|x| x.0).collect::<Vec<u16>>()
|
||||||
|
),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
).expect("Error serializing supported_switches!")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize(device: &Device) -> String {
|
||||||
|
to_string(
|
||||||
|
&[
|
||||||
|
serialize_name(device),
|
||||||
|
serialize_input_id(device),
|
||||||
|
serialize_supported_keys(device),
|
||||||
|
serialize_supported_relative_axes(device),
|
||||||
|
serialize_supported_switches(device)
|
||||||
|
]
|
||||||
|
).expect("Error serializing device!")
|
||||||
|
}
|
55
src/streams.rs
Normal file
55
src/streams.rs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
use std::net::{TcpListener, TcpStream};
|
||||||
|
|
||||||
|
pub struct StreamIter {
|
||||||
|
ip: String,
|
||||||
|
is_server: bool,
|
||||||
|
listener: Option<TcpListener>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Iterator for StreamIter {
|
||||||
|
|
||||||
|
type Item = TcpStream;
|
||||||
|
|
||||||
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
|
if self.is_server {
|
||||||
|
let mut incoming = match self.listener.as_mut() {
|
||||||
|
Some(listener) => listener.incoming(),
|
||||||
|
None => {
|
||||||
|
self.listener = Some(match TcpListener::bind(self.ip.as_str()) {
|
||||||
|
Ok(listener) => listener,
|
||||||
|
Err(_) => panic!("Unable to bind to {}", self.ip)
|
||||||
|
});
|
||||||
|
self.listener.as_mut().unwrap().incoming()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("Waiting for connection from client");
|
||||||
|
match incoming.next() {
|
||||||
|
Some(stream) => match stream {
|
||||||
|
Ok(client) => {
|
||||||
|
println!("Connection established");
|
||||||
|
Some(client)
|
||||||
|
},
|
||||||
|
Err(_) => panic!("Unable to get stream")
|
||||||
|
},
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Connecting to server");
|
||||||
|
match TcpStream::connect(self.ip.as_str()) {
|
||||||
|
Ok(client) => {
|
||||||
|
println!("Connection established");
|
||||||
|
Some(client)
|
||||||
|
},
|
||||||
|
Err(_) => panic!("Unable to connect to {}:", self.ip)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_streams(is_server: bool, ip: String) -> StreamIter {
|
||||||
|
StreamIter {
|
||||||
|
ip,
|
||||||
|
is_server,
|
||||||
|
listener: None,
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user