Add input subsystem

Co-authored-by: TinaZhangZW <ruoyuan.zw@antgroup.com>
This commit is contained in:
Cautreoxit 2025-08-22 16:08:23 +08:00 committed by Tate, Hongliang Tian
parent 32581caa7a
commit 9c062b1350
9 changed files with 1190 additions and 168 deletions

4
Cargo.lock generated
View File

@ -131,8 +131,10 @@ dependencies = [
name = "aster-input"
version = "0.1.0"
dependencies = [
"bitflags 1.3.2",
"bitvec",
"component",
"int-to-c-enum",
"log",
"ostd",
"spin",
]

View File

@ -7,9 +7,11 @@ edition = "2021"
[dependencies]
spin = "0.9.4"
log = "0.4"
ostd = { path = "../../../ostd" }
component = { path = "../../libs/comp-sys/component" }
int-to-c-enum = { path = "../../libs/int-to-c-enum" }
bitvec = { version = "1.0", default-features = false, features = ["alloc"] }
bitflags = "1.3"
[lints]
workspace = true

View File

@ -0,0 +1,360 @@
// SPDX-License-Identifier: MPL-2.0
//! Event types and codes.
//!
//! This file is based on the USB HUT 1.12 specification
//! (see <http://www.usb.org/developers/hidpage>) and follows the
//! Linux input event codes standard for maximum compatibility.
//!
//! The USB HUT standard ensures consistent event type and value
//! definitions across different input devices and platforms.
use bitflags::bitflags;
use bitvec::prelude::*;
bitflags! {
/// Input event types.
pub struct EventTypes: u32 {
/// Synchronization events.
const SYN = 1 << 0x00;
/// Key press/release events.
const KEY = 1 << 0x01;
/// Relative movement events. (mouse, trackball, etc.)
const REL = 1 << 0x02;
/// Absolute position events. (touchpad, tablet, etc.)
const ABS = 1 << 0x03;
/// Miscellaneous events.
const MSC = 1 << 0x04;
/// Switch events.
const SW = 1 << 0x05;
/// LED events.
const LED = 1 << 0x11;
/// Sound events.
const SND = 1 << 0x12;
/// Repeat events.
const REP = 1 << 0x14;
/// Force feedback events.
const FF = 1 << 0x15;
/// Power management events.
const PWR = 1 << 0x16;
/// Force feedback status events.
const FF_STATUS = 1 << 0x17;
}
}
impl Default for EventTypes {
fn default() -> Self {
Self::new()
}
}
impl EventTypes {
/// Creates a new empty set of event type flags.
pub const fn new() -> Self {
Self::empty()
}
/// Gets the event index as a `u16` value for this event type.
///
/// # Panics
///
/// This method will panic if there are multiple event bits set in `self`.
pub const fn as_index(&self) -> u16 {
// Check if exactly one bit is set
let bits = self.bits();
assert!(
bits != 0 && (bits & (bits - 1)) == 0,
"`EventTypes::as_index` expects exactly one event bit to be set"
);
match *self {
Self::SYN => 0x00,
Self::KEY => 0x01,
Self::REL => 0x02,
Self::ABS => 0x03,
Self::MSC => 0x04,
Self::SW => 0x05,
Self::LED => 0x11,
Self::SND => 0x12,
Self::REP => 0x14,
Self::FF => 0x15,
Self::PWR => 0x16,
Self::FF_STATUS => 0x17,
_ => unreachable!(),
}
}
}
/// Synchronization events.
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SynEvent {
Report = 0x00,
Config = 0x01,
MtReport = 0x02,
Dropped = 0x03,
}
/// Relative axes.
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RelCode {
X = 0x00,
Y = 0x01,
Z = 0x02,
Rx = 0x03,
Ry = 0x04,
Rz = 0x05,
HWheel = 0x06,
Dial = 0x07,
Wheel = 0x08,
Misc = 0x09,
Reserved = 0x0a,
WheelHiRes = 0x0b,
HWheelHiRes = 0x0c,
}
/// The maximum value for relative axes.
const REL_MAX: usize = 0x0f;
/// The number of relative axes.
const REL_COUNT: usize = REL_MAX + 1;
/// A set of [`RelCode`] represented as a bitmap.
#[derive(Debug, Clone)]
pub struct RelCodeSet(BitVec<u8>);
impl Default for RelCodeSet {
fn default() -> Self {
Self::new()
}
}
impl RelCodeSet {
/// Creates an empty set.
pub fn new() -> Self {
Self(BitVec::repeat(false, REL_COUNT))
}
/// Sets a relative code in the set.
pub fn set(&mut self, rel_code: RelCode) {
let index = rel_code as usize;
self.0.set(index, true);
}
/// Clears a relative code from the set.
pub fn clear(&mut self, rel_code: RelCode) {
let index = rel_code as usize;
self.0.set(index, false);
}
/// Checks if the set contains a relative code.
pub fn contain(&self, rel_code: RelCode) -> bool {
let index = rel_code as usize;
self.0.get(index).map(|b| *b).unwrap()
}
}
/// A set of [`KeyCode`] represented as a bitmap.
#[derive(Debug, Clone)]
pub struct KeyCodeSet(BitVec<u8>);
impl Default for KeyCodeSet {
fn default() -> Self {
Self::new()
}
}
impl KeyCodeSet {
/// Creates an empty set.
pub fn new() -> Self {
Self(BitVec::repeat(false, KEY_COUNT))
}
/// Sets a key code in the set.
pub fn set(&mut self, key_code: KeyCode) {
let index = key_code as usize;
self.0.set(index, true);
}
/// Clears a key code from the set.
pub fn clear(&mut self, key_code: KeyCode) {
let index = key_code as usize;
self.0.set(index, false);
}
/// Checks if the set contains a key code.
pub fn contain(&self, key_code: KeyCode) -> bool {
let index = key_code as usize;
self.0.get(index).map(|b| *b).unwrap()
}
/// Checks if the set contains any key codes in the `range`.
///
/// # Panics
///
/// This method will panic if the `range` contains invalid key codes.
pub fn contain_any(&self, range: core::ops::Range<usize>) -> bool {
assert!(range.is_empty() || range.end <= KEY_COUNT);
range.into_iter().any(|i| *self.0.get(i).unwrap())
}
}
/// Common keyboard and mouse keys.
// TODO: Add more uncommon key codes.
#[repr(u16)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyCode {
// Reserved key.
Reserved = 0,
// Function keys.
Esc = 1,
F1 = 59,
F2 = 60,
F3 = 61,
F4 = 62,
F5 = 63,
F6 = 64,
F7 = 65,
F8 = 66,
F9 = 67,
F10 = 68,
F11 = 87,
F12 = 88,
// Number row.
Num1 = 2,
Num2 = 3,
Num3 = 4,
Num4 = 5,
Num5 = 6,
Num6 = 7,
Num7 = 8,
Num8 = 9,
Num9 = 10,
Num0 = 11,
Minus = 12,
Equal = 13,
Backspace = 14,
// First row (QWERTY).
Tab = 15,
Q = 16,
W = 17,
E = 18,
R = 19,
T = 20,
Y = 21,
U = 22,
I = 23,
O = 24,
P = 25,
LeftBrace = 26, // [
RightBrace = 27, // ]
Backslash = 43, // \
// Second row (ASDF).
CapsLock = 58,
A = 30,
S = 31,
D = 32,
F = 33,
G = 34,
H = 35,
J = 36,
K = 37,
L = 38,
Semicolon = 39, // ;
Apostrophe = 40, // '
Enter = 28,
// Third row (ZXCV).
LeftShift = 42,
Z = 44,
X = 45,
C = 46,
V = 47,
B = 48,
N = 49,
M = 50,
Comma = 51,
Dot = 52,
Slash = 53, // /
RightShift = 54,
// Bottom row.
LeftCtrl = 29,
LeftAlt = 56,
Space = 57,
RightAlt = 100,
RightCtrl = 97,
// Special keys.
Grave = 41, // `
LeftMeta = 125, // Windows/Cmd key
RightMeta = 126,
Menu = 139, // Context menu key
// Arrow keys.
Up = 103,
Down = 108,
Left = 105,
Right = 106,
// Navigation cluster.
Home = 102,
End = 107,
PageUp = 104,
PageDown = 109,
Insert = 110,
Delete = 111,
// Common modifier states.
NumLock = 69,
ScrollLock = 70,
// Numpad.
Kp0 = 82,
Kp1 = 79,
Kp2 = 80,
Kp3 = 81,
Kp4 = 75,
Kp5 = 76,
Kp6 = 77,
Kp7 = 71,
Kp8 = 72,
Kp9 = 73,
KpDot = 83,
KpPlus = 78,
KpMinus = 74,
KpAsterisk = 55, // *
KpSlash = 98, // /
KpEnter = 96,
// Common media keys.
Mute = 113,
VolumeDown = 114,
VolumeUp = 115,
// Starting code of button events.
BtnMisc = 0x100,
// Mouse buttons.
BtnLeft = 0x110,
BtnRight = 0x111,
BtnMiddle = 0x112,
BtnSide = 0x113, // Mouse side button
BtnExtra = 0x114, // Mouse extra button
BtnForward = 0x115, // Mouse forward button
BtnBack = 0x116, // Mouse back button
}
/// The maximum value for key codes.
const KEY_MAX: usize = 0x120;
/// The number of key codes.
const KEY_COUNT: usize = KEY_MAX + 1;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyStatus {
Released,
Pressed,
}

