Skip to main content

openloaf_rdev/linux/
simulate.rs

1use crate::linux::common::{FALSE, TRUE};
2use crate::keycodes::linux::code_from_key;
3use crate::rdev::{Button, EventType, RawKey, SimulateError};
4use std::convert::TryInto;
5use std::os::raw::c_int;
6use std::ptr::null;
7use x11::xlib;
8use x11::xtest;
9
10unsafe fn send_native(event_type: &EventType, display: *mut xlib::Display) -> Option<()> {
11    let res = match event_type {
12        EventType::KeyPress(key) => match key {
13            crate::Key::RawKey(rawkey) => {
14                if let RawKey::LinuxXorgKeycode(keycode) = rawkey {
15                    xtest::XTestFakeKeyEvent(display, *keycode as _, TRUE, 0)
16                } else {
17                    return None;
18                }
19            }
20            _ => {
21                let code = code_from_key(*key)?;
22                xtest::XTestFakeKeyEvent(display, code, TRUE, 0)
23            }
24        },
25        EventType::KeyRelease(key) => match key {
26            crate::Key::RawKey(rawkey) => {
27                if let RawKey::LinuxXorgKeycode(keycode) = rawkey {
28                    xtest::XTestFakeKeyEvent(display, *keycode as _, FALSE, 0)
29                } else {
30                    return None;
31                }
32            }
33            _ => {
34                let code = code_from_key(*key)?;
35                xtest::XTestFakeKeyEvent(display, code, FALSE, 0)
36            }
37        },
38        EventType::ButtonPress(button) => match button {
39            Button::Left => xtest::XTestFakeButtonEvent(display, 1, TRUE, 0),
40            Button::Middle => xtest::XTestFakeButtonEvent(display, 2, TRUE, 0),
41            Button::Right => xtest::XTestFakeButtonEvent(display, 3, TRUE, 0),
42            Button::Unknown(code) => {
43                xtest::XTestFakeButtonEvent(display, (*code).try_into().ok()?, TRUE, 0)
44            }
45        },
46        EventType::ButtonRelease(button) => match button {
47            Button::Left => xtest::XTestFakeButtonEvent(display, 1, FALSE, 0),
48            Button::Middle => xtest::XTestFakeButtonEvent(display, 2, FALSE, 0),
49            Button::Right => xtest::XTestFakeButtonEvent(display, 3, FALSE, 0),
50            Button::Unknown(code) => {
51                xtest::XTestFakeButtonEvent(display, (*code).try_into().ok()?, FALSE, 0)
52            }
53        },
54        EventType::MouseMove { x, y } => {
55            //TODO: replace with clamp if it is stabalized
56            let x = if x.is_finite() {
57                x.min(c_int::max_value().into())
58                    .max(c_int::min_value().into())
59                    .round() as c_int
60            } else {
61                0
62            };
63            let y = if y.is_finite() {
64                y.min(c_int::max_value().into())
65                    .max(c_int::min_value().into())
66                    .round() as c_int
67            } else {
68                0
69            };
70            xtest::XTestFakeMotionEvent(display, 0, x, y, 0)
71            //     xlib::XWarpPointer(display, 0, root, 0, 0, 0, 0, *x as i32, *y as i32);
72        }
73        EventType::Wheel { delta_y, .. } => {
74            let code = if *delta_y > 0 { 4 } else { 5 };
75            xtest::XTestFakeButtonEvent(display, code, TRUE, 0)
76                & xtest::XTestFakeButtonEvent(display, code, FALSE, 0)
77        }
78    };
79    if res == 0 {
80        None
81    } else {
82        Some(())
83    }
84}
85
86pub fn simulate(event_type: &EventType) -> Result<(), SimulateError> {
87    unsafe {
88        let dpy = xlib::XOpenDisplay(null());
89        if dpy.is_null() {
90            return Err(SimulateError);
91        }
92        match send_native(event_type, dpy) {
93            Some(_) => {
94                xlib::XFlush(dpy);
95                xlib::XSync(dpy, 0);
96                xlib::XCloseDisplay(dpy);
97                Ok(())
98            }
99            None => {
100                xlib::XCloseDisplay(dpy);
101                Err(SimulateError)
102            }
103        }
104    }
105}
106
107unsafe fn send_native_char(chr: char, pressed: bool, display: *mut xlib::Display) -> Option<()> {
108    // unuse keycode: F24 -> 194
109    let keycode: u32 = 194;
110
111    // char to keysym
112    let ordinal: u32 = chr.into();
113    let mut keysym = if ordinal < 0x100 {
114        ordinal
115    } else {
116        ordinal | 0x01000000
117    } as libc::c_ulong;
118
119    // remap keycode to keysym
120    x11::xlib::XChangeKeyboardMapping(display, keycode as _, 1, &mut keysym, 1);
121
122    let res = if pressed {
123        xtest::XTestFakeKeyEvent(display, keycode as _, TRUE, 0)
124    } else {
125        xtest::XTestFakeKeyEvent(display, keycode as _, FALSE, 0)
126    };
127
128    if res == 0 {
129        None
130    } else {
131        Some(())
132    }
133}
134
135pub fn simulate_char(chr: char, pressed: bool) -> Result<(), SimulateError> {
136    unsafe {
137        let dpy = xlib::XOpenDisplay(null());
138        if dpy.is_null() {
139            return Err(SimulateError);
140        }
141        match send_native_char(chr, pressed, dpy) {
142            Some(_) => {
143                xlib::XFlush(dpy);
144                xlib::XSync(dpy, 0);
145                xlib::XCloseDisplay(dpy);
146                Ok(())
147            }
148            None => {
149                xlib::XCloseDisplay(dpy);
150                Err(SimulateError)
151            }
152        }
153    }
154}
155
156pub fn simulate_unicode(_unicode: u16) -> Result<(), SimulateError> {
157    Err(SimulateError)
158}