usbhidd: use rehid ReportHandler

This commit is contained in:
Jeremy Soller
2024-04-12 09:27:36 -06:00
parent 571bd9cf3e
commit c99cd3a843
4 changed files with 176 additions and 303 deletions
Generated
+2 -1
View File
@@ -1140,9 +1140,10 @@ checksum = "20145670ba436b55d91fc92d25e71160fbfbdd57831631c8d7d36377a476f1cb"
[[package]]
name = "rehid"
version = "0.1.0"
source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#9bf6c9ef7cc4f95932fcaabfa3141a24bfd39bbf"
source = "git+https://gitlab.redox-os.org/redox-os/rehid.git#d3c74a8abbdb75d93260883e3378c46b3e875fa9"
dependencies = [
"bitflags 2.5.0",
"log",
"ux",
]
+5 -5
View File
@@ -57,7 +57,7 @@ pub mod us {
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
[' ', ' '],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
@@ -236,7 +236,7 @@ pub mod dvorak {
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
[' ', ' '],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
@@ -311,7 +311,7 @@ pub mod azerty {
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
[' ', ' '],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
@@ -386,7 +386,7 @@ pub mod bepo {
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
[' ', ' '],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
@@ -461,7 +461,7 @@ pub mod it {
['\0', '\0'],
['\0', '\0'],
['\0', '\0'],
[' ', ' ']
[' ', ' '],
];
pub fn get_char(scancode: u8, shift: bool) -> char {
+168 -293
View File
@@ -2,52 +2,51 @@ use std::collections::VecDeque;
use std::env;
use std::fs::File;
use std::io::Write;
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 rehid::{
report_desc::{self, ReportTy, REPORT_DESC_TY},
report_handler::ReportHandler,
usage_tables::{GenericDesktopUsage, UsagePage},
};
use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle};
mod keymap;
mod reqs;
use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY};
fn div_round_up(num: u32, denom: u32) -> u32 {
if num % denom == 0 { num / denom } else { num / denom + 1 }
}
fn setup_logging() -> Option<&'static RedoxLogger> {
let mut logger = RedoxLogger::new()
.with_output(
OutputBuilder::stderr()
.with_filter(log::LevelFilter::Info) // limit global output to important info
.with_ansi_escape_codes()
.flush_on_newline(true)
.build()
);
let mut logger = RedoxLogger::new().with_output(
OutputBuilder::stderr()
.with_filter(log::LevelFilter::Info) // limit global output to important info
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
);
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.log") {
Ok(b) => logger = logger.with_output(
// TODO: Add a configuration file for this
b.with_filter(log::LevelFilter::Info)
.flush_on_newline(true)
.build()
),
Ok(b) => {
logger = logger.with_output(
// TODO: Add a configuration file for this
b.with_filter(log::LevelFilter::Info)
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("Failed to create hid.log: {}", error),
}
#[cfg(target_os = "redox")]
match OutputBuilder::in_redox_logging_scheme("usb", "device", "hid.ansi.log") {
Ok(b) => logger = logger.with_output(
b.with_filter(log::LevelFilter::Info)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build()
),
Ok(b) => {
logger = logger.with_output(
b.with_filter(log::LevelFilter::Info)
.with_ansi_escape_codes()
.flush_on_newline(true)
.build(),
)
}
Err(error) => eprintln!("Failed to create hid.ansi.log: {}", error),
}
@@ -63,7 +62,13 @@ fn setup_logging() -> Option<&'static RedoxLogger> {
}
}
fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool, shift_opt: Option<bool>) {
fn send_key_event(
display: &mut File,
usage_page: u32,
usage: u32,
pressed: bool,
shift_opt: Option<bool>,
) {
let scancode = match usage_page {
0x07 => match usage {
0x04 => orbclient::K_A,
@@ -170,7 +175,7 @@ fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool,
0xE0 => orbclient::K_CTRL, // TODO: left control
0xE1 => orbclient::K_LEFT_SHIFT,
0xE2 => orbclient::K_ALT,
0xE3 => 0x5B, // left super
0xE3 => 0x5B, // left super
0xE4 => orbclient::K_CTRL, // TODO: right control
0xE5 => orbclient::K_RIGHT_SHIFT,
0xE6 => orbclient::K_ALT_GR,
@@ -179,12 +184,12 @@ fn send_key_event(display: &mut File, usage_page: u32, usage: u8, pressed: bool,
_ => {
log::warn!("unknown usage_page {:#x} usage {:#x}", usage_page, usage);
return;
},
}
},
_ => {
log::warn!("unknown usage_page {:#x}", usage_page);
return;
},
}
};
//TODO: other keymaps
@@ -225,7 +230,9 @@ fn main() {
log::info!(
"USB HID driver spawned with scheme `{}`, port {}, protocol {}",
scheme, port, protocol
scheme,
port,
protocol
);
let handle = XhciClientHandle::new(scheme, port);
@@ -251,292 +258,160 @@ fn main() {
)
.expect("Failed to retrieve report descriptor");
let report_desc = ReportIter::new(ReportFlatIter::new(&report_desc_bytes)).collect::<Vec<_>>();
let mut handler =
ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor");
for item in &report_desc {
log::debug!("{:?}", item);
}
handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0, interface_desc: None, alternate_setting: None }).expect("Failed to configure endpoints");
let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new());
let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| {
log::trace!("1: {:?}", item);
match item {
&ReportIterItem::Item(ref item) => {
report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap();
report_desc::update_local_state(&mut local_state, item);
None
}
&ReportIterItem::Collection(n, ref collection) => {
let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default());
Some((n, collection, global_state, lc_state))
}
}
}).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection");
handle
.configure_endpoints(&ConfigureEndpointsReq {
config_desc: 0,
interface_desc: None,
alternate_setting: None,
})
.expect("Failed to configure endpoints");
// Get all main items, and their global item options.
{
let mut collections = VecDeque::new();
collections.push_back(application_collection);
let mut items = Vec::new();
while let Some(collection) = collections.pop_front() {
for item in collection {
log::trace!("2: {:?}", item);
match item {
ReportIterItem::Item(item) => match item {
ReportItem::Global(_) => {
report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap();
}
ReportItem::Main(m) => {
let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default());
items.push((global_state, lc_state, m));
}
ReportItem::Local(_) => {
report_desc::update_local_state(&mut local_state, item);
},
},
//TODO: does local state need to be different for inner collections?
ReportIterItem::Collection(_, collection) => {
collections.push_back(collection);
},
}
}
}
let mut bit_offset = 0;
let inputs = items.iter().filter_map(|(global_state, local_state, item)| {
log::trace!("3: {:?}", item);
if let &MainItem::Input(flags) = item {
let report_size = match global_state.report_size {
Some(s) => s,
None => return None,
};
let report_count = match global_state.report_count {
Some(c) => c,
None => return None,
};
let bit_length = report_size * report_count;
let offset = bit_offset;
bit_offset += bit_length;
Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(*flags)))
} else {
None
}
}).collect::<Vec<_>>();
let total_bit_length = inputs.iter().map(|(bit_length, _, _, _, _)| bit_length).sum();
let total_byte_length = div_round_up(total_bit_length, 8);
let mut report_buffer = vec! [0u8; total_byte_length as usize];
let mut last_buffer = report_buffer.clone();
let mut report_buffer = vec![0u8; handler.total_byte_length];
let report_ty = ReportTy::Input;
let report_id = 0;
let mut display = File::open("input:producer").expect("Failed to open orbital input socket");
let mut pressed_keys = Vec::<(u32, u8)>::new();
let mut last_pressed_keys = pressed_keys.clone();
let mut last_buttons = (false, false, false);
let mut display =
File::open("input:producer").expect("Failed to open orbital input socket");
let mut left_shift = false;
let mut right_shift = false;
let mut last_mouse_pos = (0, 0);
let mut last_buttons = [false, false, false];
loop {
//TODO: get frequency from device
std::thread::sleep(std::time::Duration::from_millis(10));
std::mem::swap(&mut report_buffer, &mut last_buffer);
reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report");
reqs::get_report(
&handle,
report_ty,
report_id,
interface_num,
&mut report_buffer,
)
.expect("Failed to get report");
if report_buffer == last_buffer {
continue
}
for &(bit_length, bit_offset, global_state, local_state, input) in &inputs {
let report_size = global_state.report_size.unwrap();
let report_count = global_state.report_count.unwrap();
log::trace!(
"size {} count {} offset {} length {} usage page {:?}",
report_size,
report_count,
bit_offset,
bit_length,
global_state.usage_page
);
// TODO: For now, the dynamic value usages cannot overlap with selector usages...
// for now.
if local_state.usage_min == Some(224) && local_state.usage_max == Some(231) {
// The usages that this descriptor references are all dynamic values.
} else {
// The usages are selectors.
}
if input.contains(MainItemFlags::VARIABLE) {
// The item is a variable.
let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize);
if report_count == 8 && report_size == 1 && global_state.usage_page == Some(7) && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) {
let bits = binary_view.read_u8(0).expect("Failed to read array item");
for bit in 0..8 {
if bits & (1 << bit) > 0 {
pressed_keys.push((0x07, 0xE0 + bit));
}
let mut mouse_pos = last_mouse_pos;
let mut mouse_dx = 0i32;
let mut mouse_dy = 0i32;
let mut buttons = last_buttons;
for event in handler
.handle(&report_buffer)
.expect("failed to parse report")
{
log::debug!("{:X?}", event);
if event.usage_page == UsagePage::GenericDesktop as u32 {
if event.usage == GenericDesktopUsage::X as u32 {
if event.relative {
mouse_dx += event.value;
} else {
mouse_pos.0 = event.value;
}
log::trace!("Report variable {:#x?}", bits);
} else if report_count == 2 && report_size == 16 && global_state.usage_page == Some(1) {
//TODO: Make this less hard-coded
let raw_x =
binary_view.read_u8(0).expect("Failed to read array item") as u16 |
(binary_view.read_u8(8).expect("Failed to read array item") as u16) << 8;
let raw_y =
binary_view.read_u8(16).expect("Failed to read array item") as u16 |
(binary_view.read_u8(24).expect("Failed to read array item") as u16) << 8;
// ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital
// expects the former range, so multiply by two here to translate
// the usb coordinates to what orbital expects.
let x = raw_x * 2;
let y = raw_y * 2;
log::trace!("Touchscreen {}, {} => {}, {}", raw_x, raw_y, x, y);
if x != 0 || y != 0 {
let mouse_event = orbclient::event::MouseEvent {
x: x as i32,
y: y as i32,
};
match display.write(&mouse_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send mouse event to orbital: {}", err);
}
}
}
} else if report_count == 3 && report_size == 8 && global_state.usage_page == Some(1) {
//TODO: Make this less hard-coded
let dx = binary_view.read_u8(0).expect("Failed to read array item") as i8;
let dy = binary_view.read_u8(8).expect("Failed to read array item") as i8;
let dz = binary_view.read_u8(16).expect("Failed to read array item") as i8;
log::trace!("Mouse {}, {}, {}", dx, dy, dz);
if dx != 0 || dy != 0 {
let mouse_event = orbclient::event::MouseRelativeEvent {
dx: dx as i32,
dy: dy as i32,
};
match display.write(&mouse_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send mouse event to orbital: {}", err);
}
}
}
if dz != 0 {
let scroll_event = orbclient::event::ScrollEvent {
x: dz as i32,
y: 0,
};
match display.write(&scroll_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send scroll event to orbital: {}", err);
}
}
}
} else if report_count == 3 && report_size == 1 && global_state.usage_page == Some(9) {
//TODO: Make this less hard-coded
let left = binary_view.get(0).expect("Failed to read array item");
let right = binary_view.get(1).expect("Failed to read array item");
let middle = binary_view.get(2).expect("Failed to read array item");
log::trace!("Left {}, Right {}, Middle {}", left, right, middle);
if last_buttons != (left, right, middle) {
last_buttons = (left, right, middle);
let button_event = orbclient::event::ButtonEvent {
left,
right,
middle,
};
match display.write(&button_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send button event to orbital: {}", err);
}
}
} else if event.usage == GenericDesktopUsage::Y as u32 {
if event.relative {
mouse_dy += event.value;
} else {
mouse_pos.1 = event.value;
}
} else {
log::trace!("Unknown report variable item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page);
log::info!(
"unsupported generic desktop usage 0x{:X}:0x{:X} value {}",
event.usage_page,
event.usage,
event.value
);
}
} else if event.usage_page == UsagePage::KeyboardOrKeypad as u32 {
let (pressed, shift_opt) = if event.value != 0 {
(true, Some(left_shift | right_shift))
} else {
(false, None)
};
if event.usage == 0xE1 {
left_shift = pressed;
} else if event.usage == 0xE5 {
right_shift = pressed;
}
send_key_event(
&mut display,
event.usage_page,
event.usage,
pressed,
shift_opt,
);
} else if event.usage_page == UsagePage::Button as u32 {
if event.usage > 0 && event.usage as usize <= buttons.len() {
buttons[event.usage as usize - 1] = event.value != 0;
} else {
log::info!(
"unsupported buttons usage 0x{:X}:0x{:X} value {}",
event.usage_page,
event.usage,
event.value
);
}
} else {
// The item is an array.
log::info!(
"unsupported usage 0x{:X}:0x{:X} value {}",
event.usage_page,
event.usage,
event.value
);
}
}
log::trace!("INPUT FLAGS: {:?}", input);
if report_size == 8 {
for report_index in 0..report_count as usize {
let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize);
let usage = binary_view.read_u8(0).expect("Failed to read array item");
if usage != 0 {
pressed_keys.push((global_state.usage_page.unwrap_or(0), usage));
}
log::trace!("Report index array {}: {:#x}", report_index, usage);
}
} else {
log::trace!("Unknown report array item: size {} count {} offset {} usage page {:?}", report_size, report_count, bit_offset, global_state.usage_page);
if mouse_pos != last_mouse_pos {
last_mouse_pos = mouse_pos;
// ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital
// expects the former range, so multiply by two here to translate
// the usb coordinates to what orbital expects.
let mouse_event = orbclient::event::MouseEvent {
x: mouse_pos.0 * 2,
y: mouse_pos.1 * 2,
};
match display.write(&mouse_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send mouse event to orbital: {}", err);
}
}
}
if mouse_dx != 0 || mouse_dy != 0 {
let mouse_event = orbclient::event::MouseRelativeEvent {
dx: mouse_dx,
dy: mouse_dy,
};
for &(usage_page, usage) in last_pressed_keys.iter() {
if ! pressed_keys.contains(&(usage_page, usage)) {
log::debug!("Released {:#x},{:#x}", usage_page, usage);
send_key_event(&mut display, usage_page, usage, false, None);
match display.write(&mouse_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send mouse event to orbital: {}", err);
}
}
}
for &(usage_page, usage) in pressed_keys.iter() {
if ! last_pressed_keys.contains(&(usage_page, usage)) {
log::debug!("Pressed {:#x},{:#x}", usage_page, usage);
send_key_event(&mut display, usage_page, usage, true, Some(
pressed_keys.contains(&(0x07, 0xE1)) || pressed_keys.contains(&(0x07, 0xE5))
));
if buttons != last_buttons {
last_buttons = buttons;
let button_event = orbclient::event::ButtonEvent {
left: buttons[0],
right: buttons[1],
middle: buttons[2],
};
match display.write(&button_event.to_event()) {
Ok(_) => (),
Err(err) => {
log::warn!("failed to send button event to orbital: {}", err);
}
}
}
std::mem::swap(&mut pressed_keys, &mut last_pressed_keys);
pressed_keys.clear();
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn binary_view() {
// 0000 1000 1100 0111
// E S
let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11);
assert_eq!(view.get(0), Some(false));
assert_eq!(view.get(2), Some(false));
assert_eq!(view.get(3), Some(true));
assert_eq!(view.get(7), Some(false));
assert_eq!(view.get(17), None);
assert_eq!(view.read_u8(0), Some(0b0001_1000));
assert_eq!(view.read_u8(1), Some(0b1000_1100));
assert_eq!(view.read_u8(2), Some(0b0100_0110));
assert_eq!(view.read_u8(3), Some(0b0010_0011));
assert_eq!(view.read_u8(7), None);
// 0000 1000 1100 0111
// E S
let view = super::BinaryView::new(&[0xC7, 0x08], 8, 8);
assert_eq!(view.read_u8(0), Some(0b0000_1000));
}
}
+1 -4
View File
@@ -80,10 +80,7 @@ pub fn set_idle(
DeviceReqData::NoData,
)
}
pub fn get_protocol(
handle: &XhciClientHandle,
if_num: u16,
) -> Result<u8, XhciClientHandleError> {
pub fn get_protocol(handle: &XhciClientHandle, if_num: u16) -> Result<u8, XhciClientHandleError> {
let mut protocol = 0;
let buffer = slice::from_mut(&mut protocol);
handle.device_request(