pub use i3stat::i3::I3Button as MouseButton; use x11::xlib; use xcb::x::{self, Drawable, WarpPointer}; use xcb::xtest::FakeInput; use xcb::{Connection, Extension}; // Use `xmodmap -pke` to list key codes #[allow(unused)] #[repr(u8)] pub enum KeyCode { Escape = 9, Num1 = 10, Num2 = 11, Num3 = 12, Num4 = 13, Num5 = 14, Num6 = 15, Num7 = 16, Num8 = 17, Num9 = 18, Num0 = 19, Minus = 20, Equal = 21, BackSpace = 22, Tab = 23, Q = 24, W = 25, E = 26, R = 27, T = 28, Y = 29, U = 30, I = 31, O = 32, P = 33, Bracketleft = 34, Bracketright = 35, Return = 36, ControlL = 37, A = 38, S = 39, D = 40, F = 41, G = 42, H = 43, J = 44, K = 45, L = 46, Semicolon = 47, Apostrophe = 48, Grave = 49, ShiftL = 50, Backslash = 51, Z = 52, X = 53, C = 54, V = 55, B = 56, N = 57, M = 58, Comma = 59, Period = 60, Slash = 61, ShiftR = 62, KpMultiply = 63, AltL = 64, Space = 65, CapsLock = 66, } pub fn x_click(x_display: impl AsRef, button: MouseButton, x: i16, y: i16) { // connect to the X server let (conn, screen_num) = Connection::connect_with_extensions( Some(x_display.as_ref()), &[Extension::Xkb, Extension::Test], &[], ) .unwrap(); // get X's root window and its geometry let setup = conn.get_setup(); let screen = setup.roots().nth(screen_num as usize).unwrap(); let root_window = screen.root(); let root_geometry = conn .wait_for_reply(conn.send_request(&x::GetGeometry { drawable: Drawable::Window(root_window), })) .unwrap(); // move mouse to click location conn.send_and_check_request(&WarpPointer { src_window: root_window, dst_window: root_window, src_x: root_geometry.x(), src_y: root_geometry.y(), src_width: root_geometry.width(), src_height: root_geometry.height(), dst_x: x, dst_y: y, }) .unwrap(); // setup fake button let mut fake_button = FakeInput { r#type: xlib::ButtonPress as _, detail: button as _, time: x::CURRENT_TIME, root: root_window, root_x: x, root_y: y, deviceid: 0, // 0 = none }; // click: button press and release conn.send_and_check_request(&fake_button).unwrap(); fake_button.r#type = xlib::ButtonRelease as _; conn.send_and_check_request(&fake_button).unwrap(); }