usbhidd: P5 slice 2 — keyboard LED sync via SET_REPORT
Add Caps Lock, Num Lock, and Scroll Lock LED synchronization following Linux 7.1 hid-input.c: hidinput_output_event(). Led state tracking: - Caps Lock (usage 0x39) → toggles bit 1 - Scroll Lock (usage 0x47) → toggles bit 2 - Num Lock (usage 0x53) → toggles bit 0 SET_REPORT (Output) via XhciClientHandle::device_request(): - PortReqTy::Class, PortReqRecipient::Interface - bRequest = 0x09 (SET_REPORT) - wValue = (0x02 << 8) | 0x00 (Output report type, report ID 0) - wIndex = interface_num - Data = 1-byte LED state The SET_REPORT is sent only when the LED state changes (tracked with last_led_state sentinel). A failed SET_REPORT is logged at warn level but does not block the input loop. Cross-reference: Linux 7.1 - drivers/hid/hid-input.c: hidinput_output_event() - drivers/hid/usbhid/hid-core.c: usbhid_output_report() - HID 1.11 spec §7.2.1: SET_REPORT request This means USB keyboards with Caps/Num/Scroll Lock LEDs will now have their LEDs synchronized with the host lock state.
This commit is contained in:
@@ -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())
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user