View File

@ -0,0 +1,197 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::{sync::Arc, vec::Vec};
use core::fmt::Debug;
use ostd::sync::{RwLock, WriteIrqDisabled};
use crate::{
input_dev::RegisteredInputDevice,
input_handler::{BoundInputHandler, InputHandlerClass},
InputDevice,
};
/// Registry entry for each registered device.
///
/// This serves as the connection point between devices and their handlers.
#[derive(Debug)]
struct InputDeviceRegistry {
/// The input device.
device: Arc<dyn InputDevice>,
/// Handlers connected to this device.
handlers: Arc<RwLock<Vec<BoundInputHandler>, WriteIrqDisabled>>,
}
/// The core component of the input subsystem.
///
/// `InputCore` manages all registered input devices and handler classes.
/// It coordinates the connection between devices and handlers, and routes
/// input events from devices to their associated handlers.
#[derive(Debug)]
pub(crate) struct InputCore {
/// All registered devices with their associated handlers.
devices: Vec<InputDeviceRegistry>,
/// All registered handler classes that can connect to devices.
handler_classes: Vec<Arc<dyn InputHandlerClass>>,
}
impl InputCore {
/// Creates a new input core.
pub(crate) fn new() -> Self {
Self {
devices: Vec::new(),
handler_classes: Vec::new(),
}
}
/// Registers a new handler class.
pub(crate) fn register_handler_class(&mut self, handler_class: Arc<dyn InputHandlerClass>) {
// Connect to all existing devices
for device_registry in self.devices.iter() {
match handler_class.connect(device_registry.device.clone()) {
Ok(handler) => {
device_registry.handlers.write().push(BoundInputHandler {
handler,
handler_class: handler_class.clone(),
});
log::info!(
"Input: successfully connected handler class {} to device {}",
handler_class.name(),
device_registry.device.name()
);
}
Err(e) => {
log::info!(
"Input: failed to connect handler class {} to device {}: {:?}",
handler_class.name(),
device_registry.device.name(),
e
);
}
}
}
log::info!("Input: registered handler class {}", handler_class.name());
self.handler_classes.push(handler_class);
}
/// Unregisters a handler class.
pub(crate) fn unregister_handler_class(
&mut self,
handler_class: &Arc<dyn InputHandlerClass>,
) -> Option<Arc<dyn InputHandlerClass>> {
// Find the handler class and remove it.
let pos = self
.handler_classes
.iter()
.position(|h| Arc::ptr_eq(h, handler_class))?;
let handler_class = self.handler_classes.swap_remove(pos);
for device_registry in self.devices.iter() {
let mut handlers = device_registry.handlers.write();
let Some(pos) = handlers
.iter()
.position(|h| Arc::ptr_eq(&h.handler_class, &handler_class))
else {
continue;
};
let handler = handlers.swap_remove(pos);
drop(handlers);
drop(handler);
handler_class.disconnect(&device_registry.device);
}
log::info!("Input: unregistered handler class {}", handler_class.name());
Some(handler_class)
}
/// Registers a new input device.
pub(crate) fn register_device(
&mut self,
device: Arc<dyn InputDevice>,
) -> RegisteredInputDevice {
// Connect all existing handler classes.
let mut connected_handlers = Vec::new();
for handler_class in self.handler_classes.iter() {
match handler_class.connect(device.clone()) {
Ok(handler) => {
connected_handlers.push(BoundInputHandler {
handler,
handler_class: handler_class.clone(),
});
log::info!(
"Input: successfully connected handler class {} to device {}",
handler_class.name(),
device.name()
);
}
Err(e) => {
log::info!(
"Input: failed to connect handler class {} to device {}: {:?}",
handler_class.name(),
device.name(),
e
);
}
}
}
let handlers = Arc::new(RwLock::new(connected_handlers));
// Add the device registry.
let new_registry = InputDeviceRegistry {
device: device.clone(),
handlers: handlers.clone(),
};
self.devices.push(new_registry);
log::info!("Input: registered device {}", device.name());
RegisteredInputDevice::new(device, handlers)
}
/// Unregisters an input device.
pub(crate) fn unregister_device(
&mut self,
device: &Arc<dyn InputDevice>,
) -> Option<Arc<dyn InputDevice>> {
// Find the device and remove it.
let pos = self
.devices
.iter()
.position(|registry| Arc::ptr_eq(&registry.device, device))?;
let device_registry = self.devices.swap_remove(pos);
// Take all handlers connected to this device and clear the list.
let mut handlers = device_registry.handlers.write();
let bound_handlers = core::mem::take(&mut *handlers);
drop(handlers);
// Disconnect handler classes that were connected.
for bound_handler in bound_handlers.into_iter() {
bound_handler
.handler_class
.disconnect(&device_registry.device);
}
log::info!("Input: unregistered device {}", device.name());
Some(device_registry.device)
}
/// Counts the number of registered devices.
pub(crate) fn count_devices(&self) -> usize {
self.devices.len()
}
/// Counts the number of registered handler classes.
pub(crate) fn count_handler_class(&self) -> usize {
self.handler_classes.len()
}
/// Gets all registered devices.
pub(crate) fn all_devices(&self) -> Vec<Arc<dyn InputDevice>> {
self.devices
.iter()
.map(|registry| registry.device.clone())
.collect()
}
}

