#[cfg(all(unix, feature = "libusb"))]
use tokio::sync::mpsc::UnboundedSender;
#[cfg(all(unix, feature = "libusb"))]
use tracing::{debug, trace, warn};
#[cfg(all(unix, feature = "libusb"))]
use usbip::hid::{UsbHidKeyboardHandler, UsbHidKeyboardReport};
#[cfg(all(unix, feature = "libusb"))]
mod hid_descriptor_type {
pub const REPORT: u8 = 0x22;
}
#[cfg(all(unix, feature = "libusb"))]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct LedState {
pub raw: u8,
}
#[cfg(all(unix, feature = "libusb"))]
impl LedState {
pub fn num_lock(&self) -> bool {
self.raw & 0x01 != 0
}
pub fn caps_lock(&self) -> bool {
self.raw & 0x02 != 0
}
pub fn scroll_lock(&self) -> bool {
self.raw & 0x04 != 0
}
pub fn compose(&self) -> bool {
self.raw & 0x08 != 0
}
pub fn kana(&self) -> bool {
self.raw & 0x10 != 0
}
}
#[cfg(all(unix, feature = "libusb"))]
pub struct NetGetKeyboardHandler {
inner: UsbHidKeyboardHandler,
led_tx: Option<UnboundedSender<LedState>>,
key_is_down: bool,
last_led: Option<LedState>,
}
#[cfg(all(unix, feature = "libusb"))]
impl std::fmt::Debug for NetGetKeyboardHandler {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("NetGetKeyboardHandler")
.field("pending_key_events", &self.inner.pending_key_events.len())
.field("last_led", &self.last_led)
.finish()
}
}
#[cfg(all(unix, feature = "libusb"))]
impl Default for NetGetKeyboardHandler {
fn default() -> Self {
Self::new()
}
}
#[cfg(all(unix, feature = "libusb"))]
impl NetGetKeyboardHandler {
pub fn new() -> Self {
Self {
inner: UsbHidKeyboardHandler::new_keyboard(),
led_tx: None,
key_is_down: false,
last_led: None,
}
}
pub fn with_led_events(mut self, led_tx: UnboundedSender<LedState>) -> Self {
self.led_tx = Some(led_tx);
self
}
pub fn queue(&mut self, report: UsbHidKeyboardReport) {
self.inner.pending_key_events.push_back(report);
}
#[allow(dead_code)]
pub fn pending_len(&self) -> usize {
self.inner.pending_key_events.len()
}
#[allow(dead_code)]
pub fn led_state(&self) -> Option<LedState> {
self.last_led
}
fn report_descriptor(&self) -> Vec<u8> {
self.inner.report_descriptor.clone()
}
fn next_input_report(&mut self) -> Vec<u8> {
if self.key_is_down {
self.key_is_down = false;
trace!("USB keyboard: key up");
return vec![0u8; 8];
}
match self.inner.pending_key_events.pop_front() {
Some(report) => {
let mut out = Vec::with_capacity(8);
out.push(report.modifier);
out.push(0); out.extend_from_slice(&report.keys);
self.key_is_down = true;
trace!(
"USB keyboard: key down modifier={:#04x} keys={:?}",
report.modifier,
report.keys
);
out
}
None => Vec::new(),
}
}
fn set_leds(&mut self, raw: u8) {
let state = LedState { raw };
if self.last_led == Some(state) {
trace!("USB keyboard LED report unchanged ({:#04x})", raw);
return;
}
self.last_led = Some(state);
debug!(
"USB keyboard LEDs: num={} caps={} scroll={} (raw {:#04x})",
state.num_lock(),
state.caps_lock(),
state.scroll_lock(),
raw
);
if let Some(ref tx) = self.led_tx {
let _ = tx.send(state);
}
}
}
#[cfg(all(unix, feature = "libusb"))]
impl usbip::UsbInterfaceHandler for NetGetKeyboardHandler {
fn handle_urb(
&mut self,
interface: &usbip::UsbInterface,
ep: usbip::UsbEndpoint,
transfer_buffer_length: u32,
setup: usbip::SetupPacket,
req: &[u8],
) -> std::result::Result<Vec<u8>, std::io::Error> {
if !ep.is_ep0() {
let _ = (interface, transfer_buffer_length, req);
if let usbip::Direction::In = ep.direction() {
return Ok(self.next_input_report());
}
return Ok(vec![]);
}
match (setup.request_type, setup.request) {
(0b1000_0001, 0x06) => {
let desc_type = (setup.value >> 8) as u8;
if desc_type == hid_descriptor_type::REPORT {
Ok(self.report_descriptor())
} else {
warn!(
"USB keyboard: unsupported descriptor type {:#04x}",
desc_type
);
Ok(vec![])
}
}
(0b0010_0001, 0x09) => {
let report_type = (setup.value >> 8) as u8;
if report_type == 0x02 {
match req.first() {
Some(&leds) => self.set_leds(leds),
None => warn!("USB keyboard SET_REPORT(Output) carried no data"),
}
} else {
debug!(
"USB keyboard SET_REPORT of type {:#04x} ignored",
report_type
);
}
Ok(vec![])
}
(0b1010_0001, 0x01) => Ok(vec![self.last_led.map_or(0, |s| s.raw)]),
(0b1010_0001, 0x02) => Ok(vec![0]), (0b1010_0001, 0x03) => Ok(vec![0]),
(0b0010_0001, 0x0A) | (0b0010_0001, 0x0B) => Ok(vec![]),
_ => {
debug!(
"USB keyboard: unhandled control request type={:#04x} request={:#04x}",
setup.request_type, setup.request
);
Ok(vec![])
}
}
}
fn get_class_specific_descriptor(&self) -> Vec<u8> {
self.inner.get_class_specific_descriptor()
}
fn as_any(&mut self) -> &mut dyn std::any::Any {
self
}
}