kanata_interception/
lib.rs

1pub extern crate interception_sys;
2
3#[macro_use]
4extern crate bitflags;
5
6pub use interception_sys as raw;
7pub mod scancode;
8
9pub use scancode::ScanCode;
10
11use std::convert::{TryFrom, TryInto};
12use std::default::Default;
13use std::time::Duration;
14use std::vec::Vec;
15
16pub type Device = i32;
17pub type Precedence = i32;
18
19pub enum Filter {
20    MouseFilter(MouseFilter),
21    KeyFilter(KeyFilter),
22}
23
24pub type Predicate = extern "C" fn(device: Device) -> bool;
25
26bitflags! {
27    pub struct MouseState: u16 {
28        const LEFT_BUTTON_DOWN = 1;
29        const LEFT_BUTTON_UP = 2;
30
31        const RIGHT_BUTTON_DOWN = 4;
32        const RIGHT_BUTTON_UP = 8;
33
34        const MIDDLE_BUTTON_DOWN = 16;
35        const MIDDLE_BUTTON_UP = 32;
36
37        const BUTTON_4_DOWN = 64;
38        const BUTTON_4_UP = 128;
39
40        const BUTTON_5_DOWN = 256;
41        const BUTTON_5_UP = 512;
42
43        const WHEEL = 1024;
44        const HWHEEL = 2048;
45
46        // MouseFilter only
47        const MOVE = 4096;
48    }
49}
50
51pub type MouseFilter = MouseState;
52
53bitflags! {
54    pub struct MouseFlags: u16 {
55        const MOVE_RELATIVE = 0;
56        const MOVE_ABSOLUTE = 1;
57
58        const VIRTUAL_DESKTOP = 2;
59        const ATTRIBUTES_CHANGED = 4;
60
61        const MOVE_NO_COALESCE = 8;
62
63        const TERMSRV_SRC_SHADOW = 256;
64    }
65}
66
67bitflags! {
68    pub struct KeyState: u16 {
69        const DOWN = 0;
70        const UP = 1;
71
72        const E0 = 2;
73        const E1 = 3;
74
75        const TERMSRV_SET_LED = 8;
76        const TERMSRV_SHADOW = 16;
77        const TERMSRV_VKPACKET = 32;
78    }
79}
80
81bitflags! {
82    pub struct KeyFilter: u16 {
83        const DOWN = 1;
84        const UP = 2;
85
86        const E0 = 4;
87        const E1 = 8;
88
89        const TERMSRV_SET_LED = 16;
90        const TERMSRV_SHADOW = 32;
91        const TERMSRV_VKPACKET = 64;
92    }
93}
94
95#[derive(Debug, Copy, Clone)]
96pub enum Stroke {
97    Mouse {
98        state: MouseState,
99        flags: MouseFlags,
100        rolling: i16,
101        x: i32,
102        y: i32,
103        information: u32,
104    },
105
106    Keyboard {
107        code: ScanCode,
108        state: KeyState,
109        information: u32,
110    },
111}
112
113impl TryFrom<raw::InterceptionMouseStroke> for Stroke {
114    type Error = &'static str;
115
116    fn try_from(raw_stroke: raw::InterceptionMouseStroke) -> Result<Self, Self::Error> {
117        let state = match MouseState::from_bits(raw_stroke.state) {
118            Some(state) => state,
119            None => return Err("Extra bits in raw mouse state"),
120        };
121
122        let flags = match MouseFlags::from_bits(raw_stroke.flags) {
123            Some(flags) => flags,
124            None => return Err("Extra bits in raw mouse flags"),
125        };
126
127        Ok(Stroke::Mouse {
128            state: state,
129            flags: flags,
130            rolling: raw_stroke.rolling,
131            x: raw_stroke.x,
132            y: raw_stroke.y,
133            information: raw_stroke.information,
134        })
135    }
136}
137
138impl TryFrom<raw::InterceptionKeyStroke> for Stroke {
139    type Error = &'static str;
140
141    fn try_from(raw_stroke: raw::InterceptionKeyStroke) -> Result<Self, Self::Error> {
142        let state = match KeyState::from_bits(raw_stroke.state) {
143            Some(state) => state,
144            None => return Err("Extra bits in raw keyboard state"),
145        };
146
147        let code = match ScanCode::try_from(raw_stroke.code) {
148            Ok(code) => code,
149            Err(_) => ScanCode::Esc,
150        };
151
152        Ok(Stroke::Keyboard {
153            code: code,
154            state: state,
155            information: raw_stroke.information,
156        })
157    }
158}
159
160impl TryFrom<Stroke> for raw::InterceptionMouseStroke {
161    type Error = &'static str;
162
163    fn try_from(stroke: Stroke) -> Result<Self, Self::Error> {
164        if let Stroke::Mouse {
165            state,
166            flags,
167            rolling,
168            x,
169            y,
170            information,
171        } = stroke
172        {
173            Ok(raw::InterceptionMouseStroke {
174                state: state.bits(),
175                flags: flags.bits(),
176                rolling: rolling,
177                x: x,
178                y: y,
179                information: information,
180            })
181        } else {
182            Err("Stroke must be a mouse stroke")
183        }
184    }
185}
186
187impl TryFrom<Stroke> for raw::InterceptionKeyStroke {
188    type Error = &'static str;
189
190    fn try_from(stroke: Stroke) -> Result<Self, Self::Error> {
191        if let Stroke::Keyboard {
192            code,
193            state,
194            information,
195        } = stroke
196        {
197            Ok(raw::InterceptionKeyStroke {
198                code: code as u16,
199                state: state.bits(),
200                information: information,
201            })
202        } else {
203            Err("Stroke must be a keyboard stroke")
204        }
205    }
206}
207
208pub struct Interception {
209    ctx: raw::InterceptionContext,
210}
211
212impl Interception {
213    pub fn new() -> Option<Self> {
214        let ctx = unsafe { raw::interception_create_context() };
215
216        if ctx == std::ptr::null_mut() {
217            return None;
218        }
219
220        Some(Interception { ctx: ctx })
221    }
222
223    pub fn get_precedence(&self, device: Device) -> Precedence {
224        unsafe { raw::interception_get_precedence(self.ctx, device) }
225    }
226
227    pub fn set_precedence(&self, device: Device, precedence: Precedence) {
228        unsafe { raw::interception_set_precedence(self.ctx, device, precedence) }
229    }
230
231    pub fn get_filter(&self, device: Device) -> Filter {
232        if is_invalid(device) {
233            return Filter::KeyFilter(KeyFilter::empty());
234        }
235
236        let raw_filter = unsafe { raw::interception_get_filter(self.ctx, device) };
237        if is_mouse(device) {
238            let filter = match MouseFilter::from_bits(raw_filter) {
239                Some(filter) => filter,
240                None => MouseFilter::empty(),
241            };
242
243            Filter::MouseFilter(filter)
244        } else {
245            let filter = match KeyFilter::from_bits(raw_filter) {
246                Some(filter) => filter,
247                None => KeyFilter::empty(),
248            };
249
250            Filter::KeyFilter(filter)
251        }
252    }
253
254    pub fn set_filter(&self, predicate: Predicate, filter: Filter) {
255        let filter = match filter {
256            Filter::MouseFilter(filter) => filter.bits(),
257            Filter::KeyFilter(filter) => filter.bits(),
258        };
259
260        unsafe {
261            let predicate = std::mem::transmute(Some(predicate));
262            raw::interception_set_filter(self.ctx, predicate, filter)
263        }
264    }
265
266    pub fn wait(&self) -> Device {
267        unsafe { raw::interception_wait(self.ctx) }
268    }
269
270    pub fn wait_with_timeout(&self, duration: Duration) -> Device {
271        let millis = match u32::try_from(duration.as_millis()) {
272            Ok(m) => m,
273            Err(_) => u32::MAX,
274        };
275
276        unsafe { raw::interception_wait_with_timeout(self.ctx, millis) }
277    }
278
279    pub fn send(&self, device: Device, strokes: &[Stroke]) -> i32 {
280        if is_mouse(device) {
281            self.send_internal::<raw::InterceptionMouseStroke>(device, strokes)
282        } else if is_keyboard(device) {
283            self.send_internal::<raw::InterceptionKeyStroke>(device, strokes)
284        } else {
285            0
286        }
287    }
288
289    fn send_internal<T: TryFrom<Stroke>>(&self, device: Device, strokes: &[Stroke]) -> i32 {
290        let mut raw_strokes = Vec::new();
291
292        for stroke in strokes {
293            if let Ok(raw_stroke) = T::try_from(*stroke) {
294                raw_strokes.push(raw_stroke)
295            }
296        }
297
298        let ptr = raw_strokes.as_ptr();
299        let len = match u32::try_from(raw_strokes.len()) {
300            Ok(l) => l,
301            Err(_) => u32::MAX,
302        };
303
304        unsafe { raw::interception_send(self.ctx, device, std::mem::transmute(ptr), len) }
305    }
306
307    pub fn receive(&self, device: Device, strokes: &mut [Stroke]) -> i32 {
308        if is_mouse(device) {
309            self.receive_internal::<raw::InterceptionMouseStroke>(device, strokes)
310        } else if is_keyboard(device) {
311            self.receive_internal::<raw::InterceptionKeyStroke>(device, strokes)
312        } else {
313            0
314        }
315    }
316
317    fn receive_internal<T: TryInto<Stroke> + Default + Copy>(
318        &self,
319        device: Device,
320        strokes: &mut [Stroke],
321    ) -> i32 {
322        let mut raw_strokes: Vec<T> = Vec::with_capacity(strokes.len());
323        raw_strokes.resize_with(strokes.len(), Default::default);
324
325        let ptr = raw_strokes.as_ptr();
326        let len = match u32::try_from(raw_strokes.len()) {
327            Ok(l) => l,
328            Err(_) => u32::MAX,
329        };
330
331        let num_read =
332            unsafe { raw::interception_receive(self.ctx, device, std::mem::transmute(ptr), len) };
333
334        let mut num_valid: i32 = 0;
335        for i in 0..num_read {
336            if let Ok(stroke) = raw_strokes[i as usize].try_into() {
337                strokes[num_valid as usize] = stroke;
338                num_valid += 1;
339            }
340        }
341
342        num_valid
343    }
344
345    pub fn get_hardware_id(&self, device: Device, buffer: &mut [u8]) -> u32 {
346        let ptr = buffer.as_mut_ptr();
347        let len = match u32::try_from(buffer.len()) {
348            Ok(l) => l,
349            Err(_) => u32::MAX,
350        };
351
352        unsafe {
353            raw::interception_get_hardware_id(self.ctx, device, std::mem::transmute(ptr), len)
354        }
355    }
356}
357
358impl Drop for Interception {
359    fn drop(&mut self) {
360        unsafe { raw::interception_destroy_context(self.ctx) }
361    }
362}
363
364pub extern "C" fn is_invalid(device: Device) -> bool {
365    unsafe { raw::interception_is_invalid(device) != 0 }
366}
367
368pub extern "C" fn is_keyboard(device: Device) -> bool {
369    unsafe { raw::interception_is_keyboard(device) != 0 }
370}
371
372pub extern "C" fn is_mouse(device: Device) -> bool {
373    unsafe { raw::interception_is_mouse(device) != 0 }
374}