View File

@ -0,0 +1,463 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::{sync::Arc, vec::Vec};
use core::{any::Any, fmt::Debug};
use ostd::{
sync::{RwLock, WriteIrqDisabled},
Pod,
};
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);
}
}
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<dyn InputDevice>,
/// Reference to bound handlers for direct event dispatch.
handlers: Arc<RwLock<Vec<BoundInputHandler>, WriteIrqDisabled>>,
}
impl RegisteredInputDevice {
pub(crate) fn new(
device: Arc<dyn InputDevice>,
handlers: Arc<RwLock<Vec<BoundInputHandler>, 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<dyn InputDevice> {
&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();
}
}

View File

@ -0,0 +1,73 @@
// SPDX-License-Identifier: MPL-2.0
use alloc::sync::Arc;
use core::{any::Any, fmt::Debug};
use crate::{input_dev::InputEvent, unregister_handler_class, InputDevice};
/// Errors that can occur when connecting to an input device.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ConnectError {
/// Device is not compatible with this handler class.
IncompatibleDevice,
/// Failed to create device node.
DeviceNodeCreationFailed,
/// Device is already connected.
AlreadyConnected,
/// Other internal error.
InternalError,
}
/// A trait that represents an input handler class.
///
/// Once registered to the input core (via [`register_handler_class`]), the
/// input handler class will try to connect to each input device (via
/// [`connect`]). If it succeeds, an [`InputHandler`] will be created to handle
/// the input events from that device.
///
/// [`register_handler_class`]: crate::register_handler_class
/// [`connect`]: Self::connect
/// [`InputHandler`]: crate::InputHandler
pub trait InputHandlerClass: Send + Sync + Any + Debug {
/// Returns the class name of the handler class.
fn name(&self) -> &str;
/// Tries to connect to the input device.
///
/// On success, this method will return `Ok()` with a new input handler.
/// Otherwise, it will return `Err(ConnectError)`.
fn connect(&self, dev: Arc<dyn InputDevice>) -> Result<Arc<dyn InputHandler>, ConnectError>;
/// Disconnects from a device.
fn disconnect(&self, dev: &Arc<dyn InputDevice>);
}
/// A trait that represents an individual input handler instance for a specific device.
///
/// Each handler instance is created by an [`InputHandlerClass`] when it successfully
/// connects to an input device (via [`InputHandlerClass::connect`]). The handler
/// is responsible for processing input events from the associated device.
///
/// [`InputHandlerClass`]: crate::InputHandlerClass
/// [`InputHandlerClass::connect`]: crate::InputHandlerClass::connect
pub trait InputHandler: Send + Sync + Debug {
/// Handles multiple input events from the device.
fn handle_events(&self, events: &[InputEvent]);
}
/// An input handler bound with the class that created it.
#[derive(Debug, Clone)]
pub(crate) struct BoundInputHandler {
pub(crate) handler: Arc<dyn InputHandler>,
pub(crate) handler_class: Arc<dyn InputHandlerClass>,
}
/// Registered input handler class that can create handlers.
#[derive(Debug)]
pub struct RegisteredInputHandlerClass(pub(crate) Arc<dyn InputHandlerClass>);
impl Drop for RegisteredInputHandlerClass {
fn drop(&mut self) {
unregister_handler_class(&self.0).unwrap();
}
}

