mirror of
https://github.com/ByteAtATime/raycast-linux.git
synced 2025-09-08 15:10:34 +00:00
refactor(snippets): simplify key mapping and state management
This commit replaces the large, brittle `match` statements for key mapping with `lazy_static` `HashMap`s, making the logic declarative and much easier to update.
This commit is contained in:
parent
3054b5bfb1
commit
b1c4693998
1 changed files with 139 additions and 276 deletions
|
@ -1,25 +1,19 @@
|
|||
use crate::clipboard_history::manager::INTERNAL_CLIPBOARD_CHANGE;
|
||||
use anyhow::Result;
|
||||
use anyhow::{Context, Result};
|
||||
use arboard::Clipboard;
|
||||
use enigo::{Enigo, Key as EnigoKey, Keyboard};
|
||||
use lazy_static::lazy_static;
|
||||
use rdev::Key;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{atomic::Ordering, Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use evdev::{uinput::VirtualDevice, KeyCode};
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::collections::HashSet;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::time::Duration;
|
||||
#[cfg(target_os = "linux")]
|
||||
use xkbcommon::xkb;
|
||||
|
||||
lazy_static! {
|
||||
static ref ENIGO: Mutex<Enigo> = Mutex::new(Enigo::new(&enigo::Settings::default()).unwrap());
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum InputEvent {
|
||||
KeyPress(char),
|
||||
|
@ -50,16 +44,20 @@ fn with_clipboard_text<F>(text: &str, paste_action: F) -> Result<()>
|
|||
where
|
||||
F: FnOnce() -> Result<()>,
|
||||
{
|
||||
const CLIPBOARD_PASTE_DELAY: Duration = Duration::from_millis(50);
|
||||
let _guard = InternalClipboardGuard::new();
|
||||
let mut clipboard = Clipboard::new().map_err(|e| anyhow::anyhow!(e))?;
|
||||
|
||||
let mut clipboard = Clipboard::new().context("Failed to initialize clipboard")?;
|
||||
let original_content = clipboard.get_text().ok();
|
||||
|
||||
clipboard.set_text(text)?;
|
||||
thread::sleep(std::time::Duration::from_millis(50));
|
||||
clipboard
|
||||
.set_text(text)
|
||||
.context("Failed to set clipboard text")?;
|
||||
thread::sleep(CLIPBOARD_PASTE_DELAY);
|
||||
|
||||
let paste_result = paste_action();
|
||||
|
||||
thread::sleep(std::time::Duration::from_millis(50));
|
||||
thread::sleep(CLIPBOARD_PASTE_DELAY);
|
||||
|
||||
if let Some(original) = original_content {
|
||||
if let Err(e) = clipboard.set_text(original) {
|
||||
|
@ -72,37 +70,36 @@ where
|
|||
paste_result
|
||||
}
|
||||
|
||||
pub struct RdevInputManager;
|
||||
pub struct RdevInputManager {
|
||||
enigo: Mutex<Enigo>,
|
||||
}
|
||||
|
||||
impl RdevInputManager {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self {
|
||||
enigo: Mutex::new(Enigo::new(&enigo::Settings::default()).unwrap()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputManager for RdevInputManager {
|
||||
fn start_listening(&self, callback: Box<dyn Fn(InputEvent) + Send + Sync>) -> Result<()> {
|
||||
let shift_pressed = Arc::new(Mutex::new(false));
|
||||
let callback = Arc::new(callback);
|
||||
|
||||
let shift_clone_press = shift_pressed.clone();
|
||||
let shift_clone_release = shift_pressed.clone();
|
||||
let callback_clone = callback.clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut shift_pressed = false;
|
||||
let cb = move |event: rdev::Event| match event.event_type {
|
||||
rdev::EventType::KeyPress(key) => {
|
||||
if key == Key::ShiftLeft || key == Key::ShiftRight {
|
||||
*shift_clone_press.lock().unwrap() = true;
|
||||
shift_pressed = true;
|
||||
}
|
||||
let is_shifted = *shift_clone_press.lock().unwrap();
|
||||
if let Some(ch) = key_to_char(&key, is_shifted) {
|
||||
callback_clone(InputEvent::KeyPress(ch));
|
||||
if let Some(ch) = key_to_char(&key, shift_pressed) {
|
||||
callback(InputEvent::KeyPress(ch));
|
||||
}
|
||||
}
|
||||
rdev::EventType::KeyRelease(key) => {
|
||||
if key == Key::ShiftLeft || key == Key::ShiftRight {
|
||||
*shift_clone_release.lock().unwrap() = false;
|
||||
shift_pressed = false;
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
@ -120,7 +117,7 @@ impl InputManager for RdevInputManager {
|
|||
}
|
||||
|
||||
with_clipboard_text(text, || {
|
||||
let mut enigo = ENIGO.lock().unwrap();
|
||||
let mut enigo = self.enigo.lock().unwrap();
|
||||
enigo.key(EnigoKey::Control, enigo::Direction::Press)?;
|
||||
enigo.key(EnigoKey::Unicode('v'), enigo::Direction::Click)?;
|
||||
enigo.key(EnigoKey::Control, enigo::Direction::Release)?;
|
||||
|
@ -129,7 +126,7 @@ impl InputManager for RdevInputManager {
|
|||
}
|
||||
|
||||
fn inject_key_clicks(&self, key: EnigoKey, count: usize) -> Result<()> {
|
||||
let mut enigo = ENIGO.lock().unwrap();
|
||||
let mut enigo = self.enigo.lock().unwrap();
|
||||
for _ in 0..count {
|
||||
enigo.key(key, enigo::Direction::Click)?;
|
||||
}
|
||||
|
@ -143,202 +140,104 @@ pub struct EvdevInputManager {
|
|||
virtual_device: Mutex<VirtualDevice>,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
lazy_static! {
|
||||
static ref EVDEV_CHAR_MAP: HashMap<char, (KeyCode, bool)> = {
|
||||
[
|
||||
('a', (KeyCode::KEY_A, false)), ('b', (KeyCode::KEY_B, false)),
|
||||
('c', (KeyCode::KEY_C, false)), ('d', (KeyCode::KEY_D, false)),
|
||||
('e', (KeyCode::KEY_E, false)), ('f', (KeyCode::KEY_F, false)),
|
||||
('g', (KeyCode::KEY_G, false)), ('h', (KeyCode::KEY_H, false)),
|
||||
('i', (KeyCode::KEY_I, false)), ('j', (KeyCode::KEY_J, false)),
|
||||
('k', (KeyCode::KEY_K, false)), ('l', (KeyCode::KEY_L, false)),
|
||||
('m', (KeyCode::KEY_M, false)), ('n', (KeyCode::KEY_N, false)),
|
||||
('o', (KeyCode::KEY_O, false)), ('p', (KeyCode::KEY_P, false)),
|
||||
('q', (KeyCode::KEY_Q, false)), ('r', (KeyCode::KEY_R, false)),
|
||||
('s', (KeyCode::KEY_S, false)), ('t', (KeyCode::KEY_T, false)),
|
||||
('u', (KeyCode::KEY_U, false)), ('v', (KeyCode::KEY_V, false)),
|
||||
('w', (KeyCode::KEY_W, false)), ('x', (KeyCode::KEY_X, false)),
|
||||
('y', (KeyCode::KEY_Y, false)), ('z', (KeyCode::KEY_Z, false)),
|
||||
('A', (KeyCode::KEY_A, true)), ('B', (KeyCode::KEY_B, true)),
|
||||
('C', (KeyCode::KEY_C, true)), ('D', (KeyCode::KEY_D, true)),
|
||||
('E', (KeyCode::KEY_E, true)), ('F', (KeyCode::KEY_F, true)),
|
||||
('G', (KeyCode::KEY_G, true)), ('H', (KeyCode::KEY_H, true)),
|
||||
('I', (KeyCode::KEY_I, true)), ('J', (KeyCode::KEY_J, true)),
|
||||
('K', (KeyCode::KEY_K, true)), ('L', (KeyCode::KEY_L, true)),
|
||||
('M', (KeyCode::KEY_M, true)), ('N', (KeyCode::KEY_N, true)),
|
||||
('O', (KeyCode::KEY_O, true)), ('P', (KeyCode::KEY_P, true)),
|
||||
('Q', (KeyCode::KEY_Q, true)), ('R', (KeyCode::KEY_R, true)),
|
||||
('S', (KeyCode::KEY_S, true)), ('T', (KeyCode::KEY_T, true)),
|
||||
('U', (KeyCode::KEY_U, true)), ('V', (KeyCode::KEY_V, true)),
|
||||
('W', (KeyCode::KEY_W, true)), ('X', (KeyCode::KEY_X, true)),
|
||||
('Y', (KeyCode::KEY_Y, true)), ('Z', (KeyCode::KEY_Z, true)),
|
||||
('1', (KeyCode::KEY_1, false)), ('2', (KeyCode::KEY_2, false)),
|
||||
('3', (KeyCode::KEY_3, false)), ('4', (KeyCode::KEY_4, false)),
|
||||
('5', (KeyCode::KEY_5, false)), ('6', (KeyCode::KEY_6, false)),
|
||||
('7', (KeyCode::KEY_7, false)), ('8', (KeyCode::KEY_8, false)),
|
||||
('9', (KeyCode::KEY_9, false)), ('0', (KeyCode::KEY_0, false)),
|
||||
('!', (KeyCode::KEY_1, true)), ('@', (KeyCode::KEY_2, true)),
|
||||
('#', (KeyCode::KEY_3, true)), ('$', (KeyCode::KEY_4, true)),
|
||||
('%', (KeyCode::KEY_5, true)), ('^', (KeyCode::KEY_6, true)),
|
||||
('&', (KeyCode::KEY_7, true)), ('*', (KeyCode::KEY_8, true)),
|
||||
('(', (KeyCode::KEY_9, true)), (')', (KeyCode::KEY_0, true)),
|
||||
('-', (KeyCode::KEY_MINUS, false)), ('_', (KeyCode::KEY_MINUS, true)),
|
||||
('=', (KeyCode::KEY_EQUAL, false)), ('+', (KeyCode::KEY_EQUAL, true)),
|
||||
('[', (KeyCode::KEY_LEFTBRACE, false)), ('{', (KeyCode::KEY_LEFTBRACE, true)),
|
||||
(']', (KeyCode::KEY_RIGHTBRACE, false)), ('}', (KeyCode::KEY_RIGHTBRACE, true)),
|
||||
('\\', (KeyCode::KEY_BACKSLASH, false)), ('|', (KeyCode::KEY_BACKSLASH, true)),
|
||||
(';', (KeyCode::KEY_SEMICOLON, false)), (':', (KeyCode::KEY_SEMICOLON, true)),
|
||||
('\'', (KeyCode::KEY_APOSTROPHE, false)), ('"', (KeyCode::KEY_APOSTROPHE, true)),
|
||||
(',', (KeyCode::KEY_COMMA, false)), ('<', (KeyCode::KEY_COMMA, true)),
|
||||
('.', (KeyCode::KEY_DOT, false)), ('>', (KeyCode::KEY_DOT, true)),
|
||||
('/', (KeyCode::KEY_SLASH, false)), ('?', (KeyCode::KEY_SLASH, true)),
|
||||
('`', (KeyCode::KEY_GRAVE, false)), ('~', (KeyCode::KEY_GRAVE, true)),
|
||||
(' ', (KeyCode::KEY_SPACE, false)), ('\n', (KeyCode::KEY_ENTER, false)),
|
||||
('\t', (KeyCode::KEY_TAB, false)),
|
||||
].iter().copied().collect()
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
impl EvdevInputManager {
|
||||
pub fn new() -> Result<Self> {
|
||||
let mut key_codes = HashSet::new();
|
||||
let mut key_codes: std::collections::HashSet<KeyCode> =
|
||||
EVDEV_CHAR_MAP.values().map(|(kc, _)| *kc).collect();
|
||||
key_codes.extend([
|
||||
KeyCode::KEY_LEFTSHIFT,
|
||||
KeyCode::KEY_LEFTCTRL,
|
||||
KeyCode::KEY_V,
|
||||
KeyCode::KEY_ENTER,
|
||||
KeyCode::KEY_TAB,
|
||||
KeyCode::KEY_SPACE,
|
||||
KeyCode::KEY_BACKSPACE,
|
||||
KeyCode::KEY_LEFT,
|
||||
]);
|
||||
|
||||
let text: &str =
|
||||
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()_+-=[]{}\\|;:'\",./<>?`~";
|
||||
for ch in text.chars() {
|
||||
if let Some((key, _)) = Self::char_to_keycode_static(ch) {
|
||||
key_codes.insert(key);
|
||||
}
|
||||
}
|
||||
|
||||
let mut attribute_set = evdev::AttributeSet::new();
|
||||
for key in key_codes {
|
||||
attribute_set.insert(key);
|
||||
}
|
||||
|
||||
let uinput_device = evdev::uinput::VirtualDevice::builder()?
|
||||
let uinput_device = evdev::uinput::VirtualDevice::builder()
|
||||
.context("Failed to get virtual device builder")?
|
||||
.name("Global Automata Text Injection")
|
||||
.with_keys(&attribute_set)?
|
||||
.build()?;
|
||||
.with_keys(&attribute_set)
|
||||
.context("Failed to set keys for virtual device")?
|
||||
.build()
|
||||
.context("Failed to build virtual device")?;
|
||||
|
||||
Ok(Self {
|
||||
virtual_device: Mutex::new(uinput_device),
|
||||
})
|
||||
}
|
||||
|
||||
fn char_to_keycode_static(c: char) -> Option<(KeyCode, bool)> {
|
||||
let (key, shift) = match c {
|
||||
'a' => (KeyCode::KEY_A, false),
|
||||
'b' => (KeyCode::KEY_B, false),
|
||||
'c' => (KeyCode::KEY_C, false),
|
||||
'd' => (KeyCode::KEY_D, false),
|
||||
'e' => (KeyCode::KEY_E, false),
|
||||
'f' => (KeyCode::KEY_F, false),
|
||||
'g' => (KeyCode::KEY_G, false),
|
||||
'h' => (KeyCode::KEY_H, false),
|
||||
'i' => (KeyCode::KEY_I, false),
|
||||
'j' => (KeyCode::KEY_J, false),
|
||||
'k' => (KeyCode::KEY_K, false),
|
||||
'l' => (KeyCode::KEY_L, false),
|
||||
'm' => (KeyCode::KEY_M, false),
|
||||
'n' => (KeyCode::KEY_N, false),
|
||||
'o' => (KeyCode::KEY_O, false),
|
||||
'p' => (KeyCode::KEY_P, false),
|
||||
'q' => (KeyCode::KEY_Q, false),
|
||||
'r' => (KeyCode::KEY_R, false),
|
||||
's' => (KeyCode::KEY_S, false),
|
||||
't' => (KeyCode::KEY_T, false),
|
||||
'u' => (KeyCode::KEY_U, false),
|
||||
'v' => (KeyCode::KEY_V, false),
|
||||
'w' => (KeyCode::KEY_W, false),
|
||||
'x' => (KeyCode::KEY_X, false),
|
||||
'y' => (KeyCode::KEY_Y, false),
|
||||
'z' => (KeyCode::KEY_Z, false),
|
||||
'A' => (KeyCode::KEY_A, true),
|
||||
'B' => (KeyCode::KEY_B, true),
|
||||
'C' => (KeyCode::KEY_C, true),
|
||||
'D' => (KeyCode::KEY_D, true),
|
||||
'E' => (KeyCode::KEY_E, true),
|
||||
'F' => (KeyCode::KEY_F, true),
|
||||
'G' => (KeyCode::KEY_G, true),
|
||||
'H' => (KeyCode::KEY_H, true),
|
||||
'I' => (KeyCode::KEY_I, true),
|
||||
'J' => (KeyCode::KEY_J, true),
|
||||
'K' => (KeyCode::KEY_K, true),
|
||||
'L' => (KeyCode::KEY_L, true),
|
||||
'M' => (KeyCode::KEY_M, true),
|
||||
'N' => (KeyCode::KEY_N, true),
|
||||
'O' => (KeyCode::KEY_O, true),
|
||||
'P' => (KeyCode::KEY_P, true),
|
||||
'Q' => (KeyCode::KEY_Q, true),
|
||||
'R' => (KeyCode::KEY_R, true),
|
||||
'S' => (KeyCode::KEY_S, true),
|
||||
'T' => (KeyCode::KEY_T, true),
|
||||
'U' => (KeyCode::KEY_U, true),
|
||||
'V' => (KeyCode::KEY_V, true),
|
||||
'W' => (KeyCode::KEY_W, true),
|
||||
'X' => (KeyCode::KEY_X, true),
|
||||
'Y' => (KeyCode::KEY_Y, true),
|
||||
'Z' => (KeyCode::KEY_Z, true),
|
||||
'1' => (KeyCode::KEY_1, false),
|
||||
'2' => (KeyCode::KEY_2, false),
|
||||
'3' => (KeyCode::KEY_3, false),
|
||||
'4' => (KeyCode::KEY_4, false),
|
||||
'5' => (KeyCode::KEY_5, false),
|
||||
'6' => (KeyCode::KEY_6, false),
|
||||
'7' => (KeyCode::KEY_7, false),
|
||||
'8' => (KeyCode::KEY_8, false),
|
||||
'9' => (KeyCode::KEY_9, false),
|
||||
'0' => (KeyCode::KEY_0, false),
|
||||
'!' => (KeyCode::KEY_1, true),
|
||||
'@' => (KeyCode::KEY_2, true),
|
||||
'#' => (KeyCode::KEY_3, true),
|
||||
'$' => (KeyCode::KEY_4, true),
|
||||
'%' => (KeyCode::KEY_5, true),
|
||||
'^' => (KeyCode::KEY_6, true),
|
||||
'&' => (KeyCode::KEY_7, true),
|
||||
'*' => (KeyCode::KEY_8, true),
|
||||
'(' => (KeyCode::KEY_9, true),
|
||||
')' => (KeyCode::KEY_0, true),
|
||||
'-' => (KeyCode::KEY_MINUS, false),
|
||||
'_' => (KeyCode::KEY_MINUS, true),
|
||||
'=' => (KeyCode::KEY_EQUAL, false),
|
||||
'+' => (KeyCode::KEY_EQUAL, true),
|
||||
'[' => (KeyCode::KEY_LEFTBRACE, false),
|
||||
'{' => (KeyCode::KEY_LEFTBRACE, true),
|
||||
']' => (KeyCode::KEY_RIGHTBRACE, false),
|
||||
'}' => (KeyCode::KEY_RIGHTBRACE, true),
|
||||
'\\' => (KeyCode::KEY_BACKSLASH, false),
|
||||
'|' => (KeyCode::KEY_BACKSLASH, true),
|
||||
';' => (KeyCode::KEY_SEMICOLON, false),
|
||||
':' => (KeyCode::KEY_SEMICOLON, true),
|
||||
'\'' => (KeyCode::KEY_APOSTROPHE, false),
|
||||
'"' => (KeyCode::KEY_APOSTROPHE, true),
|
||||
',' => (KeyCode::KEY_COMMA, false),
|
||||
'<' => (KeyCode::KEY_COMMA, true),
|
||||
'.' => (KeyCode::KEY_DOT, false),
|
||||
'>' => (KeyCode::KEY_DOT, true),
|
||||
'/' => (KeyCode::KEY_SLASH, false),
|
||||
'?' => (KeyCode::KEY_SLASH, true),
|
||||
'`' => (KeyCode::KEY_GRAVE, false),
|
||||
'~' => (KeyCode::KEY_GRAVE, true),
|
||||
' ' => (KeyCode::KEY_SPACE, false),
|
||||
'\n' => (KeyCode::KEY_ENTER, false),
|
||||
'\t' => (KeyCode::KEY_TAB, false),
|
||||
_ => return None,
|
||||
};
|
||||
Some((key, shift))
|
||||
}
|
||||
|
||||
fn inject_char(&self, device: &mut VirtualDevice, c: char) -> Result<()> {
|
||||
let (key, shift) = match Self::char_to_keycode_static(c) {
|
||||
Some(val) => val,
|
||||
None => return Ok(()),
|
||||
};
|
||||
|
||||
fn send_key_click(&self, device: &mut VirtualDevice, key: KeyCode) -> Result<()> {
|
||||
let press = evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 1);
|
||||
let release = evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 0);
|
||||
let syn = evdev::InputEvent::new(
|
||||
evdev::EventType::SYNCHRONIZATION.0,
|
||||
evdev::SynchronizationCode::SYN_REPORT.0,
|
||||
0,
|
||||
);
|
||||
|
||||
if shift {
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_LEFTSHIFT.0, 1),
|
||||
syn.clone(),
|
||||
])?;
|
||||
}
|
||||
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 1),
|
||||
syn.clone(),
|
||||
])?;
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 0),
|
||||
syn.clone(),
|
||||
])?;
|
||||
|
||||
if shift {
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_LEFTSHIFT.0, 0),
|
||||
syn.clone(),
|
||||
])?;
|
||||
}
|
||||
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn inject_key_click(&self, device: &mut VirtualDevice, key: KeyCode) -> Result<()> {
|
||||
let syn = evdev::InputEvent::new(
|
||||
evdev::EventType::SYNCHRONIZATION.0,
|
||||
evdev::SynchronizationCode::SYN_REPORT.0,
|
||||
0,
|
||||
);
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 1),
|
||||
syn.clone(),
|
||||
])?;
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, key.0, 0),
|
||||
syn.clone(),
|
||||
])?;
|
||||
|
||||
device.emit(&[press, syn.clone()])?;
|
||||
device.emit(&[release, syn])?;
|
||||
thread::sleep(Duration::from_millis(10));
|
||||
Ok(())
|
||||
}
|
||||
|
@ -397,8 +296,8 @@ impl InputManager for EvdevInputManager {
|
|||
continue;
|
||||
}
|
||||
|
||||
// evdev keycodes are offset by 8 from X11 keycodes
|
||||
let keycode = ev.code() + 8;
|
||||
const XKB_KEYCODE_OFFSET: u16 = 8;
|
||||
let keycode = ev.code() + XKB_KEYCODE_OFFSET;
|
||||
let direction = match ev.value() {
|
||||
0 => xkb::KeyDirection::Up,
|
||||
1 => xkb::KeyDirection::Down,
|
||||
|
@ -408,15 +307,15 @@ impl InputManager for EvdevInputManager {
|
|||
match direction {
|
||||
xkb::KeyDirection::Down => {
|
||||
xkb_state.update_key(keycode.into(), direction);
|
||||
let keysym = xkb_state.key_get_one_sym(keycode.into());
|
||||
if keysym == xkb::keysyms::KEY_BackSpace.into() {
|
||||
|
||||
if xkb_state.key_get_one_sym(keycode.into())
|
||||
== xkb::keysyms::KEY_BackSpace.into()
|
||||
{
|
||||
callback(InputEvent::KeyPress('\u{8}'));
|
||||
} else {
|
||||
let utf8_str = xkb_state.key_get_utf8(keycode.into());
|
||||
if !utf8_str.is_empty() {
|
||||
for ch in utf8_str.chars() {
|
||||
callback(InputEvent::KeyPress(ch));
|
||||
}
|
||||
for ch in utf8_str.chars() {
|
||||
callback(InputEvent::KeyPress(ch));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +328,7 @@ impl InputManager for EvdevInputManager {
|
|||
Err(e) => {
|
||||
if e.kind() != std::io::ErrorKind::WouldBlock {
|
||||
eprintln!(
|
||||
"Error fetching evdev events for device \"{}\": {}",
|
||||
"Error fetching evdev events for \"{}\": {}",
|
||||
device_name, e
|
||||
);
|
||||
break;
|
||||
|
@ -460,17 +359,10 @@ impl InputManager for EvdevInputManager {
|
|||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_LEFTCTRL.0, 1),
|
||||
syn.clone(),
|
||||
])?;
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_V.0, 1),
|
||||
syn.clone(),
|
||||
])?;
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_V.0, 0),
|
||||
syn.clone(),
|
||||
])?;
|
||||
self.send_key_click(&mut device, KeyCode::KEY_V)?;
|
||||
device.emit(&[
|
||||
evdev::InputEvent::new(evdev::EventType::KEY.0, KeyCode::KEY_LEFTCTRL.0, 0),
|
||||
syn.clone(),
|
||||
syn,
|
||||
])?;
|
||||
Ok(())
|
||||
})
|
||||
|
@ -480,74 +372,45 @@ impl InputManager for EvdevInputManager {
|
|||
if let Some(keycode) = Self::enigo_to_evdev(key) {
|
||||
let mut device = self.virtual_device.lock().unwrap();
|
||||
for _ in 0..count {
|
||||
self.inject_key_click(&mut *device, keycode)?;
|
||||
self.send_key_click(&mut *device, keycode)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn key_to_char(key: &Key, is_shifted: bool) -> Option<char> {
|
||||
if let Key::Backspace = key {
|
||||
return Some('\u{8}');
|
||||
}
|
||||
if let Key::Return | Key::KpReturn = key {
|
||||
return Some('\n');
|
||||
}
|
||||
if let Key::Tab = key {
|
||||
return Some('\t');
|
||||
}
|
||||
|
||||
let s = match key {
|
||||
Key::KeyA => "aA",
|
||||
Key::KeyB => "bB",
|
||||
Key::KeyC => "cC",
|
||||
Key::KeyD => "dD",
|
||||
Key::KeyE => "eE",
|
||||
Key::KeyF => "fF",
|
||||
Key::KeyG => "gG",
|
||||
Key::KeyH => "hH",
|
||||
Key::KeyI => "iI",
|
||||
Key::KeyJ => "jJ",
|
||||
Key::KeyK => "kK",
|
||||
Key::KeyL => "lL",
|
||||
Key::KeyM => "mM",
|
||||
Key::KeyN => "nN",
|
||||
Key::KeyO => "oO",
|
||||
Key::KeyP => "pP",
|
||||
Key::KeyQ => "qQ",
|
||||
Key::KeyR => "rR",
|
||||
Key::KeyS => "sS",
|
||||
Key::KeyT => "tT",
|
||||
Key::KeyU => "uU",
|
||||
Key::KeyV => "vV",
|
||||
Key::KeyW => "wW",
|
||||
Key::KeyX => "xX",
|
||||
Key::KeyY => "yY",
|
||||
Key::KeyZ => "zZ",
|
||||
Key::Num0 => "0)",
|
||||
Key::Num1 => "1!",
|
||||
Key::Num2 => "2@",
|
||||
Key::Num3 => "3#",
|
||||
Key::Num4 => "4$",
|
||||
Key::Num5 => "5%",
|
||||
Key::Num6 => "6^",
|
||||
Key::Num7 => "7&",
|
||||
Key::Num8 => "8*",
|
||||
Key::Num9 => "9(",
|
||||
Key::Space => " ",
|
||||
Key::Slash => "/?",
|
||||
Key::Dot => ".>",
|
||||
Key::Comma => ",<",
|
||||
Key::Minus => "-_",
|
||||
Key::Equal => "=+",
|
||||
Key::LeftBracket => "[{",
|
||||
Key::RightBracket => "]}",
|
||||
Key::BackSlash => "\\|",
|
||||
Key::SemiColon => ";:",
|
||||
Key::Quote => "'\"",
|
||||
Key::BackQuote => "`~",
|
||||
_ => return None,
|
||||
lazy_static! {
|
||||
static ref RDEV_KEY_MAP: HashMap<Key, (char, char)> = {
|
||||
[
|
||||
(Key::KeyA, ('a', 'A')), (Key::KeyB, ('b', 'B')), (Key::KeyC, ('c', 'C')),
|
||||
(Key::KeyD, ('d', 'D')), (Key::KeyE, ('e', 'E')), (Key::KeyF, ('f', 'F')),
|
||||
(Key::KeyG, ('g', 'G')), (Key::KeyH, ('h', 'H')), (Key::KeyI, ('i', 'I')),
|
||||
(Key::KeyJ, ('j', 'J')), (Key::KeyK, ('k', 'K')), (Key::KeyL, ('l', 'L')),
|
||||
(Key::KeyM, ('m', 'M')), (Key::KeyN, ('n', 'N')), (Key::KeyO, ('o', 'O')),
|
||||
(Key::KeyP, ('p', 'P')), (Key::KeyQ, ('q', 'Q')), (Key::KeyR, ('r', 'R')),
|
||||
(Key::KeyS, ('s', 'S')), (Key::KeyT, ('t', 'T')), (Key::KeyU, ('u', 'U')),
|
||||
(Key::KeyV, ('v', 'V')), (Key::KeyW, ('w', 'W')), (Key::KeyX, ('x', 'X')),
|
||||
(Key::KeyY, ('y', 'Y')), (Key::KeyZ, ('z', 'Z')),
|
||||
(Key::Num0, ('0', ')')), (Key::Num1, ('1', '!')), (Key::Num2, ('2', '@')),
|
||||
(Key::Num3, ('3', '#')), (Key::Num4, ('4', '$')), (Key::Num5, ('5', '%')),
|
||||
(Key::Num6, ('6', '^')), (Key::Num7, ('7', '&')), (Key::Num8, ('8', '*')),
|
||||
(Key::Num9, ('9', '(')),
|
||||
(Key::Space, (' ', ' ')), (Key::Slash, ('/', '?')), (Key::Dot, ('.', '>')),
|
||||
(Key::Comma, (',', '<')), (Key::Minus, ('-', '_')), (Key::Equal, ('=', '+')),
|
||||
(Key::LeftBracket, ('[', '{')), (Key::RightBracket, (']', '}')),
|
||||
(Key::BackSlash, ('\\', '|')), (Key::SemiColon, (';', ':')),
|
||||
(Key::Quote, ('\'', '"')), (Key::BackQuote, ('`', '~')),
|
||||
].iter().copied().collect()
|
||||
};
|
||||
s.chars().nth(if is_shifted { 1 } else { 0 })
|
||||
}
|
||||
|
||||
pub fn key_to_char(key: &Key, is_shifted: bool) -> Option<char> {
|
||||
match key {
|
||||
Key::Backspace => Some('\u{8}'),
|
||||
Key::Return | Key::KpReturn => Some('\n'),
|
||||
Key::Tab => Some('\t'),
|
||||
_ => RDEV_KEY_MAP
|
||||
.get(key)
|
||||
.map(|(c, s)| if is_shifted { *s } else { *c }),
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue