Files
RedBear-OS/drivers/input/i2c-hidd/src/input.rs
T

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(&current) {
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,
})
}