From ae76f571621be0267630ea1df88b586e7c475ce5 Mon Sep 17 00:00:00 2001 From: 4lDO2 <4lDO2@protonmail.com> Date: Sun, 9 Feb 2020 11:12:18 +0100 Subject: [PATCH] Prepare for orbital communication. --- Cargo.lock | 1 + usbhidd/Cargo.toml | 1 + usbhidd/src/main.rs | 215 ++++++++++++++++++++++++++++++++----- usbhidd/src/report_desc.rs | 33 +++++- 4 files changed, 224 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45920958a4..7609327c6f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1328,6 +1328,7 @@ name = "usbhidd" version = "0.1.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "orbclient 0.3.27 (registry+https://github.com/rust-lang/crates.io-index)", "ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "xhcid 0.1.0", ] diff --git a/usbhidd/Cargo.toml b/usbhidd/Cargo.toml index b76c7ad501..7595756e7c 100644 --- a/usbhidd/Cargo.toml +++ b/usbhidd/Cargo.toml @@ -9,5 +9,6 @@ license = "MIT" [dependencies] bitflags = "1.2" +orbclient = "0.3.27" ux = "0.1" xhcid = { path = "../xhcid" } diff --git a/usbhidd/src/main.rs b/usbhidd/src/main.rs index 7f21eb6d9d..40304bfb42 100644 --- a/usbhidd/src/main.rs +++ b/usbhidd/src/main.rs @@ -1,18 +1,78 @@ use std::env; +use std::fs::File; +use bitflags::bitflags; +use orbclient::KeyEvent as OrbKeyEvent; use xhcid_interface::{ConfigureEndpointsReq, DevDesc, PortReqRecipient, XhciClientHandle}; mod report_desc; mod reqs; mod usage_tables; -use report_desc::{MainCollectionFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; +use report_desc::{LocalItemsState, MainCollectionFlags, MainItem, MainItemFlags, GlobalItemsState, ReportFlatIter, ReportItem, ReportIter, ReportIterItem, REPORT_DESC_TY}; use reqs::ReportTy; fn div_round_up(num: u32, denom: u32) -> u32 { if num % denom == 0 { num / denom } else { num / denom + 1 } } +bitflags! { + pub struct ModifierKeys: u8 { + const LEFT_CTRL = 1 << 0; + const LEFT_SHIFT = 1 << 1; + const LEFT_ALT = 1 << 2; + const LEFT_META = 1 << 3; + const RIGHT_CTRL = 1 << 4; + const RIGHT_SHIFT = 1 << 5; + const RIGHT_ALT = 1 << 6; + const RIGHT_META = 1 << 7; + } +} + +struct BinaryView<'a> { + data: &'a [u8], + offset: usize, + len: usize, +} +impl<'a> BinaryView<'a> { + pub fn new(data: &'a [u8], offset: usize, len: usize) -> Self { + Self { + data, + offset, + len, + } + } + pub fn get(&self, bit_index: usize) -> Option { + let bit_index = self.offset + bit_index; + + if bit_index >= self.offset + self.len { return None } + + let byte_index = bit_index / 8; + let bits_from_first = bit_index % 8; + let byte = self.data.get(byte_index)?; + Some(byte & (1 << bits_from_first) != 0) + } + pub fn read_u8(&self, bit_index: usize) -> Option { + let bit_index = self.offset + bit_index; + + if bit_index >= self.offset + self.len { return None } + + let first = bit_index / 8; + let bits_from_first = bit_index % 8; + let first_byte = self.data.get(first)?; + let lo = first_byte >> bits_from_first; + + let hi = if bits_from_first > 0 { + let hi = self.data.get(first + 1)? & ((1 << bits_from_first) - 1); + let bits_to_next = 8 - bits_from_first; + hi << bits_to_next + } else { 0 }; + + + Some(lo | hi) + } +} + fn main() { let mut args = env::args().skip(1); @@ -62,56 +122,161 @@ fn main() { handle.configure_endpoints(&ConfigureEndpointsReq { config_desc: 0 }).expect("Failed to configure endpoints"); - let (mut state, mut stack) = (GlobalItemsState::default(), Vec::new()); + let (mut global_state, mut local_state, mut stack) = (GlobalItemsState::default(), LocalItemsState::default(), Vec::new()); - let (_, application_collection) = report_desc.iter().inspect(|item: &&ReportIterItem| if let ReportIterItem::Item(ref item) = item { - report_desc::update_state(&mut state, &mut stack, item).unwrap() - }).filter_map(ReportIterItem::as_collection).find(|&(n, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); + let (_, application_collection, application_global_state, application_local_state) = report_desc.iter().filter_map(|item: &ReportIterItem| + match item { + &ReportIterItem::Item(ref item) => { + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); + report_desc::update_local_state(&mut local_state, item); + None + } + &ReportIterItem::Collection(n, ref collection) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + Some((n, collection, global_state, lc_state)) + } + } + ).find(|&(n, _, _, _)| n == MainCollectionFlags::Application as u8).expect("Failed to find application collection"); // Get all main items, and their global item options. { let items = application_collection.iter().filter_map(ReportIterItem::as_item).filter_map(|item| match item { ReportItem::Global(_) => { - report_desc::update_state(&mut state, &mut stack, item).unwrap(); + report_desc::update_global_state(&mut global_state, &mut stack, item).unwrap(); None } - ReportItem::Main(m) => Some((state, m)), - ReportItem::Local(_) => None, + ReportItem::Main(m) => { + let lc_state = std::mem::replace(&mut local_state, LocalItemsState::default()); + Some((global_state, lc_state, m)) + } + ReportItem::Local(_) => { + report_desc::update_local_state(&mut local_state, item); + None + }, }); - let total_length = items.filter_map(|(state, item)| { - let report_size = match state.report_size { + let mut bit_offset = 0; + let inputs = items.filter_map(|(global_state, local_state, item)| { + let report_size = match global_state.report_size { Some(s) => s, None => return None, }; - let report_count = match state.report_count { + let report_count = match global_state.report_count { Some(c) => c, None => return None, }; - let bit_length = report_size * report_count; - - if item.report_ty() != Some(ReportTy::Input) { + if global_state.usage_page != Some(0x7) { return None; } - Some(bit_length) - }).sum(); - let length = div_round_up(total_length, 8); + let bit_length = report_size * report_count; - let mut report_buffer = vec! [0u8; length as usize]; + let offset = bit_offset; + bit_offset += bit_length; + + if let &MainItem::Input(flags) = item { + Some((bit_length, offset, global_state, local_state, MainItemFlags::from_bits_truncate(flags))) + } else { + None + } + }).collect::>(); + let total_bit_length = inputs.iter().map(|(bit_length, _, _, _, _)| bit_length).sum(); + + let total_byte_length = div_round_up(total_bit_length, 8); + + let mut report_buffer = vec! [0u8; total_byte_length as usize]; let mut last_buffer = report_buffer.clone(); let report_ty = ReportTy::Input; let report_id = 0; + let orbital_socket = File::open("display:input").expect("Failed to open orbital input socket"); + + let mut pressed_keys = vec! []; + let mut last_pressed_keys = pressed_keys.clone(); + + let mut modifier_keys = ModifierKeys::empty(); + let mut last_modifier_keys = modifier_keys; + loop { + std::thread::sleep(std::time::Duration::from_millis(10)); + std::mem::swap(&mut report_buffer, &mut last_buffer); reqs::get_report(&handle, report_ty, report_id, interface_num, &mut report_buffer).expect("Failed to get report"); - if report_buffer != last_buffer { - for byte in &report_buffer { - print!("{:#0x} ", byte); - } - println!(); + + if report_buffer == last_buffer { + continue } - std::thread::sleep(std::time::Duration::from_millis(10)) + + for &(bit_length, bit_offset, global_state, local_state, input) in &inputs { + let report_size = global_state.report_size.unwrap(); + let report_count = global_state.report_count.unwrap(); + + if input.contains(MainItemFlags::VARIABLE) { + // variable + //assert_eq!(state.logical_max.unwrap() - state.logical_min.unwrap(), report_count, "modifiers don't map"); + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize, bit_length as usize); + // PRETTYFYME + if report_count == 8 && report_size == 1 && local_state.usage_min == Some(224) && local_state.usage_max == Some(231) && global_state.logical_min == Some(0) && global_state.logical_max == Some(1) { + std::mem::swap(&mut modifier_keys, &mut last_modifier_keys); + modifier_keys = match ModifierKeys::from_bits(binary_view.read_u8(0).unwrap()) { + Some(f) => f, + None => unreachable!(), + }; + } else { + println!("unknown report variable item"); + } + } else { + std::mem::swap(&mut pressed_keys, &mut last_pressed_keys); + pressed_keys.clear(); + + println!("INPUT FLAGS: {:?}", input); + assert_eq!(report_size, 8); + // array + for report_index in 0..report_count as usize { + let binary_view = BinaryView::new(&report_buffer, bit_offset as usize + report_index * report_size as usize, report_size as usize); + let usage = binary_view.read_u8(0).expect("Failed to read array item"); + if usage != 0 { + pressed_keys.push(usage); + } + println!("Report index array {}: {}", report_index, usage); + } + + } + } + let changed_modifier_keys = modifier_keys ^ last_modifier_keys; + for (current, last) in pressed_keys.iter().copied().zip(last_pressed_keys.iter().copied()) { + if current == last { continue } + if current != 0 { + // Keycode current changed state to "pressed". + } else { + // Keycode current changed state to "released". + } + } + println!(); } } - +} + +#[cfg(test)] +mod tests { + #[test] + fn binary_view() { + // 0000 1000 1100 0111 + // E S + let view = super::BinaryView::new(&[0xC7, 0x08], 3, 11); + assert_eq!(view.get(0), Some(false)); + assert_eq!(view.get(2), Some(false)); + assert_eq!(view.get(3), Some(true)); + assert_eq!(view.get(7), Some(false)); + assert_eq!(view.get(17), None); + + assert_eq!(view.read_u8(0), Some(0b0001_1000)); + assert_eq!(view.read_u8(1), Some(0b1000_1100)); + assert_eq!(view.read_u8(2), Some(0b0100_0110)); + assert_eq!(view.read_u8(3), Some(0b0010_0011)); + assert_eq!(view.read_u8(7), None); + + // 0000 1000 1100 0111 + // E S + let view = super::BinaryView::new(&[0xC7, 0x08], 8, 8); + assert_eq!(view.read_u8(0), Some(0b0000_1000)); + } } diff --git a/usbhidd/src/report_desc.rs b/usbhidd/src/report_desc.rs index 9a0019aaba..93c3083b78 100644 --- a/usbhidd/src/report_desc.rs +++ b/usbhidd/src/report_desc.rs @@ -85,7 +85,7 @@ pub struct GlobalItemsState { #[derive(Debug)] pub struct Invalid; -pub fn update_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { +pub fn update_global_state(current_state: &mut GlobalItemsState, stack: &mut Vec, report_item: &ReportItem) -> Result<(), Invalid> { match report_item { ReportItem::Global(global) => match global { &GlobalItem::UsagePage(u) => current_state.usage_page = Some(u), @@ -120,6 +120,37 @@ pub enum LocalItem { StringMaximum(u32), Delimeter(u32), } + +#[derive(Clone, Copy, Debug, Default)] +pub struct LocalItemsState { + pub usage: Option, + pub usage_min: Option, + pub usage_max: Option, + pub desig_idx: Option, + pub desig_min: Option, + pub desig_max: Option, + pub str_idx: Option, + pub str_min: Option, + pub str_max: Option, +} +pub fn update_local_state(current_state: &mut LocalItemsState, report_item: &ReportItem) { + match report_item { + ReportItem::Local(local) => match local { + &LocalItem::Usage(u) => current_state.usage = Some(u), + &LocalItem::UsageMinimum(m) => current_state.usage_min = Some(m), + &LocalItem::UsageMaximum(m) => current_state.usage_max = Some(m), + &LocalItem::DesignatorIndex(i) => current_state.desig_idx = Some(i), + &LocalItem::DesignatorMinimum(m) => current_state.desig_min = Some(m), + &LocalItem::DesignatorMaximum(m) => current_state.desig_max = Some(m), + &LocalItem::StringIndex(i) => current_state.str_idx = Some(i), + &LocalItem::StringMinimum(m) => current_state.str_min = Some(m), + &LocalItem::StringMaximum(m) => current_state.str_max = Some(m), + &LocalItem::Delimeter(_) => todo!(), + }, + _ => todo!(), + } +} + #[derive(Debug)] pub enum ReportItem { Main(MainItem),