1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use std::ffi::OsStr;
use std::path::Path;
use libudev;
use nix;
use qualia::DeviceKind;
const INPUT_MOUSE: &'static str = "ID_INPUT_MOUSE";
const INPUT_TOUCHPAD: &'static str = "ID_INPUT_TOUCHPAD";
const INPUT_KEYBOARD: &'static str = "ID_INPUT_KEYBOARD";
pub struct Udev {
context: libudev::Context,
}
impl Udev {
pub fn new() -> Self {
Udev { context: libudev::Context::new().expect("Failed to create udev context") }
}
pub fn iterate_input_devices<F>(&self, mut f: F)
where F: FnMut(&Path, DeviceKind, &libudev::Device)
{
let mut enumerator =
libudev::Enumerator::new(&self.context).expect("Failed to create device enumerator");
enumerator.match_subsystem("input").expect("Failed to apply filter for device enumerator");
for device in enumerator.scan_devices().expect("Failed to scan devices") {
let device_kind = determine_device_kind(&device);
if device_kind != DeviceKind::Unknown && is_input_device(device.sysname()) {
if let Some(devnode) = device.devnode() {
if exists_in_filesystem(&devnode) {
f(devnode, device_kind, &device);
}
}
}
}
}
pub fn iterate_output_devices<F: FnMut(&Path, &libudev::Device)>(&self, mut f: F) {
let mut enumerator =
libudev::Enumerator::new(&self.context).expect("Failed to create device enumerator");
enumerator.match_subsystem("drm").expect("Failed to apply filter for device enumerator");
for device in enumerator.scan_devices().expect("Failed to scan devices") {
if is_output_device(device.sysname()) {
if let Some(devnode) = device.devnode() {
if exists_in_filesystem(&devnode) {
log_info1!("Found output device: {:?}", devnode);
f(devnode, &device);
}
}
}
}
}
}
pub fn exists_in_filesystem(devnode: &Path) -> bool {
nix::sys::stat::stat(devnode).is_ok()
}
pub fn is_input_device(sysname: &OsStr) -> bool {
match sysname.to_os_string().into_string() {
Ok(sysname) => sysname.starts_with("event"),
Err(_) => false,
}
}
pub fn is_output_device(sysname: &OsStr) -> bool {
match sysname.to_os_string().into_string() {
Ok(sysname) => sysname.starts_with("card"),
Err(_) => false,
}
}
pub fn determine_device_kind(device: &libudev::Device) -> DeviceKind {
for property in device.properties() {
if property.name() == INPUT_MOUSE {
return DeviceKind::Mouse;
} else if property.name() == INPUT_TOUCHPAD {
return DeviceKind::Touchpad;
} else if property.name() == INPUT_KEYBOARD {
return DeviceKind::Keyboard;
}
}
DeviceKind::Unknown
}