Files
RedBear-OS/local/patches/base/P3-usbhidd-hardening.patch
T
vasilito aca2f2913d feat: atomic patch application, colored init output, XKB bridge, USB HID hardening
Build system (src/cook/fetch.rs):
- Atomic patch application: applies patches to staging directory (cp -al),
  atomically swaps on success, discards on failure — source tree is never
  left in a partially-patched state
- normalize_patch(): strips diff --git/index/new-file-mode headers that the
  build system's patch command does not recognize
- cleanup_workspace_pollution(): removes orphaned recipes/Cargo.toml and
  recipes/Cargo.lock to prevent workspace conflicts
- Added --allow-protected CLI flag to repo binary

Input stack (local/patches/base/P3-*.patch):
- P3-ps2d-led-feedback: PS/2 LED state handling + InputProducer migration
- P3-inputd-keymap-bridge: InputProducer enum, keymap bridge query
- P3-usbhidd-hardening: HID descriptor validation, static lookup table,
  8-button mouse support, transfer retry with exponential backoff
- P3-init-colored-output: ANSI-color coded init daemon output (green OK,
  red FAILED, yellow SKIP/WARN)

XKB bridge (local/recipes/system/redbear-keymapd/source/src/xkb.rs):
- Parses X11 xkb/symbols/* format, maps XKB keycodes to PS/2 scancodes,
  80+ X11 keysym names to Unicode, 4-level key support

Patch governance (local/patches/base/absorbed/README.md):
- Documents consolidation of P0-P3 patches into redox.patch
2026-05-03 08:21:54 +01:00

726 lines
28 KiB
Diff
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
diff --git a/drivers/input/usbhidd/src/main.rs b/drivers/input/usbhidd/src/main.rs
index 15c5b778..472ec4cf 100644
--- a/drivers/input/usbhidd/src/main.rs
+++ b/drivers/input/usbhidd/src/main.rs
@@ -1,7 +1,7 @@
-use anyhow::{Context, Result};
+use anyhow::{bail, ensure, Context, Result};
use std::{env, thread, time};
-use inputd::ProducerHandle;
+use inputd::InputProducer;
use orbclient::KeyEvent as OrbKeyEvent;
use rehid::{
report_desc::{ReportTy, REPORT_DESC_TY},
@@ -15,161 +15,219 @@ use xhcid_interface::{
mod reqs;
-fn send_key_event(display: &mut ProducerHandle, usage_page: u16, usage: u16, pressed: bool) {
- let scancode = match usage_page {
- 0x07 => match usage {
- 0x04 => orbclient::K_A,
- 0x05 => orbclient::K_B,
- 0x06 => orbclient::K_C,
- 0x07 => orbclient::K_D,
- 0x08 => orbclient::K_E,
- 0x09 => orbclient::K_F,
- 0x0A => orbclient::K_G,
- 0x0B => orbclient::K_H,
- 0x0C => orbclient::K_I,
- 0x0D => orbclient::K_J,
- 0x0E => orbclient::K_K,
- 0x0F => orbclient::K_L,
- 0x10 => orbclient::K_M,
- 0x11 => orbclient::K_N,
- 0x12 => orbclient::K_O,
- 0x13 => orbclient::K_P,
- 0x14 => orbclient::K_Q,
- 0x15 => orbclient::K_R,
- 0x16 => orbclient::K_S,
- 0x17 => orbclient::K_T,
- 0x18 => orbclient::K_U,
- 0x19 => orbclient::K_V,
- 0x1A => orbclient::K_W,
- 0x1B => orbclient::K_X,
- 0x1C => orbclient::K_Y,
- 0x1D => orbclient::K_Z,
- 0x1E => orbclient::K_1,
- 0x1F => orbclient::K_2,
- 0x20 => orbclient::K_3,
- 0x21 => orbclient::K_4,
- 0x22 => orbclient::K_5,
- 0x23 => orbclient::K_6,
- 0x24 => orbclient::K_7,
- 0x25 => orbclient::K_8,
- 0x26 => orbclient::K_9,
- 0x27 => orbclient::K_0,
- 0x28 => orbclient::K_ENTER,
- 0x29 => orbclient::K_ESC,
- 0x2A => orbclient::K_BKSP,
- 0x2B => orbclient::K_TAB,
- 0x2C => orbclient::K_SPACE,
- 0x2D => orbclient::K_MINUS,
- 0x2E => orbclient::K_EQUALS,
- 0x2F => orbclient::K_BRACE_OPEN,
- 0x30 => orbclient::K_BRACE_CLOSE,
- 0x31 => orbclient::K_BACKSLASH,
- // 0x32 non-us # and ~
- 0x32 => 0x56,
- 0x33 => orbclient::K_SEMICOLON,
- 0x34 => orbclient::K_QUOTE,
- 0x35 => orbclient::K_TICK,
- 0x36 => orbclient::K_COMMA,
- 0x37 => orbclient::K_PERIOD,
- 0x38 => orbclient::K_SLASH,
- 0x39 => orbclient::K_CAPS,
- 0x3A => orbclient::K_F1,
- 0x3B => orbclient::K_F2,
- 0x3C => orbclient::K_F3,
- 0x3D => orbclient::K_F4,
- 0x3E => orbclient::K_F5,
- 0x3F => orbclient::K_F6,
- 0x40 => orbclient::K_F7,
- 0x41 => orbclient::K_F8,
- 0x42 => orbclient::K_F9,
- 0x43 => orbclient::K_F10,
- 0x44 => orbclient::K_F11,
- 0x45 => orbclient::K_F12,
- 0x46 => orbclient::K_PRTSC,
- 0x47 => orbclient::K_SCROLL,
- // 0x48 pause
- 0x49 => orbclient::K_INS,
- 0x4A => orbclient::K_HOME,
- 0x4B => orbclient::K_PGUP,
- 0x4C => orbclient::K_DEL,
- 0x4D => orbclient::K_END,
- 0x4E => orbclient::K_PGDN,
- 0x4F => orbclient::K_RIGHT,
- 0x50 => orbclient::K_LEFT,
- 0x51 => orbclient::K_DOWN,
- 0x52 => orbclient::K_UP,
- 0x53 => orbclient::K_NUM,
- 0x54 => orbclient::K_NUM_SLASH,
- 0x55 => orbclient::K_NUM_ASTERISK,
- 0x56 => orbclient::K_NUM_MINUS,
- 0x57 => orbclient::K_NUM_PLUS,
- 0x58 => orbclient::K_NUM_ENTER,
- 0x59 => orbclient::K_NUM_1,
- 0x5A => orbclient::K_NUM_2,
- 0x5B => orbclient::K_NUM_3,
- 0x5C => orbclient::K_NUM_4,
- 0x5D => orbclient::K_NUM_5,
- 0x5E => orbclient::K_NUM_6,
- 0x5F => orbclient::K_NUM_7,
- 0x60 => orbclient::K_NUM_8,
- 0x61 => orbclient::K_NUM_9,
- 0x62 => orbclient::K_NUM_0,
- // 0x62 num .
- // 0x64 non-us \ and |
- 0x64 => orbclient::K_APP,
- 0x66 => orbclient::K_POWER,
- // 0x67 num =
- // unmapped values
- 0xE0 => orbclient::K_LEFT_CTRL,
- 0xE1 => orbclient::K_LEFT_SHIFT,
- 0xE2 => orbclient::K_ALT,
- 0xE3 => orbclient::K_LEFT_SUPER,
- 0xE4 => orbclient::K_RIGHT_CTRL,
- 0xE5 => orbclient::K_RIGHT_SHIFT,
- 0xE6 => orbclient::K_ALT_GR,
- 0xE7 => orbclient::K_RIGHT_SUPER,
- // reserved values
- _ => {
- log::warn!("unknown usage_page {:#x} usage {:#x}", usage_page, usage);
- return;
- }
- },
- _ => {
- log::warn!("unknown usage_page {:#x}", usage_page);
+const MAX_MOUSE_BUTTONS: usize = 8;
+const MAX_RETRIES: u32 = 3;
+const RETRY_BASE_DELAY_MS: u64 = 2;
+const REPORT_DESC_MAX_SIZE: usize = 4096;
+const REPORT_DESC_MIN_SIZE: usize = 3;
+
+/// USB HID Usage (Keyboard page 0x07) → orbclient scancode lookup table.
+/// Covers usage codes 0x040xE7 per USB HID Usage Tables spec v1.12.
+/// Entries default to 0 (unmapped); only defined usages are populated.
+static HID_KEYBOARD_TO_SCANCODE: [u8; 0xE8] = {
+ let mut table = [0u8; 0xE8];
+ table[0x04] = orbclient::K_A;
+ table[0x05] = orbclient::K_B;
+ table[0x06] = orbclient::K_C;
+ table[0x07] = orbclient::K_D;
+ table[0x08] = orbclient::K_E;
+ table[0x09] = orbclient::K_F;
+ table[0x0A] = orbclient::K_G;
+ table[0x0B] = orbclient::K_H;
+ table[0x0C] = orbclient::K_I;
+ table[0x0D] = orbclient::K_J;
+ table[0x0E] = orbclient::K_K;
+ table[0x0F] = orbclient::K_L;
+ table[0x10] = orbclient::K_M;
+ table[0x11] = orbclient::K_N;
+ table[0x12] = orbclient::K_O;
+ table[0x13] = orbclient::K_P;
+ table[0x14] = orbclient::K_Q;
+ table[0x15] = orbclient::K_R;
+ table[0x16] = orbclient::K_S;
+ table[0x17] = orbclient::K_T;
+ table[0x18] = orbclient::K_U;
+ table[0x19] = orbclient::K_V;
+ table[0x1A] = orbclient::K_W;
+ table[0x1B] = orbclient::K_X;
+ table[0x1C] = orbclient::K_Y;
+ table[0x1D] = orbclient::K_Z;
+ table[0x1E] = orbclient::K_1;
+ table[0x1F] = orbclient::K_2;
+ table[0x20] = orbclient::K_3;
+ table[0x21] = orbclient::K_4;
+ table[0x22] = orbclient::K_5;
+ table[0x23] = orbclient::K_6;
+ table[0x24] = orbclient::K_7;
+ table[0x25] = orbclient::K_8;
+ table[0x26] = orbclient::K_9;
+ table[0x27] = orbclient::K_0;
+ table[0x28] = orbclient::K_ENTER;
+ table[0x29] = orbclient::K_ESC;
+ table[0x2A] = orbclient::K_BKSP;
+ table[0x2B] = orbclient::K_TAB;
+ table[0x2C] = orbclient::K_SPACE;
+ table[0x2D] = orbclient::K_MINUS;
+ table[0x2E] = orbclient::K_EQUALS;
+ table[0x2F] = orbclient::K_BRACE_OPEN;
+ table[0x30] = orbclient::K_BRACE_CLOSE;
+ table[0x31] = orbclient::K_BACKSLASH;
+ table[0x32] = 0x56;
+ table[0x33] = orbclient::K_SEMICOLON;
+ table[0x34] = orbclient::K_QUOTE;
+ table[0x35] = orbclient::K_TICK;
+ table[0x36] = orbclient::K_COMMA;
+ table[0x37] = orbclient::K_PERIOD;
+ table[0x38] = orbclient::K_SLASH;
+ table[0x39] = orbclient::K_CAPS;
+ table[0x3A] = orbclient::K_F1;
+ table[0x3B] = orbclient::K_F2;
+ table[0x3C] = orbclient::K_F3;
+ table[0x3D] = orbclient::K_F4;
+ table[0x3E] = orbclient::K_F5;
+ table[0x3F] = orbclient::K_F6;
+ table[0x40] = orbclient::K_F7;
+ table[0x41] = orbclient::K_F8;
+ table[0x42] = orbclient::K_F9;
+ table[0x43] = orbclient::K_F10;
+ table[0x44] = orbclient::K_F11;
+ table[0x45] = orbclient::K_F12;
+ table[0x46] = orbclient::K_PRTSC;
+ table[0x47] = orbclient::K_SCROLL;
+ table[0x49] = orbclient::K_INS;
+ table[0x4A] = orbclient::K_HOME;
+ table[0x4B] = orbclient::K_PGUP;
+ table[0x4C] = orbclient::K_DEL;
+ table[0x4D] = orbclient::K_END;
+ table[0x4E] = orbclient::K_PGDN;
+ table[0x4F] = orbclient::K_RIGHT;
+ table[0x50] = orbclient::K_LEFT;
+ table[0x51] = orbclient::K_DOWN;
+ table[0x52] = orbclient::K_UP;
+ table[0x53] = orbclient::K_NUM;
+ table[0x54] = orbclient::K_NUM_SLASH;
+ table[0x55] = orbclient::K_NUM_ASTERISK;
+ table[0x56] = orbclient::K_NUM_MINUS;
+ table[0x57] = orbclient::K_NUM_PLUS;
+ table[0x58] = orbclient::K_NUM_ENTER;
+ table[0x59] = orbclient::K_NUM_1;
+ table[0x5A] = orbclient::K_NUM_2;
+ table[0x5B] = orbclient::K_NUM_3;
+ table[0x5C] = orbclient::K_NUM_4;
+ table[0x5D] = orbclient::K_NUM_5;
+ table[0x5E] = orbclient::K_NUM_6;
+ table[0x5F] = orbclient::K_NUM_7;
+ table[0x60] = orbclient::K_NUM_8;
+ table[0x61] = orbclient::K_NUM_9;
+ table[0x62] = orbclient::K_NUM_0;
+ table[0x64] = orbclient::K_APP;
+ table[0x66] = orbclient::K_POWER;
+ table[0xE0] = orbclient::K_LEFT_CTRL;
+ table[0xE1] = orbclient::K_LEFT_SHIFT;
+ table[0xE2] = orbclient::K_ALT;
+ table[0xE3] = orbclient::K_LEFT_SUPER;
+ table[0xE4] = orbclient::K_RIGHT_CTRL;
+ table[0xE5] = orbclient::K_RIGHT_SHIFT;
+ table[0xE6] = orbclient::K_ALT_GR;
+ table[0xE7] = orbclient::K_RIGHT_SUPER;
+ table
+};
+
+fn hid_usage_to_scancode(usage: u16) -> Option<u8> {
+ let idx = usage as usize;
+ if idx < HID_KEYBOARD_TO_SCANCODE.len() {
+ let sc = HID_KEYBOARD_TO_SCANCODE[idx];
+ if sc != 0 {
+ return Some(sc);
+ }
+ }
+ None
+}
+
+fn send_key_event(display: &mut InputProducer, usage_page: u16, usage: u16, pressed: bool) {
+ if usage_page != 0x07 {
+ log::warn!("send_key_event: unexpected usage_page {:#x}", usage_page);
+ return;
+ }
+ let scancode = match hid_usage_to_scancode(usage) {
+ Some(sc) => sc,
+ None => {
+ log::warn!("unmapped HID keyboard usage {:#x}", usage);
return;
}
};
-
let key_event = OrbKeyEvent {
character: '\0',
scancode,
pressed,
};
+ if let Err(err) = display.write_event(key_event.to_event()) {
+ log::warn!("failed to send key event: {}", err);
+ }
+}
- match display.write_event(key_event.to_event()) {
- Ok(_) => (),
- Err(err) => {
- log::warn!("failed to send key event to orbital: {}", err);
+fn validate_report_descriptor(bytes: &[u8]) -> Result<()> {
+ ensure!(
+ bytes.len() >= REPORT_DESC_MIN_SIZE,
+ "report descriptor too short: {} bytes (minimum {})",
+ bytes.len(),
+ REPORT_DESC_MIN_SIZE
+ );
+ ensure!(
+ bytes.len() <= REPORT_DESC_MAX_SIZE,
+ "report descriptor too large: {} bytes (maximum {})",
+ bytes.len(),
+ REPORT_DESC_MAX_SIZE
+ );
+ let mut depth = 0u32;
+ let mut i = 0;
+ while i < bytes.len() {
+ let b = bytes[i];
+ let size = match b & 0x03 {
+ 0 => 0,
+ 1 => 1,
+ 2 => 2,
+ 3 => 4,
+ _ => unreachable!(),
+ };
+ let item_type = (b >> 2) & 0x03;
+ if item_type == 0x0A {
+ depth += 1;
+ } else if item_type == 0x0C {
+ if depth == 0 {
+ bail!(
+ "unbalanced Collection/EndCollection in report descriptor at offset {}",
+ i
+ );
+ }
+ depth -= 1;
}
+ i += 1 + size as usize;
}
+ ensure!(
+ depth == 0,
+ "unbalanced Collection/EndCollection (depth {} at end)",
+ depth
+ );
+ Ok(())
}
fn main() -> Result<()> {
let mut args = env::args().skip(1);
- const USAGE: &'static str = "usbhidd <scheme> <port> <interface>";
+ const USAGE: &str = "usbhidd <scheme> <port> <interface>";
- let scheme = args.next().expect(USAGE);
- let port = args
+ let scheme = args.next().context(USAGE)?;
+ let port: PortId = args
.next()
- .expect(USAGE)
- .parse::<PortId>()
- .expect("Expected port ID");
- let interface_num = args
+ .context(USAGE)?
+ .parse()
+ .map_err(|e| anyhow::anyhow!("Expected port ID: {}", e))?;
+ let interface_num: u8 = args
.next()
- .expect(USAGE)
- .parse::<u8>()
- .expect("Expected integer as input of interface");
+ .context(USAGE)?
+ .parse()
+ .map_err(|e| anyhow::anyhow!("Expected interface number: {}", e))?;
let name = format!("{}_{}_{}_hid", scheme, port, interface_num);
common::setup_logging(
@@ -218,7 +276,6 @@ fn main() -> Result<()> {
}
});
let hid_desc = if_desc.hid_descs.iter().find_map(|hid_desc| {
- //TODO: should we do any filtering?
Some(hid_desc)
})?;
Some((if_desc.clone(), endp_desc_opt, hid_desc))
@@ -240,31 +297,39 @@ fn main() -> Result<()> {
})
.context("Failed to configure endpoints")?;
- //TODO: do we need to set protocol to report? It fails for mice.
-
- //TODO: dynamically create good values, fix xhcid so it does not block on each request
- // This sets all reports to a duration of 4ms
reqs::set_idle(&handle, 1, 0, interface_num as u16).context("Failed to set idle")?;
- let report_desc_len = hid_desc.desc_len;
- assert_eq!(hid_desc.desc_ty, REPORT_DESC_TY);
+ let report_desc_len = hid_desc.desc_len as usize;
+ ensure!(
+ hid_desc.desc_ty == REPORT_DESC_TY,
+ "unexpected HID descriptor type: expected {}, got {}",
+ REPORT_DESC_TY,
+ hid_desc.desc_ty
+ );
+ ensure!(
+ report_desc_len >= REPORT_DESC_MIN_SIZE && report_desc_len <= REPORT_DESC_MAX_SIZE,
+ "suspicious report descriptor length: {}",
+ report_desc_len
+ );
- let mut report_desc_bytes = vec![0u8; report_desc_len as usize];
+ let mut report_desc_bytes = vec![0u8; report_desc_len];
handle
.get_descriptor(
PortReqRecipient::Interface,
REPORT_DESC_TY,
0,
- //TODO: should this be an index into interface_descs?
interface_num as u16,
&mut report_desc_bytes,
)
.context("Failed to retrieve report descriptor")?;
+ validate_report_descriptor(&report_desc_bytes)
+ .context("HID report descriptor validation failed")?;
+
let mut handler =
- ReportHandler::new(&report_desc_bytes).expect("failed to parse report descriptor");
+ ReportHandler::new(&report_desc_bytes).map_err(|e| anyhow::anyhow!("failed to parse report descriptor: {}", e))?;
- let report_len = match endp_desc_opt {
+ let report_len = match &endp_desc_opt {
Some((_endp_num, endp_desc)) => endp_desc.max_packet_size as usize,
None => handler.total_byte_length as usize,
};
@@ -272,7 +337,9 @@ fn main() -> Result<()> {
let report_ty = ReportTy::Input;
let report_id = 0;
- let mut display = ProducerHandle::new().context("Failed to open input socket")?;
+ let producer_name = format!("usb-{}-if{}", port, interface_num);
+ let mut display = InputProducer::new_named_or_fallback(&producer_name)
+ .context("Failed to open input socket")?;
let mut endpoint_opt = match endp_desc_opt {
Some((endp_num, _endp_desc)) => match handle.open_endpoint(endp_num as u8) {
Ok(ok) => Some(ok),
@@ -286,172 +353,168 @@ fn main() -> Result<()> {
let mut left_shift = false;
let mut right_shift = false;
let mut last_mouse_pos = (0, 0);
- let mut last_buttons = [false, false, false];
+ let mut last_buttons = [false; MAX_MOUSE_BUTTONS];
+ let mut consecutive_errors: u32 = 0;
+
loop {
- //TODO: get frequency from device
- //TODO: use sleeps when accuracy is better: thread::sleep(time::Duration::from_millis(10));
- let timer = time::Instant::now();
- while timer.elapsed() < time::Duration::from_millis(1) {
- thread::yield_now();
- }
+ thread::sleep(time::Duration::from_millis(1));
- if let Some(endpoint) = &mut endpoint_opt {
- // interrupt transfer
- endpoint
- .transfer_read(&mut report_buffer)
- .context("failed to get report")?;
+ let transfer_result: Result<(), anyhow::Error> = if let Some(endpoint) = &mut endpoint_opt {
+ endpoint.transfer_read(&mut report_buffer)
+ .map(|_| ())
+ .context("interrupt transfer failed")
} else {
- // control transfer
- reqs::get_report(
- &handle,
- report_ty,
- report_id,
- //TODO: should this be an index into interface_descs?
- interface_num as u16,
- &mut report_buffer,
- )
- .context("failed to get report")?;
+ reqs::get_report(&handle, report_ty, report_id, interface_num as u16, &mut report_buffer)
+ .map(|_| ())
+ .context("control transfer failed")
+ };
+
+ if let Err(err) = transfer_result {
+ consecutive_errors += 1;
+ if consecutive_errors >= MAX_RETRIES {
+ bail!(
+ "transfer failed {} times consecutively: {}",
+ consecutive_errors,
+ err
+ );
+ }
+ let delay = RETRY_BASE_DELAY_MS * (1 << consecutive_errors.min(4));
+ log::warn!(
+ "transfer failed ({}/{}), retry in {}ms: {}",
+ consecutive_errors,
+ MAX_RETRIES,
+ delay,
+ err
+ );
+ thread::sleep(time::Duration::from_millis(delay));
+ continue;
}
+ consecutive_errors = 0;
let mut mouse_pos = last_mouse_pos;
let mut mouse_dx = 0i32;
let mut mouse_dy = 0i32;
let mut scroll_y = 0i32;
let mut buttons = last_buttons;
- for event in handler
- .handle(&report_buffer)
- .expect("failed to parse report")
- {
- log::debug!("{}", event);
- if event.usage_page == UsagePage::GenericDesktop as u16 {
- if event.usage == GenericDesktopUsage::X as u16 {
- if event.relative {
- mouse_dx += event.value as i32;
- } else {
- mouse_pos.0 = event.value as i32;
- }
- } else if event.usage == GenericDesktopUsage::Y as u16 {
- if event.relative {
- mouse_dy += event.value as i32;
- } else {
- mouse_pos.1 = event.value as i32;
- }
- } else if event.usage == GenericDesktopUsage::Wheel as u16 {
- //TODO: what is X scroll?
- if event.relative {
- scroll_y += event.value as i32;
- } else {
- log::warn!("absolute mouse wheel not supported");
+
+ match handler.handle(&report_buffer) {
+ Ok(events) => {
+ for event in events {
+ log::debug!("{}", event);
+ if event.usage_page == UsagePage::GenericDesktop as u16 {
+ if event.usage == GenericDesktopUsage::X as u16 {
+ if event.relative {
+ mouse_dx += event.value as i32;
+ } else {
+ mouse_pos.0 = event.value as i32;
+ }
+ } else if event.usage == GenericDesktopUsage::Y as u16 {
+ if event.relative {
+ mouse_dy += event.value as i32;
+ } else {
+ mouse_pos.1 = event.value as i32;
+ }
+ } else if event.usage == GenericDesktopUsage::Wheel as u16 {
+ if event.relative {
+ scroll_y += event.value as i32;
+ } else {
+ log::warn!("absolute mouse wheel not supported");
+ }
+ } else if event.usage == GenericDesktopUsage::Z as u16 {
+ if event.relative && event.value != 0 {
+ let scroll_event = orbclient::event::ScrollEvent {
+ x: event.value as i32,
+ y: 0,
+ };
+ if let Err(err) = display.write_event(scroll_event.to_event()) {
+ log::warn!("failed to send hscroll: {}", err);
+ }
+ }
+ } else {
+ 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 u16 {
+ let pressed = event.value != 0;
+ 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);
+ } else if event.usage_page == UsagePage::Button as u16 {
+ let btn_idx = event.usage as usize;
+ if btn_idx > 0 && btn_idx <= MAX_MOUSE_BUTTONS {
+ buttons[btn_idx - 1] = event.value != 0;
+ } else if btn_idx > MAX_MOUSE_BUTTONS {
+ log::debug!(
+ "ignoring button {} (max {})",
+ btn_idx,
+ MAX_MOUSE_BUTTONS
+ );
+ }
+ } else if event.usage_page < 0xFF00 {
+ log::info!(
+ "unsupported usage 0x{:X}:0x{:X} value {}",
+ event.usage_page,
+ event.usage,
+ event.value
+ );
}
- } else {
- 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 u16 {
- 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);
- } else if event.usage_page == UsagePage::Button as u16 {
- 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 if event.usage_page >= 0xFF00 {
- // Ignore vendor defined event
- } else {
- log::info!(
- "unsupported usage 0x{:X}:0x{:X} value {}",
- event.usage_page,
- event.usage,
- event.value
- );
+ }
+ Err(err) => {
+ log::warn!("failed to parse HID report: {}", err);
}
}
if mouse_pos != last_mouse_pos {
last_mouse_pos = mouse_pos;
-
- // TODO
// ps2d uses 0..=65535 as range, while usb uses 0..=32767. orbital
// expects the former range, so multiply by two here to temporarily
- // align with orbital expectation. This workaround will make cursor
- // looks out of sync in QEMU using virtio-vga with usb-tablet.
+ // align with orbital expectation.
let mouse_event = orbclient::event::MouseEvent {
x: mouse_pos.0 * 2,
y: mouse_pos.1 * 2,
};
-
- match display.write_event(mouse_event.to_event()) {
- Ok(_) => (),
- Err(err) => {
- log::warn!("failed to send mouse event to orbital: {}", err);
- }
+ if let Err(err) = display.write_event(mouse_event.to_event()) {
+ log::warn!("failed to send mouse event: {}", err);
}
}
if mouse_dx != 0 || mouse_dy != 0 {
- // TODO: This is a filter to prevent random mouse jumps
if mouse_dx > -127 && mouse_dx < 127 {
let mouse_event = orbclient::event::MouseRelativeEvent {
dx: mouse_dx,
dy: mouse_dy,
};
-
- match display.write_event(mouse_event.to_event()) {
- Ok(_) => (),
- Err(err) => {
- log::warn!("failed to send mouse event to orbital: {}", err);
- }
+ if let Err(err) = display.write_event(mouse_event.to_event()) {
+ log::warn!("failed to send relative mouse event: {}", err);
}
}
}
if scroll_y != 0 {
let scroll_event = orbclient::event::ScrollEvent { x: 0, y: scroll_y };
-
- match display.write_event(scroll_event.to_event()) {
- Ok(_) => (),
- Err(err) => {
- log::warn!("failed to send scroll event to orbital: {}", err);
- }
+ if let Err(err) = display.write_event(scroll_event.to_event()) {
+ log::warn!("failed to send scroll event: {}", err);
}
}
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_event(button_event.to_event()) {
- Ok(_) => (),
- Err(err) => {
- log::warn!("failed to send button event to orbital: {}", err);
- }
+ if let Err(err) = display.write_event(button_event.to_event()) {
+ log::warn!("failed to send button event: {}", err);
}
}
-
- // log::trace!("took {}ms", timer.elapsed().as_millis())
}
}