x11_input_mirror/
keyboard_and_clicks.rs1use mouse;
2
3use std::io::Read;
4use std::process::{Command, Stdio};
5use std::sync::mpsc::{channel, Receiver, Sender};
6use std::thread::{sleep, spawn};
7use std::time::Duration;
8
9#[derive(Debug)]
10pub enum EventKind {
11 KeyDown,
12 KeyUp,
13 MouseDown,
14 MouseUp,
15}
16
17#[derive(Debug)]
18pub struct Event {
19 pub kind: EventKind,
20 pub code: u8,
22 pub x: u16,
24 pub y: u16,
26}
27
28pub fn spawn_thread(interval_ms: u64) -> Receiver<Event> {
29 use self::EventKind::*;
30 let interval = Duration::from_millis(interval_ms);
31 let (tx, rx) = channel();
32 spawn(move || {
33 let r = Command::new("xinput")
34 .arg("test-xi2")
35 .arg("--root")
36 .stdout(Stdio::piped())
37 .spawn()
38 .unwrap();
39 let mut stdout = r.stdout.unwrap();
40 let mut buf = vec![0u8; 64 * 1024 * 1024];
41 let mut mode = None;
42 loop {
43 let num = stdout.read(&mut buf).unwrap();
44 if num == 0 {
45 sleep(interval);
46 continue;
47 }
48 let lines = String::from_utf8_lossy(&buf[0..num]);
49
50 for line in lines.split('\n') {
51 match mode {
52 None => {
53 if line.starts_with("EVENT type 2") {
54 mode = Some(KeyDown);
55 } else if line.starts_with("EVENT type 3") {
56 mode = Some(KeyUp);
57 } else if line.starts_with("EVENT type 4") {
58 mode = Some(MouseDown);
59 } else if line.starts_with("EVENT type 5") {
60 mode = Some(MouseUp);
61 } else if line.starts_with("EVENT type 15") {
62 mode = Some(MouseDown);
63 } else if line.starts_with("EVENT type 16") {
64 mode = Some(MouseUp);
65 }
66 }
67 Some(KeyDown) => mode = parse_keyboard(&tx, line, KeyDown),
68 Some(KeyUp) => mode = parse_keyboard(&tx, line, KeyUp),
69 Some(MouseDown) => mode = parse_click(&tx, line, MouseDown),
70 Some(MouseUp) => mode = parse_click(&tx, line, MouseUp),
71 }
72 }
73 }
74 });
75 rx
76}
77
78fn parse_keyboard(tx: &Sender<Event>, line: &str, mode: EventKind) -> Option<EventKind> {
79 if line.starts_with(" detail: ") {
80 let num = &line[12..];
81 let num = num.parse::<u8>().unwrap();
82 tx.send(Event {
83 kind: mode,
84 code: num,
85 x: 0,
86 y: 0,
87 }).unwrap();
88 return None;
89 }
90 Some(mode)
91}
92
93fn parse_click(tx: &Sender<Event>, line: &str, mode: EventKind) -> Option<EventKind> {
94 if line.starts_with(" detail: ") {
95 let code = &line[12..];
96 let code = code.parse::<u8>().unwrap();
97 let mouse::Event { x, y } = mouse::get_current_mouse_location();
98 tx.send(Event {
99 kind: mode,
100 code,
101 x,
102 y,
103 }).unwrap();
104 None
105 } else {
106 Some(mode)
107 }
108}