176 lines
4.9 KiB
Rust
176 lines
4.9 KiB
Rust
use std::collections::BTreeSet;
|
|
|
|
use anyhow::Result;
|
|
use inputd::ProducerHandle;
|
|
use orbclient::{
|
|
ButtonEvent, KeyEvent, MouseRelativeEvent, ScrollEvent, K_ALT, K_ALT_GR, K_BKSP, K_BRACE_CLOSE,
|
|
K_BRACE_OPEN, K_CAPS, K_COMMA, K_ENTER, K_EQUALS, K_ESC, K_LEFT_CTRL, K_LEFT_SHIFT,
|
|
K_LEFT_SUPER, K_MINUS, K_PERIOD, K_QUOTE, K_RIGHT_CTRL, K_RIGHT_SHIFT, K_RIGHT_SUPER,
|
|
K_SEMICOLON, K_SLASH, K_SPACE, K_TAB, K_TICK,
|
|
};
|
|
|
|
use crate::hid::ReportDescriptorSummary;
|
|
|
|
pub struct InputForwarder {
|
|
producer: ProducerHandle,
|
|
keyboard_state: BTreeSet<u8>,
|
|
last_buttons: u8,
|
|
}
|
|
|
|
impl InputForwarder {
|
|
pub fn new() -> Result<Self> {
|
|
Ok(Self {
|
|
producer: ProducerHandle::new()?,
|
|
keyboard_state: BTreeSet::new(),
|
|
last_buttons: 0,
|
|
})
|
|
}
|
|
|
|
pub fn forward_report(
|
|
&mut self,
|
|
summary: &ReportDescriptorSummary,
|
|
report: &[u8],
|
|
) -> Result<()> {
|
|
if report.is_empty() {
|
|
return Ok(());
|
|
}
|
|
|
|
if summary.has_keyboard_page && report.len() >= 8 {
|
|
self.forward_boot_keyboard(report)?;
|
|
return Ok(());
|
|
}
|
|
|
|
if summary.has_pointer_page && report.len() >= 3 {
|
|
self.forward_boot_pointer(report)?;
|
|
return Ok(());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn forward_boot_keyboard(&mut self, report: &[u8]) -> Result<()> {
|
|
let modifiers = report[0];
|
|
for (bit, scancode) in [
|
|
(0_u8, K_LEFT_CTRL),
|
|
(1, K_LEFT_SHIFT),
|
|
(2, K_ALT),
|
|
(3, K_LEFT_SUPER),
|
|
(4, K_RIGHT_CTRL),
|
|
(5, K_RIGHT_SHIFT),
|
|
(6, K_ALT_GR),
|
|
(7, K_RIGHT_SUPER),
|
|
] {
|
|
self.producer.write_event(
|
|
KeyEvent {
|
|
character: '\0',
|
|
scancode,
|
|
pressed: modifiers & (1 << bit) != 0,
|
|
}
|
|
.to_event(),
|
|
)?;
|
|
}
|
|
|
|
let current = report[2..8]
|
|
.iter()
|
|
.copied()
|
|
.filter(|code| *code != 0)
|
|
.collect::<BTreeSet<_>>();
|
|
|
|
for code in current.difference(&self.keyboard_state) {
|
|
if let Some(scancode) = map_boot_keyboard_usage(*code) {
|
|
self.producer.write_event(
|
|
KeyEvent {
|
|
character: '\0',
|
|
scancode,
|
|
pressed: true,
|
|
}
|
|
.to_event(),
|
|
)?;
|
|
}
|
|
}
|
|
for code in self.keyboard_state.difference(¤t) {
|
|
if let Some(scancode) = map_boot_keyboard_usage(*code) {
|
|
self.producer.write_event(
|
|
KeyEvent {
|
|
character: '\0',
|
|
scancode,
|
|
pressed: false,
|
|
}
|
|
.to_event(),
|
|
)?;
|
|
}
|
|
}
|
|
|
|
self.keyboard_state = current;
|
|
Ok(())
|
|
}
|
|
|
|
fn forward_boot_pointer(&mut self, report: &[u8]) -> Result<()> {
|
|
let dx = i8::from_ne_bytes([report[1]]) as i32;
|
|
let dy = i8::from_ne_bytes([report[2]]) as i32;
|
|
if dx != 0 || dy != 0 {
|
|
self.producer
|
|
.write_event(MouseRelativeEvent { dx, dy }.to_event())?;
|
|
}
|
|
|
|
if let Some(scroll) = report.get(3).copied() {
|
|
let scroll = i8::from_ne_bytes([scroll]) as i32;
|
|
if scroll != 0 {
|
|
self.producer
|
|
.write_event(ScrollEvent { x: 0, y: scroll }.to_event())?;
|
|
}
|
|
}
|
|
|
|
let buttons = report[0] & 0x07;
|
|
for index in 0..3 {
|
|
let mask = 1 << index;
|
|
if (buttons & mask) != (self.last_buttons & mask) {
|
|
self.producer.write_event(
|
|
ButtonEvent {
|
|
left: buttons & 0x01 != 0,
|
|
middle: buttons & 0x04 != 0,
|
|
right: buttons & 0x02 != 0,
|
|
}
|
|
.to_event(),
|
|
)?;
|
|
break;
|
|
}
|
|
}
|
|
self.last_buttons = buttons;
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
fn map_boot_keyboard_usage(usage: u8) -> Option<u8> {
|
|
Some(match usage {
|
|
0x04..=0x1D => b'a' + (usage - 0x04),
|
|
0x1E => b'1',
|
|
0x1F => b'2',
|
|
0x20 => b'3',
|
|
0x21 => b'4',
|
|
0x22 => b'5',
|
|
0x23 => b'6',
|
|
0x24 => b'7',
|
|
0x25 => b'8',
|
|
0x26 => b'9',
|
|
0x27 => b'0',
|
|
0x28 => K_ENTER,
|
|
0x29 => K_ESC,
|
|
0x2A => K_BKSP,
|
|
0x2B => K_TAB,
|
|
0x2C => K_SPACE,
|
|
0x2D => K_MINUS,
|
|
0x2E => K_EQUALS,
|
|
0x2F => K_BRACE_OPEN,
|
|
0x30 => K_BRACE_CLOSE,
|
|
0x33 => K_SEMICOLON,
|
|
0x34 => K_QUOTE,
|
|
0x35 => K_TICK,
|
|
0x36 => K_COMMA,
|
|
0x37 => K_PERIOD,
|
|
0x38 => K_SLASH,
|
|
0x39 => K_CAPS,
|
|
_ => return None,
|
|
})
|
|
}
|