pub extern crate interception_sys;
#[macro_use]
extern crate bitflags;
pub use interception_sys 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;
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<raw::InterceptionMouseStroke> for Stroke {
type Error = &'static str;
fn try_from(raw_stroke: raw::InterceptionMouseStroke) -> Result<Self, Self::Error> {
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<raw::InterceptionKeyStroke> for Stroke {
type Error = &'static str;
fn try_from(raw_stroke: raw::InterceptionKeyStroke) -> Result<Self, Self::Error> {
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<Stroke> for raw::InterceptionMouseStroke {
type Error = &'static str;
fn try_from(stroke: Stroke) -> Result<Self, Self::Error> {
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<Stroke> for raw::InterceptionKeyStroke {
type Error = &'static str;
fn try_from(stroke: Stroke) -> Result<Self, Self::Error> {
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<Self> {
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::<raw::InterceptionMouseStroke>(device, strokes)
} else if is_keyboard(device) {
self.send_internal::<raw::InterceptionKeyStroke>(device, strokes)
} else {
0
}
}
fn send_internal<T: TryFrom<Stroke>>(&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::<raw::InterceptionMouseStroke>(device, strokes)
} else if is_keyboard(device) {
self.receive_internal::<raw::InterceptionKeyStroke>(device, strokes)
} else {
0
}
}
fn receive_internal<T: TryInto<Stroke> + Default + Copy>(
&self,
device: Device,
strokes: &mut [Stroke],
) -> i32 {
let mut raw_strokes: Vec<T> = 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 }
}