diff --git a/drivers/input/usbhidd/src/main.rs b/drivers/input/usbhidd/src/main.rs index 3b90a1708d..e37b6795ff 100644 --- a/drivers/input/usbhidd/src/main.rs +++ b/drivers/input/usbhidd/src/main.rs @@ -324,6 +324,11 @@ fn main() -> Result<()> { let mut right_shift = false; let mut last_mouse_pos = (0, 0); let mut last_buttons = [false, false, false]; + + // Keyboard LED state (HID boot keyboard output report, 1 byte) + let mut led_state: u8 = 0; + let mut last_led_state: u8 = 0xFF; // force first SET_REPORT + loop { //TODO: get frequency from device //TODO: use sleeps when accuracy is better: thread::sleep(time::Duration::from_millis(10)); @@ -399,6 +404,15 @@ fn main() -> Result<()> { } else if event.usage == 0xE5 { right_shift = pressed; } + // Track LED state from lock-key presses (Linux 7.1 hid-input.c) + if pressed { + match event.usage { + 0x39 => led_state ^= 0x02, // Caps Lock + 0x47 => led_state ^= 0x04, // Scroll Lock + 0x53 => led_state ^= 0x01, // Num Lock + _ => {} + } + } 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() { @@ -495,6 +509,26 @@ fn main() -> Result<()> { } } + // Keyboard LED sync: send HID output report when LED state changes. + // Linux 7.1 hid-input.c: hidinput_output_event() → hid_hw_output_report() + // → SET_REPORT (Output) via control transfer. + if led_state != last_led_state { + last_led_state = led_state; + let led_bytes = [led_state]; + if let Err(e) = handle.device_request( + xhcid_interface::PortReqTy::Class, + xhcid_interface::PortReqRecipient::Interface, + 0x09, // SET_REPORT + (0x02u16) << 8, // Output report type, report ID 0 + interface_num as u16, + xhcid_interface::DeviceReqData::Out(unsafe { + std::slice::from_raw_parts(led_bytes.as_ptr(), 1) + }), + ) { + log::warn!("usbhidd: SET_REPORT(LED) failed: {}", e); + } + } + // log::trace!("took {}ms", timer.elapsed().as_millis()) } }