use super::xdo::EnigoXdo; use crate::{Key, KeyboardControllable, MouseButton, MouseControllable}; use std::io::Read; use tfc::{traits::*, Context as TFC_Context, Key as TFC_Key}; pub type CustomKeyboard = Box; pub type CustomMouce = Box; /// The main struct for handling the event emitting // #[derive(Default)] pub struct Enigo { xdo: EnigoXdo, is_x11: bool, tfc: Option, custom_keyboard: Option, cutsom_mouse: Option, } impl Enigo { /// Get delay of xdo implementation. pub fn delay(&self) -> u64 { self.xdo.delay() } /// Set delay of xdo implemetation. pub fn set_delay(&mut self, delay: u64) { self.xdo.set_delay(delay) } /// Set custom keyboard. pub fn set_custom_keyboard(&mut self, custom_keyboard: CustomKeyboard) { self.custom_keyboard = Some(custom_keyboard) } /// Set custom mouse. pub fn set_custom_mouse(&mut self, custom_mouse: CustomMouce) { self.cutsom_mouse = Some(custom_mouse) } /// Get custom keyboard. pub fn get_custom_keyboard(&mut self) -> &mut Option { &mut self.custom_keyboard } /// Get custom mouse. pub fn get_custom_mouse(&mut self) -> &mut Option { &mut self.cutsom_mouse } fn tfc_key_down_or_up(&mut self, key: Key, down: bool, up: bool) -> bool { match &mut self.tfc { None => false, Some(tfc) => { if let Key::Layout(chr) = key { if down { if let Err(_) = tfc.unicode_char_down(chr) { return false; } } if up { if let Err(_) = tfc.unicode_char_up(chr) { return false; } } return true; } let key = match convert_to_tfc_key(key) { Some(key) => key, None => { return false; } }; if down { if let Err(_) = tfc.key_down(key) { return false; } }; if up { if let Err(_) = tfc.key_up(key) { return false; } }; return true; } } } } impl Default for Enigo { fn default() -> Self { let is_x11 = "x11" == hbb_common::platform::linux::get_display_server(); Self { is_x11, tfc: if is_x11 { Some(TFC_Context::new().expect("kbd context error")) } else { None }, custom_keyboard: None, cutsom_mouse: None, xdo: EnigoXdo::default(), } } } impl MouseControllable for Enigo { fn as_any(&self) -> &dyn std::any::Any { self } fn as_mut_any(&mut self) -> &mut dyn std::any::Any { self } fn mouse_move_to(&mut self, x: i32, y: i32) { if self.is_x11 { self.xdo.mouse_move_to(x, y); } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_move_to(x, y) } } } fn mouse_move_relative(&mut self, x: i32, y: i32) { if self.is_x11 { self.xdo.mouse_move_relative(x, y); } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_move_relative(x, y) } } } fn mouse_down(&mut self, button: MouseButton) -> crate::ResultType { if self.is_x11 { self.xdo.mouse_down(button) } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_down(button) } else { Ok(()) } } } fn mouse_up(&mut self, button: MouseButton) { if self.is_x11 { self.xdo.mouse_up(button) } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_up(button) } } } fn mouse_click(&mut self, button: MouseButton) { if self.is_x11 { self.xdo.mouse_click(button) } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_click(button) } } } fn mouse_scroll_x(&mut self, length: i32) { if self.is_x11 { self.xdo.mouse_scroll_x(length) } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_scroll_x(length) } } } fn mouse_scroll_y(&mut self, length: i32) { if self.is_x11 { self.xdo.mouse_scroll_y(length) } else { if let Some(mouse) = &mut self.cutsom_mouse { mouse.mouse_scroll_y(length) } } } } fn get_led_state(key: Key) -> bool { let led_file = match key { Key::CapsLock => "/sys/class/leds/input1::capslock/brightness", Key::NumLock => "/sys/class/leds/input1::numlock/brightness", _ => { return false; } }; let status = if let Ok(mut file) = std::fs::File::open(&led_file) { let mut content = String::new(); file.read_to_string(&mut content).ok(); let status = content.trim_end().to_string().parse::().unwrap_or(0); status } else { 0 }; status == 1 } impl KeyboardControllable for Enigo { fn as_any(&self) -> &dyn std::any::Any { self } fn as_mut_any(&mut self) -> &mut dyn std::any::Any { self } fn get_key_state(&mut self, key: Key) -> bool { if self.is_x11 { self.xdo.get_key_state(key) } else { if let Some(keyboard) = &mut self.custom_keyboard { keyboard.get_key_state(key) } else { get_led_state(key) } } } fn key_sequence(&mut self, sequence: &str) { if self.is_x11 { self.xdo.key_sequence(sequence) } else { if let Some(keyboard) = &mut self.custom_keyboard { keyboard.key_sequence(sequence) } } } fn key_down(&mut self, key: Key) -> crate::ResultType { if self.is_x11 { let has_down = self.tfc_key_down_or_up(key, true, false); if !has_down { self.xdo.key_down(key) } else { Ok(()) } } else { if let Some(keyboard) = &mut self.custom_keyboard { keyboard.key_down(key) } else { Ok(()) } } } fn key_up(&mut self, key: Key) { if self.is_x11 { let has_down = self.tfc_key_down_or_up(key, false, true); if !has_down { self.xdo.key_up(key) } } else { if let Some(keyboard) = &mut self.custom_keyboard { keyboard.key_up(key) } } } fn key_click(&mut self, key: Key) { self.key_down(key).ok(); self.key_up(key); } } fn convert_to_tfc_key(key: Key) -> Option { let key = match key { Key::Alt => TFC_Key::Alt, Key::Backspace => TFC_Key::DeleteOrBackspace, Key::CapsLock => TFC_Key::CapsLock, Key::Control => TFC_Key::Control, Key::Delete => TFC_Key::ForwardDelete, Key::DownArrow => TFC_Key::DownArrow, Key::End => TFC_Key::End, Key::Escape => TFC_Key::Escape, Key::F1 => TFC_Key::F1, Key::F10 => TFC_Key::F10, Key::F11 => TFC_Key::F11, Key::F12 => TFC_Key::F12, Key::F2 => TFC_Key::F2, Key::F3 => TFC_Key::F3, Key::F4 => TFC_Key::F4, Key::F5 => TFC_Key::F5, Key::F6 => TFC_Key::F6, Key::F7 => TFC_Key::F7, Key::F8 => TFC_Key::F8, Key::F9 => TFC_Key::F9, Key::Home => TFC_Key::Home, Key::LeftArrow => TFC_Key::LeftArrow, Key::PageDown => TFC_Key::PageDown, Key::PageUp => TFC_Key::PageUp, Key::Return => TFC_Key::ReturnOrEnter, Key::RightArrow => TFC_Key::RightArrow, Key::Shift => TFC_Key::Shift, Key::Space => TFC_Key::Space, Key::Tab => TFC_Key::Tab, Key::UpArrow => TFC_Key::UpArrow, Key::Numpad0 => TFC_Key::N0, Key::Numpad1 => TFC_Key::N1, Key::Numpad2 => TFC_Key::N2, Key::Numpad3 => TFC_Key::N3, Key::Numpad4 => TFC_Key::N4, Key::Numpad5 => TFC_Key::N5, Key::Numpad6 => TFC_Key::N6, Key::Numpad7 => TFC_Key::N7, Key::Numpad8 => TFC_Key::N8, Key::Numpad9 => TFC_Key::N9, Key::Decimal => TFC_Key::NumpadDecimal, Key::Clear => TFC_Key::NumpadClear, Key::Pause => TFC_Key::PlayPause, Key::Print => TFC_Key::Print, Key::Snapshot => TFC_Key::PrintScreen, Key::Insert => TFC_Key::Insert, Key::Scroll => TFC_Key::ScrollLock, Key::NumLock => TFC_Key::NumLock, Key::RWin => TFC_Key::Meta, Key::Apps => TFC_Key::Apps, Key::Multiply => TFC_Key::NumpadMultiply, Key::Add => TFC_Key::NumpadPlus, Key::Subtract => TFC_Key::NumpadMinus, Key::Divide => TFC_Key::NumpadDivide, Key::Equals => TFC_Key::NumpadEquals, Key::NumpadEnter => TFC_Key::NumpadEnter, Key::RightShift => TFC_Key::RightShift, Key::RightControl => TFC_Key::RightControl, Key::RightAlt => TFC_Key::RightAlt, Key::Command | Key::Super | Key::Windows | Key::Meta => TFC_Key::Meta, _ => { return None; } }; Some(key) }