├── .gitignore ├── nasskan.service ├── examples ├── caps2esc.yaml └── my-personal-config.yaml ├── Cargo.toml ├── src ├── config │ └── validation.rs ├── main.rs ├── remapper.rs └── config.rs ├── README.md ├── LICENSE └── Cargo.lock /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | **/*.rs.bk 3 | -------------------------------------------------------------------------------- /nasskan.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=Yet another key remapper 3 | After=multi-user.target 4 | 5 | [Service] 6 | Type=simple 7 | ExecStart=/usr/bin/nasskan 8 | Environment=RUST_LOG=info 9 | Nice=-20 10 | 11 | [Install] 12 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /examples/caps2esc.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | devices: 3 | - if: 4 | ID_VENDOR_ID: 05f3 5 | ID_MODEL_ID: 0007 6 | then: 7 | - from: 8 | key: CAPSLOCK 9 | to: 10 | key: LEFTCTRL 11 | tap: 12 | key: ESC 13 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "nasskan" 3 | version = "0.1.0" 4 | authors = ["tadosappo "] 5 | edition = "2018" 6 | 7 | [dependencies] 8 | udev = "0.2" 9 | mio = "0.6" 10 | env_logger = "0.7" 11 | log = "0.4" 12 | serde = { version = "1.0", features = ["derive"] } 13 | serde_yaml = "0.8" 14 | lazy_static = "1.4" 15 | evdev-rs = "0.3" 16 | nix = "0.13.0" 17 | maplit = "1.0" 18 | -------------------------------------------------------------------------------- /src/config/validation.rs: -------------------------------------------------------------------------------- 1 | use super::{Config, Modifier}; 2 | use std::convert::TryInto; 3 | 4 | pub(crate) fn validate_order(config: &Config) { 5 | for device in config.devices.iter() { 6 | let mut key_found = false; 7 | for rule in device.then.iter() { 8 | if ((&rule.to.key).try_into().ok() as Option).is_none() { 9 | key_found = true; 10 | } else if key_found { 11 | panic!("Remap rules for modifiers should be at first"); 12 | } 13 | } 14 | } 15 | } 16 | 17 | pub(crate) fn validate_tap(config: &Config) { 18 | for device in config.devices.iter() { 19 | for rule in device.then.iter() { 20 | if rule.tap.is_some() 21 | && (rule 22 | .from 23 | .with 24 | .as_ref() 25 | .map(|modifiers| 0 < modifiers.len()) 26 | .unwrap_or(false) 27 | || rule 28 | .from 29 | .without 30 | .as_ref() 31 | .map(|modifiers| 0 < modifiers.len()) 32 | .unwrap_or(false) 33 | || rule 34 | .to 35 | .with 36 | .as_ref() 37 | .map(|modifiers| 0 < modifiers.len()) 38 | .unwrap_or(false)) 39 | { 40 | panic!("Remap rules with tap should not have from.with, from.without or to.with clause"); 41 | } 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nasskan 2 | A key remapper for Wayland environments. 3 | 4 | - Works without X 5 | - Easy configuration with YAML 6 | - From key combination to key combination mapping 7 | - One-shot modifier 8 | - Reacts to attach of external keyboards 9 | 10 | This software is in beta. There's a possibility for your keyboard to be unresponsive. Use at your own risk. 11 | 12 | # Install 13 | ```sh 14 | git clone https://github.com/tadosappo/nasskan.git 15 | cd nasskan 16 | 17 | cargo build --release 18 | cp target/release/nasskan /usr/bin/ 19 | cp nasskan.service /etc/systemd/system/ 20 | systemctl enable --now nasskan 21 | ``` 22 | 23 | ## Configuration 24 | Nasskan reads `/etc/nasskan/config.yaml`. See [examples](https://github.com/tadosappo/nasskan/blob/master/examples). 25 | 26 | ``` 27 | version: 1 28 | device: 29 | - if: 30 | ID_VENDOR_ID: 31 | ID_MODEL_ID: 32 | then: 33 | - from: 34 | key: 35 | with: # optional 36 | - 37 | without: # optional 38 | - 39 | to: 40 | key: 41 | with: # optional 42 | - 43 | tap: # optional 44 | key: 45 | ``` 46 | 47 | ### if 48 | Nasskan has to know which keyboard the remapping rules are for. In order to do so, nasskan uses udev device properties such as ID_VENDOR or ID_MODEL. You can check your keyboard's device properties by `udevadm info /dev/input/`. You can check your keyboard's device file path by `libinput list-devices`. I recommend that you write your keyboard's ID_VENDOR_ID and ID_MODEL_ID in `if` section. but writing other properties should be fine. 49 | 50 | ### KEY 51 | [Possible values are defined here](https://github.com/tadosappo/nasskan/blob/4f064d3c7292e4d0d3ef3e6bd7649f3d7ad6c65c/src/config.rs#L124). 52 | 53 | ### MODIFIER 54 | [Possible values are defined here](https://github.com/tadosappo/nasskan/blob/4f064d3c7292e4d0d3ef3e6bd7649f3d7ad6c65c/src/config.rs#L61). 55 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use evdev_rs as evdev; 2 | use log::*; 3 | use mio::unix::EventedFd; 4 | use mio::*; 5 | use std::cell::RefCell; 6 | use std::collections::BTreeMap; 7 | use std::convert::TryInto; 8 | use std::fs::OpenOptions; 9 | use std::os::unix::fs::OpenOptionsExt; 10 | use std::os::unix::io::{AsRawFd, RawFd}; 11 | use std::rc::Rc; 12 | 13 | mod remapper; 14 | use remapper::*; 15 | mod config; 16 | use config::*; 17 | 18 | trait AsyncWorker: AsRawFd { 19 | fn step(&mut self, manager: &mut WorkerManager); 20 | } 21 | 22 | struct WorkerManager { 23 | poll: mio::Poll, 24 | workers: BTreeMap>>, 25 | } 26 | 27 | impl WorkerManager { 28 | fn new() -> Self { 29 | Self { 30 | poll: Poll::new().unwrap(), 31 | workers: BTreeMap::new(), 32 | } 33 | } 34 | 35 | fn run(&mut self) { 36 | let mut events = Events::with_capacity(128); 37 | loop { 38 | self.poll.poll(&mut events, None).unwrap(); 39 | 40 | for event in events.iter() { 41 | if let Some(worker) = self.workers.get_mut(&event.token().0) { 42 | Rc::clone(worker).borrow_mut().step(self); 43 | } 44 | // The reason why I use Vec>> instead of Vec> is: 45 | // While doing `worker.step(manager)`, there's a possibility for `step` to remove `worker` itself using `manager`. 46 | // It took a while to figure out what cryptic messages from borrow checker means... 47 | } 48 | } 49 | } 50 | 51 | fn start(&mut self, id: usize, worker: T) { 52 | self 53 | .poll 54 | .register( 55 | &EventedFd(&worker.as_raw_fd()), 56 | Token(id), 57 | Ready::readable(), 58 | PollOpt::edge(), 59 | ) 60 | .unwrap(); 61 | 62 | self.workers.insert(id, Rc::new(RefCell::new(worker))); 63 | } 64 | 65 | fn stop(&mut self, id: usize) { 66 | match self.workers.remove(&id) { 67 | Some(worker) => self 68 | .poll 69 | .deregister(&EventedFd(&worker.borrow().as_raw_fd())) 70 | .unwrap(), 71 | None => return, 72 | } 73 | } 74 | } 75 | 76 | struct KeyboardConnectionWorker { 77 | monitor: udev::MonitorSocket, 78 | } 79 | 80 | impl KeyboardConnectionWorker { 81 | fn new(ctx: &udev::Context) -> Self { 82 | let mut builder = udev::MonitorBuilder::new(ctx).unwrap(); 83 | builder.match_subsystem("input").unwrap(); 84 | let monitor = builder.listen().unwrap(); 85 | 86 | Self { monitor } 87 | } 88 | } 89 | 90 | impl AsRawFd for KeyboardConnectionWorker { 91 | fn as_raw_fd(&self) -> RawFd { 92 | self.monitor.as_raw_fd() 93 | } 94 | } 95 | 96 | impl AsyncWorker for KeyboardConnectionWorker { 97 | fn step(&mut self, manager: &mut WorkerManager) { 98 | loop { 99 | let event = match self.monitor.next() { 100 | Some(event) => event, 101 | None => return, 102 | }; 103 | 104 | let connected_device = event.device(); 105 | let device_id = match connected_device.devnum() { 106 | Some(devnum) => devnum, 107 | None => return, 108 | }; 109 | 110 | match event.event_type() { 111 | udev::EventType::Add => { 112 | if let Some(worker) = KeyPressWorker::for_keyboard(&connected_device) { 113 | info!("keyboard {} connected", device_id); 114 | manager.start(device_id.try_into().unwrap(), worker); 115 | } 116 | } 117 | udev::EventType::Remove => { 118 | info!("keyboard {} disconnected", device_id); 119 | manager.stop(device_id.try_into().unwrap()); 120 | } 121 | _ => {} 122 | } 123 | } 124 | } 125 | } 126 | 127 | struct KeyPressWorker { 128 | actual_keyboard: evdev::Device, 129 | virtual_keyboard: evdev::UInputDevice, 130 | remapper: Remapper, 131 | } 132 | 133 | impl KeyPressWorker { 134 | fn new(path: &std::path::Path, remapper: Remapper) -> Result { 135 | let file = OpenOptions::new() 136 | .read(true) 137 | .custom_flags(nix::fcntl::OFlag::O_NONBLOCK.bits()) 138 | .open(path) 139 | .unwrap(); 140 | let mut actual_keyboard = evdev::Device::new_from_fd(file)?; 141 | let virtual_keyboard = evdev::UInputDevice::create_from_device(&actual_keyboard) 142 | .expect("Creating uinput device failed. Maybe uinput kernel module is not loaded?"); 143 | actual_keyboard.grab(evdev::GrabMode::Grab).expect("Some process have grabbed this keyboard already. Maybe there's an another instance of nasskan running?"); 144 | 145 | Ok(Self { 146 | actual_keyboard, 147 | virtual_keyboard, 148 | remapper, 149 | }) 150 | } 151 | 152 | fn for_keyboard(keyboard: &udev::Device) -> Option { 153 | let device_file_path = match keyboard.devnode() { 154 | Some(devnode) => devnode, 155 | None => return None, 156 | }; 157 | 158 | for config_device in CONFIG.devices.iter() { 159 | let is_connected = config_device 160 | .if_ 161 | .iter() 162 | .all(|(name, value)| keyboard.property_value(name).and_then(|x| x.to_str()) == Some(value)); 163 | 164 | if is_connected { 165 | let remapper = Remapper::new(&config_device.then); 166 | if let Ok(x) = KeyPressWorker::new(device_file_path, remapper) { 167 | return Some(x); 168 | }; 169 | 170 | warn!("evdev_new_from_fd failed. It means some non-keyboard device matched with devices.if clause in your config. You should write it more strictly") 171 | } 172 | } 173 | 174 | None 175 | } 176 | 177 | fn handle_event(&mut self, input_event: evdev::InputEvent) { 178 | let key: EventKey = match &input_event.event_code { 179 | evdev::enums::EventCode::EV_KEY(ref key) => { 180 | trace!("Received an evdev event: {:?}", input_event); 181 | key.clone().into() 182 | } 183 | _ => { 184 | trace!("Ignored an evdev event: {:?}", input_event); 185 | return; 186 | } 187 | }; 188 | let event_type: EventType = input_event 189 | .value 190 | .try_into() 191 | .expect("an evdev event has invalid value"); 192 | let event = remapper::Event { event_type, key }; 193 | 194 | debug!("Input: {:?}", event); 195 | let remapped_events = self.remapper.remap(event); 196 | debug!("Output: {:?}", remapped_events); 197 | 198 | for remapped_event in remapped_events { 199 | self 200 | .virtual_keyboard 201 | .write_event(&evdev::InputEvent::new( 202 | &input_event.time, 203 | &evdev::enums::EventCode::EV_KEY(remapped_event.key.into()), 204 | remapped_event.event_type.into(), 205 | )) 206 | .unwrap(); 207 | } 208 | 209 | self 210 | .virtual_keyboard 211 | .write_event(&evdev::InputEvent { 212 | event_type: evdev::enums::EventType::EV_SYN, 213 | event_code: evdev::enums::EventCode::EV_SYN(evdev::enums::EV_SYN::SYN_REPORT), 214 | value: 0, 215 | ..input_event 216 | }) 217 | .unwrap(); 218 | } 219 | } 220 | 221 | impl AsRawFd for KeyPressWorker { 222 | fn as_raw_fd(&self) -> RawFd { 223 | let file = self.actual_keyboard.fd().unwrap(); 224 | let fd = file.as_raw_fd(); 225 | 226 | // Why do I have to do this... 227 | // When `file` dropped, its destructor gets called, and `fd` becomes invalid. 228 | // TODO: Fill a bug report to evdev-rs 229 | std::mem::forget(file); 230 | 231 | fd 232 | } 233 | } 234 | 235 | impl AsyncWorker for KeyPressWorker { 236 | fn step(&mut self, _: &mut WorkerManager) { 237 | let mut flag = evdev::ReadFlag::NORMAL; 238 | loop { 239 | match self.actual_keyboard.next_event(flag) { 240 | Ok((evdev::ReadStatus::Success, event)) => self.handle_event(event), 241 | Ok((evdev::ReadStatus::Sync, event)) => { 242 | warn!("Nasskan could not keep up with you typing so fast... now trying to recover."); 243 | flag = evdev::ReadFlag::SYNC; 244 | self.handle_event(event); 245 | } 246 | Err(nix::errno::Errno::EAGAIN) => return, 247 | Err(nix::errno::Errno::ENODEV) => return, 248 | Err(error) => { 249 | error!("evdev error: {:?}", error); 250 | return; 251 | } 252 | }; 253 | } 254 | } 255 | } 256 | 257 | fn find_keyboards(ctx: &udev::Context) -> udev::Devices { 258 | let mut scanner = udev::Enumerator::new(ctx).unwrap(); 259 | scanner.match_subsystem("input").unwrap(); 260 | scanner.scan_devices().unwrap() 261 | } 262 | 263 | fn main() { 264 | match std::env::var("RUST_LOG") { 265 | Ok(_) => env_logger::init(), 266 | Err(_) => env_logger::builder() 267 | .filter_level(LevelFilter::Trace) 268 | .init(), 269 | } 270 | 271 | let mut manager = WorkerManager::new(); 272 | let ctx = udev::Context::new().unwrap(); 273 | let worker = KeyboardConnectionWorker::new(&ctx); 274 | // It's safe to use 0 as worker id because udev::Device::devnum never returns Some(0) 275 | manager.start(0, worker); 276 | info!("Start watching keyboard connections..."); 277 | 278 | for keyboard in find_keyboards(&ctx) { 279 | let device_id = match keyboard.devnum() { 280 | Some(devnum) => devnum, 281 | None => continue, 282 | }; 283 | 284 | if let Some(worker) = KeyPressWorker::for_keyboard(&keyboard) { 285 | info!("keyboard found!"); 286 | manager.start(device_id.try_into().unwrap(), worker); 287 | } 288 | } 289 | 290 | manager.run() 291 | } 292 | -------------------------------------------------------------------------------- /src/remapper.rs: -------------------------------------------------------------------------------- 1 | use crate::config::*; 2 | use evdev_rs::enums::EV_KEY; 3 | use maplit::btreeset; 4 | use std::cmp::Ordering; 5 | use std::collections::{BTreeMap, BTreeSet}; 6 | use std::convert::{TryFrom, TryInto}; 7 | use std::ops::Deref; 8 | 9 | // Remaps Event to Vec 10 | pub(crate) struct Remapper { 11 | keymap: &'static Vec, 12 | keyboard_state: Vec, 13 | last_key: EventKey, 14 | } 15 | 16 | impl Remapper { 17 | pub(crate) fn new(keymap: &'static Vec) -> Self { 18 | Self { 19 | keymap, 20 | keyboard_state: Vec::new(), 21 | last_key: EV_KEY::KEY_RESERVED.into(), 22 | } 23 | } 24 | 25 | pub(crate) fn remap(&mut self, received: Event) -> BTreeSet { 26 | let old_virtually_pressed = self.virtually_pressed(); 27 | 28 | self.add_remove_actives(&received); 29 | self.convert_actives(); 30 | 31 | let mut to_be_sent = BTreeSet::new(); 32 | to_be_sent.extend(self.events_for_diff(&old_virtually_pressed)); 33 | to_be_sent.extend(self.events_for_tap(&received)); 34 | to_be_sent.extend(self.events_for_keyrepeats(received.clone())); 35 | self.last_key = received.key.clone(); 36 | 37 | to_be_sent 38 | } 39 | 40 | fn add_remove_actives(&mut self, received: &Event) { 41 | let empty = BTreeSet::new(); 42 | let modifier_map = self.modifier_map(); 43 | let remapped_modifier = modifier_map.get(&received.key); 44 | 45 | match received.event_type { 46 | EventType::Press => { 47 | self 48 | .keyboard_state 49 | .push(KeyState::Passthru(received.key.clone())); 50 | } 51 | EventType::Release => self.keyboard_state.retain(|key_state| match key_state { 52 | KeyState::Passthru(key) => key != &received.key, 53 | KeyState::Remapped(rule) => { 54 | rule.from.key != received.key 55 | && remapped_modifier 56 | .map(|remapped_modifier| { 57 | !rule 58 | .from 59 | .with 60 | .as_ref() 61 | .unwrap_or(&empty) 62 | .contains(remapped_modifier) 63 | }) 64 | .unwrap_or(true) 65 | } 66 | }), 67 | EventType::Repeat => {} 68 | } 69 | } 70 | 71 | // TODO: Refactoring 72 | fn convert_actives(&mut self) { 73 | let original_keys: Vec = self 74 | .keyboard_state 75 | .iter() 76 | .map(|key_state| key_state.original_key()) 77 | .collect(); 78 | 79 | // Initialize modifier state 80 | for key_state in self.keyboard_state.iter_mut() { 81 | *key_state = KeyState::Passthru(EV_KEY::KEY_RESERVED.into()) 82 | } 83 | 84 | for config_rule in self.keymap.iter() { 85 | for (i, original_key) in original_keys.iter().enumerate() { 86 | if let KeyState::Remapped(_) = self.keyboard_state[i] { 87 | continue; 88 | } 89 | 90 | if self.is_active(config_rule, &original_key) { 91 | std::mem::replace(&mut self.keyboard_state[i], KeyState::Remapped(config_rule)); 92 | break; 93 | } 94 | } 95 | } 96 | 97 | for (i, key_state) in self.keyboard_state.iter_mut().enumerate() { 98 | if key_state == &KeyState::Passthru(EV_KEY::KEY_RESERVED.into()) { 99 | *key_state = KeyState::Passthru(original_keys[i].clone()); 100 | } 101 | } 102 | } 103 | 104 | fn events_for_diff(&self, old_virtually_pressed: &BTreeSet) -> BTreeSet { 105 | let mut result = BTreeSet::new(); 106 | 107 | for press in self.virtually_pressed().difference(old_virtually_pressed) { 108 | result.insert(Event { 109 | event_type: EventType::Press, 110 | key: press.clone(), 111 | }); 112 | } 113 | 114 | for release in old_virtually_pressed.difference(&self.virtually_pressed()) { 115 | result.insert(Event { 116 | event_type: EventType::Release, 117 | key: release.clone(), 118 | }); 119 | } 120 | 121 | result 122 | } 123 | 124 | fn events_for_keyrepeats(&self, received: Event) -> Option { 125 | if received.event_type != EventType::Repeat { 126 | return None; 127 | } 128 | 129 | for rule in self.active_rules() { 130 | if received.key == rule.from.key { 131 | return Some(Event { 132 | event_type: EventType::Repeat, 133 | key: rule.to.key.clone(), 134 | }); 135 | } 136 | } 137 | 138 | Some(received) 139 | } 140 | 141 | fn events_for_tap(&self, received: &Event) -> BTreeSet { 142 | if received.event_type != EventType::Release { 143 | return BTreeSet::new(); 144 | } 145 | 146 | if self.last_key != received.key { 147 | return BTreeSet::new(); 148 | } 149 | 150 | for rule in self.keymap.iter() { 151 | if let Some(tap) = &rule.tap { 152 | if received.key == rule.from.key { 153 | return btreeset![ 154 | Event { 155 | event_type: EventType::Press, 156 | key: tap.key.clone() 157 | }, 158 | Event { 159 | event_type: EventType::Release, 160 | key: tap.key.clone() 161 | } 162 | ]; 163 | } 164 | } 165 | } 166 | 167 | BTreeSet::new() 168 | } 169 | 170 | fn is_active(&self, rule: &'static Rule, pressed: &EventKey) -> bool { 171 | let remapped_modifiers: BTreeSet = self 172 | .keyboard_state 173 | .iter() 174 | .map(|key_state| key_state.remapped_key()) 175 | .filter_map(|key| key.try_into().ok()) 176 | .collect(); 177 | 178 | pressed == &rule.from.key 179 | && rule 180 | .from 181 | .with 182 | .as_ref() 183 | .map(|config_modifiers| remapped_modifiers.is_superset(&config_modifiers)) 184 | .unwrap_or(true) 185 | && rule 186 | .from 187 | .without 188 | .as_ref() 189 | .map(|config_modifiers| remapped_modifiers.is_disjoint(&config_modifiers)) 190 | .unwrap_or(true) 191 | } 192 | 193 | fn virtually_pressed(&self) -> BTreeSet { 194 | let empty = BTreeSet::new(); 195 | let mut result: BTreeSet = self 196 | .keyboard_state 197 | .iter() 198 | .map(|key_state| key_state.remapped_key()) 199 | .collect(); 200 | 201 | if let Some(last_key_state) = self.keyboard_state.last() { 202 | if let KeyState::Remapped(last_rule) = last_key_state { 203 | for modifier in last_rule.from.with.as_ref().unwrap_or(&empty).iter() { 204 | result.remove(&modifier.into()); 205 | } 206 | 207 | result.insert(last_rule.to.key.clone()); 208 | 209 | for modifier in last_rule.to.with.as_ref().unwrap_or(&empty).iter() { 210 | result.insert(modifier.into()); 211 | } 212 | } 213 | } 214 | 215 | result 216 | } 217 | 218 | fn active_rules<'a>(&'a self) -> impl Iterator + 'a { 219 | self 220 | .keyboard_state 221 | .iter() 222 | .filter_map(|key_state| match key_state { 223 | KeyState::Passthru(_) => None, 224 | KeyState::Remapped(rule) => Some(*rule), 225 | }) 226 | } 227 | 228 | fn modifier_map(&self) -> BTreeMap { 229 | let mut result = BTreeMap::new(); 230 | 231 | for rule in self.keymap.iter() { 232 | if let Some(modifier) = (&rule.to.key).try_into().ok() { 233 | result.insert(rule.from.key.clone(), modifier); 234 | } 235 | } 236 | 237 | result 238 | } 239 | } 240 | 241 | #[derive(Debug, Clone, Eq, PartialEq)] 242 | enum KeyState { 243 | Passthru(EventKey), 244 | Remapped(&'static Rule), 245 | } 246 | 247 | impl KeyState { 248 | fn original_key(&self) -> EventKey { 249 | match self { 250 | KeyState::Passthru(passthru) => passthru.clone(), 251 | KeyState::Remapped(rule) => rule.from.key.clone(), 252 | } 253 | } 254 | 255 | fn remapped_key(&self) -> EventKey { 256 | match self { 257 | KeyState::Passthru(passthru) => passthru.clone(), 258 | KeyState::Remapped(rule) => rule.to.key.clone(), 259 | } 260 | } 261 | } 262 | 263 | #[derive(Debug, Clone, Eq, PartialEq)] 264 | pub(crate) struct Event { 265 | pub(crate) event_type: EventType, 266 | pub(crate) key: EventKey, 267 | } 268 | 269 | impl Ord for Event { 270 | // events for modifier keys are smaller 271 | // cuz those events need to get sent first 272 | fn cmp(&self, other: &Self) -> Ordering { 273 | let modifier1: Option = (&self.key).try_into().ok(); 274 | let modifier2: Option = (&other.key).try_into().ok(); 275 | 276 | match (modifier1, modifier2) { 277 | (Some(_), None) => Ordering::Less, 278 | (None, Some(_)) => Ordering::Greater, 279 | _ => (self.key.clone(), self.event_type).cmp(&(other.key.clone(), other.event_type)), 280 | } 281 | } 282 | } 283 | 284 | impl PartialOrd for Event { 285 | fn partial_cmp(&self, other: &Self) -> Option { 286 | Some(self.cmp(other)) 287 | } 288 | } 289 | 290 | #[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd)] 291 | pub(crate) enum EventType { 292 | Press, 293 | Release, 294 | Repeat, 295 | } 296 | 297 | impl TryFrom for EventType { 298 | type Error = (); 299 | 300 | fn try_from(value: i32) -> Result { 301 | match value { 302 | 0 => Ok(Self::Release), 303 | 1 => Ok(Self::Press), 304 | 2 => Ok(Self::Repeat), 305 | _ => Err(()), 306 | } 307 | } 308 | } 309 | 310 | impl Into for EventType { 311 | fn into(self) -> i32 { 312 | match self { 313 | Self::Release => 0, 314 | Self::Press => 1, 315 | Self::Repeat => 2, 316 | } 317 | } 318 | } 319 | 320 | impl TryFrom for Modifier { 321 | type Error = (); 322 | 323 | fn try_from(key: EventKey) -> Result { 324 | (&key).try_into() 325 | } 326 | } 327 | 328 | impl TryFrom<&EventKey> for Modifier { 329 | type Error = (); 330 | 331 | fn try_from(key: &EventKey) -> Result { 332 | match key.deref() { 333 | EV_KEY::KEY_LEFTSHIFT => Ok(Self::LEFTSHIFT), 334 | EV_KEY::KEY_RIGHTSHIFT => Ok(Self::RIGHTSHIFT), 335 | EV_KEY::KEY_LEFTCTRL => Ok(Self::LEFTCTRL), 336 | EV_KEY::KEY_RIGHTCTRL => Ok(Self::RIGHTCTRL), 337 | EV_KEY::KEY_LEFTALT => Ok(Self::LEFTALT), 338 | EV_KEY::KEY_RIGHTALT => Ok(Self::RIGHTALT), 339 | EV_KEY::KEY_LEFTMETA => Ok(Self::LEFTMETA), 340 | EV_KEY::KEY_RIGHTMETA => Ok(Self::RIGHTMETA), 341 | _ => Err(()), 342 | } 343 | } 344 | } 345 | 346 | impl Into for Modifier { 347 | fn into(self) -> EventKey { 348 | (&self).into() 349 | } 350 | } 351 | 352 | impl Into for &Modifier { 353 | fn into(self) -> EventKey { 354 | match self { 355 | Modifier::LEFTSHIFT => EV_KEY::KEY_LEFTSHIFT.into(), 356 | Modifier::RIGHTSHIFT => EV_KEY::KEY_RIGHTSHIFT.into(), 357 | Modifier::LEFTCTRL => EV_KEY::KEY_LEFTCTRL.into(), 358 | Modifier::RIGHTCTRL => EV_KEY::KEY_RIGHTCTRL.into(), 359 | Modifier::LEFTALT => EV_KEY::KEY_LEFTALT.into(), 360 | Modifier::RIGHTALT => EV_KEY::KEY_RIGHTALT.into(), 361 | Modifier::LEFTMETA => EV_KEY::KEY_LEFTMETA.into(), 362 | Modifier::RIGHTMETA => EV_KEY::KEY_RIGHTMETA.into(), 363 | } 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Mozilla Public License Version 2.0 2 | ================================== 3 | 4 | 1. Definitions 5 | -------------- 6 | 7 | 1.1. "Contributor" 8 | means each individual or legal entity that creates, contributes to 9 | the creation of, or owns Covered Software. 10 | 11 | 1.2. "Contributor Version" 12 | means the combination of the Contributions of others (if any) used 13 | by a Contributor and that particular Contributor's Contribution. 14 | 15 | 1.3. "Contribution" 16 | means Covered Software of a particular Contributor. 17 | 18 | 1.4. "Covered Software" 19 | means Source Code Form to which the initial Contributor has attached 20 | the notice in Exhibit A, the Executable Form of such Source Code 21 | Form, and Modifications of such Source Code Form, in each case 22 | including portions thereof. 23 | 24 | 1.5. "Incompatible With Secondary Licenses" 25 | means 26 | 27 | (a) that the initial Contributor has attached the notice described 28 | in Exhibit B to the Covered Software; or 29 | 30 | (b) that the Covered Software was made available under the terms of 31 | version 1.1 or earlier of the License, but not also under the 32 | terms of a Secondary License. 33 | 34 | 1.6. "Executable Form" 35 | means any form of the work other than Source Code Form. 36 | 37 | 1.7. "Larger Work" 38 | means a work that combines Covered Software with other material, in 39 | a separate file or files, that is not Covered Software. 40 | 41 | 1.8. "License" 42 | means this document. 43 | 44 | 1.9. "Licensable" 45 | means having the right to grant, to the maximum extent possible, 46 | whether at the time of the initial grant or subsequently, any and 47 | all of the rights conveyed by this License. 48 | 49 | 1.10. "Modifications" 50 | means any of the following: 51 | 52 | (a) any file in Source Code Form that results from an addition to, 53 | deletion from, or modification of the contents of Covered 54 | Software; or 55 | 56 | (b) any new file in Source Code Form that contains any Covered 57 | Software. 58 | 59 | 1.11. "Patent Claims" of a Contributor 60 | means any patent claim(s), including without limitation, method, 61 | process, and apparatus claims, in any patent Licensable by such 62 | Contributor that would be infringed, but for the grant of the 63 | License, by the making, using, selling, offering for sale, having 64 | made, import, or transfer of either its Contributions or its 65 | Contributor Version. 66 | 67 | 1.12. "Secondary License" 68 | means either the GNU General Public License, Version 2.0, the GNU 69 | Lesser General Public License, Version 2.1, the GNU Affero General 70 | Public License, Version 3.0, or any later versions of those 71 | licenses. 72 | 73 | 1.13. "Source Code Form" 74 | means the form of the work preferred for making modifications. 75 | 76 | 1.14. "You" (or "Your") 77 | means an individual or a legal entity exercising rights under this 78 | License. For legal entities, "You" includes any entity that 79 | controls, is controlled by, or is under common control with You. For 80 | purposes of this definition, "control" means (a) the power, direct 81 | or indirect, to cause the direction or management of such entity, 82 | whether by contract or otherwise, or (b) ownership of more than 83 | fifty percent (50%) of the outstanding shares or beneficial 84 | ownership of such entity. 85 | 86 | 2. License Grants and Conditions 87 | -------------------------------- 88 | 89 | 2.1. Grants 90 | 91 | Each Contributor hereby grants You a world-wide, royalty-free, 92 | non-exclusive license: 93 | 94 | (a) under intellectual property rights (other than patent or trademark) 95 | Licensable by such Contributor to use, reproduce, make available, 96 | modify, display, perform, distribute, and otherwise exploit its 97 | Contributions, either on an unmodified basis, with Modifications, or 98 | as part of a Larger Work; and 99 | 100 | (b) under Patent Claims of such Contributor to make, use, sell, offer 101 | for sale, have made, import, and otherwise transfer either its 102 | Contributions or its Contributor Version. 103 | 104 | 2.2. Effective Date 105 | 106 | The licenses granted in Section 2.1 with respect to any Contribution 107 | become effective for each Contribution on the date the Contributor first 108 | distributes such Contribution. 109 | 110 | 2.3. Limitations on Grant Scope 111 | 112 | The licenses granted in this Section 2 are the only rights granted under 113 | this License. No additional rights or licenses will be implied from the 114 | distribution or licensing of Covered Software under this License. 115 | Notwithstanding Section 2.1(b) above, no patent license is granted by a 116 | Contributor: 117 | 118 | (a) for any code that a Contributor has removed from Covered Software; 119 | or 120 | 121 | (b) for infringements caused by: (i) Your and any other third party's 122 | modifications of Covered Software, or (ii) the combination of its 123 | Contributions with other software (except as part of its Contributor 124 | Version); or 125 | 126 | (c) under Patent Claims infringed by Covered Software in the absence of 127 | its Contributions. 128 | 129 | This License does not grant any rights in the trademarks, service marks, 130 | or logos of any Contributor (except as may be necessary to comply with 131 | the notice requirements in Section 3.4). 132 | 133 | 2.4. Subsequent Licenses 134 | 135 | No Contributor makes additional grants as a result of Your choice to 136 | distribute the Covered Software under a subsequent version of this 137 | License (see Section 10.2) or under the terms of a Secondary License (if 138 | permitted under the terms of Section 3.3). 139 | 140 | 2.5. Representation 141 | 142 | Each Contributor represents that the Contributor believes its 143 | Contributions are its original creation(s) or it has sufficient rights 144 | to grant the rights to its Contributions conveyed by this License. 145 | 146 | 2.6. Fair Use 147 | 148 | This License is not intended to limit any rights You have under 149 | applicable copyright doctrines of fair use, fair dealing, or other 150 | equivalents. 151 | 152 | 2.7. Conditions 153 | 154 | Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted 155 | in Section 2.1. 156 | 157 | 3. Responsibilities 158 | ------------------- 159 | 160 | 3.1. Distribution of Source Form 161 | 162 | All distribution of Covered Software in Source Code Form, including any 163 | Modifications that You create or to which You contribute, must be under 164 | the terms of this License. You must inform recipients that the Source 165 | Code Form of the Covered Software is governed by the terms of this 166 | License, and how they can obtain a copy of this License. You may not 167 | attempt to alter or restrict the recipients' rights in the Source Code 168 | Form. 169 | 170 | 3.2. Distribution of Executable Form 171 | 172 | If You distribute Covered Software in Executable Form then: 173 | 174 | (a) such Covered Software must also be made available in Source Code 175 | Form, as described in Section 3.1, and You must inform recipients of 176 | the Executable Form how they can obtain a copy of such Source Code 177 | Form by reasonable means in a timely manner, at a charge no more 178 | than the cost of distribution to the recipient; and 179 | 180 | (b) You may distribute such Executable Form under the terms of this 181 | License, or sublicense it under different terms, provided that the 182 | license for the Executable Form does not attempt to limit or alter 183 | the recipients' rights in the Source Code Form under this License. 184 | 185 | 3.3. Distribution of a Larger Work 186 | 187 | You may create and distribute a Larger Work under terms of Your choice, 188 | provided that You also comply with the requirements of this License for 189 | the Covered Software. If the Larger Work is a combination of Covered 190 | Software with a work governed by one or more Secondary Licenses, and the 191 | Covered Software is not Incompatible With Secondary Licenses, this 192 | License permits You to additionally distribute such Covered Software 193 | under the terms of such Secondary License(s), so that the recipient of 194 | the Larger Work may, at their option, further distribute the Covered 195 | Software under the terms of either this License or such Secondary 196 | License(s). 197 | 198 | 3.4. Notices 199 | 200 | You may not remove or alter the substance of any license notices 201 | (including copyright notices, patent notices, disclaimers of warranty, 202 | or limitations of liability) contained within the Source Code Form of 203 | the Covered Software, except that You may alter any license notices to 204 | the extent required to remedy known factual inaccuracies. 205 | 206 | 3.5. Application of Additional Terms 207 | 208 | You may choose to offer, and to charge a fee for, warranty, support, 209 | indemnity or liability obligations to one or more recipients of Covered 210 | Software. However, You may do so only on Your own behalf, and not on 211 | behalf of any Contributor. You must make it absolutely clear that any 212 | such warranty, support, indemnity, or liability obligation is offered by 213 | You alone, and You hereby agree to indemnify every Contributor for any 214 | liability incurred by such Contributor as a result of warranty, support, 215 | indemnity or liability terms You offer. You may include additional 216 | disclaimers of warranty and limitations of liability specific to any 217 | jurisdiction. 218 | 219 | 4. Inability to Comply Due to Statute or Regulation 220 | --------------------------------------------------- 221 | 222 | If it is impossible for You to comply with any of the terms of this 223 | License with respect to some or all of the Covered Software due to 224 | statute, judicial order, or regulation then You must: (a) comply with 225 | the terms of this License to the maximum extent possible; and (b) 226 | describe the limitations and the code they affect. Such description must 227 | be placed in a text file included with all distributions of the Covered 228 | Software under this License. Except to the extent prohibited by statute 229 | or regulation, such description must be sufficiently detailed for a 230 | recipient of ordinary skill to be able to understand it. 231 | 232 | 5. Termination 233 | -------------- 234 | 235 | 5.1. The rights granted under this License will terminate automatically 236 | if You fail to comply with any of its terms. However, if You become 237 | compliant, then the rights granted under this License from a particular 238 | Contributor are reinstated (a) provisionally, unless and until such 239 | Contributor explicitly and finally terminates Your grants, and (b) on an 240 | ongoing basis, if such Contributor fails to notify You of the 241 | non-compliance by some reasonable means prior to 60 days after You have 242 | come back into compliance. Moreover, Your grants from a particular 243 | Contributor are reinstated on an ongoing basis if such Contributor 244 | notifies You of the non-compliance by some reasonable means, this is the 245 | first time You have received notice of non-compliance with this License 246 | from such Contributor, and You become compliant prior to 30 days after 247 | Your receipt of the notice. 248 | 249 | 5.2. If You initiate litigation against any entity by asserting a patent 250 | infringement claim (excluding declaratory judgment actions, 251 | counter-claims, and cross-claims) alleging that a Contributor Version 252 | directly or indirectly infringes any patent, then the rights granted to 253 | You by any and all Contributors for the Covered Software under Section 254 | 2.1 of this License shall terminate. 255 | 256 | 5.3. In the event of termination under Sections 5.1 or 5.2 above, all 257 | end user license agreements (excluding distributors and resellers) which 258 | have been validly granted by You or Your distributors under this License 259 | prior to termination shall survive termination. 260 | 261 | ************************************************************************ 262 | * * 263 | * 6. Disclaimer of Warranty * 264 | * ------------------------- * 265 | * * 266 | * Covered Software is provided under this License on an "as is" * 267 | * basis, without warranty of any kind, either expressed, implied, or * 268 | * statutory, including, without limitation, warranties that the * 269 | * Covered Software is free of defects, merchantable, fit for a * 270 | * particular purpose or non-infringing. The entire risk as to the * 271 | * quality and performance of the Covered Software is with You. * 272 | * Should any Covered Software prove defective in any respect, You * 273 | * (not any Contributor) assume the cost of any necessary servicing, * 274 | * repair, or correction. This disclaimer of warranty constitutes an * 275 | * essential part of this License. No use of any Covered Software is * 276 | * authorized under this License except under this disclaimer. * 277 | * * 278 | ************************************************************************ 279 | 280 | ************************************************************************ 281 | * * 282 | * 7. Limitation of Liability * 283 | * -------------------------- * 284 | * * 285 | * Under no circumstances and under no legal theory, whether tort * 286 | * (including negligence), contract, or otherwise, shall any * 287 | * Contributor, or anyone who distributes Covered Software as * 288 | * permitted above, be liable to You for any direct, indirect, * 289 | * special, incidental, or consequential damages of any character * 290 | * including, without limitation, damages for lost profits, loss of * 291 | * goodwill, work stoppage, computer failure or malfunction, or any * 292 | * and all other commercial damages or losses, even if such party * 293 | * shall have been informed of the possibility of such damages. This * 294 | * limitation of liability shall not apply to liability for death or * 295 | * personal injury resulting from such party's negligence to the * 296 | * extent applicable law prohibits such limitation. Some * 297 | * jurisdictions do not allow the exclusion or limitation of * 298 | * incidental or consequential damages, so this exclusion and * 299 | * limitation may not apply to You. * 300 | * * 301 | ************************************************************************ 302 | 303 | 8. Litigation 304 | ------------- 305 | 306 | Any litigation relating to this License may be brought only in the 307 | courts of a jurisdiction where the defendant maintains its principal 308 | place of business and such litigation shall be governed by laws of that 309 | jurisdiction, without reference to its conflict-of-law provisions. 310 | Nothing in this Section shall prevent a party's ability to bring 311 | cross-claims or counter-claims. 312 | 313 | 9. Miscellaneous 314 | ---------------- 315 | 316 | This License represents the complete agreement concerning the subject 317 | matter hereof. If any provision of this License is held to be 318 | unenforceable, such provision shall be reformed only to the extent 319 | necessary to make it enforceable. Any law or regulation which provides 320 | that the language of a contract shall be construed against the drafter 321 | shall not be used to construe this License against a Contributor. 322 | 323 | 10. Versions of the License 324 | --------------------------- 325 | 326 | 10.1. New Versions 327 | 328 | Mozilla Foundation is the license steward. Except as provided in Section 329 | 10.3, no one other than the license steward has the right to modify or 330 | publish new versions of this License. Each version will be given a 331 | distinguishing version number. 332 | 333 | 10.2. Effect of New Versions 334 | 335 | You may distribute the Covered Software under the terms of the version 336 | of the License under which You originally received the Covered Software, 337 | or under the terms of any subsequent version published by the license 338 | steward. 339 | 340 | 10.3. Modified Versions 341 | 342 | If you create software not governed by this License, and you want to 343 | create a new license for such software, you may create and use a 344 | modified version of this License if you rename the license and remove 345 | any references to the name of the license steward (except to note that 346 | such modified license differs from this License). 347 | 348 | 10.4. Distributing Source Code Form that is Incompatible With Secondary 349 | Licenses 350 | 351 | If You choose to distribute Source Code Form that is Incompatible With 352 | Secondary Licenses under the terms of this version of the License, the 353 | notice described in Exhibit B of this License must be attached. 354 | 355 | Exhibit A - Source Code Form License Notice 356 | ------------------------------------------- 357 | 358 | This Source Code Form is subject to the terms of the Mozilla Public 359 | License, v. 2.0. If a copy of the MPL was not distributed with this 360 | file, You can obtain one at http://mozilla.org/MPL/2.0/. 361 | 362 | If it is not possible or desirable to put the notice in a particular 363 | file, then You may include the notice in a location (such as a LICENSE 364 | file in a relevant directory) where a recipient would be likely to look 365 | for such a notice. 366 | 367 | You may add additional accurate notices of copyright ownership. 368 | 369 | Exhibit B - "Incompatible With Secondary Licenses" Notice 370 | --------------------------------------------------------- 371 | 372 | This Source Code Form is "Incompatible With Secondary Licenses", as 373 | defined by the Mozilla Public License, v. 2.0. 374 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aho-corasick" 5 | version = "0.7.6" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | dependencies = [ 8 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 9 | ] 10 | 11 | [[package]] 12 | name = "atty" 13 | version = "0.2.13" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | dependencies = [ 16 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 17 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 18 | ] 19 | 20 | [[package]] 21 | name = "bitflags" 22 | version = "1.2.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | 25 | [[package]] 26 | name = "cc" 27 | version = "1.0.48" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | 30 | [[package]] 31 | name = "cfg-if" 32 | version = "0.1.10" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | 35 | [[package]] 36 | name = "dtoa" 37 | version = "0.4.4" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | 40 | [[package]] 41 | name = "env_logger" 42 | version = "0.7.1" 43 | source = "registry+https://github.com/rust-lang/crates.io-index" 44 | dependencies = [ 45 | "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 46 | "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 47 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 48 | "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 49 | "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 50 | ] 51 | 52 | [[package]] 53 | name = "evdev-rs" 54 | version = "0.3.1" 55 | source = "registry+https://github.com/rust-lang/crates.io-index" 56 | dependencies = [ 57 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 58 | "evdev-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 59 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 60 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 61 | "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 62 | ] 63 | 64 | [[package]] 65 | name = "evdev-sys" 66 | version = "0.2.0" 67 | source = "registry+https://github.com/rust-lang/crates.io-index" 68 | dependencies = [ 69 | "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", 70 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 71 | "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", 72 | ] 73 | 74 | [[package]] 75 | name = "fuchsia-zircon" 76 | version = "0.3.3" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | dependencies = [ 79 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 80 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 81 | ] 82 | 83 | [[package]] 84 | name = "fuchsia-zircon-sys" 85 | version = "0.3.3" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | 88 | [[package]] 89 | name = "humantime" 90 | version = "1.3.0" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | dependencies = [ 93 | "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 94 | ] 95 | 96 | [[package]] 97 | name = "iovec" 98 | version = "0.1.4" 99 | source = "registry+https://github.com/rust-lang/crates.io-index" 100 | dependencies = [ 101 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 102 | ] 103 | 104 | [[package]] 105 | name = "kernel32-sys" 106 | version = "0.2.2" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | dependencies = [ 109 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 110 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 111 | ] 112 | 113 | [[package]] 114 | name = "lazy_static" 115 | version = "1.4.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | 118 | [[package]] 119 | name = "libc" 120 | version = "0.2.66" 121 | source = "registry+https://github.com/rust-lang/crates.io-index" 122 | 123 | [[package]] 124 | name = "libudev-sys" 125 | version = "0.1.4" 126 | source = "registry+https://github.com/rust-lang/crates.io-index" 127 | dependencies = [ 128 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 129 | "pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", 130 | ] 131 | 132 | [[package]] 133 | name = "linked-hash-map" 134 | version = "0.5.2" 135 | source = "registry+https://github.com/rust-lang/crates.io-index" 136 | 137 | [[package]] 138 | name = "log" 139 | version = "0.4.8" 140 | source = "registry+https://github.com/rust-lang/crates.io-index" 141 | dependencies = [ 142 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 143 | ] 144 | 145 | [[package]] 146 | name = "maplit" 147 | version = "1.0.2" 148 | source = "registry+https://github.com/rust-lang/crates.io-index" 149 | 150 | [[package]] 151 | name = "memchr" 152 | version = "2.2.1" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | 155 | [[package]] 156 | name = "mio" 157 | version = "0.6.21" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | dependencies = [ 160 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 161 | "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 162 | "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 163 | "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 164 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 165 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 166 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 167 | "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 168 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 169 | "slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 170 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 171 | ] 172 | 173 | [[package]] 174 | name = "miow" 175 | version = "0.2.1" 176 | source = "registry+https://github.com/rust-lang/crates.io-index" 177 | dependencies = [ 178 | "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 179 | "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 180 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 181 | "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 182 | ] 183 | 184 | [[package]] 185 | name = "nasskan" 186 | version = "0.1.0" 187 | dependencies = [ 188 | "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 189 | "evdev-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 190 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 191 | "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 192 | "maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 193 | "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", 194 | "nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 195 | "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 196 | "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", 197 | "udev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 198 | ] 199 | 200 | [[package]] 201 | name = "net2" 202 | version = "0.2.33" 203 | source = "registry+https://github.com/rust-lang/crates.io-index" 204 | dependencies = [ 205 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 206 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 207 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 208 | ] 209 | 210 | [[package]] 211 | name = "nix" 212 | version = "0.13.1" 213 | source = "registry+https://github.com/rust-lang/crates.io-index" 214 | dependencies = [ 215 | "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 216 | "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", 217 | "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 218 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 219 | "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 220 | ] 221 | 222 | [[package]] 223 | name = "pkg-config" 224 | version = "0.3.17" 225 | source = "registry+https://github.com/rust-lang/crates.io-index" 226 | 227 | [[package]] 228 | name = "proc-macro2" 229 | version = "1.0.6" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | dependencies = [ 232 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 233 | ] 234 | 235 | [[package]] 236 | name = "quick-error" 237 | version = "1.2.2" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | 240 | [[package]] 241 | name = "quote" 242 | version = "1.0.2" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | dependencies = [ 245 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 246 | ] 247 | 248 | [[package]] 249 | name = "regex" 250 | version = "1.3.1" 251 | source = "registry+https://github.com/rust-lang/crates.io-index" 252 | dependencies = [ 253 | "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 254 | "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 255 | "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", 256 | "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 257 | ] 258 | 259 | [[package]] 260 | name = "regex-syntax" 261 | version = "0.6.12" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | 264 | [[package]] 265 | name = "serde" 266 | version = "1.0.103" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | dependencies = [ 269 | "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 270 | ] 271 | 272 | [[package]] 273 | name = "serde_derive" 274 | version = "1.0.103" 275 | source = "registry+https://github.com/rust-lang/crates.io-index" 276 | dependencies = [ 277 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 278 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 279 | "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)", 280 | ] 281 | 282 | [[package]] 283 | name = "serde_yaml" 284 | version = "0.8.11" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | dependencies = [ 287 | "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 288 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 289 | "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 290 | "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 291 | ] 292 | 293 | [[package]] 294 | name = "slab" 295 | version = "0.4.2" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | 298 | [[package]] 299 | name = "syn" 300 | version = "1.0.11" 301 | source = "registry+https://github.com/rust-lang/crates.io-index" 302 | dependencies = [ 303 | "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 304 | "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 305 | "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 306 | ] 307 | 308 | [[package]] 309 | name = "termcolor" 310 | version = "1.0.5" 311 | source = "registry+https://github.com/rust-lang/crates.io-index" 312 | dependencies = [ 313 | "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 314 | ] 315 | 316 | [[package]] 317 | name = "thread_local" 318 | version = "0.3.6" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | dependencies = [ 321 | "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 322 | ] 323 | 324 | [[package]] 325 | name = "udev" 326 | version = "0.2.0" 327 | source = "registry+https://github.com/rust-lang/crates.io-index" 328 | dependencies = [ 329 | "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)", 330 | "libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 331 | ] 332 | 333 | [[package]] 334 | name = "unicode-xid" 335 | version = "0.2.0" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | 338 | [[package]] 339 | name = "void" 340 | version = "1.0.2" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | 343 | [[package]] 344 | name = "winapi" 345 | version = "0.2.8" 346 | source = "registry+https://github.com/rust-lang/crates.io-index" 347 | 348 | [[package]] 349 | name = "winapi" 350 | version = "0.3.8" 351 | source = "registry+https://github.com/rust-lang/crates.io-index" 352 | dependencies = [ 353 | "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 354 | "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 355 | ] 356 | 357 | [[package]] 358 | name = "winapi-build" 359 | version = "0.1.1" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | 362 | [[package]] 363 | name = "winapi-i686-pc-windows-gnu" 364 | version = "0.4.0" 365 | source = "registry+https://github.com/rust-lang/crates.io-index" 366 | 367 | [[package]] 368 | name = "winapi-util" 369 | version = "0.1.2" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | dependencies = [ 372 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 373 | ] 374 | 375 | [[package]] 376 | name = "winapi-x86_64-pc-windows-gnu" 377 | version = "0.4.0" 378 | source = "registry+https://github.com/rust-lang/crates.io-index" 379 | 380 | [[package]] 381 | name = "wincolor" 382 | version = "1.0.2" 383 | source = "registry+https://github.com/rust-lang/crates.io-index" 384 | dependencies = [ 385 | "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 386 | "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 387 | ] 388 | 389 | [[package]] 390 | name = "ws2_32-sys" 391 | version = "0.2.1" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | dependencies = [ 394 | "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 395 | "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 396 | ] 397 | 398 | [[package]] 399 | name = "yaml-rust" 400 | version = "0.4.3" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | dependencies = [ 403 | "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 404 | ] 405 | 406 | [metadata] 407 | "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 408 | "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 409 | "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" 410 | "checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" 411 | "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 412 | "checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" 413 | "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" 414 | "checksum evdev-rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "95f73dad019df28348aad51f059684bdf628822325c26d34fbe126e513369799" 415 | "checksum evdev-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "378763626609036d7177780326a4f589516dd058c81c99277a5a31d63bb938c0" 416 | "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 417 | "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 418 | "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" 419 | "checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" 420 | "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" 421 | "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 422 | "checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" 423 | "checksum libudev-sys 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3c8469b4a23b962c1396b9b451dda50ef5b283e8dd309d69033475fa9b334324" 424 | "checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 425 | "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 426 | "checksum maplit 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" 427 | "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 428 | "checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" 429 | "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 430 | "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 431 | "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" 432 | "checksum pkg-config 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "05da548ad6865900e60eaba7f589cc0783590a92e940c26953ff81ddbab2d677" 433 | "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" 434 | "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 435 | "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 436 | "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" 437 | "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" 438 | "checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" 439 | "checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" 440 | "checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 441 | "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 442 | "checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238" 443 | "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" 444 | "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 445 | "checksum udev 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "47504d1a49b2ea1b133e7ddd1d9f0a83cf03feb9b440c2c470d06db4589cf301" 446 | "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" 447 | "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 448 | "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" 449 | "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" 450 | "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" 451 | "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 452 | "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" 453 | "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 454 | "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" 455 | "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 456 | "checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" 457 | -------------------------------------------------------------------------------- /examples/my-personal-config.yaml: -------------------------------------------------------------------------------- 1 | version: 1 2 | devices: 3 | - if: 4 | ID_VENDOR_ID: 29ea 5 | ID_MODEL_ID: 0102 6 | then: 7 | - from: 8 | key: CAPSLOCK 9 | to: 10 | key: LEFTMETA 11 | tap: 12 | key: ENTER 13 | - from: 14 | key: BACKSPACE 15 | to: 16 | key: LEFTSHIFT 17 | - from: 18 | key: DELETE 19 | to: 20 | key: LEFTCTRL 21 | tap: 22 | key: MUHENKAN 23 | - from: 24 | key: ENTER 25 | to: 26 | key: RIGHTALT 27 | tap: 28 | key: HENKAN 29 | - from: 30 | key: EQUAL 31 | with: 32 | - LEFTSHIFT 33 | without: 34 | - LEFTCTRL 35 | - RIGHTCTRL 36 | - LEFTALT 37 | - RIGHTALT 38 | - LEFTMETA 39 | - RIGHTMETA 40 | to: 41 | key: BACKSLASH 42 | with: 43 | - LEFTSHIFT 44 | - from: 45 | key: EQUAL 46 | to: 47 | key: 1 48 | with: 49 | - LEFTSHIFT 50 | - from: 51 | key: 1 52 | with: 53 | - LEFTSHIFT 54 | without: 55 | - LEFTCTRL 56 | - RIGHTCTRL 57 | - LEFTALT 58 | - RIGHTALT 59 | - LEFTMETA 60 | - RIGHTMETA 61 | to: 62 | key: 2 63 | with: 64 | - LEFTSHIFT 65 | - from: 66 | key: 1 67 | to: 68 | key: 0 69 | - from: 70 | key: 2 71 | with: 72 | - LEFTSHIFT 73 | without: 74 | - LEFTCTRL 75 | - RIGHTCTRL 76 | - LEFTALT 77 | - RIGHTALT 78 | - LEFTMETA 79 | - RIGHTMETA 80 | to: 81 | key: LEFTBRACE 82 | with: 83 | - LEFTSHIFT 84 | - from: 85 | key: 2 86 | to: 87 | key: 1 88 | - from: 89 | key: 3 90 | with: 91 | - LEFTSHIFT 92 | without: 93 | - LEFTCTRL 94 | - RIGHTCTRL 95 | - LEFTALT 96 | - RIGHTALT 97 | - LEFTMETA 98 | - RIGHTMETA 99 | to: 100 | key: LEFTBRACE 101 | - from: 102 | key: 3 103 | to: 104 | key: 2 105 | - from: 106 | key: 4 107 | with: 108 | - LEFTSHIFT 109 | without: 110 | - LEFTCTRL 111 | - RIGHTCTRL 112 | - LEFTALT 113 | - RIGHTALT 114 | - LEFTMETA 115 | - RIGHTMETA 116 | to: 117 | key: 9 118 | with: 119 | - LEFTSHIFT 120 | - from: 121 | key: 4 122 | to: 123 | key: 3 124 | - from: 125 | key: 5 126 | with: 127 | - LEFTSHIFT 128 | without: 129 | - LEFTCTRL 130 | - RIGHTCTRL 131 | - LEFTALT 132 | - RIGHTALT 133 | - LEFTMETA 134 | - RIGHTMETA 135 | to: 136 | key: COMMA 137 | with: 138 | - LEFTSHIFT 139 | - from: 140 | key: 5 141 | to: 142 | key: 4 143 | - from: 144 | key: 6 145 | with: 146 | - LEFTSHIFT 147 | without: 148 | - LEFTCTRL 149 | - RIGHTCTRL 150 | - LEFTALT 151 | - RIGHTALT 152 | - LEFTMETA 153 | - RIGHTMETA 154 | to: 155 | key: DOT 156 | with: 157 | - LEFTSHIFT 158 | - from: 159 | key: 6 160 | to: 161 | key: 5 162 | - from: 163 | key: 7 164 | with: 165 | - LEFTSHIFT 166 | without: 167 | - LEFTCTRL 168 | - RIGHTCTRL 169 | - LEFTALT 170 | - RIGHTALT 171 | - LEFTMETA 172 | - RIGHTMETA 173 | to: 174 | key: 0 175 | with: 176 | - LEFTSHIFT 177 | - from: 178 | key: 7 179 | to: 180 | key: 6 181 | - from: 182 | key: 8 183 | with: 184 | - LEFTSHIFT 185 | without: 186 | - LEFTCTRL 187 | - RIGHTCTRL 188 | - LEFTALT 189 | - RIGHTALT 190 | - LEFTMETA 191 | - RIGHTMETA 192 | to: 193 | key: RIGHTBRACE 194 | - from: 195 | key: 8 196 | to: 197 | key: 7 198 | - from: 199 | key: 9 200 | with: 201 | - LEFTSHIFT 202 | without: 203 | - LEFTCTRL 204 | - RIGHTCTRL 205 | - LEFTALT 206 | - RIGHTALT 207 | - LEFTMETA 208 | - RIGHTMETA 209 | to: 210 | key: RIGHTBRACE 211 | with: 212 | - LEFTSHIFT 213 | - from: 214 | key: 9 215 | to: 216 | key: 8 217 | - from: 218 | key: 0 219 | with: 220 | - LEFTSHIFT 221 | without: 222 | - LEFTCTRL 223 | - RIGHTCTRL 224 | - LEFTALT 225 | - RIGHTALT 226 | - LEFTMETA 227 | - RIGHTMETA 228 | to: 229 | key: 8 230 | with: 231 | - LEFTSHIFT 232 | - from: 233 | key: 0 234 | to: 235 | key: 9 236 | - from: 237 | key: MINUS 238 | with: 239 | - LEFTSHIFT 240 | without: 241 | - LEFTCTRL 242 | - RIGHTCTRL 243 | - LEFTALT 244 | - RIGHTALT 245 | - LEFTMETA 246 | - RIGHTMETA 247 | to: 248 | key: 7 249 | with: 250 | - LEFTSHIFT 251 | - from: 252 | key: MINUS 253 | to: 254 | key: SLASH 255 | with: 256 | - LEFTSHIFT 257 | - from: 258 | key: TAB 259 | with: 260 | - LEFTSHIFT 261 | without: 262 | - LEFTCTRL 263 | - RIGHTCTRL 264 | - LEFTALT 265 | - RIGHTALT 266 | - LEFTMETA 267 | - RIGHTMETA 268 | to: 269 | key: GRAVE 270 | - from: 271 | key: TAB 272 | to: 273 | key: GRAVE 274 | with: 275 | - LEFTSHIFT 276 | - from: 277 | key: Q 278 | to: 279 | key: APOSTROPHE 280 | - from: 281 | key: W 282 | with: 283 | - LEFTSHIFT 284 | without: 285 | - LEFTCTRL 286 | - RIGHTCTRL 287 | - LEFTALT 288 | - RIGHTALT 289 | - LEFTMETA 290 | - RIGHTMETA 291 | to: 292 | key: 3 293 | with: 294 | - LEFTSHIFT 295 | - from: 296 | key: W 297 | to: 298 | key: COMMA 299 | - from: 300 | key: E 301 | with: 302 | - LEFTSHIFT 303 | without: 304 | - LEFTCTRL 305 | - RIGHTCTRL 306 | - LEFTALT 307 | - RIGHTALT 308 | - LEFTMETA 309 | - RIGHTMETA 310 | to: 311 | key: 4 312 | with: 313 | - LEFTSHIFT 314 | - from: 315 | key: E 316 | to: 317 | key: DOT 318 | - from: 319 | key: R 320 | to: 321 | key: P 322 | - from: 323 | key: T 324 | to: 325 | key: Y 326 | - from: 327 | key: Y 328 | to: 329 | key: F 330 | - from: 331 | key: U 332 | with: 333 | - LEFTMETA 334 | to: 335 | key: HOME 336 | - from: 337 | key: U 338 | to: 339 | key: G 340 | - from: 341 | key: I 342 | with: 343 | - LEFTMETA 344 | to: 345 | key: LEFT 346 | with: 347 | - RIGHTCTRL 348 | - from: 349 | key: O 350 | with: 351 | - LEFTMETA 352 | to: 353 | key: RIGHT 354 | with: 355 | - RIGHTCTRL 356 | - from: 357 | key: P 358 | with: 359 | - LEFTMETA 360 | to: 361 | key: END 362 | - from: 363 | key: I 364 | to: 365 | key: C 366 | - from: 367 | key: O 368 | to: 369 | key: R 370 | - from: 371 | key: P 372 | to: 373 | key: L 374 | - from: 375 | key: BACKSLASH 376 | with: 377 | - LEFTSHIFT 378 | without: 379 | - LEFTCTRL 380 | - RIGHTCTRL 381 | - LEFTALT 382 | - RIGHTALT 383 | - LEFTMETA 384 | - RIGHTMETA 385 | to: 386 | key: 5 387 | with: 388 | - LEFTSHIFT 389 | - from: 390 | key: BACKSLASH 391 | to: 392 | key: SLASH 393 | - from: 394 | key: S 395 | to: 396 | key: O 397 | - from: 398 | key: D 399 | to: 400 | key: E 401 | - from: 402 | key: F 403 | to: 404 | key: U 405 | - from: 406 | key: G 407 | to: 408 | key: I 409 | - from: 410 | key: H 411 | with: 412 | - LEFTMETA 413 | to: 414 | key: BACKSPACE 415 | - from: 416 | key: H 417 | to: 418 | key: D 419 | - from: 420 | key: J 421 | with: 422 | - LEFTMETA 423 | to: 424 | key: LEFT 425 | - from: 426 | key: J 427 | to: 428 | key: H 429 | - from: 430 | key: K 431 | with: 432 | - LEFTMETA 433 | to: 434 | key: UP 435 | - from: 436 | key: K 437 | to: 438 | key: T 439 | - from: 440 | key: L 441 | with: 442 | - LEFTMETA 443 | to: 444 | key: DOWN 445 | - from: 446 | key: L 447 | to: 448 | key: N 449 | - from: 450 | key: SEMICOLON 451 | with: 452 | - LEFTMETA 453 | to: 454 | key: RIGHT 455 | - from: 456 | key: SEMICOLON 457 | to: 458 | key: S 459 | - from: 460 | key: APOSTROPHE 461 | with: 462 | - LEFTMETA 463 | to: 464 | key: DELETE 465 | - from: 466 | key: APOSTROPHE 467 | to: 468 | key: MINUS 469 | - from: 470 | key: LEFTSHIFT 471 | with: 472 | - LEFTSHIFT 473 | without: 474 | - LEFTCTRL 475 | - RIGHTCTRL 476 | - LEFTALT 477 | - RIGHTALT 478 | - LEFTMETA 479 | - RIGHTMETA 480 | to: 481 | key: 6 482 | with: 483 | - LEFTSHIFT 484 | - from: 485 | key: LEFTSHIFT 486 | to: 487 | key: BACKSLASH 488 | - from: 489 | key: Z 490 | to: 491 | key: SEMICOLON 492 | - from: 493 | key: X 494 | to: 495 | key: Q 496 | - from: 497 | key: C 498 | to: 499 | key: J 500 | - from: 501 | key: V 502 | to: 503 | key: K 504 | - from: 505 | key: B 506 | to: 507 | key: X 508 | - from: 509 | key: N 510 | to: 511 | key: B 512 | - from: 513 | key: COMMA 514 | to: 515 | key: W 516 | - from: 517 | key: DOT 518 | to: 519 | key: V 520 | - from: 521 | key: SLASH 522 | to: 523 | key: Z 524 | - from: 525 | key: RIGHTSHIFT 526 | to: 527 | key: EQUAL 528 | - from: 529 | key: GRAVE 530 | to: 531 | key: ESC 532 | - from: 533 | key: 102ND 534 | to: 535 | key: TAB 536 | - from: 537 | key: LEFT 538 | to: 539 | key: BACKSPACE 540 | - from: 541 | key: RIGHT 542 | to: 543 | key: DELETE 544 | - from: 545 | key: UP 546 | to: 547 | key: LEFT 548 | - from: 549 | key: DOWN 550 | to: 551 | key: UP 552 | - from: 553 | key: LEFTBRACE 554 | to: 555 | key: DOWN 556 | - from: 557 | key: RIGHTBRACE 558 | to: 559 | key: RIGHT 560 | - if: 561 | MAJOR: 13 562 | MINOR: 68 563 | then: 564 | - from: 565 | key: CAPSLOCK 566 | to: 567 | key: LEFTMETA 568 | tap: 569 | key: ENTER 570 | - from: 571 | key: LEFTALT 572 | to: 573 | key: LEFTSHIFT 574 | tap: 575 | key: MUHENKAN 576 | - from: 577 | key: RIGHTALT 578 | to: 579 | key: RIGHTCTRL 580 | tap: 581 | key: HENKAN 582 | - from: 583 | key: RIGHTCTRL 584 | to: 585 | key: RIGHTALT 586 | - from: 587 | key: GRAVE 588 | with: 589 | - LEFTSHIFT 590 | without: 591 | - LEFTCTRL 592 | - RIGHTCTRL 593 | - LEFTALT 594 | - RIGHTALT 595 | - LEFTMETA 596 | - RIGHTMETA 597 | to: 598 | key: BACKSLASH 599 | with: 600 | - LEFTSHIFT 601 | - from: 602 | key: GRAVE 603 | to: 604 | key: 1 605 | with: 606 | - LEFTSHIFT 607 | - from: 608 | key: 1 609 | with: 610 | - LEFTSHIFT 611 | without: 612 | - LEFTCTRL 613 | - RIGHTCTRL 614 | - LEFTALT 615 | - RIGHTALT 616 | - LEFTMETA 617 | - RIGHTMETA 618 | to: 619 | key: 2 620 | with: 621 | - LEFTSHIFT 622 | - from: 623 | key: 1 624 | to: 625 | key: 0 626 | - from: 627 | key: 2 628 | with: 629 | - LEFTSHIFT 630 | without: 631 | - LEFTCTRL 632 | - RIGHTCTRL 633 | - LEFTALT 634 | - RIGHTALT 635 | - LEFTMETA 636 | - RIGHTMETA 637 | to: 638 | key: LEFTBRACE 639 | with: 640 | - LEFTSHIFT 641 | - from: 642 | key: 2 643 | to: 644 | key: 1 645 | - from: 646 | key: 3 647 | with: 648 | - LEFTSHIFT 649 | without: 650 | - LEFTCTRL 651 | - RIGHTCTRL 652 | - LEFTALT 653 | - RIGHTALT 654 | - LEFTMETA 655 | - RIGHTMETA 656 | to: 657 | key: LEFTBRACE 658 | - from: 659 | key: 3 660 | to: 661 | key: 2 662 | - from: 663 | key: 4 664 | with: 665 | - LEFTSHIFT 666 | without: 667 | - LEFTCTRL 668 | - RIGHTCTRL 669 | - LEFTALT 670 | - RIGHTALT 671 | - LEFTMETA 672 | - RIGHTMETA 673 | to: 674 | key: 9 675 | with: 676 | - LEFTSHIFT 677 | - from: 678 | key: 4 679 | to: 680 | key: 3 681 | - from: 682 | key: 5 683 | with: 684 | - LEFTSHIFT 685 | without: 686 | - LEFTCTRL 687 | - RIGHTCTRL 688 | - LEFTALT 689 | - RIGHTALT 690 | - LEFTMETA 691 | - RIGHTMETA 692 | to: 693 | key: COMMA 694 | with: 695 | - LEFTSHIFT 696 | - from: 697 | key: 5 698 | to: 699 | key: 4 700 | - from: 701 | key: 6 702 | to: 703 | key: PRINT 704 | - from: 705 | key: 7 706 | with: 707 | - LEFTSHIFT 708 | without: 709 | - LEFTCTRL 710 | - RIGHTCTRL 711 | - LEFTALT 712 | - RIGHTALT 713 | - LEFTMETA 714 | - RIGHTMETA 715 | to: 716 | key: DOT 717 | with: 718 | - LEFTSHIFT 719 | - from: 720 | key: 7 721 | to: 722 | key: 5 723 | - from: 724 | key: 8 725 | with: 726 | - LEFTSHIFT 727 | without: 728 | - LEFTCTRL 729 | - RIGHTCTRL 730 | - LEFTALT 731 | - RIGHTALT 732 | - LEFTMETA 733 | - RIGHTMETA 734 | to: 735 | key: 0 736 | with: 737 | - LEFTSHIFT 738 | - from: 739 | key: 8 740 | to: 741 | key: 6 742 | - from: 743 | key: 9 744 | with: 745 | - LEFTSHIFT 746 | without: 747 | - LEFTCTRL 748 | - RIGHTCTRL 749 | - LEFTALT 750 | - RIGHTALT 751 | - LEFTMETA 752 | - RIGHTMETA 753 | to: 754 | key: RIGHTBRACE 755 | - from: 756 | key: 9 757 | to: 758 | key: 7 759 | - from: 760 | key: 0 761 | with: 762 | - LEFTSHIFT 763 | without: 764 | - LEFTCTRL 765 | - RIGHTCTRL 766 | - LEFTALT 767 | - RIGHTALT 768 | - LEFTMETA 769 | - RIGHTMETA 770 | to: 771 | key: RIGHTBRACE 772 | with: 773 | - LEFTSHIFT 774 | - from: 775 | key: 0 776 | to: 777 | key: 8 778 | - from: 779 | key: MINUS 780 | with: 781 | - LEFTSHIFT 782 | without: 783 | - LEFTCTRL 784 | - RIGHTCTRL 785 | - LEFTALT 786 | - RIGHTALT 787 | - LEFTMETA 788 | - RIGHTMETA 789 | to: 790 | key: 8 791 | with: 792 | - LEFTSHIFT 793 | - from: 794 | key: MINUS 795 | to: 796 | key: 9 797 | - from: 798 | key: EQUAL 799 | with: 800 | - LEFTSHIFT 801 | without: 802 | - LEFTCTRL 803 | - RIGHTCTRL 804 | - LEFTALT 805 | - RIGHTALT 806 | - LEFTMETA 807 | - RIGHTMETA 808 | to: 809 | key: 7 810 | with: 811 | - LEFTSHIFT 812 | - from: 813 | key: EQUAL 814 | to: 815 | key: SLASH 816 | with: 817 | - LEFTSHIFT 818 | - from: 819 | key: TAB 820 | with: 821 | - LEFTSHIFT 822 | without: 823 | - LEFTCTRL 824 | - RIGHTCTRL 825 | - LEFTALT 826 | - RIGHTALT 827 | - LEFTMETA 828 | - RIGHTMETA 829 | to: 830 | key: GRAVE 831 | - from: 832 | key: TAB 833 | to: 834 | key: GRAVE 835 | with: 836 | - LEFTSHIFT 837 | - from: 838 | key: Q 839 | to: 840 | key: APOSTROPHE 841 | - from: 842 | key: W 843 | with: 844 | - LEFTSHIFT 845 | without: 846 | - LEFTCTRL 847 | - RIGHTCTRL 848 | - LEFTALT 849 | - RIGHTALT 850 | - LEFTMETA 851 | - RIGHTMETA 852 | to: 853 | key: 3 854 | with: 855 | - LEFTSHIFT 856 | - from: 857 | key: W 858 | to: 859 | key: COMMA 860 | - from: 861 | key: E 862 | with: 863 | - LEFTSHIFT 864 | without: 865 | - LEFTCTRL 866 | - RIGHTCTRL 867 | - LEFTALT 868 | - RIGHTALT 869 | - LEFTMETA 870 | - RIGHTMETA 871 | to: 872 | key: 4 873 | with: 874 | - LEFTSHIFT 875 | - from: 876 | key: E 877 | to: 878 | key: DOT 879 | - from: 880 | key: R 881 | to: 882 | key: P 883 | - from: 884 | key: T 885 | to: 886 | key: Y 887 | - from: 888 | key: Y 889 | to: 890 | key: F 891 | - from: 892 | key: U 893 | with: 894 | - LEFTMETA 895 | to: 896 | key: HOME 897 | - from: 898 | key: U 899 | to: 900 | key: G 901 | - from: 902 | key: I 903 | with: 904 | - LEFTMETA 905 | to: 906 | key: LEFT 907 | with: 908 | - RIGHTCTRL 909 | - from: 910 | key: O 911 | with: 912 | - LEFTMETA 913 | to: 914 | key: RIGHT 915 | with: 916 | - RIGHTCTRL 917 | - from: 918 | key: P 919 | with: 920 | - LEFTMETA 921 | to: 922 | key: END 923 | - from: 924 | key: I 925 | to: 926 | key: C 927 | - from: 928 | key: O 929 | to: 930 | key: R 931 | - from: 932 | key: P 933 | to: 934 | key: L 935 | - from: 936 | key: LEFTBRACE 937 | with: 938 | - LEFTSHIFT 939 | without: 940 | - LEFTCTRL 941 | - RIGHTCTRL 942 | - LEFTALT 943 | - RIGHTALT 944 | - LEFTMETA 945 | - RIGHTMETA 946 | to: 947 | key: 5 948 | with: 949 | - LEFTSHIFT 950 | - from: 951 | key: LEFTBRACE 952 | to: 953 | key: SLASH 954 | - from: 955 | key: RIGHTBRACE 956 | to: 957 | key: EQUAL 958 | - from: 959 | key: S 960 | to: 961 | key: O 962 | - from: 963 | key: D 964 | to: 965 | key: E 966 | - from: 967 | key: F 968 | to: 969 | key: U 970 | - from: 971 | key: G 972 | to: 973 | key: I 974 | - from: 975 | key: H 976 | with: 977 | - LEFTMETA 978 | to: 979 | key: BACKSPACE 980 | - from: 981 | key: H 982 | to: 983 | key: D 984 | - from: 985 | key: J 986 | with: 987 | - LEFTMETA 988 | to: 989 | key: LEFT 990 | - from: 991 | key: J 992 | to: 993 | key: H 994 | - from: 995 | key: K 996 | with: 997 | - LEFTMETA 998 | to: 999 | key: UP 1000 | - from: 1001 | key: K 1002 | to: 1003 | key: T 1004 | - from: 1005 | key: L 1006 | with: 1007 | - LEFTMETA 1008 | to: 1009 | key: DOWN 1010 | - from: 1011 | key: L 1012 | to: 1013 | key: N 1014 | - from: 1015 | key: SEMICOLON 1016 | with: 1017 | - LEFTMETA 1018 | to: 1019 | key: RIGHT 1020 | - from: 1021 | key: SEMICOLON 1022 | to: 1023 | key: S 1024 | - from: 1025 | key: APOSTROPHE 1026 | with: 1027 | - LEFTMETA 1028 | to: 1029 | key: DELETE 1030 | - from: 1031 | key: APOSTROPHE 1032 | to: 1033 | key: MINUS 1034 | - from: 1035 | key: ENTER 1036 | to: 1037 | key: TAB 1038 | - from: 1039 | key: LEFTSHIFT 1040 | with: 1041 | - LEFTSHIFT 1042 | without: 1043 | - LEFTCTRL 1044 | - RIGHTCTRL 1045 | - LEFTALT 1046 | - RIGHTALT 1047 | - LEFTMETA 1048 | - RIGHTMETA 1049 | to: 1050 | key: 6 1051 | with: 1052 | - LEFTSHIFT 1053 | - from: 1054 | key: LEFTSHIFT 1055 | to: 1056 | key: BACKSLASH 1057 | - from: 1058 | key: Z 1059 | to: 1060 | key: SEMICOLON 1061 | - from: 1062 | key: X 1063 | to: 1064 | key: Q 1065 | - from: 1066 | key: C 1067 | to: 1068 | key: J 1069 | - from: 1070 | key: V 1071 | to: 1072 | key: K 1073 | - from: 1074 | key: B 1075 | to: 1076 | key: X 1077 | - from: 1078 | key: N 1079 | to: 1080 | key: B 1081 | - from: 1082 | key: COMMA 1083 | to: 1084 | key: W 1085 | - from: 1086 | key: DOT 1087 | to: 1088 | key: V 1089 | - from: 1090 | key: SLASH 1091 | to: 1092 | key: Z 1093 | - from: 1094 | key: RIGHTSHIFT 1095 | to: 1096 | key: ESC 1097 | -------------------------------------------------------------------------------- /src/config.rs: -------------------------------------------------------------------------------- 1 | use evdev_rs::enums::EV_KEY; 2 | use lazy_static::lazy_static; 3 | use serde::de::Visitor; 4 | use serde::{Deserialize, Deserializer}; 5 | use std::cmp::{Ordering, PartialOrd}; 6 | use std::collections::{BTreeMap, BTreeSet}; 7 | use std::ops::Deref; 8 | 9 | mod validation; 10 | use validation::*; 11 | 12 | lazy_static! { 13 | pub(crate) static ref CONFIG: Config = { 14 | let file = std::fs::File::open("/etc/nasskan/config.yaml") 15 | .expect("/etc/nasskan/config.yaml could not be opened"); 16 | let reader = std::io::BufReader::new(file); 17 | let config: Config = 18 | serde_yaml::from_reader(reader).expect("/etc/nasskan/config.yaml has invalid shape"); 19 | 20 | validate_order(&config); 21 | validate_tap(&config); 22 | 23 | assert_eq!(config.version, 1); 24 | config 25 | }; 26 | } 27 | 28 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 29 | pub(crate) struct Config { 30 | pub(crate) version: u8, 31 | pub(crate) devices: Vec, 32 | } 33 | 34 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 35 | pub(crate) struct Device { 36 | #[serde(rename(deserialize = "if"))] 37 | pub(crate) if_: BTreeMap, 38 | pub(crate) then: Vec, 39 | } 40 | 41 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 42 | pub(crate) struct Rule { 43 | pub(crate) from: From_, 44 | pub(crate) to: To, 45 | pub(crate) tap: Option, 46 | } 47 | 48 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 49 | pub(crate) struct From_ { 50 | pub(crate) key: EventKey, 51 | pub(crate) with: Option>, 52 | pub(crate) without: Option>, 53 | } 54 | 55 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 56 | pub(crate) struct To { 57 | pub(crate) key: EventKey, 58 | pub(crate) with: Option>, 59 | } 60 | 61 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 62 | pub(crate) struct Tap { 63 | pub(crate) key: EventKey, 64 | } 65 | 66 | #[derive(Deserialize, Debug, Clone, Eq, PartialEq, Ord, PartialOrd)] 67 | pub(crate) enum Modifier { 68 | LEFTSHIFT, 69 | RIGHTSHIFT, 70 | LEFTCTRL, 71 | RIGHTCTRL, 72 | LEFTALT, 73 | RIGHTALT, 74 | LEFTMETA, 75 | RIGHTMETA, 76 | } 77 | 78 | #[derive(Debug, Clone, Eq, PartialEq)] 79 | pub(crate) struct EventKey(EV_KEY); 80 | 81 | impl From for EventKey { 82 | fn from(key: EV_KEY) -> Self { 83 | Self(key) 84 | } 85 | } 86 | 87 | impl Into for EventKey { 88 | fn into(self) -> EV_KEY { 89 | self.0 90 | } 91 | } 92 | 93 | impl Deref for EventKey { 94 | type Target = EV_KEY; 95 | 96 | fn deref(&self) -> &EV_KEY { 97 | &self.0 98 | } 99 | } 100 | 101 | impl Ord for EventKey { 102 | fn cmp(&self, other: &Self) -> Ordering { 103 | (self.0.clone() as u32).cmp(&(other.0.clone() as u32)) 104 | } 105 | } 106 | 107 | impl PartialOrd for EventKey { 108 | fn partial_cmp(&self, other: &Self) -> Option { 109 | (self.0.clone() as u32).partial_cmp(&(other.0.clone() as u32)) 110 | } 111 | } 112 | 113 | impl<'a> Deserialize<'a> for EventKey { 114 | fn deserialize>(deserializer: T) -> Result { 115 | deserializer.deserialize_str(EventKeyVisitor) 116 | } 117 | } 118 | 119 | struct EventKeyVisitor; 120 | impl<'a> Visitor<'a> for EventKeyVisitor { 121 | type Value = EventKey; 122 | 123 | fn expecting(&self, formatter: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { 124 | formatter.write_str("keycode name") 125 | } 126 | 127 | fn visit_str(self, value: &str) -> Result { 128 | match value { 129 | "RESERVED" => Ok(EventKey(EV_KEY::KEY_RESERVED)), 130 | "ESC" => Ok(EventKey(EV_KEY::KEY_ESC)), 131 | "1" => Ok(EventKey(EV_KEY::KEY_1)), 132 | "2" => Ok(EventKey(EV_KEY::KEY_2)), 133 | "3" => Ok(EventKey(EV_KEY::KEY_3)), 134 | "4" => Ok(EventKey(EV_KEY::KEY_4)), 135 | "5" => Ok(EventKey(EV_KEY::KEY_5)), 136 | "6" => Ok(EventKey(EV_KEY::KEY_6)), 137 | "7" => Ok(EventKey(EV_KEY::KEY_7)), 138 | "8" => Ok(EventKey(EV_KEY::KEY_8)), 139 | "9" => Ok(EventKey(EV_KEY::KEY_9)), 140 | "0" => Ok(EventKey(EV_KEY::KEY_0)), 141 | "MINUS" => Ok(EventKey(EV_KEY::KEY_MINUS)), 142 | "EQUAL" => Ok(EventKey(EV_KEY::KEY_EQUAL)), 143 | "BACKSPACE" => Ok(EventKey(EV_KEY::KEY_BACKSPACE)), 144 | "TAB" => Ok(EventKey(EV_KEY::KEY_TAB)), 145 | "Q" => Ok(EventKey(EV_KEY::KEY_Q)), 146 | "W" => Ok(EventKey(EV_KEY::KEY_W)), 147 | "E" => Ok(EventKey(EV_KEY::KEY_E)), 148 | "R" => Ok(EventKey(EV_KEY::KEY_R)), 149 | "T" => Ok(EventKey(EV_KEY::KEY_T)), 150 | "Y" => Ok(EventKey(EV_KEY::KEY_Y)), 151 | "U" => Ok(EventKey(EV_KEY::KEY_U)), 152 | "I" => Ok(EventKey(EV_KEY::KEY_I)), 153 | "O" => Ok(EventKey(EV_KEY::KEY_O)), 154 | "P" => Ok(EventKey(EV_KEY::KEY_P)), 155 | "LEFTBRACE" => Ok(EventKey(EV_KEY::KEY_LEFTBRACE)), 156 | "RIGHTBRACE" => Ok(EventKey(EV_KEY::KEY_RIGHTBRACE)), 157 | "ENTER" => Ok(EventKey(EV_KEY::KEY_ENTER)), 158 | "LEFTCTRL" => Ok(EventKey(EV_KEY::KEY_LEFTCTRL)), 159 | "A" => Ok(EventKey(EV_KEY::KEY_A)), 160 | "S" => Ok(EventKey(EV_KEY::KEY_S)), 161 | "D" => Ok(EventKey(EV_KEY::KEY_D)), 162 | "F" => Ok(EventKey(EV_KEY::KEY_F)), 163 | "G" => Ok(EventKey(EV_KEY::KEY_G)), 164 | "H" => Ok(EventKey(EV_KEY::KEY_H)), 165 | "J" => Ok(EventKey(EV_KEY::KEY_J)), 166 | "K" => Ok(EventKey(EV_KEY::KEY_K)), 167 | "L" => Ok(EventKey(EV_KEY::KEY_L)), 168 | "SEMICOLON" => Ok(EventKey(EV_KEY::KEY_SEMICOLON)), 169 | "APOSTROPHE" => Ok(EventKey(EV_KEY::KEY_APOSTROPHE)), 170 | "GRAVE" => Ok(EventKey(EV_KEY::KEY_GRAVE)), 171 | "LEFTSHIFT" => Ok(EventKey(EV_KEY::KEY_LEFTSHIFT)), 172 | "BACKSLASH" => Ok(EventKey(EV_KEY::KEY_BACKSLASH)), 173 | "Z" => Ok(EventKey(EV_KEY::KEY_Z)), 174 | "X" => Ok(EventKey(EV_KEY::KEY_X)), 175 | "C" => Ok(EventKey(EV_KEY::KEY_C)), 176 | "V" => Ok(EventKey(EV_KEY::KEY_V)), 177 | "B" => Ok(EventKey(EV_KEY::KEY_B)), 178 | "N" => Ok(EventKey(EV_KEY::KEY_N)), 179 | "M" => Ok(EventKey(EV_KEY::KEY_M)), 180 | "COMMA" => Ok(EventKey(EV_KEY::KEY_COMMA)), 181 | "DOT" => Ok(EventKey(EV_KEY::KEY_DOT)), 182 | "SLASH" => Ok(EventKey(EV_KEY::KEY_SLASH)), 183 | "RIGHTSHIFT" => Ok(EventKey(EV_KEY::KEY_RIGHTSHIFT)), 184 | "KPASTERISK" => Ok(EventKey(EV_KEY::KEY_KPASTERISK)), 185 | "LEFTALT" => Ok(EventKey(EV_KEY::KEY_LEFTALT)), 186 | "SPACE" => Ok(EventKey(EV_KEY::KEY_SPACE)), 187 | "CAPSLOCK" => Ok(EventKey(EV_KEY::KEY_CAPSLOCK)), 188 | "F1" => Ok(EventKey(EV_KEY::KEY_F1)), 189 | "F2" => Ok(EventKey(EV_KEY::KEY_F2)), 190 | "F3" => Ok(EventKey(EV_KEY::KEY_F3)), 191 | "F4" => Ok(EventKey(EV_KEY::KEY_F4)), 192 | "F5" => Ok(EventKey(EV_KEY::KEY_F5)), 193 | "F6" => Ok(EventKey(EV_KEY::KEY_F6)), 194 | "F7" => Ok(EventKey(EV_KEY::KEY_F7)), 195 | "F8" => Ok(EventKey(EV_KEY::KEY_F8)), 196 | "F9" => Ok(EventKey(EV_KEY::KEY_F9)), 197 | "F10" => Ok(EventKey(EV_KEY::KEY_F10)), 198 | "NUMLOCK" => Ok(EventKey(EV_KEY::KEY_NUMLOCK)), 199 | "SCROLLLOCK" => Ok(EventKey(EV_KEY::KEY_SCROLLLOCK)), 200 | "KP7" => Ok(EventKey(EV_KEY::KEY_KP7)), 201 | "KP8" => Ok(EventKey(EV_KEY::KEY_KP8)), 202 | "KP9" => Ok(EventKey(EV_KEY::KEY_KP9)), 203 | "KPMINUS" => Ok(EventKey(EV_KEY::KEY_KPMINUS)), 204 | "KP4" => Ok(EventKey(EV_KEY::KEY_KP4)), 205 | "KP5" => Ok(EventKey(EV_KEY::KEY_KP5)), 206 | "KP6" => Ok(EventKey(EV_KEY::KEY_KP6)), 207 | "KPPLUS" => Ok(EventKey(EV_KEY::KEY_KPPLUS)), 208 | "KP1" => Ok(EventKey(EV_KEY::KEY_KP1)), 209 | "KP2" => Ok(EventKey(EV_KEY::KEY_KP2)), 210 | "KP3" => Ok(EventKey(EV_KEY::KEY_KP3)), 211 | "KP0" => Ok(EventKey(EV_KEY::KEY_KP0)), 212 | "KPDOT" => Ok(EventKey(EV_KEY::KEY_KPDOT)), 213 | "ZENKAKUHANKAKU" => Ok(EventKey(EV_KEY::KEY_ZENKAKUHANKAKU)), 214 | "102ND" => Ok(EventKey(EV_KEY::KEY_102ND)), 215 | "F11" => Ok(EventKey(EV_KEY::KEY_F11)), 216 | "F12" => Ok(EventKey(EV_KEY::KEY_F12)), 217 | "RO" => Ok(EventKey(EV_KEY::KEY_RO)), 218 | "KATAKANA" => Ok(EventKey(EV_KEY::KEY_KATAKANA)), 219 | "HIRAGANA" => Ok(EventKey(EV_KEY::KEY_HIRAGANA)), 220 | "HENKAN" => Ok(EventKey(EV_KEY::KEY_HENKAN)), 221 | "KATAKANAHIRAGANA" => Ok(EventKey(EV_KEY::KEY_KATAKANAHIRAGANA)), 222 | "MUHENKAN" => Ok(EventKey(EV_KEY::KEY_MUHENKAN)), 223 | "KPJPCOMMA" => Ok(EventKey(EV_KEY::KEY_KPJPCOMMA)), 224 | "KPENTER" => Ok(EventKey(EV_KEY::KEY_KPENTER)), 225 | "RIGHTCTRL" => Ok(EventKey(EV_KEY::KEY_RIGHTCTRL)), 226 | "KPSLASH" => Ok(EventKey(EV_KEY::KEY_KPSLASH)), 227 | "SYSRQ" => Ok(EventKey(EV_KEY::KEY_SYSRQ)), 228 | "RIGHTALT" => Ok(EventKey(EV_KEY::KEY_RIGHTALT)), 229 | "LINEFEED" => Ok(EventKey(EV_KEY::KEY_LINEFEED)), 230 | "HOME" => Ok(EventKey(EV_KEY::KEY_HOME)), 231 | "UP" => Ok(EventKey(EV_KEY::KEY_UP)), 232 | "PAGEUP" => Ok(EventKey(EV_KEY::KEY_PAGEUP)), 233 | "LEFT" => Ok(EventKey(EV_KEY::KEY_LEFT)), 234 | "RIGHT" => Ok(EventKey(EV_KEY::KEY_RIGHT)), 235 | "END" => Ok(EventKey(EV_KEY::KEY_END)), 236 | "DOWN" => Ok(EventKey(EV_KEY::KEY_DOWN)), 237 | "PAGEDOWN" => Ok(EventKey(EV_KEY::KEY_PAGEDOWN)), 238 | "INSERT" => Ok(EventKey(EV_KEY::KEY_INSERT)), 239 | "DELETE" => Ok(EventKey(EV_KEY::KEY_DELETE)), 240 | "MACRO" => Ok(EventKey(EV_KEY::KEY_MACRO)), 241 | "MUTE" => Ok(EventKey(EV_KEY::KEY_MUTE)), 242 | "VOLUMEDOWN" => Ok(EventKey(EV_KEY::KEY_VOLUMEDOWN)), 243 | "VOLUMEUP" => Ok(EventKey(EV_KEY::KEY_VOLUMEUP)), 244 | "POWER" => Ok(EventKey(EV_KEY::KEY_POWER)), 245 | "KPEQUAL" => Ok(EventKey(EV_KEY::KEY_KPEQUAL)), 246 | "KPPLUSMINUS" => Ok(EventKey(EV_KEY::KEY_KPPLUSMINUS)), 247 | "PAUSE" => Ok(EventKey(EV_KEY::KEY_PAUSE)), 248 | "SCALE" => Ok(EventKey(EV_KEY::KEY_SCALE)), 249 | "KPCOMMA" => Ok(EventKey(EV_KEY::KEY_KPCOMMA)), 250 | "HANGEUL" => Ok(EventKey(EV_KEY::KEY_HANGEUL)), 251 | "HANJA" => Ok(EventKey(EV_KEY::KEY_HANJA)), 252 | "YEN" => Ok(EventKey(EV_KEY::KEY_YEN)), 253 | "LEFTMETA" => Ok(EventKey(EV_KEY::KEY_LEFTMETA)), 254 | "RIGHTMETA" => Ok(EventKey(EV_KEY::KEY_RIGHTMETA)), 255 | "COMPOSE" => Ok(EventKey(EV_KEY::KEY_COMPOSE)), 256 | "STOP" => Ok(EventKey(EV_KEY::KEY_STOP)), 257 | "AGAIN" => Ok(EventKey(EV_KEY::KEY_AGAIN)), 258 | "PROPS" => Ok(EventKey(EV_KEY::KEY_PROPS)), 259 | "UNDO" => Ok(EventKey(EV_KEY::KEY_UNDO)), 260 | "FRONT" => Ok(EventKey(EV_KEY::KEY_FRONT)), 261 | "COPY" => Ok(EventKey(EV_KEY::KEY_COPY)), 262 | "OPEN" => Ok(EventKey(EV_KEY::KEY_OPEN)), 263 | "PASTE" => Ok(EventKey(EV_KEY::KEY_PASTE)), 264 | "FIND" => Ok(EventKey(EV_KEY::KEY_FIND)), 265 | "CUT" => Ok(EventKey(EV_KEY::KEY_CUT)), 266 | "HELP" => Ok(EventKey(EV_KEY::KEY_HELP)), 267 | "MENU" => Ok(EventKey(EV_KEY::KEY_MENU)), 268 | "CALC" => Ok(EventKey(EV_KEY::KEY_CALC)), 269 | "SETUP" => Ok(EventKey(EV_KEY::KEY_SETUP)), 270 | "SLEEP" => Ok(EventKey(EV_KEY::KEY_SLEEP)), 271 | "WAKEUP" => Ok(EventKey(EV_KEY::KEY_WAKEUP)), 272 | "FILE" => Ok(EventKey(EV_KEY::KEY_FILE)), 273 | "SENDFILE" => Ok(EventKey(EV_KEY::KEY_SENDFILE)), 274 | "DELETEFILE" => Ok(EventKey(EV_KEY::KEY_DELETEFILE)), 275 | "XFER" => Ok(EventKey(EV_KEY::KEY_XFER)), 276 | "PROG1" => Ok(EventKey(EV_KEY::KEY_PROG1)), 277 | "PROG2" => Ok(EventKey(EV_KEY::KEY_PROG2)), 278 | "WWW" => Ok(EventKey(EV_KEY::KEY_WWW)), 279 | "MSDOS" => Ok(EventKey(EV_KEY::KEY_MSDOS)), 280 | "COFFEE" => Ok(EventKey(EV_KEY::KEY_COFFEE)), 281 | "ROTATE_DISPLAY" => Ok(EventKey(EV_KEY::KEY_ROTATE_DISPLAY)), 282 | "CYCLEWINDOWS" => Ok(EventKey(EV_KEY::KEY_CYCLEWINDOWS)), 283 | "MAIL" => Ok(EventKey(EV_KEY::KEY_MAIL)), 284 | "BOOKMARKS" => Ok(EventKey(EV_KEY::KEY_BOOKMARKS)), 285 | "COMPUTER" => Ok(EventKey(EV_KEY::KEY_COMPUTER)), 286 | "BACK" => Ok(EventKey(EV_KEY::KEY_BACK)), 287 | "FORWARD" => Ok(EventKey(EV_KEY::KEY_FORWARD)), 288 | "CLOSECD" => Ok(EventKey(EV_KEY::KEY_CLOSECD)), 289 | "EJECTCD" => Ok(EventKey(EV_KEY::KEY_EJECTCD)), 290 | "EJECTCLOSECD" => Ok(EventKey(EV_KEY::KEY_EJECTCLOSECD)), 291 | "NEXTSONG" => Ok(EventKey(EV_KEY::KEY_NEXTSONG)), 292 | "PLAYPAUSE" => Ok(EventKey(EV_KEY::KEY_PLAYPAUSE)), 293 | "PREVIOUSSONG" => Ok(EventKey(EV_KEY::KEY_PREVIOUSSONG)), 294 | "STOPCD" => Ok(EventKey(EV_KEY::KEY_STOPCD)), 295 | "RECORD" => Ok(EventKey(EV_KEY::KEY_RECORD)), 296 | "REWIND" => Ok(EventKey(EV_KEY::KEY_REWIND)), 297 | "PHONE" => Ok(EventKey(EV_KEY::KEY_PHONE)), 298 | "ISO" => Ok(EventKey(EV_KEY::KEY_ISO)), 299 | "CONFIG" => Ok(EventKey(EV_KEY::KEY_CONFIG)), 300 | "HOMEPAGE" => Ok(EventKey(EV_KEY::KEY_HOMEPAGE)), 301 | "REFRESH" => Ok(EventKey(EV_KEY::KEY_REFRESH)), 302 | "EXIT" => Ok(EventKey(EV_KEY::KEY_EXIT)), 303 | "MOVE" => Ok(EventKey(EV_KEY::KEY_MOVE)), 304 | "EDIT" => Ok(EventKey(EV_KEY::KEY_EDIT)), 305 | "SCROLLUP" => Ok(EventKey(EV_KEY::KEY_SCROLLUP)), 306 | "SCROLLDOWN" => Ok(EventKey(EV_KEY::KEY_SCROLLDOWN)), 307 | "KPLEFTPAREN" => Ok(EventKey(EV_KEY::KEY_KPLEFTPAREN)), 308 | "KPRIGHTPAREN" => Ok(EventKey(EV_KEY::KEY_KPRIGHTPAREN)), 309 | "NEW" => Ok(EventKey(EV_KEY::KEY_NEW)), 310 | "REDO" => Ok(EventKey(EV_KEY::KEY_REDO)), 311 | "F13" => Ok(EventKey(EV_KEY::KEY_F13)), 312 | "F14" => Ok(EventKey(EV_KEY::KEY_F14)), 313 | "F15" => Ok(EventKey(EV_KEY::KEY_F15)), 314 | "F16" => Ok(EventKey(EV_KEY::KEY_F16)), 315 | "F17" => Ok(EventKey(EV_KEY::KEY_F17)), 316 | "F18" => Ok(EventKey(EV_KEY::KEY_F18)), 317 | "F19" => Ok(EventKey(EV_KEY::KEY_F19)), 318 | "F20" => Ok(EventKey(EV_KEY::KEY_F20)), 319 | "F21" => Ok(EventKey(EV_KEY::KEY_F21)), 320 | "F22" => Ok(EventKey(EV_KEY::KEY_F22)), 321 | "F23" => Ok(EventKey(EV_KEY::KEY_F23)), 322 | "F24" => Ok(EventKey(EV_KEY::KEY_F24)), 323 | "PLAYCD" => Ok(EventKey(EV_KEY::KEY_PLAYCD)), 324 | "PAUSECD" => Ok(EventKey(EV_KEY::KEY_PAUSECD)), 325 | "PROG3" => Ok(EventKey(EV_KEY::KEY_PROG3)), 326 | "PROG4" => Ok(EventKey(EV_KEY::KEY_PROG4)), 327 | "DASHBOARD" => Ok(EventKey(EV_KEY::KEY_DASHBOARD)), 328 | "SUSPEND" => Ok(EventKey(EV_KEY::KEY_SUSPEND)), 329 | "CLOSE" => Ok(EventKey(EV_KEY::KEY_CLOSE)), 330 | "PLAY" => Ok(EventKey(EV_KEY::KEY_PLAY)), 331 | "FASTFORWARD" => Ok(EventKey(EV_KEY::KEY_FASTFORWARD)), 332 | "BASSBOOST" => Ok(EventKey(EV_KEY::KEY_BASSBOOST)), 333 | "PRINT" => Ok(EventKey(EV_KEY::KEY_PRINT)), 334 | "HP" => Ok(EventKey(EV_KEY::KEY_HP)), 335 | "CAMERA" => Ok(EventKey(EV_KEY::KEY_CAMERA)), 336 | "SOUND" => Ok(EventKey(EV_KEY::KEY_SOUND)), 337 | "QUESTION" => Ok(EventKey(EV_KEY::KEY_QUESTION)), 338 | "EMAIL" => Ok(EventKey(EV_KEY::KEY_EMAIL)), 339 | "CHAT" => Ok(EventKey(EV_KEY::KEY_CHAT)), 340 | "SEARCH" => Ok(EventKey(EV_KEY::KEY_SEARCH)), 341 | "CONNECT" => Ok(EventKey(EV_KEY::KEY_CONNECT)), 342 | "FINANCE" => Ok(EventKey(EV_KEY::KEY_FINANCE)), 343 | "SPORT" => Ok(EventKey(EV_KEY::KEY_SPORT)), 344 | "SHOP" => Ok(EventKey(EV_KEY::KEY_SHOP)), 345 | "ALTERASE" => Ok(EventKey(EV_KEY::KEY_ALTERASE)), 346 | "CANCEL" => Ok(EventKey(EV_KEY::KEY_CANCEL)), 347 | "BRIGHTNESSDOWN" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESSDOWN)), 348 | "BRIGHTNESSUP" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESSUP)), 349 | "MEDIA" => Ok(EventKey(EV_KEY::KEY_MEDIA)), 350 | "SWITCHVIDEOMODE" => Ok(EventKey(EV_KEY::KEY_SWITCHVIDEOMODE)), 351 | "KBDILLUMTOGGLE" => Ok(EventKey(EV_KEY::KEY_KBDILLUMTOGGLE)), 352 | "KBDILLUMDOWN" => Ok(EventKey(EV_KEY::KEY_KBDILLUMDOWN)), 353 | "KBDILLUMUP" => Ok(EventKey(EV_KEY::KEY_KBDILLUMUP)), 354 | "SEND" => Ok(EventKey(EV_KEY::KEY_SEND)), 355 | "REPLY" => Ok(EventKey(EV_KEY::KEY_REPLY)), 356 | "FORWARDMAIL" => Ok(EventKey(EV_KEY::KEY_FORWARDMAIL)), 357 | "SAVE" => Ok(EventKey(EV_KEY::KEY_SAVE)), 358 | "DOCUMENTS" => Ok(EventKey(EV_KEY::KEY_DOCUMENTS)), 359 | "BATTERY" => Ok(EventKey(EV_KEY::KEY_BATTERY)), 360 | "BLUETOOTH" => Ok(EventKey(EV_KEY::KEY_BLUETOOTH)), 361 | "WLAN" => Ok(EventKey(EV_KEY::KEY_WLAN)), 362 | "UWB" => Ok(EventKey(EV_KEY::KEY_UWB)), 363 | "UNKNOWN" => Ok(EventKey(EV_KEY::KEY_UNKNOWN)), 364 | "VIDEO_NEXT" => Ok(EventKey(EV_KEY::KEY_VIDEO_NEXT)), 365 | "VIDEO_PREV" => Ok(EventKey(EV_KEY::KEY_VIDEO_PREV)), 366 | "BRIGHTNESS_CYCLE" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESS_CYCLE)), 367 | "BRIGHTNESS_AUTO" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESS_AUTO)), 368 | "DISPLAY_OFF" => Ok(EventKey(EV_KEY::KEY_DISPLAY_OFF)), 369 | "WWAN" => Ok(EventKey(EV_KEY::KEY_WWAN)), 370 | "RFKILL" => Ok(EventKey(EV_KEY::KEY_RFKILL)), 371 | "MICMUTE" => Ok(EventKey(EV_KEY::KEY_MICMUTE)), 372 | "OK" => Ok(EventKey(EV_KEY::KEY_OK)), 373 | "SELECT" => Ok(EventKey(EV_KEY::KEY_SELECT)), 374 | "GOTO" => Ok(EventKey(EV_KEY::KEY_GOTO)), 375 | "CLEAR" => Ok(EventKey(EV_KEY::KEY_CLEAR)), 376 | "POWER2" => Ok(EventKey(EV_KEY::KEY_POWER2)), 377 | "OPTION" => Ok(EventKey(EV_KEY::KEY_OPTION)), 378 | "INFO" => Ok(EventKey(EV_KEY::KEY_INFO)), 379 | "TIME" => Ok(EventKey(EV_KEY::KEY_TIME)), 380 | "VENDOR" => Ok(EventKey(EV_KEY::KEY_VENDOR)), 381 | "ARCHIVE" => Ok(EventKey(EV_KEY::KEY_ARCHIVE)), 382 | "PROGRAM" => Ok(EventKey(EV_KEY::KEY_PROGRAM)), 383 | "CHANNEL" => Ok(EventKey(EV_KEY::KEY_CHANNEL)), 384 | "FAVORITES" => Ok(EventKey(EV_KEY::KEY_FAVORITES)), 385 | "EPG" => Ok(EventKey(EV_KEY::KEY_EPG)), 386 | "PVR" => Ok(EventKey(EV_KEY::KEY_PVR)), 387 | "MHP" => Ok(EventKey(EV_KEY::KEY_MHP)), 388 | "LANGUAGE" => Ok(EventKey(EV_KEY::KEY_LANGUAGE)), 389 | "TITLE" => Ok(EventKey(EV_KEY::KEY_TITLE)), 390 | "SUBTITLE" => Ok(EventKey(EV_KEY::KEY_SUBTITLE)), 391 | "ANGLE" => Ok(EventKey(EV_KEY::KEY_ANGLE)), 392 | "ZOOM" => Ok(EventKey(EV_KEY::KEY_ZOOM)), 393 | "MODE" => Ok(EventKey(EV_KEY::KEY_MODE)), 394 | "KEYBOARD" => Ok(EventKey(EV_KEY::KEY_KEYBOARD)), 395 | "SCREEN" => Ok(EventKey(EV_KEY::KEY_SCREEN)), 396 | "PC" => Ok(EventKey(EV_KEY::KEY_PC)), 397 | "TV" => Ok(EventKey(EV_KEY::KEY_TV)), 398 | "TV2" => Ok(EventKey(EV_KEY::KEY_TV2)), 399 | "VCR" => Ok(EventKey(EV_KEY::KEY_VCR)), 400 | "VCR2" => Ok(EventKey(EV_KEY::KEY_VCR2)), 401 | "SAT" => Ok(EventKey(EV_KEY::KEY_SAT)), 402 | "SAT2" => Ok(EventKey(EV_KEY::KEY_SAT2)), 403 | "CD" => Ok(EventKey(EV_KEY::KEY_CD)), 404 | "TAPE" => Ok(EventKey(EV_KEY::KEY_TAPE)), 405 | "RADIO" => Ok(EventKey(EV_KEY::KEY_RADIO)), 406 | "TUNER" => Ok(EventKey(EV_KEY::KEY_TUNER)), 407 | "PLAYER" => Ok(EventKey(EV_KEY::KEY_PLAYER)), 408 | "TEXT" => Ok(EventKey(EV_KEY::KEY_TEXT)), 409 | "DVD" => Ok(EventKey(EV_KEY::KEY_DVD)), 410 | "AUX" => Ok(EventKey(EV_KEY::KEY_AUX)), 411 | "MP3" => Ok(EventKey(EV_KEY::KEY_MP3)), 412 | "AUDIO" => Ok(EventKey(EV_KEY::KEY_AUDIO)), 413 | "VIDEO" => Ok(EventKey(EV_KEY::KEY_VIDEO)), 414 | "DIRECTORY" => Ok(EventKey(EV_KEY::KEY_DIRECTORY)), 415 | "LIST" => Ok(EventKey(EV_KEY::KEY_LIST)), 416 | "MEMO" => Ok(EventKey(EV_KEY::KEY_MEMO)), 417 | "CALENDAR" => Ok(EventKey(EV_KEY::KEY_CALENDAR)), 418 | "RED" => Ok(EventKey(EV_KEY::KEY_RED)), 419 | "GREEN" => Ok(EventKey(EV_KEY::KEY_GREEN)), 420 | "YELLOW" => Ok(EventKey(EV_KEY::KEY_YELLOW)), 421 | "BLUE" => Ok(EventKey(EV_KEY::KEY_BLUE)), 422 | "CHANNELUP" => Ok(EventKey(EV_KEY::KEY_CHANNELUP)), 423 | "CHANNELDOWN" => Ok(EventKey(EV_KEY::KEY_CHANNELDOWN)), 424 | "FIRST" => Ok(EventKey(EV_KEY::KEY_FIRST)), 425 | "LAST" => Ok(EventKey(EV_KEY::KEY_LAST)), 426 | "AB" => Ok(EventKey(EV_KEY::KEY_AB)), 427 | "NEXT" => Ok(EventKey(EV_KEY::KEY_NEXT)), 428 | "RESTART" => Ok(EventKey(EV_KEY::KEY_RESTART)), 429 | "SLOW" => Ok(EventKey(EV_KEY::KEY_SLOW)), 430 | "SHUFFLE" => Ok(EventKey(EV_KEY::KEY_SHUFFLE)), 431 | "BREAK" => Ok(EventKey(EV_KEY::KEY_BREAK)), 432 | "PREVIOUS" => Ok(EventKey(EV_KEY::KEY_PREVIOUS)), 433 | "DIGITS" => Ok(EventKey(EV_KEY::KEY_DIGITS)), 434 | "TEEN" => Ok(EventKey(EV_KEY::KEY_TEEN)), 435 | "TWEN" => Ok(EventKey(EV_KEY::KEY_TWEN)), 436 | "VIDEOPHONE" => Ok(EventKey(EV_KEY::KEY_VIDEOPHONE)), 437 | "GAMES" => Ok(EventKey(EV_KEY::KEY_GAMES)), 438 | "ZOOMIN" => Ok(EventKey(EV_KEY::KEY_ZOOMIN)), 439 | "ZOOMOUT" => Ok(EventKey(EV_KEY::KEY_ZOOMOUT)), 440 | "ZOOMRESET" => Ok(EventKey(EV_KEY::KEY_ZOOMRESET)), 441 | "WORDPROCESSOR" => Ok(EventKey(EV_KEY::KEY_WORDPROCESSOR)), 442 | "EDITOR" => Ok(EventKey(EV_KEY::KEY_EDITOR)), 443 | "SPREADSHEET" => Ok(EventKey(EV_KEY::KEY_SPREADSHEET)), 444 | "GRAPHICSEDITOR" => Ok(EventKey(EV_KEY::KEY_GRAPHICSEDITOR)), 445 | "PRESENTATION" => Ok(EventKey(EV_KEY::KEY_PRESENTATION)), 446 | "DATABASE" => Ok(EventKey(EV_KEY::KEY_DATABASE)), 447 | "NEWS" => Ok(EventKey(EV_KEY::KEY_NEWS)), 448 | "VOICEMAIL" => Ok(EventKey(EV_KEY::KEY_VOICEMAIL)), 449 | "ADDRESSBOOK" => Ok(EventKey(EV_KEY::KEY_ADDRESSBOOK)), 450 | "MESSENGER" => Ok(EventKey(EV_KEY::KEY_MESSENGER)), 451 | "DISPLAYTOGGLE" => Ok(EventKey(EV_KEY::KEY_DISPLAYTOGGLE)), 452 | "SPELLCHECK" => Ok(EventKey(EV_KEY::KEY_SPELLCHECK)), 453 | "LOGOFF" => Ok(EventKey(EV_KEY::KEY_LOGOFF)), 454 | "DOLLAR" => Ok(EventKey(EV_KEY::KEY_DOLLAR)), 455 | "EURO" => Ok(EventKey(EV_KEY::KEY_EURO)), 456 | "FRAMEBACK" => Ok(EventKey(EV_KEY::KEY_FRAMEBACK)), 457 | "FRAMEFORWARD" => Ok(EventKey(EV_KEY::KEY_FRAMEFORWARD)), 458 | "CONTEXT_MENU" => Ok(EventKey(EV_KEY::KEY_CONTEXT_MENU)), 459 | "MEDIA_REPEAT" => Ok(EventKey(EV_KEY::KEY_MEDIA_REPEAT)), 460 | "10CHANNELSUP" => Ok(EventKey(EV_KEY::KEY_10CHANNELSUP)), 461 | "10CHANNELSDOWN" => Ok(EventKey(EV_KEY::KEY_10CHANNELSDOWN)), 462 | "IMAGES" => Ok(EventKey(EV_KEY::KEY_IMAGES)), 463 | "DEL_EOL" => Ok(EventKey(EV_KEY::KEY_DEL_EOL)), 464 | "DEL_EOS" => Ok(EventKey(EV_KEY::KEY_DEL_EOS)), 465 | "INS_LINE" => Ok(EventKey(EV_KEY::KEY_INS_LINE)), 466 | "DEL_LINE" => Ok(EventKey(EV_KEY::KEY_DEL_LINE)), 467 | "FN" => Ok(EventKey(EV_KEY::KEY_FN)), 468 | "FN_ESC" => Ok(EventKey(EV_KEY::KEY_FN_ESC)), 469 | "FN_F1" => Ok(EventKey(EV_KEY::KEY_FN_F1)), 470 | "FN_F2" => Ok(EventKey(EV_KEY::KEY_FN_F2)), 471 | "FN_F3" => Ok(EventKey(EV_KEY::KEY_FN_F3)), 472 | "FN_F4" => Ok(EventKey(EV_KEY::KEY_FN_F4)), 473 | "FN_F5" => Ok(EventKey(EV_KEY::KEY_FN_F5)), 474 | "FN_F6" => Ok(EventKey(EV_KEY::KEY_FN_F6)), 475 | "FN_F7" => Ok(EventKey(EV_KEY::KEY_FN_F7)), 476 | "FN_F8" => Ok(EventKey(EV_KEY::KEY_FN_F8)), 477 | "FN_F9" => Ok(EventKey(EV_KEY::KEY_FN_F9)), 478 | "FN_F10" => Ok(EventKey(EV_KEY::KEY_FN_F10)), 479 | "FN_F11" => Ok(EventKey(EV_KEY::KEY_FN_F11)), 480 | "FN_F12" => Ok(EventKey(EV_KEY::KEY_FN_F12)), 481 | "FN_1" => Ok(EventKey(EV_KEY::KEY_FN_1)), 482 | "FN_2" => Ok(EventKey(EV_KEY::KEY_FN_2)), 483 | "FN_D" => Ok(EventKey(EV_KEY::KEY_FN_D)), 484 | "FN_E" => Ok(EventKey(EV_KEY::KEY_FN_E)), 485 | "FN_F" => Ok(EventKey(EV_KEY::KEY_FN_F)), 486 | "FN_S" => Ok(EventKey(EV_KEY::KEY_FN_S)), 487 | "FN_B" => Ok(EventKey(EV_KEY::KEY_FN_B)), 488 | "BRL_DOT1" => Ok(EventKey(EV_KEY::KEY_BRL_DOT1)), 489 | "BRL_DOT2" => Ok(EventKey(EV_KEY::KEY_BRL_DOT2)), 490 | "BRL_DOT3" => Ok(EventKey(EV_KEY::KEY_BRL_DOT3)), 491 | "BRL_DOT4" => Ok(EventKey(EV_KEY::KEY_BRL_DOT4)), 492 | "BRL_DOT5" => Ok(EventKey(EV_KEY::KEY_BRL_DOT5)), 493 | "BRL_DOT6" => Ok(EventKey(EV_KEY::KEY_BRL_DOT6)), 494 | "BRL_DOT7" => Ok(EventKey(EV_KEY::KEY_BRL_DOT7)), 495 | "BRL_DOT8" => Ok(EventKey(EV_KEY::KEY_BRL_DOT8)), 496 | "BRL_DOT9" => Ok(EventKey(EV_KEY::KEY_BRL_DOT9)), 497 | "BRL_DOT10" => Ok(EventKey(EV_KEY::KEY_BRL_DOT10)), 498 | "NUMERIC_0" => Ok(EventKey(EV_KEY::KEY_NUMERIC_0)), 499 | "NUMERIC_1" => Ok(EventKey(EV_KEY::KEY_NUMERIC_1)), 500 | "NUMERIC_2" => Ok(EventKey(EV_KEY::KEY_NUMERIC_2)), 501 | "NUMERIC_3" => Ok(EventKey(EV_KEY::KEY_NUMERIC_3)), 502 | "NUMERIC_4" => Ok(EventKey(EV_KEY::KEY_NUMERIC_4)), 503 | "NUMERIC_5" => Ok(EventKey(EV_KEY::KEY_NUMERIC_5)), 504 | "NUMERIC_6" => Ok(EventKey(EV_KEY::KEY_NUMERIC_6)), 505 | "NUMERIC_7" => Ok(EventKey(EV_KEY::KEY_NUMERIC_7)), 506 | "NUMERIC_8" => Ok(EventKey(EV_KEY::KEY_NUMERIC_8)), 507 | "NUMERIC_9" => Ok(EventKey(EV_KEY::KEY_NUMERIC_9)), 508 | "NUMERIC_STAR" => Ok(EventKey(EV_KEY::KEY_NUMERIC_STAR)), 509 | "NUMERIC_POUND" => Ok(EventKey(EV_KEY::KEY_NUMERIC_POUND)), 510 | "NUMERIC_A" => Ok(EventKey(EV_KEY::KEY_NUMERIC_A)), 511 | "NUMERIC_B" => Ok(EventKey(EV_KEY::KEY_NUMERIC_B)), 512 | "NUMERIC_C" => Ok(EventKey(EV_KEY::KEY_NUMERIC_C)), 513 | "NUMERIC_D" => Ok(EventKey(EV_KEY::KEY_NUMERIC_D)), 514 | "CAMERA_FOCUS" => Ok(EventKey(EV_KEY::KEY_CAMERA_FOCUS)), 515 | "WPS_BUTTON" => Ok(EventKey(EV_KEY::KEY_WPS_BUTTON)), 516 | "TOUCHPAD_TOGGLE" => Ok(EventKey(EV_KEY::KEY_TOUCHPAD_TOGGLE)), 517 | "TOUCHPAD_ON" => Ok(EventKey(EV_KEY::KEY_TOUCHPAD_ON)), 518 | "TOUCHPAD_OFF" => Ok(EventKey(EV_KEY::KEY_TOUCHPAD_OFF)), 519 | "CAMERA_ZOOMIN" => Ok(EventKey(EV_KEY::KEY_CAMERA_ZOOMIN)), 520 | "CAMERA_ZOOMOUT" => Ok(EventKey(EV_KEY::KEY_CAMERA_ZOOMOUT)), 521 | "CAMERA_UP" => Ok(EventKey(EV_KEY::KEY_CAMERA_UP)), 522 | "CAMERA_DOWN" => Ok(EventKey(EV_KEY::KEY_CAMERA_DOWN)), 523 | "CAMERA_LEFT" => Ok(EventKey(EV_KEY::KEY_CAMERA_LEFT)), 524 | "CAMERA_RIGHT" => Ok(EventKey(EV_KEY::KEY_CAMERA_RIGHT)), 525 | "ATTENDANT_ON" => Ok(EventKey(EV_KEY::KEY_ATTENDANT_ON)), 526 | "ATTENDANT_OFF" => Ok(EventKey(EV_KEY::KEY_ATTENDANT_OFF)), 527 | "ATTENDANT_TOGGLE" => Ok(EventKey(EV_KEY::KEY_ATTENDANT_TOGGLE)), 528 | "LIGHTS_TOGGLE" => Ok(EventKey(EV_KEY::KEY_LIGHTS_TOGGLE)), 529 | "ALS_TOGGLE" => Ok(EventKey(EV_KEY::KEY_ALS_TOGGLE)), 530 | "ROTATE_LOCK_TOGGLE" => Ok(EventKey(EV_KEY::KEY_ROTATE_LOCK_TOGGLE)), 531 | "BUTTONCONFIG" => Ok(EventKey(EV_KEY::KEY_BUTTONCONFIG)), 532 | "TASKMANAGER" => Ok(EventKey(EV_KEY::KEY_TASKMANAGER)), 533 | "JOURNAL" => Ok(EventKey(EV_KEY::KEY_JOURNAL)), 534 | "CONTROLPANEL" => Ok(EventKey(EV_KEY::KEY_CONTROLPANEL)), 535 | "APPSELECT" => Ok(EventKey(EV_KEY::KEY_APPSELECT)), 536 | "SCREENSAVER" => Ok(EventKey(EV_KEY::KEY_SCREENSAVER)), 537 | "VOICECOMMAND" => Ok(EventKey(EV_KEY::KEY_VOICECOMMAND)), 538 | "ASSISTANT" => Ok(EventKey(EV_KEY::KEY_ASSISTANT)), 539 | "BRIGHTNESS_MIN" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESS_MIN)), 540 | "BRIGHTNESS_MAX" => Ok(EventKey(EV_KEY::KEY_BRIGHTNESS_MAX)), 541 | "KBDINPUTASSIST_PREV" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_PREV)), 542 | "KBDINPUTASSIST_NEXT" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_NEXT)), 543 | "KBDINPUTASSIST_PREVGROUP" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_PREVGROUP)), 544 | "KBDINPUTASSIST_NEXTGROUP" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_NEXTGROUP)), 545 | "KBDINPUTASSIST_ACCEPT" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_ACCEPT)), 546 | "KBDINPUTASSIST_CANCEL" => Ok(EventKey(EV_KEY::KEY_KBDINPUTASSIST_CANCEL)), 547 | "RIGHT_UP" => Ok(EventKey(EV_KEY::KEY_RIGHT_UP)), 548 | "RIGHT_DOWN" => Ok(EventKey(EV_KEY::KEY_RIGHT_DOWN)), 549 | "LEFT_UP" => Ok(EventKey(EV_KEY::KEY_LEFT_UP)), 550 | "LEFT_DOWN" => Ok(EventKey(EV_KEY::KEY_LEFT_DOWN)), 551 | "ROOT_MENU" => Ok(EventKey(EV_KEY::KEY_ROOT_MENU)), 552 | "MEDIA_TOP_MENU" => Ok(EventKey(EV_KEY::KEY_MEDIA_TOP_MENU)), 553 | "NUMERIC_11" => Ok(EventKey(EV_KEY::KEY_NUMERIC_11)), 554 | "NUMERIC_12" => Ok(EventKey(EV_KEY::KEY_NUMERIC_12)), 555 | "AUDIO_DESC" => Ok(EventKey(EV_KEY::KEY_AUDIO_DESC)), 556 | "3D_MODE" => Ok(EventKey(EV_KEY::KEY_3D_MODE)), 557 | "NEXT_FAVORITE" => Ok(EventKey(EV_KEY::KEY_NEXT_FAVORITE)), 558 | "STOP_RECORD" => Ok(EventKey(EV_KEY::KEY_STOP_RECORD)), 559 | "PAUSE_RECORD" => Ok(EventKey(EV_KEY::KEY_PAUSE_RECORD)), 560 | "VOD" => Ok(EventKey(EV_KEY::KEY_VOD)), 561 | "UNMUTE" => Ok(EventKey(EV_KEY::KEY_UNMUTE)), 562 | "FASTREVERSE" => Ok(EventKey(EV_KEY::KEY_FASTREVERSE)), 563 | "SLOWREVERSE" => Ok(EventKey(EV_KEY::KEY_SLOWREVERSE)), 564 | "DATA" => Ok(EventKey(EV_KEY::KEY_DATA)), 565 | "ONSCREEN_KEYBOARD" => Ok(EventKey(EV_KEY::KEY_ONSCREEN_KEYBOARD)), 566 | "MAX" => Ok(EventKey(EV_KEY::KEY_MAX)), 567 | value => Err(serde::de::Error::unknown_variant(value, &["keycode name"])), 568 | } 569 | } 570 | } 571 | --------------------------------------------------------------------------------