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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#![cfg(all(target_os = "linux", feature = "uhid"))]
use log::error;
use uhid_virt::{Bus, CreateParams, UHIDDevice};
/// Virtual HID device for injecting key events into the Linux HID subsystem
pub struct VirtKbd {
device: UHIDDevice<std::fs::File>,
}
impl Default for VirtKbd {
fn default() -> Self {
Self::new()
}
}
impl VirtKbd {
pub fn new() -> Self {
VirtKbd {
device: UHIDDevice::create(CreateParams {
name: String::from("cherryrgb"),
phys: String::from(""), // ?
uniq: String::from(""), // ?
bus: Bus::USB,
vendor: 0xdead,
product: 0xbeef,
version: 0,
country: 0,
#[rustfmt::skip]
rd_data: [
// Annotated report descriptor generated by running hid-decode
// on the event device of my Cherry MX 10.0 N RGB
// hid-decode is part of hid-tools
// See: https://gitlab.freedesktop.org/libevdev/hid-tools
//
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x06, // Usage (Keyboard)
0xa1, 0x01, // Collection (Application)
0x85, 0x01, // Report ID (1)
0x05, 0x07, // Usage Page (Keyboard)
0x19, 0x04, // Usage Minimum (4)
0x29, 0x70, // Usage Maximum (112)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x78, // Report Count (120)
0x81, 0x02, // Input (Data,Var,Abs)
0xc0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x80, // Usage (System Control)
0xa1, 0x01, // Collection (Application)
0x85, 0x02, // Report ID (2)
0x05, 0x01, // Usage Page (Generic Desktop)
0x19, 0x81, // Usage Minimum (129)
0x29, 0x83, // Usage Maximum (131)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x03, // Report Count (3)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs)
0x95, 0x01, // Report Count (1)
0x75, 0x05, // Report Size (5)
0x81, 0x01, // Input (Cnst,Arr,Abs)
0xc0, // End Collection
0x05, 0x0c, // Usage Page (Consumer Devices)
0x09, 0x01, // Usage (Consumer Control)
0xa1, 0x01, // Collection (Application)
0x85, 0x03, // Report ID (3)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x1f, // Logical Maximum (8191)
0x19, 0x00, // Usage Minimum (0)
0x2a, 0xff, 0x1f, // Usage Maximum (8191)
0x75, 0x10, // Report Size (16)
0x95, 0x01, // Report Count (1)
0x81, 0x00, // Input (Data,Arr,Abs)
0xc0, // End Collection
0x06, 0x1c, 0xff, // Usage Page (Vendor Usage Page 0xff1c)
0x09, 0x92, // Usage (Vendor Usage 0x92)
0xa1, 0x01, // Collection (Application)
0x85, 0x04, // Report ID (4)
0x19, 0x00, // Usage Minimum (0)
0x2a, 0xff, 0x00, // Usage Maximum (255)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xff, 0x00, // Logical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x3f, // Report Count (63)
0x91, 0x00, // Output (Data,Arr,Abs)
0x19, 0x00, // Usage Minimum (0)
0x29, 0xff, // Usage Maximum (255)
0x81, 0x00, // Input (Data,Arr,Abs)
0xc0, // End Collection
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x02, // Usage (Mouse)
0xa1, 0x01, // Collection (Application)
0x85, 0x05, // Report ID (5)
0x09, 0x01, // Usage (Pointer)
0xa1, 0x00, // Collection (Physical)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (1)
0x29, 0x05, // Usage Maximum (5)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x95, 0x05, // Report Count (5)
0x75, 0x01, // Report Size (1)
0x81, 0x02, // Input (Data,Var,Abs)
0x95, 0x01, // Report Count (1)
0x75, 0x03, // Report Size (3)
0x81, 0x01, // Input (Cnst,Arr,Abs)
0x05, 0x01, // Usage Page (Generic Desktop)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x16, 0x00, 0x80, // Logical Minimum (-32768)
0x26, 0xff, 0x7f, // Logical Maximum (32767)
0x75, 0x10, // Report Size (16)
0x95, 0x02, // Report Count (2)
0x81, 0x06, // Input (Data,Var,Rel)
0x09, 0x38, // Usage (Wheel)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7f, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel)
0x05, 0x0c, // Usage Page (Consumer Devices)
0x0a, 0x38, 0x02, // Usage (AC Pan)
0x15, 0x81, // Logical Minimum (-127)
0x25, 0x7f, // Logical Maximum (127)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x81, 0x06, // Input (Data,Var,Rel)
0xc0, // End Collection
0xc0, // End Collection
]
.to_vec(),
})
.map_err(|err| error!("Could not create VirtKbd: {:?}", err))
.expect("Could not create VirtKbd"),
}
}
/// Forward a single HID event.
/// See: CherryKeyboard::forward_filtered_keys()
pub fn forward(&mut self, input: &[u8]) {
self.device.write(input).unwrap();
}
}