129 lines
4.6 KiB
Rust
129 lines
4.6 KiB
Rust
use std::{collections::HashMap, sync::Arc, path::Path};
|
|
use tokio::sync::Mutex;
|
|
use tokio::task::JoinHandle;
|
|
use tokio_stream::StreamExt;
|
|
use evdev::{Device, EventStream, Key, uinput::VirtualDeviceBuilder};
|
|
use crate::Config;
|
|
use crate::event_reader::EventReader;
|
|
use crate::virtual_devices::VirtualDevices;
|
|
|
|
|
|
pub async fn start_monitoring_udev(config_files: Vec<Config>, mut tasks: Vec<JoinHandle<()>>) {
|
|
launch_tasks(&config_files, &mut tasks);
|
|
let mut monitor = tokio_udev::AsyncMonitorSocket::new(
|
|
tokio_udev::MonitorBuilder::new().unwrap()
|
|
.match_subsystem(std::ffi::OsStr::new("input")).unwrap()
|
|
.listen().unwrap()
|
|
).unwrap();
|
|
while let Some(Ok(event)) = monitor.next().await {
|
|
if is_mapped(&event.device(), &config_files) {
|
|
println!("Reinitializing...");
|
|
for task in &tasks {
|
|
task.abort();
|
|
}
|
|
tasks.clear();
|
|
launch_tasks(&config_files, &mut tasks)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn launch_tasks(config_files: &Vec<Config>, tasks: &mut Vec<JoinHandle<()>>) {
|
|
let devices: evdev::EnumerateDevices = evdev::enumerate();
|
|
for device in devices {
|
|
let mut config_map: HashMap<String, Config> = HashMap::new();
|
|
for config in config_files {
|
|
let split_config_name = config.name.split("::").collect::<Vec<&str>>();
|
|
let associated_device_name = split_config_name[0];
|
|
if associated_device_name == device.1.name().unwrap() {
|
|
let window_class = if split_config_name.len() == 1 {
|
|
String::from("default")
|
|
} else {
|
|
split_config_name[1].to_string()
|
|
};
|
|
config_map.insert(window_class, config.clone());
|
|
};
|
|
}
|
|
if !config_map.is_empty() {
|
|
tasks.push(
|
|
tokio::spawn(
|
|
create_new_reader(
|
|
device.0.as_path().to_str().unwrap().to_string(),
|
|
config_map.clone()
|
|
)
|
|
)
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
pub async fn create_new_reader(device: String, config: HashMap<String, Config>) {
|
|
let stream: Arc<Mutex<EventStream>> = Arc::new (
|
|
Mutex::new (
|
|
get_event_stream (
|
|
Path::new(&device),
|
|
config.clone()
|
|
)
|
|
)
|
|
);
|
|
let virt_dev: Arc<Mutex<VirtualDevices>> = Arc::new (
|
|
Mutex::new(new_virtual_devices())
|
|
);
|
|
let reader = EventReader::new(config.clone(), stream, virt_dev);
|
|
println!("Mapped device detected at {}, reading events.", device);
|
|
tokio::join!(
|
|
reader.start(),
|
|
reader.cursor_loop(),
|
|
);
|
|
println!("Disconnected device at {}.", device);
|
|
}
|
|
|
|
pub fn get_event_stream(path: &Path, config: HashMap<String, Config>) -> EventStream {
|
|
let mut device: Device = Device::open(path).expect("Couldn't open device path.");
|
|
if config.get("default")
|
|
.unwrap()
|
|
.settings
|
|
.get("GRAB_DEVICE")
|
|
.expect("No GRAB_DEVICE setting specified, this device will be ignored.") == &"true".to_string()
|
|
{
|
|
device.grab().unwrap();
|
|
};
|
|
|
|
let stream: EventStream = device.into_event_stream().unwrap();
|
|
return stream
|
|
}
|
|
|
|
pub fn new_virtual_devices() -> VirtualDevices {
|
|
let mut key_capabilities = evdev::AttributeSet::new();
|
|
for i in 1..334 {key_capabilities.insert(Key(i));};
|
|
let mut rel_capabilities = evdev::AttributeSet::new();
|
|
for i in 0..13 {rel_capabilities.insert(evdev::RelativeAxisType(i));};
|
|
let keys_builder = VirtualDeviceBuilder::new().unwrap()
|
|
.name("Makima Virtual Keyboard/Mouse")
|
|
.with_keys(&key_capabilities).unwrap();
|
|
let rel_builder = VirtualDeviceBuilder::new().unwrap()
|
|
.name("Makima Virtual Pointer")
|
|
.with_relative_axes(&rel_capabilities).unwrap();
|
|
let virtual_device_keys = keys_builder.build().unwrap();
|
|
let virtual_device_rel = rel_builder.build().unwrap();
|
|
let virtual_devices = VirtualDevices::new(virtual_device_keys, virtual_device_rel);
|
|
return virtual_devices;
|
|
}
|
|
|
|
pub fn is_mapped(udev_device: &tokio_udev::Device, config_files: &Vec<Config>) -> bool {
|
|
match udev_device.devnode() {
|
|
Some(devnode) => {
|
|
let evdev_devices: evdev::EnumerateDevices = evdev::enumerate();
|
|
for evdev_device in evdev_devices {
|
|
for config in config_files {
|
|
if config.name.contains(&evdev_device.1.name().unwrap().to_string())
|
|
&& devnode.to_path_buf() == evdev_device.0 {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
_ => return false
|
|
}
|
|
return false
|
|
}
|
|
|