when osu sound i guess
at main 9.0 kB view raw
1#[cfg(target_os = "linux")] 2mod linux { 3 use evdev::{Device, EventSummary, KeyCode}; 4 use std::collections::HashSet; 5 use std::fs::{self, OpenOptions}; 6 use std::os::unix::io::AsRawFd; 7 use std::path::Path; 8 9 pub struct EvdevInput { 10 devices: Vec<Device>, 11 held_keys: HashSet<u16>, 12 } 13 14 impl EvdevInput { 15 pub fn new() -> std::io::Result<Self> { 16 let mut devices = Vec::new(); 17 18 // Find all keyboard devices in /dev/input 19 let input_dir = Path::new("/dev/input"); 20 if let Ok(entries) = fs::read_dir(input_dir) { 21 for entry in entries.flatten() { 22 let path = entry.path(); 23 if let Some(name) = path.file_name() { 24 if name.to_string_lossy().starts_with("event") { 25 if let Ok(file) = OpenOptions::new().read(true).open(&path) { 26 // Set non-blocking mode 27 let fd = file.as_raw_fd(); 28 unsafe { 29 let flags = libc::fcntl(fd, libc::F_GETFL, 0); 30 if flags != -1 { 31 libc::fcntl(fd, libc::F_SETFL, flags | libc::O_NONBLOCK); 32 } 33 } 34 35 if let Ok(device) = Device::from_fd(file.into()) { 36 // Check if this device supports keyboard events 37 if device.supported_keys().map_or(false, |keys| { 38 keys.contains(KeyCode::KEY_A) || keys.contains(KeyCode::KEY_SPACE) 39 }) { 40 devices.push(device); 41 } 42 } 43 } 44 } 45 } 46 } 47 } 48 49 if devices.is_empty() { 50 eprintln!("Warning: No keyboard devices found. Make sure you have read permissions for /dev/input/event* devices."); 51 eprintln!("You may need to add your user to the 'input' group or run with appropriate permissions."); 52 } 53 54 Ok(Self { 55 devices, 56 held_keys: HashSet::new(), 57 }) 58 } 59 60 pub fn query_keymap(&mut self) -> HashSet<u16> { 61 // Process events from all devices 62 for device in &mut self.devices { 63 while let Ok(events) = device.fetch_events() { 64 for event in events { 65 if let EventSummary::Key(_, key, value) = event.destructure() { 66 let code = key.code(); 67 match value { 68 0 => { 69 // Key released 70 self.held_keys.remove(&code); 71 } 72 1 | 2 => { 73 // Key pressed (1) or repeated (2) 74 self.held_keys.insert(code); 75 } 76 _ => {} 77 } 78 } 79 } 80 } 81 } 82 83 self.held_keys.clone() 84 } 85 } 86 87 // Key code constants 88 #[allow(dead_code)] 89 pub const KEY_A: u16 = KeyCode::KEY_A.code(); 90 pub const KEY_C: u16 = KeyCode::KEY_C.code(); 91 pub const KEY_CAPSLOCK: u16 = KeyCode::KEY_CAPSLOCK.code(); 92 pub const KEY_DELETE: u16 = KeyCode::KEY_DELETE.code(); 93 pub const KEY_BACKSPACE: u16 = KeyCode::KEY_BACKSPACE.code(); 94 pub const KEY_UP: u16 = KeyCode::KEY_UP.code(); 95 pub const KEY_DOWN: u16 = KeyCode::KEY_DOWN.code(); 96 pub const KEY_LEFT: u16 = KeyCode::KEY_LEFT.code(); 97 pub const KEY_RIGHT: u16 = KeyCode::KEY_RIGHT.code(); 98 pub const KEY_LEFTSHIFT: u16 = KeyCode::KEY_LEFTSHIFT.code(); 99 pub const KEY_RIGHTSHIFT: u16 = KeyCode::KEY_RIGHTSHIFT.code(); 100 pub const KEY_LEFTCTRL: u16 = KeyCode::KEY_LEFTCTRL.code(); 101 pub const KEY_RIGHTCTRL: u16 = KeyCode::KEY_RIGHTCTRL.code(); 102 pub const KEY_LEFTALT: u16 = KeyCode::KEY_LEFTALT.code(); 103 pub const KEY_RIGHTALT: u16 = KeyCode::KEY_RIGHTALT.code(); 104 pub const KEY_LEFTMETA: u16 = KeyCode::KEY_LEFTMETA.code(); 105 pub const KEY_RIGHTMETA: u16 = KeyCode::KEY_RIGHTMETA.code(); 106 107 pub fn is_modifier_key(key: u16) -> bool { 108 matches!( 109 key, 110 KEY_LEFTSHIFT 111 | KEY_RIGHTSHIFT 112 | KEY_LEFTCTRL 113 | KEY_RIGHTCTRL 114 | KEY_RIGHTALT 115 | KEY_LEFTALT 116 | KEY_RIGHTMETA 117 | KEY_LEFTMETA 118 | KEY_CAPSLOCK 119 ) 120 } 121} 122 123#[cfg(not(target_os = "linux"))] 124mod fallback { 125 use device_query::{DeviceQuery, DeviceState, Keycode}; 126 use std::collections::HashSet; 127 128 pub struct DeviceQueryInput { 129 state: DeviceState, 130 } 131 132 impl DeviceQueryInput { 133 pub fn new() -> Self { 134 Self { 135 state: DeviceState::new(), 136 } 137 } 138 139 pub fn query_keymap(&mut self) -> HashSet<u16> { 140 self.state 141 .query_keymap() 142 .into_iter() 143 .map(keycode_to_u16) 144 .collect() 145 } 146 } 147 148 fn keycode_to_u16(keycode: Keycode) -> u16 { 149 // Map device_query keycodes to arbitrary u16 values 150 // We use values that won't collide with Linux key codes 151 match keycode { 152 Keycode::A => 1000, 153 Keycode::B => 1001, 154 Keycode::C => 1002, 155 Keycode::D => 1003, 156 Keycode::E => 1004, 157 Keycode::F => 1005, 158 Keycode::G => 1006, 159 Keycode::H => 1007, 160 Keycode::I => 1008, 161 Keycode::J => 1009, 162 Keycode::K => 1010, 163 Keycode::L => 1011, 164 Keycode::M => 1012, 165 Keycode::N => 1013, 166 Keycode::O => 1014, 167 Keycode::P => 1015, 168 Keycode::Q => 1016, 169 Keycode::R => 1017, 170 Keycode::S => 1018, 171 Keycode::T => 1019, 172 Keycode::U => 1020, 173 Keycode::V => 1021, 174 Keycode::W => 1022, 175 Keycode::X => 1023, 176 Keycode::Y => 1024, 177 Keycode::Z => 1025, 178 Keycode::CapsLock => 1026, 179 Keycode::Delete => 1027, 180 Keycode::Backspace => 1028, 181 Keycode::Up => 1029, 182 Keycode::Down => 1030, 183 Keycode::Left => 1031, 184 Keycode::Right => 1032, 185 Keycode::LShift => 1033, 186 Keycode::RShift => 1034, 187 Keycode::LControl => 1035, 188 Keycode::RControl => 1036, 189 Keycode::LAlt => 1037, 190 Keycode::RAlt => 1038, 191 Keycode::LMeta => 1039, 192 Keycode::RMeta => 1040, 193 _ => { 194 // For any other key, use a hash of the debug string 195 use std::collections::hash_map::DefaultHasher; 196 use std::hash::{Hash, Hasher}; 197 let mut hasher = DefaultHasher::new(); 198 format!("{:?}", keycode).hash(&mut hasher); 199 (hasher.finish() as u16).wrapping_add(2000) 200 } 201 } 202 } 203 204 // Key code constants - matching the values in keycode_to_u16 205 #[allow(dead_code)] 206 pub const KEY_A: u16 = 1000; 207 pub const KEY_C: u16 = 1002; 208 pub const KEY_CAPSLOCK: u16 = 1026; 209 pub const KEY_DELETE: u16 = 1027; 210 pub const KEY_BACKSPACE: u16 = 1028; 211 pub const KEY_UP: u16 = 1029; 212 pub const KEY_DOWN: u16 = 1030; 213 pub const KEY_LEFT: u16 = 1031; 214 pub const KEY_RIGHT: u16 = 1032; 215 pub const KEY_LEFTSHIFT: u16 = 1033; 216 pub const KEY_RIGHTSHIFT: u16 = 1034; 217 pub const KEY_LEFTCTRL: u16 = 1035; 218 pub const KEY_RIGHTCTRL: u16 = 1036; 219 pub const KEY_LEFTALT: u16 = 1037; 220 pub const KEY_RIGHTALT: u16 = 1038; 221 pub const KEY_LEFTMETA: u16 = 1039; 222 pub const KEY_RIGHTMETA: u16 = 1040; 223 224 pub fn is_modifier_key(key: u16) -> bool { 225 matches!( 226 key, 227 KEY_LEFTSHIFT 228 | KEY_RIGHTSHIFT 229 | KEY_LEFTCTRL 230 | KEY_RIGHTCTRL 231 | KEY_RIGHTALT 232 | KEY_LEFTALT 233 | KEY_RIGHTMETA 234 | KEY_LEFTMETA 235 | KEY_CAPSLOCK 236 ) 237 } 238} 239 240#[cfg(target_os = "linux")] 241pub use linux::*; 242 243#[cfg(not(target_os = "linux"))] 244pub use fallback::*; 245 246#[cfg(target_os = "linux")] 247pub type Input = linux::EvdevInput; 248 249#[cfg(not(target_os = "linux"))] 250pub type Input = fallback::DeviceQueryInput; 251 252pub fn create_input() -> std::io::Result<Input> { 253 Input::new() 254}