View File

@ -1,128 +0,0 @@
// SPDX-License-Identifier: MPL-2.0
use int_to_c_enum::TryFromInt;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, TryFromInt)]
#[repr(u16)]
pub enum Key {
Reserved = 0,
ESC = 1,
One = 2,
Two = 3,
Three = 4,
Four = 5,
Five = 6,
Six = 7,
Seven = 8,
Eight = 9,
Nine = 10,
Zero = 11,
Minus = 12,
Equal = 13,
BackSpace = 14,
Tab = 15,
Q = 16,
W = 17,
E = 18,
R = 19,
T = 20,
Y = 21,
U = 22,
I = 23,
O = 24,
P = 25,
/// Symbol: [
LeftBrace = 26,
/// Symbol: ]
RightBrace = 27,
Enter = 28,
LeftCtrl = 29,
A = 30,
S = 31,
D = 32,
F = 33,
G = 34,
H = 35,
J = 36,
K = 37,
L = 38,
/// Symbol: ;
SemiColon = 39,
/// Symbol: '
Apostrophe = 40,
/// Symbol: `
Grave = 41,
LeftShift = 42,
/// Symbol: \
BackSlash = 43,
Z = 44,
X = 45,
C = 46,
V = 47,
B = 48,
N = 49,
M = 50,
Comma = 51,
Dot = 52,
// Symbol: /
Slash = 53,
RightShift = 54,
/// Keypad asterisk, Symbol: *
KpAsterisk = 55,
LeftAlt = 56,
Space = 57,
Capslock = 58,
F1 = 59,
F2 = 60,
F3 = 61,
F4 = 62,
F5 = 63,
F6 = 64,
F7 = 65,
F8 = 66,
F9 = 67,
F10 = 68,
NumLock = 69,
ScrollLock = 70,
Kp7 = 71,
Kp8 = 72,
Kp9 = 73,
KpMinus = 74,
Kp4 = 75,
Kp5 = 76,
Kp6 = 77,
KpPlus = 78,
Kp1 = 79,
Kp2 = 80,
Kp3 = 81,
Kp0 = 82,
KpDot = 83,
F11 = 87,
F12 = 88,
KpEnter = 96,
RightCtrl = 97,
KpSlash = 98,
RightAlt = 100,
LineFeed = 101,
Home = 102,
Up = 103,
PageUp = 104,
Left = 105,
Right = 106,
End = 107,
Down = 108,
PageDown = 109,
Insert = 110,
Delete = 111,
LeftMeta = 125,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyStatus {
Pressed,
Released,
}

View File

@ -1,76 +1,129 @@
// SPDX-License-Identifier: MPL-2.0
//! The input devices of Asterinas.
//!
//! This crate provides a comprehensive input subsystem for handling various input devices,
//! including keyboards, mice, etc. It implements an event-driven architecture similar to
//! the Linux input subsystem.
//!
//! # Architecture
//!
//! ```text
//! Input Device → Input Core → Input Handler
//! ↓ ↓ ↓
//! Hardware Event Router Event Consumer
//! (e.g., evdev)
//! ```
//!
//! # Example Usage
//!
//! ```
//! // Register an input device
//! let device = Arc::new(MyInputDevice::new());
//! let registered_device = input::register_device(device);
//!
//! // Register an input handler
//! let handler = Arc::new(MyInputHandler::new());
//! input::register_handler(handler);
//!
//! // Submit a key event from device
//! let key_event = InputEvent::from_key_and_status(linux_key, key_status);
//! registered_device.submit_events(&[key_event]);
//! ```
//!
#![no_std]
#![deny(unsafe_code)]
#![feature(fn_traits)]
extern crate alloc;
pub mod key;
pub mod event_type_codes;
mod input_core;
pub mod input_dev;
pub mod input_handler;
use alloc::{collections::BTreeMap, string::String, sync::Arc, vec::Vec};
use core::{any::Any, fmt::Debug};
use alloc::{sync::Arc, vec::Vec};
use component::{init_component, ComponentInitError};
use key::{Key, KeyStatus};
use ostd::sync::SpinLock;
use spin::Once;
#[derive(Debug, Clone, Copy)]
pub enum InputEvent {
KeyBoard(Key, KeyStatus),
}
use self::input_core::InputCore;
use crate::{
input_dev::{InputDevice, RegisteredInputDevice},
input_handler::{InputHandlerClass, RegisteredInputHandlerClass},
};
pub trait InputDevice: Send + Sync + Any + Debug {
fn register_callbacks(&self, function: &'static (dyn Fn(InputEvent) + Send + Sync));
}
pub fn register_device(name: String, device: Arc<dyn InputDevice>) {
COMPONENT
.get()
.unwrap()
.input_device_table
/// Registers a handler class.
pub fn register_handler_class(
handler_class: Arc<dyn InputHandlerClass>,
) -> RegisteredInputHandlerClass {
let component = COMPONENT.get().unwrap();
component
.input_core
.lock()
.insert(name, device);
.register_handler_class(handler_class.clone());
RegisteredInputHandlerClass(handler_class)
}
pub fn get_device(str: &str) -> Option<Arc<dyn InputDevice>> {
COMPONENT
.get()
.unwrap()
.input_device_table
/// Unregisters a handler class.
pub(crate) fn unregister_handler_class(
handler_class: &Arc<dyn InputHandlerClass>,
) -> Option<Arc<dyn InputHandlerClass>> {
let component = COMPONENT.get().unwrap();
component
.input_core
.lock()
.get(str)
.cloned()
.unregister_handler_class(handler_class)
}
pub fn all_devices() -> Vec<(String, Arc<dyn InputDevice>)> {
let input_devs = COMPONENT.get().unwrap().input_device_table.lock();
input_devs
.iter()
.map(|(name, device)| (name.clone(), device.clone()))
.collect()
/// Registers an input device.
pub fn register_device(device: Arc<dyn InputDevice>) -> RegisteredInputDevice {
let component = COMPONENT.get().unwrap();
component.input_core.lock().register_device(device)
}
/// Unregisters an input device.
pub(crate) fn unregister_device(device: &Arc<dyn InputDevice>) -> Option<Arc<dyn InputDevice>> {
let component = COMPONENT.get().unwrap();
component.input_core.lock().unregister_device(device)
}
/// Counts the number of registered devices.
pub fn count_devices() -> usize {
let component = COMPONENT.get().unwrap();
component.input_core.lock().count_devices()
}
/// Counts the number of registered handler classes.
pub fn count_handler_class() -> usize {
let component = COMPONENT.get().unwrap();
component.input_core.lock().count_handler_class()
}
/// Gets all registered devices.
pub fn all_devices() -> Vec<Arc<dyn InputDevice>> {
let component = COMPONENT.get().unwrap();
component.input_core.lock().all_devices()
}
static COMPONENT: Once<Component> = Once::new();
#[init_component]
fn component_init() -> Result<(), ComponentInitError> {
let a = Component::init()?;
COMPONENT.call_once(|| a);
let component = Component::init()?;
COMPONENT.call_once(|| component);
Ok(())
}
#[derive(Debug)]
struct Component {
input_device_table: SpinLock<BTreeMap<String, Arc<dyn InputDevice>>>,
input_core: SpinLock<InputCore>,
}
impl Component {
pub fn init() -> Result<Self, ComponentInitError> {
Ok(Self {
input_device_table: SpinLock::new(BTreeMap::new()),
input_core: SpinLock::new(InputCore::new()),
})
}
}

View File

@ -7,8 +7,8 @@ use log::info;
pub fn init() {
// print all the input device to make sure input crate will compile
for (name, _) in aster_input::all_devices() {
info!("Found Input device, name:{}", name);
for device in aster_input::all_devices() {
info!("Found Input device, name:{}", device.name());
}
if let Some(console) = FRAMEBUFFER_CONSOLE.get() {