Add input subsystem
Co-authored-by: TinaZhangZW <ruoyuan.zw@antgroup.com>
This commit is contained in:
parent
32581caa7a
commit
9c062b1350
|
|
@ -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",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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(®istry.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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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,
|
||||
}
|
||||
|
|
@ -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()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue