// SPDX-License-Identifier: MPL-2.0 use alloc::{sync::Arc, vec::Vec}; use core::{any::Any, fmt::Debug}; use ostd::{ Pod, sync::{RwLock, WriteIrqDisabled}, }; use crate::{ event_type_codes::{EventTypes, KeyCode, KeyCodeSet, KeyStatus, RelCode, RelCodeSet, SynEvent}, input_handler::BoundInputHandler, unregister_device, }; /// Input event. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum InputEvent { /// Synchronization events (EV_SYN) Sync(SynEvent), /// Key press/release events (EV_KEY) Key(KeyCode, KeyStatus), /// Relative movement events (EV_REL) Relative(RelCode, i32), // TODO: Add EV_ABS, EV_MSC, EV_SW, EV_LED, EV_SND, ... as needed } impl InputEvent { /// Creates a synchronization event. pub fn from_sync_event(sync_type: SynEvent) -> Self { Self::Sync(sync_type) } /// Creates a key event. pub fn from_key_and_status(key: KeyCode, status: KeyStatus) -> Self { Self::Key(key, status) } /// Creates a relative movement event. pub fn from_relative_move(axis: RelCode, value: i32) -> Self { Self::Relative(axis, value) } /// Converts enum to raw Linux input event triplet (type, code, value). pub fn to_raw(&self) -> (u16, u16, i32) { match self { InputEvent::Sync(sync_type) => ( EventTypes::SYN.as_index(), *sync_type as u16, 0, // Sync events always have value = 0 ), InputEvent::Key(key, status) => { (EventTypes::KEY.as_index(), *key as u16, *status as i32) } InputEvent::Relative(axis, value) => (EventTypes::REL.as_index(), *axis as u16, *value), } } /// Gets the event type. pub fn event_type(&self) -> EventTypes { match self { InputEvent::Sync(_) => EventTypes::SYN, InputEvent::Key(_, _) => EventTypes::KEY, InputEvent::Relative(_, _) => EventTypes::REL, } } } /// Input device identifier. #[repr(C)] #[derive(Debug, Clone, Copy, Pod)] pub struct InputId { /// Bus type identifier. bustype: u16, /// Vendor ID of the device manufacturer. vendor: u16, /// Product ID of the specific device model. product: u16, /// Version number of the device. version: u16, } impl InputId { /// Creates a new `InputId` with the specified values. pub fn new(bustype: u16, vendor: u16, product: u16, version: u16) -> Self { Self { bustype, vendor, product, version, } } /// Gets the bus type. pub fn bustype(&self) -> u16 { self.bustype } /// Gets the vendor ID. pub fn vendor(&self) -> u16 { self.vendor } /// Gets the product ID. pub fn product(&self) -> u16 { self.product } /// Gets the version number. pub fn version(&self) -> u16 { self.version } // Common bus types. pub const BUS_PCI: u16 = 0x01; pub const BUS_ISAPNP: u16 = 0x02; pub const BUS_USB: u16 = 0x03; pub const BUS_HIL: u16 = 0x04; pub const BUS_BLUETOOTH: u16 = 0x05; pub const BUS_VIRTUAL: u16 = 0x06; pub const BUS_ISA: u16 = 0x10; pub const BUS_I8042: u16 = 0x11; pub const BUS_XTKBD: u16 = 0x12; pub const BUS_RS232: u16 = 0x13; pub const BUS_GAMEPORT: u16 = 0x14; pub const BUS_PARPORT: u16 = 0x15; pub const BUS_AMIGA: u16 = 0x16; pub const BUS_ADB: u16 = 0x17; pub const BUS_I2C: u16 = 0x18; pub const BUS_HOST: u16 = 0x19; pub const BUS_GSC: u16 = 0x1A; pub const BUS_ATARI: u16 = 0x1B; pub const BUS_SPI: u16 = 0x1C; pub const BUS_RMI: u16 = 0x1D; pub const BUS_CEC: u16 = 0x1E; pub const BUS_INTEL_ISHTP: u16 = 0x1F; } /// Input device capability bitmaps. #[derive(Debug, Clone)] pub struct InputCapability { /// Supported event types (`EV_KEY`, `EV_REL`, etc.) supported_event_types: EventTypes, /// Supported key/button codes. supported_keys: KeyCodeSet, /// Supported relative axis codes. supported_relative_axes: RelCodeSet, // TODO: Add supported_absolute_axes, supported_misc, etc. } impl Default for InputCapability { fn default() -> Self { Self::new() } } impl InputCapability { /// Creates a new empty input capability. pub fn new() -> Self { Self { supported_event_types: EventTypes::new(), supported_keys: KeyCodeSet::new(), supported_relative_axes: RelCodeSet::new(), } } /// Sets event type capability. pub fn set_supported_event_type(&mut self, event_type: EventTypes) { self.supported_event_types |= event_type; } /// Checks if an event type is supported. pub fn support_event_type(&self, event_type: EventTypes) -> bool { self.supported_event_types.contains(event_type) } /// Removes support for an event type. pub fn clear_supported_event_type(&mut self, event_type: EventTypes) { self.supported_event_types &= !event_type; } /// Sets key capability. pub fn set_supported_key(&mut self, key_code: KeyCode) { self.supported_keys.set(key_code); self.set_supported_event_type(EventTypes::KEY); } /// Checks if a key code is supported. pub fn support_key(&self, key_code: KeyCode) -> bool { self.supported_keys.contain(key_code) } /// Detects whether the device is keyboard-like. /// /// We follow the rules defined by Linux: a device is a keyboard if /// - it supports `EV_KEY`, and /// - it has any non-button key set (i.e., below `BTN_MISC`). pub fn look_like_keyboard(&self) -> bool { if !self.support_event_type(EventTypes::KEY) { return false; } self.supported_keys .contain_any(0..KeyCode::BtnMisc as usize) } /// Removes support for a key code. pub fn clear_supported_key(&mut self, key_code: KeyCode) { self.supported_keys.clear(key_code); } /// Sets relative axis capability. pub fn set_supported_relative_axis(&mut self, rel_code: RelCode) { self.supported_relative_axes.set(rel_code); self.set_supported_event_type(EventTypes::REL); } /// Checks if a relative code is supported. pub fn support_relative_axis(&self, rel_code: RelCode) -> bool { self.supported_relative_axes.contain(rel_code) } /// Removes support for a relative code. pub fn clear_supported_relative_axis(&mut self, rel_code: RelCode) { self.supported_relative_axes.clear(rel_code); } /// Returns the supported event types as a bitmap. pub fn event_types_bits(&self) -> u32 { self.supported_event_types.bits() } /// Returns the supported key code bitmap as bytes. pub fn supported_keys_bitmap(&self) -> &[u8] { self.supported_keys.as_raw_slice() } /// Returns the supported relative axes bitmap as bytes. pub fn supported_relative_axes_bitmap(&self) -> &[u8] { self.supported_relative_axes.as_raw_slice() } } pub trait InputDevice: Send + Sync + Any + Debug { /// Device name. fn name(&self) -> &str; /// Physical location of the device in the system topology. /// /// This string describes the physical path through which the device is connected /// to the system. It helps identify where the device is physically located and /// how it's connected (e.g., USB port, ISA bus, etc.). /// /// # Examples /// - `"isa0060/serio0/input0"` - i8042 keyboard connected via ISA bus /// - `"usb-0000:00:1d.0-1/input0"` - USB device connected to specific USB port fn phys(&self) -> &str; /// Unique identifier for the device instance. /// /// This string provides a unique identifier for the specific device instance, /// typically derived from device-specific information like serial numbers, /// MAC addresses, or other hardware-level unique identifiers. /// /// # Examples /// - `"00:1B:DC:0F:AC:27"` - MAC address for Bluetooth devices /// - `"S/N: 12345678"` - Device serial number /// - `""` - Empty string for devices without unique identifiers fn uniq(&self) -> &str; /// Device ID. fn id(&self) -> InputId; /// Device capabilities. fn capability(&self) -> &InputCapability; } /// Registered input device that can submit events to handlers. #[derive(Debug)] pub struct RegisteredInputDevice { /// Original device. device: Arc, /// Reference to bound handlers for direct event dispatch. handlers: Arc, WriteIrqDisabled>>, } impl RegisteredInputDevice { pub(crate) fn new( device: Arc, handlers: Arc, WriteIrqDisabled>>, ) -> Self { Self { device, handlers } } /// Submits multiple events in batch. pub fn submit_events(&self, events: &[InputEvent]) { debug_assert!( events.iter().all(|e| self.is_event_supported(e)), "Device '{}' submitted unsupported event", self.device.name() ); let handlers = self.handlers.read(); if handlers.is_empty() { log::debug!( "Input: dropped events from device {} because it has no handlers", self.device.name() ); return; } for bound_handler in handlers.iter() { bound_handler.handler.handle_events(events); } } /// Gets the underlying device reference. pub fn device(&self) -> &Arc { &self.device } /// Counts the number of connected handlers. pub fn count_handlers(&self) -> usize { self.handlers.read().len() } /// Checks if the device supports a specific event based on its capabilities. fn is_event_supported(&self, event: &InputEvent) -> bool { let capability = self.device.capability(); match event { InputEvent::Sync(_) => capability.support_event_type(EventTypes::SYN), InputEvent::Key(key_event, _) => { capability.support_event_type(EventTypes::KEY) && capability.support_key(*key_event) } InputEvent::Relative(rel_event, _) => { capability.support_event_type(EventTypes::REL) && capability.support_relative_axis(*rel_event) } } } } impl InputCapability { /// Adds all standard keyboard keys to the capability. pub fn add_standard_keyboard_keys(&mut self) { let standard_keys = [ // Function keys KeyCode::Esc, KeyCode::F1, KeyCode::F2, KeyCode::F3, KeyCode::F4, KeyCode::F5, KeyCode::F6, KeyCode::F7, KeyCode::F8, KeyCode::F9, KeyCode::F10, KeyCode::F11, KeyCode::F12, // Number row KeyCode::Num1, KeyCode::Num2, KeyCode::Num3, KeyCode::Num4, KeyCode::Num5, KeyCode::Num6, KeyCode::Num7, KeyCode::Num8, KeyCode::Num9, KeyCode::Num0, KeyCode::Minus, KeyCode::Equal, KeyCode::Backspace, // First row (QWERTY) KeyCode::Tab, KeyCode::Q, KeyCode::W, KeyCode::E, KeyCode::R, KeyCode::T, KeyCode::Y, KeyCode::U, KeyCode::I, KeyCode::O, KeyCode::P, KeyCode::LeftBrace, KeyCode::RightBrace, KeyCode::Backslash, // Second row (ASDF) KeyCode::CapsLock, KeyCode::A, KeyCode::S, KeyCode::D, KeyCode::F, KeyCode::G, KeyCode::H, KeyCode::J, KeyCode::K, KeyCode::L, KeyCode::Semicolon, KeyCode::Apostrophe, KeyCode::Enter, // Third row (ZXCV) KeyCode::LeftShift, KeyCode::Z, KeyCode::X, KeyCode::C, KeyCode::V, KeyCode::B, KeyCode::N, KeyCode::M, KeyCode::Comma, KeyCode::Dot, KeyCode::Slash, KeyCode::RightShift, // Bottom row KeyCode::LeftCtrl, KeyCode::LeftAlt, KeyCode::Space, KeyCode::RightAlt, KeyCode::RightCtrl, // Special keys KeyCode::Grave, KeyCode::LeftMeta, KeyCode::RightMeta, KeyCode::Menu, // Arrow keys KeyCode::Up, KeyCode::Down, KeyCode::Left, KeyCode::Right, // Navigation cluster KeyCode::Home, KeyCode::End, KeyCode::PageUp, KeyCode::PageDown, KeyCode::Insert, KeyCode::Delete, // Lock keys KeyCode::NumLock, KeyCode::ScrollLock, // Numpad KeyCode::Kp0, KeyCode::Kp1, KeyCode::Kp2, KeyCode::Kp3, KeyCode::Kp4, KeyCode::Kp5, KeyCode::Kp6, KeyCode::Kp7, KeyCode::Kp8, KeyCode::Kp9, KeyCode::KpDot, KeyCode::KpPlus, KeyCode::KpMinus, KeyCode::KpAsterisk, KeyCode::KpSlash, KeyCode::KpEnter, // Common media keys KeyCode::Mute, KeyCode::VolumeDown, KeyCode::VolumeUp, ]; for key in standard_keys { self.set_supported_key(key); } } } impl Drop for RegisteredInputDevice { fn drop(&mut self) { unregister_device(&self.device).unwrap(); } }