usbhidd: move code to rehid
This commit is contained in:
Generated
+10
-1
@@ -1137,6 +1137,15 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
|
||||
|
||||
[[package]]
|
||||
name = "rehid"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#9bf6c9ef7cc4f95932fcaabfa3141a24bfd39bbf"
|
||||
dependencies = [
|
||||
"bitflags 2.5.0",
|
||||
"ux",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rtl8139d"
|
||||
version = "0.1.0"
|
||||
@@ -1520,7 +1529,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"redox-log",
|
||||
"redox_syscall 0.5.1",
|
||||
"ux",
|
||||
"rehid",
|
||||
"xhcid",
|
||||
]
|
||||
|
||||
|
||||
+1
-1
@@ -13,5 +13,5 @@ log = "0.4"
|
||||
orbclient = "0.3.47"
|
||||
redox-log = "0.1"
|
||||
redox_syscall = "0.5"
|
||||
ux = "0.1"
|
||||
rehid = { git = "https://gitlab.redox-os.org/redox-os/rehid.git" }
|
||||
xhcid = { path = "../xhcid" }
|
||||
|
||||
+6
-51
@@ -7,64 +7,18 @@ use std::os::unix::io::AsRawFd;
|
||||
use bitflags::bitflags;
|
||||
use orbclient::KeyEvent as OrbKeyEvent;
|
||||
use redox_log::{OutputBuilder, RedoxLogger};
|
||||
use rehid::{binary_view::BinaryView, report_desc::{self, ReportTy}, usage_tables};
|
||||
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle};
|
||||
|
||||
mod keymap;
|
||||
mod report_desc;
|
||||
mod reqs;
|
||||
mod usage_tables;
|
||||
|
||||
use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY};
|
||||
use reqs::ReportTy;
|
||||
|
||||
fn div_round_up(num: u32, denom: u32) -> u32 {
|
||||
if num % denom == 0 { num / denom } else { num / denom + 1 }
|
||||
}
|
||||
|
||||
struct BinaryView<'a> {
|
||||
data: &'a [u8],
|
||||
offset: usize,
|
||||
len: usize,
|
||||
}
|
||||
impl<'a> BinaryView<'a> {
|
||||
pub fn new(data: &'a [u8], offset: usize, len: usize) -> Self {
|
||||
Self {
|
||||
data,
|
||||
offset,
|
||||
len,
|
||||
}
|
||||
}
|
||||
pub fn get(&self, bit_index: usize) -> Option<bool> {
|
||||
let bit_index = self.offset + bit_index;
|
||||
|
||||
if bit_index >= self.offset + self.len { return None }
|
||||
|
||||
let byte_index = bit_index / 8;
|
||||
let bits_from_first = bit_index % 8;
|
||||
let byte = self.data.get(byte_index)?;
|
||||
Some(byte & (1 << bits_from_first) != 0)
|
||||
}
|
||||
pub fn read_u8(&self, bit_index: usize) -> Option<u8> {
|
||||
let bit_index = self.offset + bit_index;
|
||||
|
||||
if bit_index >= self.offset + self.len { return None }
|
||||
|
||||
let first = bit_index / 8;
|
||||
let bits_from_first = bit_index % 8;
|
||||
let first_byte = self.data.get(first)?;
|
||||
let lo = first_byte >> bits_from_first;
|
||||
|
||||
let hi = if bits_from_first > 0 {
|
||||
let hi = self.data.get(first + 1)? & ((1 << bits_from_first) - 1);
|
||||
let bits_to_next = 8 - bits_from_first;
|
||||
hi << bits_to_next
|
||||
} else { 0 };
|
||||
|
||||
|
||||
Some(lo | hi)
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_logging() -> Option<&'static RedoxLogger> {
|
||||
let mut logger = RedoxLogger::new()
|
||||
.with_output(
|
||||
@@ -403,11 +357,12 @@ fn main() {
|
||||
let report_count = global_state.report_count.unwrap();
|
||||
|
||||
log::trace!(
|
||||
"size {} count {} at {} length {}",
|
||||
"size {} count {} offset {} length {} usage page {:?}",
|
||||
report_size,
|
||||
report_count,
|
||||
bit_offset,
|
||||
bit_length
|
||||
bit_length,
|
||||
global_state.usage_page
|
||||
);
|
||||
|
||||
// TODO: For now, the dynamic value usages cannot overlap with selector usages...
|
||||
@@ -516,7 +471,7 @@ fn main() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log::trace!("Unknown report variable item: size {} count {} at {}", report_size, report_count, bit_offset);
|
||||
log::trace!("Unknown report variable item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page);
|
||||
}
|
||||
} else {
|
||||
// The item is an array.
|
||||
@@ -532,7 +487,7 @@ fn main() {
|
||||
log::trace!("Report index array {}: {:#x}", report_index, usage);
|
||||
}
|
||||
} else {
|
||||
log::trace!("Unknown report array item: size {} count {} at {}", report_size, report_count, bit_offset);
|
||||
log::trace!("Unknown report array item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,393 +0,0 @@
|
||||
use bitflags::bitflags;
|
||||
use ux::{u2, u4};
|
||||
|
||||
use crate::reqs::ReportTy;
|
||||
|
||||
/*#[repr(u8)]
|
||||
enum Protocol {
|
||||
|
||||
}*/
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct MainItemFlags: u32 {
|
||||
const CONSTANT = 1 << 0;
|
||||
const VARIABLE = 1 << 1;
|
||||
const RELATIVE = 1 << 2;
|
||||
const WRAP = 1 << 3;
|
||||
const NONLINEAR = 1 << 4;
|
||||
const NO_PREFERRED_STATE = 1 << 5;
|
||||
const NULL_STATE = 1 << 6;
|
||||
const VOLATILE = 1 << 7;
|
||||
const BUFFERED_BYTES = 1 << 8;
|
||||
}
|
||||
}
|
||||
#[repr(u8)]
|
||||
pub enum MainCollectionFlags {
|
||||
Physical = 0,
|
||||
Application,
|
||||
Logical,
|
||||
Report,
|
||||
NamedArray,
|
||||
UsageSwitch,
|
||||
UsageModifier,
|
||||
}
|
||||
|
||||
pub const REPORT_DESC_TY: u8 = 34;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum MainItem {
|
||||
Input(u32),
|
||||
Output(u32),
|
||||
Feature(u32),
|
||||
Collection(u8),
|
||||
EndOfCollection,
|
||||
}
|
||||
impl MainItem {
|
||||
pub fn report_ty(&self) -> Option<ReportTy> {
|
||||
match self {
|
||||
Self::Input(_) => Some(ReportTy::Input),
|
||||
Self::Output(_) => Some(ReportTy::Output),
|
||||
Self::Feature(_) => Some(ReportTy::Feature),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum GlobalItem {
|
||||
UsagePage(u32),
|
||||
LogicalMinimum(u32),
|
||||
LogicalMaximum(u32),
|
||||
PhysicalMinimum(u32),
|
||||
PhysicalMaximum(u32),
|
||||
UnitExponent(u32),
|
||||
Unit(u32),
|
||||
ReportSize(u32),
|
||||
ReportId(u32),
|
||||
ReportCount(u32),
|
||||
Push,
|
||||
Pop,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct GlobalItemsState {
|
||||
pub usage_page: Option<u32>,
|
||||
pub logical_min: Option<u32>,
|
||||
pub logical_max: Option<u32>,
|
||||
pub physical_min: Option<u32>,
|
||||
pub physical_max: Option<u32>,
|
||||
pub unit_exponent: Option<u32>,
|
||||
pub unit: Option<u32>,
|
||||
pub report_size: Option<u32>,
|
||||
pub report_id: Option<u32>,
|
||||
pub report_count: Option<u32>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Invalid;
|
||||
|
||||
pub fn update_global_state(current_state: &mut GlobalItemsState, stack: &mut Vec<GlobalItemsState>, report_item: &ReportItem) -> Result<(), Invalid> {
|
||||
match report_item {
|
||||
ReportItem::Global(global) => match global {
|
||||
&GlobalItem::UsagePage(u) => current_state.usage_page = Some(u),
|
||||
&GlobalItem::LogicalMinimum(m) => current_state.logical_min = Some(m),
|
||||
&GlobalItem::LogicalMaximum(m) => current_state.logical_max = Some(m),
|
||||
&GlobalItem::PhysicalMinimum(m) => current_state.physical_min = Some(m),
|
||||
&GlobalItem::PhysicalMaximum(m) => current_state.physical_max = Some(m),
|
||||
&GlobalItem::UnitExponent(e) => current_state.unit_exponent = Some(e),
|
||||
&GlobalItem::Unit(u) => current_state.unit = Some(u),
|
||||
&GlobalItem::ReportSize(s) => current_state.report_size = Some(s),
|
||||
&GlobalItem::ReportId(i) => current_state.report_id = Some(i),
|
||||
&GlobalItem::ReportCount(c) => current_state.report_count = Some(c),
|
||||
&GlobalItem::Push => stack.push(*current_state),
|
||||
&GlobalItem::Pop => *current_state = stack.pop().ok_or(Invalid)?,
|
||||
}
|
||||
ReportItem::Local(local) => (), // TODO
|
||||
ReportItem::Main(_) => (),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum LocalItem {
|
||||
Usage(u32),
|
||||
UsageMinimum(u32),
|
||||
UsageMaximum(u32),
|
||||
DesignatorIndex(u32),
|
||||
DesignatorMinimum(u32),
|
||||
DesignatorMaximum(u32),
|
||||
StringIndex(u32),
|
||||
StringMinimum(u32),
|
||||
StringMaximum(u32),
|
||||
Delimeter(u32),
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct LocalItemsState {
|
||||
pub usage: Option<u32>,
|
||||
pub usage_min: Option<u32>,
|
||||
pub usage_max: Option<u32>,
|
||||
pub desig_idx: Option<u32>,
|
||||
pub desig_min: Option<u32>,
|
||||
pub desig_max: Option<u32>,
|
||||
pub str_idx: Option<u32>,
|
||||
pub str_min: Option<u32>,
|
||||
pub str_max: Option<u32>,
|
||||
}
|
||||
pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &ReportItem) {
|
||||
match report_item {
|
||||
ReportItem::Local(local) => match local {
|
||||
&LocalItem::Usage(u) => current_state.usage = Some(u),
|
||||
&LocalItem::UsageMinimum(m) => current_state.usage_min = Some(m),
|
||||
&LocalItem::UsageMaximum(m) => current_state.usage_max = Some(m),
|
||||
&LocalItem::DesignatorIndex(i) => current_state.desig_idx = Some(i),
|
||||
&LocalItem::DesignatorMinimum(m) => current_state.desig_min = Some(m),
|
||||
&LocalItem::DesignatorMaximum(m) => current_state.desig_max = Some(m),
|
||||
&LocalItem::StringIndex(i) => current_state.str_idx = Some(i),
|
||||
&LocalItem::StringMinimum(m) => current_state.str_min = Some(m),
|
||||
&LocalItem::StringMaximum(m) => current_state.str_max = Some(m),
|
||||
&LocalItem::Delimeter(_) => todo!(),
|
||||
},
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ReportItem {
|
||||
Main(MainItem),
|
||||
Global(GlobalItem),
|
||||
Local(LocalItem),
|
||||
}
|
||||
impl ReportItem {
|
||||
pub fn as_main_item(&self) -> Option<&MainItem> {
|
||||
match self {
|
||||
Self::Main(m) => Some(m),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<MainItem> for ReportItem {
|
||||
fn from(main: MainItem) -> Self {
|
||||
Self::Main(main)
|
||||
}
|
||||
}
|
||||
impl From<GlobalItem> for ReportItem {
|
||||
fn from(main: GlobalItem) -> Self {
|
||||
Self::Global(main)
|
||||
}
|
||||
}
|
||||
impl From<LocalItem> for ReportItem {
|
||||
fn from(main: LocalItem) -> Self {
|
||||
Self::Local(main)
|
||||
}
|
||||
}
|
||||
|
||||
impl ReportItem {
|
||||
pub fn size(size: u2) -> u8 {
|
||||
match u8::from(size) {
|
||||
0 => 0,
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
3 => 4,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
pub fn parse_short(size: u2, ty: u2, tag: u4, bytes: &[u8]) -> Option<(Self, usize)> {
|
||||
Some(match (u8::from(tag), u8::from(ty)) {
|
||||
(tag, 0b00) => {
|
||||
let real_size = Self::size(size) as usize;
|
||||
let mut value_bytes = [0u8; 4];
|
||||
if real_size > 0 {
|
||||
value_bytes[..real_size].copy_from_slice(&bytes[..real_size])
|
||||
};
|
||||
let value = u32::from_le_bytes(value_bytes);
|
||||
|
||||
match tag {
|
||||
0b1000 => (MainItem::Input(value).into(), 1 + real_size),
|
||||
0b1001 => (MainItem::Output(value).into(), 1 + real_size),
|
||||
0b1011 => (MainItem::Feature(value).into(), 1 + real_size),
|
||||
0b1010 => (MainItem::Collection(bytes[0]).into(), 2),
|
||||
0b1100 => (MainItem::EndOfCollection.into(), 1 + real_size),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
(tag, 0b01) => {
|
||||
let real_size = Self::size(size) as usize;
|
||||
let mut value_bytes = [0u8; 4];
|
||||
if real_size > 0 {
|
||||
value_bytes[..real_size].copy_from_slice(&bytes[..real_size])
|
||||
};
|
||||
let value = u32::from_le_bytes(value_bytes);
|
||||
match tag {
|
||||
0b0000 => (GlobalItem::UsagePage(value).into(), 1 + real_size),
|
||||
0b0001 => (GlobalItem::LogicalMinimum(value).into(), 1 + real_size),
|
||||
0b0010 => (GlobalItem::LogicalMaximum(value).into(), 1 + real_size),
|
||||
0b0011 => (GlobalItem::PhysicalMinimum(value).into(), 1 + real_size),
|
||||
0b0100 => (GlobalItem::PhysicalMaximum(value).into(), 1 + real_size),
|
||||
0b0101 => (GlobalItem::UnitExponent(value).into(), 1 + real_size),
|
||||
0b0110 => (GlobalItem::Unit(value).into(), 1 + real_size),
|
||||
0b0111 => (GlobalItem::ReportSize(value).into(), 1 + real_size),
|
||||
0b1000 => (GlobalItem::ReportId(value).into(), 1 + real_size),
|
||||
0b1001 => (GlobalItem::ReportCount(value).into(), 1 + real_size),
|
||||
0b1010 => (GlobalItem::Push.into(), 1),
|
||||
0b1011 => (GlobalItem::Pop.into(), 1),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
(tag, 0b10) => {
|
||||
let real_size = Self::size(size) as usize;
|
||||
let mut value_bytes = [0u8; 4];
|
||||
if real_size > 0 {
|
||||
value_bytes[..real_size].copy_from_slice(&bytes[..real_size])
|
||||
};
|
||||
let value = u32::from_le_bytes(value_bytes);
|
||||
match tag {
|
||||
0b0000 => (LocalItem::Usage(value).into(), 1 + real_size),
|
||||
0b0001 => (LocalItem::UsageMinimum(value).into(), 1 + real_size),
|
||||
0b0010 => (LocalItem::UsageMaximum(value).into(), 1 + real_size),
|
||||
0b0011 => (LocalItem::DesignatorIndex(value).into(), 1 + real_size),
|
||||
0b0100 => (LocalItem::DesignatorMinimum(value).into(), 1 + real_size),
|
||||
0b0101 => (LocalItem::DesignatorMaximum(value).into(), 1 + real_size),
|
||||
0b0111 => (LocalItem::StringIndex(value).into(), 1 + real_size),
|
||||
0b1000 => (LocalItem::StringMinimum(value).into(), 1 + real_size),
|
||||
0b1001 => (LocalItem::StringMaximum(value).into(), 1 + real_size),
|
||||
0b1010 => (LocalItem::Delimeter(value).into(), 1 + real_size),
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
(_, 0b11) => panic!("Calling parse_short but with long item"),
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
pub fn parse_long(size: u8, long_tag: u8, bytes: &[u8]) -> (Self, usize) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReportFlatIter<'a> {
|
||||
desc: &'a [u8],
|
||||
offset: usize,
|
||||
}
|
||||
impl<'a> ReportFlatIter<'a> {
|
||||
pub fn new(desc: &'a [u8]) -> Self {
|
||||
Self { desc, offset: 0 }
|
||||
}
|
||||
}
|
||||
impl<'a> Iterator for ReportFlatIter<'a> {
|
||||
type Item = ReportItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.offset >= self.desc.len() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let first = self.desc[self.offset];
|
||||
let size = first & 0b11;
|
||||
let ty = (first & 0b1100) >> 2;
|
||||
let tag = (first & 0b11110000) >> 4;
|
||||
|
||||
if size == 0b10 && ty == 3 && tag == 0b1111 {
|
||||
// Long Item
|
||||
let size = self.desc[self.offset + 1];
|
||||
let long_tag = self.desc[self.offset + 2];
|
||||
let data = &self.desc[self.offset + 2..self.offset + 2 + size as usize];
|
||||
|
||||
let (item, len) = ReportItem::parse_long(size, long_tag, data);
|
||||
self.offset += len;
|
||||
Some(item)
|
||||
} else {
|
||||
// Short Item
|
||||
|
||||
// Although there is a 2-bit size field, the size doesn't have to be the actual size of the data.
|
||||
let data = &self.desc[self.offset + 1..];
|
||||
|
||||
let (item, len) =
|
||||
ReportItem::parse_short(u2::new(size), u2::new(ty), u4::new(tag), data)?;
|
||||
self.offset += len;
|
||||
Some(item)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReportIter<'a> {
|
||||
flat: ReportFlatIter<'a>,
|
||||
error: bool,
|
||||
// this is just for reusing the vec
|
||||
// TODO: When GATs are available, this could be done simply using iterators. Every collection
|
||||
// yields a child iterator, which returns the mutable reference to the flat iter to its parent
|
||||
// when dropped.
|
||||
open_collections: Vec<(u8, Vec<ReportIterItem>)>,
|
||||
}
|
||||
#[derive(Debug)]
|
||||
pub enum ReportIterItem {
|
||||
// collection and end of collection tags will never be found here
|
||||
Item(ReportItem),
|
||||
Collection(u8, Vec<ReportIterItem>),
|
||||
}
|
||||
impl ReportIterItem {
|
||||
pub fn as_item(&self) -> Option<&ReportItem> {
|
||||
match self {
|
||||
Self::Item(i) => Some(i),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn as_collection(&self) -> Option<(u8, &[ReportIterItem])> {
|
||||
match self {
|
||||
&Self::Collection(n, ref c) => Some((n, c)),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> ReportIter<'a> {
|
||||
pub fn new(flat: ReportFlatIter<'a>) -> Self {
|
||||
Self {
|
||||
flat,
|
||||
error: false,
|
||||
open_collections: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a> Iterator for ReportIter<'a> {
|
||||
type Item = ReportIterItem;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.error {
|
||||
return None;
|
||||
}
|
||||
|
||||
self.open_collections.clear();
|
||||
|
||||
loop {
|
||||
let item = self.flat.next()?;
|
||||
|
||||
match item {
|
||||
ReportItem::Main(MainItem::Collection(m)) => {
|
||||
self.open_collections.push((m, Vec::new()));
|
||||
}
|
||||
ReportItem::Main(MainItem::EndOfCollection) => {
|
||||
let (value, finished_collection) = match self.open_collections.pop() {
|
||||
Some(finished) => finished,
|
||||
None => {
|
||||
self.error = true;
|
||||
return None;
|
||||
}
|
||||
};
|
||||
if let Some((_, ref mut last)) = self.open_collections.last_mut() {
|
||||
last.push(ReportIterItem::Collection(value, finished_collection));
|
||||
} else {
|
||||
return Some(ReportIterItem::Collection(value, finished_collection));
|
||||
}
|
||||
}
|
||||
other if self.open_collections.is_empty() => {
|
||||
return Some(ReportIterItem::Item(other))
|
||||
}
|
||||
other => self
|
||||
.open_collections
|
||||
.last_mut()
|
||||
.unwrap()
|
||||
.1
|
||||
.push(ReportIterItem::Item(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-8
@@ -1,5 +1,6 @@
|
||||
use std::slice;
|
||||
|
||||
use rehid::report_desc::ReportTy;
|
||||
use xhcid_interface::{
|
||||
DeviceReqData, PortReqRecipient, PortReqTy, XhciClientHandle, XhciClientHandleError,
|
||||
};
|
||||
@@ -11,14 +12,6 @@ const SET_IDLE_REQ: u8 = 0xA;
|
||||
const GET_PROTOCOL_REQ: u8 = 0x3;
|
||||
const SET_PROTOCOL_REQ: u8 = 0xB;
|
||||
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum ReportTy {
|
||||
Input = 1,
|
||||
Output,
|
||||
Feature,
|
||||
}
|
||||
|
||||
fn concat(hi: u8, lo: u8) -> u16 {
|
||||
(u16::from(hi) << 8) | u16::from(lo)
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
// See https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum UsagePage {
|
||||
GenericDesktop = 1,
|
||||
SimulationsControl,
|
||||
VrControls,
|
||||
SportControls,
|
||||
GameControls,
|
||||
GenericDeviceControls,
|
||||
KeyboardOrKeypad,
|
||||
Led,
|
||||
Button,
|
||||
Ordinal,
|
||||
TelephonyDevice,
|
||||
Consumer,
|
||||
Digitizer,
|
||||
Unicode = 0x10,
|
||||
AlphanumericDisplay = 0x14,
|
||||
MedicalInstrument = 0x40,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum GenericDesktopUsage {
|
||||
Pointer = 0x01,
|
||||
Mouse,
|
||||
Joystick = 0x04,
|
||||
GamePad,
|
||||
Keyboard,
|
||||
Keypad,
|
||||
MultiAxisController,
|
||||
|
||||
// 0x0A-0x2F are reserved
|
||||
|
||||
CountedBuffer = 0x3A,
|
||||
SysControl = 0x80,
|
||||
}
|
||||
|
||||
#[repr(u8)]
|
||||
pub enum KeyboardOrKeypadUsage {
|
||||
KbdErrorRollover = 0x1,
|
||||
KbdPostFail,
|
||||
KbdErrorUndefined,
|
||||
// the rest are used as regular keycodes
|
||||
}
|
||||
Reference in New Issue
Block a user