#[macro_use] extern crate bitflags; mod bindings; use bindings as raw; pub mod scancode; pub use scancode::ScanCode; use std::convert::{TryFrom, TryInto}; use std::default::Default; use std::time::Duration; use std::vec::Vec; pub type Device = i32; pub type Precedence = i32; pub enum Filter { MouseFilter(MouseFilter), KeyFilter(KeyFilter), } pub type Predicate = extern "C" fn(device: Device) -> bool; bitflags! { pub struct MouseState: u16 { const LEFT_BUTTON_DOWN = 1; const LEFT_BUTTON_UP = 2; const RIGHT_BUTTON_DOWN = 4; const RIGHT_BUTTON_UP = 8; const MIDDLE_BUTTON_DOWN = 16; const MIDDLE_BUTTON_UP = 32; const BUTTON_4_DOWN = 64; const BUTTON_4_UP = 128; const BUTTON_5_DOWN = 256; const BUTTON_5_UP = 512; const WHEEL = 1024; const HWHEEL = 2048; // MouseFilter only const MOVE = 4096; } } pub type MouseFilter = MouseState; bitflags! { pub struct MouseFlags: u16 { const MOVE_RELATIVE = 0; const MOVE_ABSOLUTE = 1; const VIRTUAL_DESKTOP = 2; const ATTRIBUTES_CHANGED = 4; const MOVE_NO_COALESCE = 8; const TERMSRV_SRC_SHADOW = 256; } } bitflags! { pub struct KeyState: u16 { const DOWN = 0; const UP = 1; const E0 = 2; const E1 = 3; const TERMSRV_SET_LED = 8; const TERMSRV_SHADOW = 16; const TERMSRV_VKPACKET = 32; } } bitflags! { pub struct KeyFilter: u16 { const DOWN = 1; const UP = 2; const E0 = 4; const E1 = 8; const TERMSRV_SET_LED = 16; const TERMSRV_SHADOW = 32; const TERMSRV_VKPACKET = 64; } } #[derive(Debug, Copy, Clone)] pub enum Stroke { Mouse { state: MouseState, flags: MouseFlags, rolling: i16, x: i32, y: i32, information: u32, }, Keyboard { code: ScanCode, state: KeyState, information: u32, }, } impl TryFrom for Stroke { type Error = &'static str; fn try_from(raw_stroke: raw::InterceptionMouseStroke) -> Result { let state = match MouseState::from_bits(raw_stroke.state) { Some(state) => state, None => return Err("Extra bits in raw mouse state"), }; let flags = match MouseFlags::from_bits(raw_stroke.flags) { Some(flags) => flags, None => return Err("Extra bits in raw mouse flags"), }; Ok(Stroke::Mouse { state: state, flags: flags, rolling: raw_stroke.rolling, x: raw_stroke.x, y: raw_stroke.y, information: raw_stroke.information, }) } } impl TryFrom for Stroke { type Error = &'static str; fn try_from(raw_stroke: raw::InterceptionKeyStroke) -> Result { let state = match KeyState::from_bits(raw_stroke.state) { Some(state) => state, None => return Err("Extra bits in raw keyboard state"), }; let code = match ScanCode::try_from(raw_stroke.code) { Ok(code) => code, Err(_) => ScanCode::Esc, }; Ok(Stroke::Keyboard { code: code, state: state, information: raw_stroke.information, }) } } impl TryFrom for raw::InterceptionMouseStroke { type Error = &'static str; fn try_from(stroke: Stroke) -> Result { if let Stroke::Mouse { state, flags, rolling, x, y, information, } = stroke { Ok(raw::InterceptionMouseStroke { state: state.bits(), flags: flags.bits(), rolling: rolling, x: x, y: y, information: information, }) } else { Err("Stroke must be a mouse stroke") } } } impl TryFrom for raw::InterceptionKeyStroke { type Error = &'static str; fn try_from(stroke: Stroke) -> Result { if let Stroke::Keyboard { code, state, information, } = stroke { Ok(raw::InterceptionKeyStroke { code: code as u16, state: state.bits(), information: information, }) } else { Err("Stroke must be a keyboard stroke") } } } pub struct Interception { ctx: raw::InterceptionContext, } impl Interception { pub fn new() -> Option { let ctx = unsafe { raw::interception_create_context() }; if ctx == std::ptr::null_mut() { return None; } Some(Interception { ctx: ctx }) } pub fn get_precedence(&self, device: Device) -> Precedence { unsafe { raw::interception_get_precedence(self.ctx, device) } } pub fn set_precedence(&self, device: Device, precedence: Precedence) { unsafe { raw::interception_set_precedence(self.ctx, device, precedence) } } pub fn get_filter(&self, device: Device) -> Filter { if is_invalid(device) { return Filter::KeyFilter(KeyFilter::empty()); } let raw_filter = unsafe { raw::interception_get_filter(self.ctx, device) }; if is_mouse(device) { let filter = match MouseFilter::from_bits(raw_filter) { Some(filter) => filter, None => MouseFilter::empty(), }; Filter::MouseFilter(filter) } else { let filter = match KeyFilter::from_bits(raw_filter) { Some(filter) => filter, None => KeyFilter::empty(), }; Filter::KeyFilter(filter) } } pub fn set_filter(&self, predicate: Predicate, filter: Filter) { let filter = match filter { Filter::MouseFilter(filter) => filter.bits(), Filter::KeyFilter(filter) => filter.bits(), }; unsafe { let predicate = std::mem::transmute(Some(predicate)); raw::interception_set_filter(self.ctx, predicate, filter) } } pub fn wait(&self) -> Device { unsafe { raw::interception_wait(self.ctx) } } pub fn wait_with_timeout(&self, duration: Duration) -> Device { let millis = match u32::try_from(duration.as_millis()) { Ok(m) => m, Err(_) => u32::MAX, }; unsafe { raw::interception_wait_with_timeout(self.ctx, millis) } } pub fn send(&self, device: Device, strokes: &[Stroke]) -> i32 { if is_mouse(device) { self.send_internal::(device, strokes) } else if is_keyboard(device) { self.send_internal::(device, strokes) } else { 0 } } fn send_internal>(&self, device: Device, strokes: &[Stroke]) -> i32 { let mut raw_strokes = Vec::new(); for stroke in strokes { if let Ok(raw_stroke) = T::try_from(*stroke) { raw_strokes.push(raw_stroke) } } let ptr = raw_strokes.as_ptr(); let len = match u32::try_from(raw_strokes.len()) { Ok(l) => l, Err(_) => u32::MAX, }; unsafe { raw::interception_send(self.ctx, device, std::mem::transmute(ptr), len) } } pub fn receive(&self, device: Device, strokes: &mut [Stroke]) -> i32 { if is_mouse(device) { self.receive_internal::(device, strokes) } else if is_keyboard(device) { self.receive_internal::(device, strokes) } else { 0 } } fn receive_internal + Default + Copy>( &self, device: Device, strokes: &mut [Stroke], ) -> i32 { let mut raw_strokes: Vec = Vec::with_capacity(strokes.len()); raw_strokes.resize_with(strokes.len(), Default::default); let ptr = raw_strokes.as_ptr(); let len = match u32::try_from(raw_strokes.len()) { Ok(l) => l, Err(_) => u32::MAX, }; let num_read = unsafe { raw::interception_receive(self.ctx, device, std::mem::transmute(ptr), len) }; let mut num_valid: i32 = 0; for i in 0..num_read { if let Ok(stroke) = raw_strokes[i as usize].try_into() { strokes[num_valid as usize] = stroke; num_valid += 1; } } num_valid } pub fn get_hardware_id(&self, device: Device, buffer: &mut [u8]) -> u32 { let ptr = buffer.as_mut_ptr(); let len = match u32::try_from(buffer.len()) { Ok(l) => l, Err(_) => u32::MAX, }; unsafe { raw::interception_get_hardware_id(self.ctx, device, std::mem::transmute(ptr), len) } } } impl Drop for Interception { fn drop(&mut self) { unsafe { raw::interception_destroy_context(self.ctx) } } } pub extern "C" fn is_invalid(device: Device) -> bool { unsafe { raw::interception_is_invalid(device) != 0 } } pub extern "C" fn is_keyboard(device: Device) -> bool { unsafe { raw::interception_is_keyboard(device) != 0 } } pub extern "C" fn is_mouse(device: Device) -> bool { unsafe { raw::interception_is_mouse(device) != 0 } }