2022-12-08 18:51:20 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-11-16 15:09:29 +08:00
|
|
|
|
use crate::client::get_key_state;
|
|
|
|
|
use crate::common::GrabState;
|
|
|
|
|
#[cfg(feature = "flutter")]
|
2023-01-20 21:03:30 +08:00
|
|
|
|
use crate::flutter::{CUR_SESSION_ID, SESSIONS};
|
2023-03-19 11:57:19 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-04-01 18:09:53 +08:00
|
|
|
|
use crate::platform::windows::{get_char_from_vk, get_unicode_from_vk};
|
2022-12-29 00:02:31 +08:00
|
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
2023-01-20 21:03:30 +08:00
|
|
|
|
use crate::ui::CUR_SESSION;
|
2023-02-16 20:48:42 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
use hbb_common::log;
|
2023-03-19 11:57:19 +08:00
|
|
|
|
use hbb_common::message_proto::*;
|
2023-03-26 21:08:58 +08:00
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
|
|
|
|
use rdev::KeyCode;
|
|
|
|
|
use rdev::{Event, EventType, Key};
|
2022-12-15 23:10:57 +08:00
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
|
|
|
|
use std::sync::atomic::{AtomicBool, Ordering};
|
2022-12-09 21:16:09 +08:00
|
|
|
|
use std::{
|
|
|
|
|
collections::{HashMap, HashSet},
|
2022-12-15 23:10:57 +08:00
|
|
|
|
sync::{Arc, Mutex},
|
2022-12-09 21:16:09 +08:00
|
|
|
|
time::SystemTime,
|
|
|
|
|
};
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2022-12-15 23:10:57 +08:00
|
|
|
|
#[cfg(windows)]
|
2022-12-08 11:31:32 +08:00
|
|
|
|
static mut IS_ALT_GR: bool = false;
|
2022-12-15 23:10:57 +08:00
|
|
|
|
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
const OS_LOWER_WINDOWS: &str = "windows";
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
const OS_LOWER_LINUX: &str = "linux";
|
|
|
|
|
#[allow(dead_code)]
|
|
|
|
|
const OS_LOWER_MACOS: &str = "macos";
|
|
|
|
|
|
2022-12-15 23:10:57 +08:00
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
2022-12-09 21:16:09 +08:00
|
|
|
|
static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false);
|
2022-12-08 11:31:32 +08:00
|
|
|
|
|
2022-11-16 15:09:29 +08:00
|
|
|
|
lazy_static::lazy_static! {
|
|
|
|
|
static ref TO_RELEASE: Arc<Mutex<HashSet<Key>>> = Arc::new(Mutex::new(HashSet::<Key>::new()));
|
|
|
|
|
static ref MODIFIERS_STATE: Mutex<HashMap<Key, bool>> = {
|
|
|
|
|
let mut m = HashMap::new();
|
|
|
|
|
m.insert(Key::ShiftLeft, false);
|
|
|
|
|
m.insert(Key::ShiftRight, false);
|
|
|
|
|
m.insert(Key::ControlLeft, false);
|
|
|
|
|
m.insert(Key::ControlRight, false);
|
|
|
|
|
m.insert(Key::Alt, false);
|
|
|
|
|
m.insert(Key::AltGr, false);
|
|
|
|
|
m.insert(Key::MetaLeft, false);
|
|
|
|
|
m.insert(Key::MetaRight, false);
|
|
|
|
|
Mutex::new(m)
|
|
|
|
|
};
|
2022-12-09 21:16:09 +08:00
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
|
|
|
|
pub mod client {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
use super::*;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
|
|
|
|
pub fn get_keyboard_mode() -> String {
|
2023-01-20 21:03:30 +08:00
|
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
|
if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() {
|
|
|
|
|
return session.get_keyboard_mode();
|
|
|
|
|
}
|
|
|
|
|
#[cfg(feature = "flutter")]
|
|
|
|
|
if let Some(session) = SESSIONS
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.get(&*CUR_SESSION_ID.read().unwrap())
|
|
|
|
|
{
|
|
|
|
|
return session.get_keyboard_mode();
|
2023-01-10 00:40:41 +08:00
|
|
|
|
}
|
2022-12-29 00:02:31 +08:00
|
|
|
|
"legacy".to_string()
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn start_grab_loop() {
|
2022-12-09 22:33:50 +08:00
|
|
|
|
super::start_grab_loop();
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn change_grab_status(state: GrabState) {
|
2022-12-09 21:42:26 +08:00
|
|
|
|
match state {
|
|
|
|
|
GrabState::Ready => {}
|
|
|
|
|
GrabState::Run => {
|
2023-01-27 23:45:07 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
update_grab_get_key_name();
|
2022-12-09 21:42:26 +08:00
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
|
|
|
|
KEYBOARD_HOOKED.swap(true, Ordering::SeqCst);
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2022-12-11 22:22:24 +08:00
|
|
|
|
rdev::enable_grab();
|
2022-12-09 21:42:26 +08:00
|
|
|
|
}
|
|
|
|
|
GrabState::Wait => {
|
|
|
|
|
release_remote_keys();
|
|
|
|
|
|
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
|
|
|
|
KEYBOARD_HOOKED.swap(false, Ordering::SeqCst);
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2022-12-11 22:22:24 +08:00
|
|
|
|
rdev::disable_grab();
|
2022-12-09 21:42:26 +08:00
|
|
|
|
}
|
|
|
|
|
GrabState::Exit => {
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2022-12-11 22:22:24 +08:00
|
|
|
|
rdev::exit_grab_listen();
|
2022-12-09 21:42:26 +08:00
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-06 16:26:27 +08:00
|
|
|
|
pub fn process_event(event: &Event, lock_modes: Option<i32>) -> KeyboardMode {
|
|
|
|
|
let keyboard_mode = get_keyboard_mode_enum();
|
|
|
|
|
|
2022-12-08 11:31:32 +08:00
|
|
|
|
if is_long_press(&event) {
|
2023-02-06 16:26:27 +08:00
|
|
|
|
return keyboard_mode;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2023-02-02 22:27:11 +08:00
|
|
|
|
|
2023-02-06 16:26:27 +08:00
|
|
|
|
for key_event in event_to_key_events(&event, keyboard_mode, lock_modes) {
|
2022-12-15 21:30:49 +08:00
|
|
|
|
send_key_event(&key_event);
|
|
|
|
|
}
|
2023-02-06 16:26:27 +08:00
|
|
|
|
keyboard_mode
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_modifiers_state(
|
|
|
|
|
alt: bool,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
command: bool,
|
|
|
|
|
) -> (bool, bool, bool, bool) {
|
2022-12-08 12:32:34 +08:00
|
|
|
|
let modifiers_lock = MODIFIERS_STATE.lock().unwrap();
|
|
|
|
|
let ctrl = *modifiers_lock.get(&Key::ControlLeft).unwrap()
|
|
|
|
|
|| *modifiers_lock.get(&Key::ControlRight).unwrap()
|
|
|
|
|
|| ctrl;
|
|
|
|
|
let shift = *modifiers_lock.get(&Key::ShiftLeft).unwrap()
|
|
|
|
|
|| *modifiers_lock.get(&Key::ShiftRight).unwrap()
|
|
|
|
|
|| shift;
|
|
|
|
|
let command = *modifiers_lock.get(&Key::MetaLeft).unwrap()
|
|
|
|
|
|| *modifiers_lock.get(&Key::MetaRight).unwrap()
|
|
|
|
|
|| command;
|
2022-12-08 18:51:20 +08:00
|
|
|
|
let alt = *modifiers_lock.get(&Key::Alt).unwrap()
|
|
|
|
|
|| *modifiers_lock.get(&Key::AltGr).unwrap()
|
|
|
|
|
|| alt;
|
|
|
|
|
|
2022-12-08 12:32:34 +08:00
|
|
|
|
(alt, ctrl, shift, command)
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn legacy_modifiers(
|
|
|
|
|
key_event: &mut KeyEvent,
|
|
|
|
|
alt: bool,
|
|
|
|
|
ctrl: bool,
|
|
|
|
|
shift: bool,
|
|
|
|
|
command: bool,
|
|
|
|
|
) {
|
|
|
|
|
if alt
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Alt)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RAlt)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Alt.into());
|
|
|
|
|
}
|
|
|
|
|
if shift
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Shift)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RShift)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Shift.into());
|
|
|
|
|
}
|
|
|
|
|
if ctrl
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Control)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RControl)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Control.into());
|
|
|
|
|
}
|
|
|
|
|
if command
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::Meta)
|
|
|
|
|
&& !crate::is_control_key(&key_event, &ControlKey::RWin)
|
|
|
|
|
{
|
|
|
|
|
key_event.modifiers.push(ControlKey::Meta.into());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-20 21:03:30 +08:00
|
|
|
|
pub fn event_lock_screen() -> KeyEvent {
|
2022-11-16 15:09:29 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.set_control_key(ControlKey::LockScreen);
|
|
|
|
|
key_event.down = true;
|
|
|
|
|
key_event.mode = KeyboardMode::Legacy.into();
|
2023-01-20 21:03:30 +08:00
|
|
|
|
key_event
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-20 21:03:30 +08:00
|
|
|
|
#[inline]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-01-20 21:03:30 +08:00
|
|
|
|
pub fn lock_screen() {
|
|
|
|
|
send_key_event(&event_lock_screen());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn event_ctrl_alt_del() -> KeyEvent {
|
2022-11-16 15:09:29 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
if get_peer_platform() == "Windows" {
|
|
|
|
|
key_event.set_control_key(ControlKey::CtrlAltDel);
|
|
|
|
|
key_event.down = true;
|
|
|
|
|
} else {
|
|
|
|
|
key_event.set_control_key(ControlKey::Delete);
|
|
|
|
|
legacy_modifiers(&mut key_event, true, true, false, false);
|
|
|
|
|
key_event.press = true;
|
|
|
|
|
}
|
|
|
|
|
key_event.mode = KeyboardMode::Legacy.into();
|
2023-01-20 21:03:30 +08:00
|
|
|
|
key_event
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-01-20 21:03:30 +08:00
|
|
|
|
pub fn ctrl_alt_del() {
|
|
|
|
|
send_key_event(&event_ctrl_alt_del());
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2023-01-27 23:45:07 +08:00
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
pub fn update_grab_get_key_name() {
|
|
|
|
|
match get_keyboard_mode_enum() {
|
2023-02-08 19:17:43 +08:00
|
|
|
|
KeyboardMode::Map => rdev::set_get_key_unicode(false),
|
|
|
|
|
KeyboardMode::Translate => rdev::set_get_key_unicode(true),
|
2023-01-27 23:45:07 +08:00
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 09:48:04 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-02-08 13:31:49 +08:00
|
|
|
|
static mut IS_0X021D_DOWN: bool = false;
|
2023-02-08 09:48:04 +08:00
|
|
|
|
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
static mut IS_LEFT_OPTION_DOWN: bool = false;
|
|
|
|
|
|
2022-12-09 22:33:50 +08:00
|
|
|
|
pub fn start_grab_loop() {
|
2023-03-08 21:00:56 +08:00
|
|
|
|
std::env::set_var("KEYBOARD_ONLY", "y");
|
2022-12-09 21:42:26 +08:00
|
|
|
|
#[cfg(any(target_os = "windows", target_os = "macos"))]
|
|
|
|
|
std::thread::spawn(move || {
|
2022-12-10 12:40:45 +08:00
|
|
|
|
let try_handle_keyboard = move |event: Event, key: Key, is_press: bool| -> Option<Event> {
|
|
|
|
|
// fix #2211:CAPS LOCK don't work
|
|
|
|
|
if key == Key::CapsLock || key == Key::NumLock {
|
|
|
|
|
return Some(event);
|
|
|
|
|
}
|
2023-02-08 09:48:04 +08:00
|
|
|
|
|
2023-02-08 13:31:49 +08:00
|
|
|
|
let mut _keyboard_mode = KeyboardMode::Map;
|
2023-03-21 15:23:48 +08:00
|
|
|
|
let _scan_code = event.position_code;
|
2023-03-25 23:44:20 +08:00
|
|
|
|
let _code = event.platform_code as KeyCode;
|
2023-02-08 13:31:49 +08:00
|
|
|
|
let res = if KEYBOARD_HOOKED.load(Ordering::SeqCst) {
|
|
|
|
|
_keyboard_mode = client::process_event(&event, None);
|
2022-12-10 12:40:45 +08:00
|
|
|
|
if is_press {
|
2023-02-08 13:31:49 +08:00
|
|
|
|
None
|
2022-12-09 21:42:26 +08:00
|
|
|
|
} else {
|
2023-02-08 13:31:49 +08:00
|
|
|
|
Some(event)
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
2022-12-10 12:40:45 +08:00
|
|
|
|
} else {
|
2023-02-08 13:31:49 +08:00
|
|
|
|
Some(event)
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-02-08 19:17:59 +08:00
|
|
|
|
match _scan_code {
|
2023-02-08 13:31:49 +08:00
|
|
|
|
0x1D | 0x021D => rdev::set_modifier(Key::ControlLeft, is_press),
|
|
|
|
|
0xE01D => rdev::set_modifier(Key::ControlRight, is_press),
|
|
|
|
|
0x2A => rdev::set_modifier(Key::ShiftLeft, is_press),
|
|
|
|
|
0x36 => rdev::set_modifier(Key::ShiftRight, is_press),
|
|
|
|
|
0x38 => rdev::set_modifier(Key::Alt, is_press),
|
|
|
|
|
// Right Alt
|
|
|
|
|
0xE038 => rdev::set_modifier(Key::AltGr, is_press),
|
|
|
|
|
0xE05B => rdev::set_modifier(Key::MetaLeft, is_press),
|
|
|
|
|
0xE05C => rdev::set_modifier(Key::MetaRight, is_press),
|
|
|
|
|
_ => {}
|
2022-12-09 21:42:26 +08:00
|
|
|
|
}
|
2023-02-08 13:31:49 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
unsafe {
|
|
|
|
|
// AltGr
|
2023-02-08 19:17:59 +08:00
|
|
|
|
if _scan_code == 0x021D {
|
2023-02-08 13:31:49 +08:00
|
|
|
|
IS_0X021D_DOWN = is_press;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
unsafe {
|
2023-03-25 23:44:20 +08:00
|
|
|
|
if _code == rdev::kVK_Option {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
IS_LEFT_OPTION_DOWN = is_press;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 13:31:49 +08:00
|
|
|
|
return res;
|
2022-12-10 12:40:45 +08:00
|
|
|
|
};
|
|
|
|
|
let func = move |event: Event| match event.event_type {
|
|
|
|
|
EventType::KeyPress(key) => try_handle_keyboard(event, key, true),
|
|
|
|
|
EventType::KeyRelease(key) => try_handle_keyboard(event, key, false),
|
2022-12-09 21:42:26 +08:00
|
|
|
|
_ => Some(event),
|
|
|
|
|
};
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
rdev::set_is_main_thread(false);
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
rdev::set_event_popup(false);
|
2022-12-09 21:42:26 +08:00
|
|
|
|
if let Err(error) = rdev::grab(func) {
|
|
|
|
|
log::error!("rdev Error: {:?}", error)
|
|
|
|
|
}
|
|
|
|
|
});
|
2022-12-08 11:31:32 +08:00
|
|
|
|
|
2022-12-09 21:42:26 +08:00
|
|
|
|
#[cfg(target_os = "linux")]
|
2022-12-11 22:22:24 +08:00
|
|
|
|
if let Err(err) = rdev::start_grab_listen(move |event: Event| match event.event_type {
|
2022-12-09 21:42:26 +08:00
|
|
|
|
EventType::KeyPress(key) | EventType::KeyRelease(key) => {
|
|
|
|
|
if let Key::Unknown(keycode) = key {
|
|
|
|
|
log::error!("rdev get unknown key, keycode is : {:?}", keycode);
|
|
|
|
|
} else {
|
2023-01-10 14:11:49 +08:00
|
|
|
|
client::process_event(&event, None);
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
2022-12-09 21:42:26 +08:00
|
|
|
|
None
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-09 21:42:26 +08:00
|
|
|
|
_ => Some(event),
|
2022-12-11 22:22:24 +08:00
|
|
|
|
}) {
|
|
|
|
|
log::error!("Failed to init rdev grab thread: {:?}", err);
|
|
|
|
|
};
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2022-12-08 11:31:32 +08:00
|
|
|
|
pub fn is_long_press(event: &Event) -> bool {
|
2022-12-08 18:51:20 +08:00
|
|
|
|
let keys = MODIFIERS_STATE.lock().unwrap();
|
2022-12-08 11:31:32 +08:00
|
|
|
|
match event.event_type {
|
|
|
|
|
EventType::KeyPress(k) => {
|
|
|
|
|
if let Some(&state) = keys.get(&k) {
|
|
|
|
|
if state == true {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn release_remote_keys() {
|
|
|
|
|
// todo!: client quit suddenly, how to release keys?
|
2022-12-09 22:33:50 +08:00
|
|
|
|
let to_release = TO_RELEASE.lock().unwrap().clone();
|
|
|
|
|
TO_RELEASE.lock().unwrap().clear();
|
|
|
|
|
for key in to_release {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
let event_type = EventType::KeyRelease(key);
|
|
|
|
|
let event = event_type_to_event(event_type);
|
2023-01-20 21:03:30 +08:00
|
|
|
|
// to-do: BUG
|
|
|
|
|
// Release events should be sent to the corresponding sessions, instead of current session.
|
2023-01-10 14:11:49 +08:00
|
|
|
|
client::process_event(&event, None);
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 18:51:20 +08:00
|
|
|
|
pub fn get_keyboard_mode_enum() -> KeyboardMode {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
match client::get_keyboard_mode().as_str() {
|
|
|
|
|
"map" => KeyboardMode::Map,
|
|
|
|
|
"translate" => KeyboardMode::Translate,
|
2023-03-25 17:47:39 +08:00
|
|
|
|
"legacy" => KeyboardMode::Legacy,
|
|
|
|
|
_ => {
|
2023-04-07 14:46:18 +08:00
|
|
|
|
// Set "map" as default mode if version >= 1.2.0.
|
|
|
|
|
if crate::is_peer_version_ge("1.2.0") {
|
2023-03-25 17:47:39 +08:00
|
|
|
|
KeyboardMode::Map
|
|
|
|
|
} else {
|
|
|
|
|
KeyboardMode::Legacy
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2023-03-29 15:40:05 +08:00
|
|
|
|
#[inline]
|
2023-04-08 20:28:34 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-29 15:40:05 +08:00
|
|
|
|
pub fn is_modifier(key: &rdev::Key) -> bool {
|
|
|
|
|
matches!(
|
|
|
|
|
key,
|
|
|
|
|
Key::ShiftLeft
|
|
|
|
|
| Key::ShiftRight
|
|
|
|
|
| Key::ControlLeft
|
|
|
|
|
| Key::ControlRight
|
|
|
|
|
| Key::MetaLeft
|
|
|
|
|
| Key::MetaRight
|
|
|
|
|
| Key::Alt
|
|
|
|
|
| Key::AltGr
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-08 19:07:24 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
pub fn is_numpad_rdev_key(key: &rdev::Key) -> bool {
|
|
|
|
|
matches!(
|
|
|
|
|
key,
|
|
|
|
|
Key::Kp0
|
|
|
|
|
| Key::Kp1
|
|
|
|
|
| Key::Kp2
|
|
|
|
|
| Key::Kp3
|
|
|
|
|
| Key::Kp4
|
|
|
|
|
| Key::Kp5
|
|
|
|
|
| Key::Kp6
|
|
|
|
|
| Key::Kp7
|
|
|
|
|
| Key::Kp8
|
|
|
|
|
| Key::Kp9
|
|
|
|
|
| Key::KpMinus
|
|
|
|
|
| Key::KpMultiply
|
|
|
|
|
| Key::KpDivide
|
|
|
|
|
| Key::KpPlus
|
|
|
|
|
| Key::KpDecimal
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
pub fn is_letter_rdev_key(key: &rdev::Key) -> bool {
|
|
|
|
|
matches!(
|
|
|
|
|
key,
|
|
|
|
|
Key::KeyA
|
|
|
|
|
| Key::KeyB
|
|
|
|
|
| Key::KeyC
|
|
|
|
|
| Key::KeyD
|
|
|
|
|
| Key::KeyE
|
|
|
|
|
| Key::KeyF
|
|
|
|
|
| Key::KeyG
|
|
|
|
|
| Key::KeyH
|
|
|
|
|
| Key::KeyI
|
|
|
|
|
| Key::KeyJ
|
|
|
|
|
| Key::KeyK
|
|
|
|
|
| Key::KeyL
|
|
|
|
|
| Key::KeyM
|
|
|
|
|
| Key::KeyN
|
|
|
|
|
| Key::KeyO
|
|
|
|
|
| Key::KeyP
|
|
|
|
|
| Key::KeyQ
|
|
|
|
|
| Key::KeyR
|
|
|
|
|
| Key::KeyS
|
|
|
|
|
| Key::KeyT
|
|
|
|
|
| Key::KeyU
|
|
|
|
|
| Key::KeyV
|
|
|
|
|
| Key::KeyW
|
|
|
|
|
| Key::KeyX
|
|
|
|
|
| Key::KeyY
|
|
|
|
|
| Key::KeyZ
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-26 12:21:17 +08:00
|
|
|
|
#[inline]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-26 12:21:17 +08:00
|
|
|
|
fn is_numpad_key(event: &Event) -> bool {
|
2023-04-08 19:07:24 +08:00
|
|
|
|
matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if is_numpad_rdev_key(&key))
|
2023-03-27 12:06:38 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[inline]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-27 12:06:38 +08:00
|
|
|
|
fn is_letter_key(event: &Event) -> bool {
|
2023-04-08 19:07:24 +08:00
|
|
|
|
matches!(event.event_type, EventType::KeyPress(key) | EventType::KeyRelease(key) if is_letter_rdev_key(&key))
|
2023-03-26 12:21:17 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 18:51:20 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-27 12:06:38 +08:00
|
|
|
|
fn parse_add_lock_modes_modifiers(
|
|
|
|
|
key_event: &mut KeyEvent,
|
|
|
|
|
lock_modes: i32,
|
|
|
|
|
is_numpad_key: bool,
|
|
|
|
|
is_letter_key: bool,
|
|
|
|
|
) {
|
2023-01-10 14:11:49 +08:00
|
|
|
|
const CAPS_LOCK: i32 = 1;
|
|
|
|
|
const NUM_LOCK: i32 = 2;
|
|
|
|
|
// const SCROLL_LOCK: i32 = 3;
|
2023-03-27 12:06:38 +08:00
|
|
|
|
if is_letter_key && (lock_modes & (1 << CAPS_LOCK) != 0) {
|
2023-01-10 14:11:49 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::CapsLock.into());
|
|
|
|
|
}
|
2023-03-27 12:06:38 +08:00
|
|
|
|
if is_numpad_key && lock_modes & (1 << NUM_LOCK) != 0 {
|
2023-01-10 14:11:49 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::NumLock.into());
|
|
|
|
|
}
|
|
|
|
|
// if lock_modes & (1 << SCROLL_LOCK) != 0 {
|
|
|
|
|
// key_event.modifiers.push(ControlKey::ScrollLock.into());
|
|
|
|
|
// }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-27 12:06:38 +08:00
|
|
|
|
fn add_lock_modes_modifiers(key_event: &mut KeyEvent, is_numpad_key: bool, is_letter_key: bool) {
|
|
|
|
|
if is_letter_key && get_key_state(enigo::Key::CapsLock) {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::CapsLock.into());
|
|
|
|
|
}
|
2023-03-27 12:06:38 +08:00
|
|
|
|
if is_numpad_key && get_key_state(enigo::Key::NumLock) {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.modifiers.push(ControlKey::NumLock.into());
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2022-12-08 18:51:20 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-12-08 11:31:32 +08:00
|
|
|
|
pub fn convert_numpad_keys(key: Key) -> Key {
|
|
|
|
|
if get_key_state(enigo::Key::NumLock) {
|
|
|
|
|
return key;
|
|
|
|
|
}
|
|
|
|
|
match key {
|
|
|
|
|
Key::Kp0 => Key::Insert,
|
|
|
|
|
Key::KpDecimal => Key::Delete,
|
|
|
|
|
Key::Kp1 => Key::End,
|
|
|
|
|
Key::Kp2 => Key::DownArrow,
|
|
|
|
|
Key::Kp3 => Key::PageDown,
|
|
|
|
|
Key::Kp4 => Key::LeftArrow,
|
|
|
|
|
Key::Kp5 => Key::Clear,
|
|
|
|
|
Key::Kp6 => Key::RightArrow,
|
|
|
|
|
Key::Kp7 => Key::Home,
|
|
|
|
|
Key::Kp8 => Key::UpArrow,
|
|
|
|
|
Key::Kp9 => Key::PageUp,
|
|
|
|
|
_ => key,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn update_modifiers_state(event: &Event) {
|
|
|
|
|
// for mouse
|
|
|
|
|
let mut keys = MODIFIERS_STATE.lock().unwrap();
|
|
|
|
|
match event.event_type {
|
|
|
|
|
EventType::KeyPress(k) => {
|
|
|
|
|
if keys.contains_key(&k) {
|
|
|
|
|
keys.insert(k, true);
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
EventType::KeyRelease(k) => {
|
|
|
|
|
if keys.contains_key(&k) {
|
|
|
|
|
keys.insert(k, false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
_ => {}
|
|
|
|
|
};
|
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2023-02-08 09:48:04 +08:00
|
|
|
|
pub fn event_to_key_events(
|
|
|
|
|
event: &Event,
|
|
|
|
|
keyboard_mode: KeyboardMode,
|
2023-03-27 19:13:29 +08:00
|
|
|
|
_lock_modes: Option<i32>,
|
2023-02-08 09:48:04 +08:00
|
|
|
|
) -> Vec<KeyEvent> {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
let mut key_event = KeyEvent::new();
|
|
|
|
|
update_modifiers_state(event);
|
|
|
|
|
|
|
|
|
|
match event.event_type {
|
|
|
|
|
EventType::KeyPress(key) => {
|
2022-12-09 22:33:50 +08:00
|
|
|
|
TO_RELEASE.lock().unwrap().insert(key);
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
EventType::KeyRelease(key) => {
|
2022-12-09 22:33:50 +08:00
|
|
|
|
TO_RELEASE.lock().unwrap().remove(&key);
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
_ => {}
|
|
|
|
|
}
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2023-02-14 15:42:02 +08:00
|
|
|
|
let mut peer = get_peer_platform().to_lowercase();
|
|
|
|
|
peer.retain(|c| !c.is_whitespace());
|
|
|
|
|
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.mode = keyboard_mode.into();
|
2023-03-27 19:13:29 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
let mut key_events;
|
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
|
let key_events;
|
|
|
|
|
key_events = match keyboard_mode {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
KeyboardMode::Map => match map_keyboard_mode(peer.as_str(), event, key_event) {
|
2023-02-02 22:27:11 +08:00
|
|
|
|
Some(event) => [event].to_vec(),
|
|
|
|
|
None => Vec::new(),
|
|
|
|
|
},
|
2023-02-14 15:42:02 +08:00
|
|
|
|
KeyboardMode::Translate => translate_keyboard_mode(peer.as_str(), event, key_event),
|
2022-12-08 11:31:32 +08:00
|
|
|
|
_ => {
|
2022-12-08 18:51:20 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2022-12-21 11:38:54 +08:00
|
|
|
|
{
|
2023-02-02 22:27:11 +08:00
|
|
|
|
legacy_keyboard_mode(event, key_event)
|
2022-12-21 11:38:54 +08:00
|
|
|
|
}
|
2022-12-21 10:57:41 +08:00
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
2022-12-21 11:38:54 +08:00
|
|
|
|
{
|
2023-02-02 22:27:11 +08:00
|
|
|
|
Vec::new()
|
2022-12-21 11:38:54 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
};
|
2023-02-02 22:27:11 +08:00
|
|
|
|
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-02-02 22:27:11 +08:00
|
|
|
|
if keyboard_mode != KeyboardMode::Translate {
|
2023-03-27 12:06:38 +08:00
|
|
|
|
let is_numpad_key = is_numpad_key(&event);
|
|
|
|
|
let is_letter_key = is_letter_key(&event);
|
2023-02-02 22:27:11 +08:00
|
|
|
|
for key_event in &mut key_events {
|
2023-03-27 19:13:29 +08:00
|
|
|
|
if let Some(lock_modes) = _lock_modes {
|
2023-03-27 12:06:38 +08:00
|
|
|
|
parse_add_lock_modes_modifiers(key_event, lock_modes, is_numpad_key, is_letter_key);
|
2023-02-02 22:27:11 +08:00
|
|
|
|
} else {
|
2023-03-27 12:06:38 +08:00
|
|
|
|
add_lock_modes_modifiers(key_event, is_numpad_key, is_letter_key);
|
2023-02-02 22:27:11 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-10 14:11:49 +08:00
|
|
|
|
}
|
2023-02-02 22:27:11 +08:00
|
|
|
|
key_events
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn event_type_to_event(event_type: EventType) -> Event {
|
|
|
|
|
Event {
|
|
|
|
|
event_type,
|
|
|
|
|
time: SystemTime::now(),
|
2023-02-03 10:41:47 +08:00
|
|
|
|
unicode: None,
|
2023-03-21 14:58:10 +08:00
|
|
|
|
platform_code: 0,
|
|
|
|
|
position_code: 0,
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn send_key_event(key_event: &KeyEvent) {
|
2023-01-20 21:03:30 +08:00
|
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
|
if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() {
|
|
|
|
|
session.send_key_event(key_event);
|
|
|
|
|
}
|
|
|
|
|
#[cfg(feature = "flutter")]
|
|
|
|
|
if let Some(session) = SESSIONS
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.get(&*CUR_SESSION_ID.read().unwrap())
|
|
|
|
|
{
|
|
|
|
|
session.send_key_event(key_event);
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn get_peer_platform() -> String {
|
2023-01-20 21:03:30 +08:00
|
|
|
|
#[cfg(not(any(feature = "flutter", feature = "cli")))]
|
|
|
|
|
if let Some(session) = CUR_SESSION.lock().unwrap().as_ref() {
|
|
|
|
|
return session.peer_platform();
|
|
|
|
|
}
|
|
|
|
|
#[cfg(feature = "flutter")]
|
|
|
|
|
if let Some(session) = SESSIONS
|
|
|
|
|
.read()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.get(&*CUR_SESSION_ID.read().unwrap())
|
|
|
|
|
{
|
|
|
|
|
return session.peer_platform();
|
2023-01-10 00:40:41 +08:00
|
|
|
|
}
|
2022-12-29 00:02:31 +08:00
|
|
|
|
"Windows".to_string()
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
|
2022-12-08 18:51:20 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-02-02 22:27:11 +08:00
|
|
|
|
pub fn legacy_keyboard_mode(event: &Event, mut key_event: KeyEvent) -> Vec<KeyEvent> {
|
|
|
|
|
let mut events = Vec::new();
|
2022-12-08 11:31:32 +08:00
|
|
|
|
// legacy mode(0): Generate characters locally, look for keycode on other side.
|
|
|
|
|
let (mut key, down_or_up) = match event.event_type {
|
|
|
|
|
EventType::KeyPress(key) => (key, true),
|
|
|
|
|
EventType::KeyRelease(key) => (key, false),
|
|
|
|
|
_ => {
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
2022-12-29 00:02:31 +08:00
|
|
|
|
};
|
2022-12-08 11:31:32 +08:00
|
|
|
|
|
|
|
|
|
let peer = get_peer_platform();
|
|
|
|
|
let is_win = peer == "Windows";
|
|
|
|
|
if is_win {
|
|
|
|
|
key = convert_numpad_keys(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let alt = get_key_state(enigo::Key::Alt);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let ctrl = {
|
|
|
|
|
let mut tmp = get_key_state(enigo::Key::Control) || get_key_state(enigo::Key::RightControl);
|
|
|
|
|
unsafe {
|
|
|
|
|
if IS_ALT_GR {
|
|
|
|
|
if alt || key == Key::AltGr {
|
|
|
|
|
if tmp {
|
|
|
|
|
tmp = false;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
} else {
|
|
|
|
|
IS_ALT_GR = false;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
tmp
|
|
|
|
|
};
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
let ctrl = get_key_state(enigo::Key::Control) || get_key_state(enigo::Key::RightControl);
|
|
|
|
|
let shift = get_key_state(enigo::Key::Shift) || get_key_state(enigo::Key::RightShift);
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
|
let command = crate::platform::windows::get_win_key_state();
|
|
|
|
|
#[cfg(not(windows))]
|
|
|
|
|
let command = get_key_state(enigo::Key::Meta);
|
|
|
|
|
let control_key = match key {
|
|
|
|
|
Key::Alt => Some(ControlKey::Alt),
|
|
|
|
|
Key::AltGr => Some(ControlKey::RAlt),
|
|
|
|
|
Key::Backspace => Some(ControlKey::Backspace),
|
|
|
|
|
Key::ControlLeft => {
|
|
|
|
|
// when pressing AltGr, an extra VK_LCONTROL with a special
|
|
|
|
|
// scancode with bit 9 set is sent, let's ignore this.
|
|
|
|
|
#[cfg(windows)]
|
2023-03-21 15:23:48 +08:00
|
|
|
|
if (event.position_code >> 8) == 0xE0 {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
unsafe {
|
|
|
|
|
IS_ALT_GR = true;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
Some(ControlKey::Control)
|
|
|
|
|
}
|
|
|
|
|
Key::ControlRight => Some(ControlKey::RControl),
|
|
|
|
|
Key::DownArrow => Some(ControlKey::DownArrow),
|
|
|
|
|
Key::Escape => Some(ControlKey::Escape),
|
|
|
|
|
Key::F1 => Some(ControlKey::F1),
|
|
|
|
|
Key::F10 => Some(ControlKey::F10),
|
|
|
|
|
Key::F11 => Some(ControlKey::F11),
|
|
|
|
|
Key::F12 => Some(ControlKey::F12),
|
|
|
|
|
Key::F2 => Some(ControlKey::F2),
|
|
|
|
|
Key::F3 => Some(ControlKey::F3),
|
|
|
|
|
Key::F4 => Some(ControlKey::F4),
|
|
|
|
|
Key::F5 => Some(ControlKey::F5),
|
|
|
|
|
Key::F6 => Some(ControlKey::F6),
|
|
|
|
|
Key::F7 => Some(ControlKey::F7),
|
|
|
|
|
Key::F8 => Some(ControlKey::F8),
|
|
|
|
|
Key::F9 => Some(ControlKey::F9),
|
|
|
|
|
Key::LeftArrow => Some(ControlKey::LeftArrow),
|
|
|
|
|
Key::MetaLeft => Some(ControlKey::Meta),
|
|
|
|
|
Key::MetaRight => Some(ControlKey::RWin),
|
|
|
|
|
Key::Return => Some(ControlKey::Return),
|
|
|
|
|
Key::RightArrow => Some(ControlKey::RightArrow),
|
|
|
|
|
Key::ShiftLeft => Some(ControlKey::Shift),
|
|
|
|
|
Key::ShiftRight => Some(ControlKey::RShift),
|
|
|
|
|
Key::Space => Some(ControlKey::Space),
|
|
|
|
|
Key::Tab => Some(ControlKey::Tab),
|
|
|
|
|
Key::UpArrow => Some(ControlKey::UpArrow),
|
|
|
|
|
Key::Delete => {
|
|
|
|
|
if is_win && ctrl && alt {
|
|
|
|
|
client::ctrl_alt_del();
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
Some(ControlKey::Delete)
|
|
|
|
|
}
|
|
|
|
|
Key::Apps => Some(ControlKey::Apps),
|
|
|
|
|
Key::Cancel => Some(ControlKey::Cancel),
|
|
|
|
|
Key::Clear => Some(ControlKey::Clear),
|
|
|
|
|
Key::Kana => Some(ControlKey::Kana),
|
|
|
|
|
Key::Hangul => Some(ControlKey::Hangul),
|
|
|
|
|
Key::Junja => Some(ControlKey::Junja),
|
|
|
|
|
Key::Final => Some(ControlKey::Final),
|
|
|
|
|
Key::Hanja => Some(ControlKey::Hanja),
|
|
|
|
|
Key::Hanji => Some(ControlKey::Hanja),
|
|
|
|
|
Key::Convert => Some(ControlKey::Convert),
|
|
|
|
|
Key::Print => Some(ControlKey::Print),
|
|
|
|
|
Key::Select => Some(ControlKey::Select),
|
|
|
|
|
Key::Execute => Some(ControlKey::Execute),
|
|
|
|
|
Key::PrintScreen => Some(ControlKey::Snapshot),
|
|
|
|
|
Key::Help => Some(ControlKey::Help),
|
|
|
|
|
Key::Sleep => Some(ControlKey::Sleep),
|
|
|
|
|
Key::Separator => Some(ControlKey::Separator),
|
|
|
|
|
Key::KpReturn => Some(ControlKey::NumpadEnter),
|
|
|
|
|
Key::Kp0 => Some(ControlKey::Numpad0),
|
|
|
|
|
Key::Kp1 => Some(ControlKey::Numpad1),
|
|
|
|
|
Key::Kp2 => Some(ControlKey::Numpad2),
|
|
|
|
|
Key::Kp3 => Some(ControlKey::Numpad3),
|
|
|
|
|
Key::Kp4 => Some(ControlKey::Numpad4),
|
|
|
|
|
Key::Kp5 => Some(ControlKey::Numpad5),
|
|
|
|
|
Key::Kp6 => Some(ControlKey::Numpad6),
|
|
|
|
|
Key::Kp7 => Some(ControlKey::Numpad7),
|
|
|
|
|
Key::Kp8 => Some(ControlKey::Numpad8),
|
|
|
|
|
Key::Kp9 => Some(ControlKey::Numpad9),
|
|
|
|
|
Key::KpDivide => Some(ControlKey::Divide),
|
|
|
|
|
Key::KpMultiply => Some(ControlKey::Multiply),
|
|
|
|
|
Key::KpDecimal => Some(ControlKey::Decimal),
|
|
|
|
|
Key::KpMinus => Some(ControlKey::Subtract),
|
|
|
|
|
Key::KpPlus => Some(ControlKey::Add),
|
|
|
|
|
Key::CapsLock | Key::NumLock | Key::ScrollLock => {
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
Key::Home => Some(ControlKey::Home),
|
|
|
|
|
Key::End => Some(ControlKey::End),
|
|
|
|
|
Key::Insert => Some(ControlKey::Insert),
|
|
|
|
|
Key::PageUp => Some(ControlKey::PageUp),
|
|
|
|
|
Key::PageDown => Some(ControlKey::PageDown),
|
|
|
|
|
Key::Pause => Some(ControlKey::Pause),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
if let Some(k) = control_key {
|
|
|
|
|
key_event.set_control_key(k);
|
|
|
|
|
} else {
|
2023-02-08 09:48:04 +08:00
|
|
|
|
let name = event
|
|
|
|
|
.unicode
|
|
|
|
|
.as_ref()
|
|
|
|
|
.and_then(|unicode| unicode.name.clone());
|
2023-02-03 10:41:47 +08:00
|
|
|
|
let mut chr = match &name {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
Some(ref s) => {
|
|
|
|
|
if s.len() <= 2 {
|
|
|
|
|
// exclude chinese characters
|
|
|
|
|
s.chars().next().unwrap_or('\0')
|
|
|
|
|
} else {
|
|
|
|
|
'\0'
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
_ => '\0',
|
|
|
|
|
};
|
|
|
|
|
if chr == '·' {
|
|
|
|
|
// special for Chinese
|
|
|
|
|
chr = '`';
|
|
|
|
|
}
|
|
|
|
|
if chr == '\0' {
|
|
|
|
|
chr = match key {
|
|
|
|
|
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::Num0 => '0',
|
|
|
|
|
Key::KeyA => 'a',
|
|
|
|
|
Key::KeyB => 'b',
|
|
|
|
|
Key::KeyC => 'c',
|
|
|
|
|
Key::KeyD => 'd',
|
|
|
|
|
Key::KeyE => 'e',
|
|
|
|
|
Key::KeyF => 'f',
|
|
|
|
|
Key::KeyG => 'g',
|
|
|
|
|
Key::KeyH => 'h',
|
|
|
|
|
Key::KeyI => 'i',
|
|
|
|
|
Key::KeyJ => 'j',
|
|
|
|
|
Key::KeyK => 'k',
|
|
|
|
|
Key::KeyL => 'l',
|
|
|
|
|
Key::KeyM => 'm',
|
|
|
|
|
Key::KeyN => 'n',
|
|
|
|
|
Key::KeyO => 'o',
|
|
|
|
|
Key::KeyP => 'p',
|
|
|
|
|
Key::KeyQ => 'q',
|
|
|
|
|
Key::KeyR => 'r',
|
|
|
|
|
Key::KeyS => 's',
|
|
|
|
|
Key::KeyT => 't',
|
|
|
|
|
Key::KeyU => 'u',
|
|
|
|
|
Key::KeyV => 'v',
|
|
|
|
|
Key::KeyW => 'w',
|
|
|
|
|
Key::KeyX => 'x',
|
|
|
|
|
Key::KeyY => 'y',
|
|
|
|
|
Key::KeyZ => 'z',
|
|
|
|
|
Key::Comma => ',',
|
|
|
|
|
Key::Dot => '.',
|
|
|
|
|
Key::SemiColon => ';',
|
|
|
|
|
Key::Quote => '\'',
|
|
|
|
|
Key::LeftBracket => '[',
|
|
|
|
|
Key::RightBracket => ']',
|
|
|
|
|
Key::Slash => '/',
|
|
|
|
|
Key::BackSlash => '\\',
|
|
|
|
|
Key::Minus => '-',
|
|
|
|
|
Key::Equal => '=',
|
|
|
|
|
Key::BackQuote => '`',
|
|
|
|
|
_ => '\0',
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
}
|
|
|
|
|
if chr != '\0' {
|
|
|
|
|
if chr == 'l' && is_win && command {
|
|
|
|
|
client::lock_screen();
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.set_chr(chr as _);
|
|
|
|
|
} else {
|
|
|
|
|
log::error!("Unknown key {:?}", &event);
|
2023-02-02 22:27:11 +08:00
|
|
|
|
return events;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-12-08 12:32:34 +08:00
|
|
|
|
let (alt, ctrl, shift, command) = client::get_modifiers_state(alt, ctrl, shift, command);
|
2022-12-15 21:30:49 +08:00
|
|
|
|
client::legacy_modifiers(&mut key_event, alt, ctrl, shift, command);
|
2022-11-16 15:09:29 +08:00
|
|
|
|
|
2022-12-08 11:31:32 +08:00
|
|
|
|
if down_or_up == true {
|
|
|
|
|
key_event.down = true;
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2023-02-02 22:27:11 +08:00
|
|
|
|
events.push(key_event);
|
|
|
|
|
events
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-03-27 19:13:29 +08:00
|
|
|
|
pub fn map_keyboard_mode(_peer: &str, event: &Event, mut key_event: KeyEvent) -> Option<KeyEvent> {
|
2022-12-15 23:14:33 +08:00
|
|
|
|
match event.event_type {
|
|
|
|
|
EventType::KeyPress(..) => {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.down = true;
|
|
|
|
|
}
|
2022-12-15 23:14:33 +08:00
|
|
|
|
EventType::KeyRelease(..) => {
|
2022-12-08 11:31:32 +08:00
|
|
|
|
key_event.down = false;
|
|
|
|
|
}
|
2022-12-15 21:30:49 +08:00
|
|
|
|
_ => return None,
|
2022-12-08 11:31:32 +08:00
|
|
|
|
};
|
2022-12-15 17:16:05 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
let keycode = match _peer {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
OS_LOWER_WINDOWS => {
|
2023-01-10 00:40:41 +08:00
|
|
|
|
// https://github.com/rustdesk/rustdesk/issues/1371
|
2023-01-10 11:09:08 +08:00
|
|
|
|
// Filter scancodes that are greater than 255 and the hight word is not 0xE0.
|
2023-03-21 15:23:48 +08:00
|
|
|
|
if event.position_code > 255 && (event.position_code >> 8) != 0xE0 {
|
2023-01-10 00:40:41 +08:00
|
|
|
|
return None;
|
|
|
|
|
}
|
2023-03-21 15:23:48 +08:00
|
|
|
|
event.position_code
|
2023-01-10 00:40:41 +08:00
|
|
|
|
}
|
2023-02-14 15:42:02 +08:00
|
|
|
|
OS_LOWER_MACOS => {
|
2022-12-29 00:02:31 +08:00
|
|
|
|
if hbb_common::config::LocalConfig::get_kb_layout_type() == "ISO" {
|
2023-03-21 15:23:48 +08:00
|
|
|
|
rdev::win_scancode_to_macos_iso_code(event.position_code)?
|
2022-12-27 16:45:13 +08:00
|
|
|
|
} else {
|
2023-03-21 15:23:48 +08:00
|
|
|
|
rdev::win_scancode_to_macos_code(event.position_code)?
|
2022-12-27 16:45:13 +08:00
|
|
|
|
}
|
2022-12-29 00:02:31 +08:00
|
|
|
|
}
|
2023-03-21 15:23:48 +08:00
|
|
|
|
_ => rdev::win_scancode_to_linux_code(event.position_code)?,
|
2022-12-08 11:31:32 +08:00
|
|
|
|
};
|
2022-12-15 17:16:05 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
let keycode = match _peer {
|
2023-03-22 06:38:42 +08:00
|
|
|
|
OS_LOWER_WINDOWS => rdev::macos_code_to_win_scancode(event.platform_code as _)?,
|
|
|
|
|
OS_LOWER_MACOS => event.platform_code as _,
|
|
|
|
|
_ => rdev::macos_code_to_linux_code(event.platform_code as _)?,
|
2022-12-15 17:16:05 +08:00
|
|
|
|
};
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2023-03-27 19:13:29 +08:00
|
|
|
|
let keycode = match _peer {
|
2023-03-21 14:58:10 +08:00
|
|
|
|
OS_LOWER_WINDOWS => rdev::linux_code_to_win_scancode(event.position_code as _)?,
|
2023-02-14 15:42:02 +08:00
|
|
|
|
OS_LOWER_MACOS => {
|
2022-12-29 00:02:31 +08:00
|
|
|
|
if hbb_common::config::LocalConfig::get_kb_layout_type() == "ISO" {
|
2023-03-21 14:58:10 +08:00
|
|
|
|
rdev::linux_code_to_macos_iso_code(event.position_code as _)?
|
2022-12-27 16:45:13 +08:00
|
|
|
|
} else {
|
2023-03-21 14:58:10 +08:00
|
|
|
|
rdev::linux_code_to_macos_code(event.position_code as _)?
|
2022-12-27 16:45:13 +08:00
|
|
|
|
}
|
2022-12-29 00:02:31 +08:00
|
|
|
|
}
|
2023-03-21 14:58:10 +08:00
|
|
|
|
_ => event.position_code as _,
|
2022-12-15 17:16:05 +08:00
|
|
|
|
};
|
2022-12-21 14:30:24 +08:00
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
|
|
|
let keycode = 0;
|
2022-12-15 17:16:05 +08:00
|
|
|
|
|
2023-03-26 12:57:32 +08:00
|
|
|
|
key_event.set_chr(keycode as _);
|
2022-12-15 21:30:49 +08:00
|
|
|
|
Some(key_event)
|
2022-11-16 15:09:29 +08:00
|
|
|
|
}
|
2022-12-08 11:31:32 +08:00
|
|
|
|
|
2023-03-27 19:13:29 +08:00
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-31 12:13:50 +08:00
|
|
|
|
fn try_fill_unicode(_peer: &str, event: &Event, key_event: &KeyEvent, events: &mut Vec<KeyEvent>) {
|
2023-02-03 10:41:47 +08:00
|
|
|
|
match &event.unicode {
|
|
|
|
|
Some(unicode_info) => {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
if let Some(name) = &unicode_info.name {
|
2023-02-10 09:03:19 +08:00
|
|
|
|
if name.len() > 0 {
|
|
|
|
|
let mut evt = key_event.clone();
|
2023-02-14 15:42:02 +08:00
|
|
|
|
evt.set_seq(name.to_string());
|
2023-04-01 21:35:59 +08:00
|
|
|
|
evt.down = true;
|
2023-02-10 09:03:19 +08:00
|
|
|
|
events.push(evt);
|
|
|
|
|
}
|
2023-02-03 10:41:47 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-20 10:13:06 +08:00
|
|
|
|
None =>
|
|
|
|
|
{
|
2023-03-19 11:57:19 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-03-31 12:13:50 +08:00
|
|
|
|
if _peer == OS_LOWER_LINUX {
|
2023-03-31 11:48:37 +08:00
|
|
|
|
if is_hot_key_modifiers_down() && unsafe { !IS_0X021D_DOWN } {
|
2023-04-01 18:09:53 +08:00
|
|
|
|
if let Some(chr) = get_char_from_vk(event.platform_code as u32) {
|
2023-03-31 11:48:37 +08:00
|
|
|
|
let mut evt = key_event.clone();
|
|
|
|
|
evt.set_seq(chr.to_string());
|
2023-04-01 21:35:59 +08:00
|
|
|
|
evt.down = true;
|
2023-03-31 11:48:37 +08:00
|
|
|
|
events.push(evt);
|
|
|
|
|
}
|
2023-03-19 11:57:19 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-02-03 10:41:47 +08:00
|
|
|
|
}
|
2023-02-08 09:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 18:09:53 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
fn try_file_win2win_hotkey(
|
|
|
|
|
peer: &str,
|
|
|
|
|
event: &Event,
|
|
|
|
|
key_event: &KeyEvent,
|
|
|
|
|
events: &mut Vec<KeyEvent>,
|
|
|
|
|
) {
|
|
|
|
|
if peer == OS_LOWER_WINDOWS && is_hot_key_modifiers_down() && unsafe { !IS_0X021D_DOWN } {
|
2023-04-01 19:30:22 +08:00
|
|
|
|
let mut down = false;
|
2023-04-01 18:09:53 +08:00
|
|
|
|
let win2win_hotkey = match event.event_type {
|
|
|
|
|
EventType::KeyPress(..) => {
|
2023-04-01 19:30:22 +08:00
|
|
|
|
down = true;
|
2023-04-01 18:09:53 +08:00
|
|
|
|
if let Some(unicode) = get_unicode_from_vk(event.platform_code as u32) {
|
|
|
|
|
Some((unicode as u32 & 0x0000FFFF) | (event.platform_code << 16))
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
EventType::KeyRelease(..) => Some(event.platform_code << 16),
|
|
|
|
|
_ => None,
|
|
|
|
|
};
|
|
|
|
|
if let Some(code) = win2win_hotkey {
|
|
|
|
|
let mut evt = key_event.clone();
|
|
|
|
|
evt.set_win2win_hotkey(code);
|
2023-04-01 19:30:22 +08:00
|
|
|
|
evt.down = down;
|
2023-04-01 18:09:53 +08:00
|
|
|
|
events.push(evt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 09:48:04 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
fn is_hot_key_modifiers_down() -> bool {
|
|
|
|
|
if rdev::get_modifier(Key::ControlLeft) || rdev::get_modifier(Key::ControlRight) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if rdev::get_modifier(Key::Alt) || rdev::get_modifier(Key::AltGr) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if rdev::get_modifier(Key::MetaLeft) || rdev::get_modifier(Key::MetaRight) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-22 08:11:41 +08:00
|
|
|
|
#[inline]
|
2023-03-22 20:32:15 +08:00
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
2023-03-22 08:11:41 +08:00
|
|
|
|
fn is_altgr(event: &Event) -> bool {
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
if event.platform_code == 0xFE03 {
|
|
|
|
|
true
|
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-03-22 20:09:02 +08:00
|
|
|
|
if unsafe { IS_0X021D_DOWN } && event.position_code == 0xE038 {
|
|
|
|
|
true
|
2023-03-22 08:11:41 +08:00
|
|
|
|
} else {
|
|
|
|
|
false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-25 18:23:57 +08:00
|
|
|
|
#[inline]
|
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
2023-03-22 08:17:11 +08:00
|
|
|
|
fn is_press(event: &Event) -> bool {
|
|
|
|
|
matches!(event.event_type, EventType::KeyPress(_))
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 11:42:10 +08:00
|
|
|
|
// https://github.com/fufesou/rustdesk/wiki/Keyboard-mode----Translate-Mode
|
2023-02-14 15:42:02 +08:00
|
|
|
|
pub fn translate_keyboard_mode(peer: &str, event: &Event, key_event: KeyEvent) -> Vec<KeyEvent> {
|
2023-02-08 09:48:04 +08:00
|
|
|
|
let mut events: Vec<KeyEvent> = Vec::new();
|
2023-04-01 21:35:59 +08:00
|
|
|
|
|
2023-02-08 19:17:43 +08:00
|
|
|
|
if let Some(unicode_info) = &event.unicode {
|
|
|
|
|
if unicode_info.is_dead {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
if peer != OS_LOWER_MACOS && unsafe { IS_LEFT_OPTION_DOWN } {
|
|
|
|
|
// try clear dead key state
|
|
|
|
|
// rdev::clear_dead_key_state();
|
|
|
|
|
} else {
|
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
#[cfg(not(target_os = "macos"))]
|
2023-02-08 19:17:43 +08:00
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-03-27 19:13:29 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
2023-03-26 07:52:05 +08:00
|
|
|
|
if is_numpad_key(&event) {
|
2023-04-01 18:09:53 +08:00
|
|
|
|
if let Some(evt) = map_keyboard_mode(peer, event, key_event) {
|
2023-03-26 07:52:05 +08:00
|
|
|
|
events.push(evt);
|
|
|
|
|
}
|
|
|
|
|
return events;
|
|
|
|
|
}
|
2023-02-08 19:17:43 +08:00
|
|
|
|
|
2023-03-22 20:09:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
// ignore right option key
|
2023-03-25 23:44:20 +08:00
|
|
|
|
if event.platform_code == rdev::kVK_RightOption as u32 {
|
2023-03-22 20:09:02 +08:00
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-22 20:32:15 +08:00
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
2023-03-22 08:11:41 +08:00
|
|
|
|
if is_altgr(event) {
|
2023-02-14 15:42:02 +08:00
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-08 09:48:04 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
2023-03-22 08:11:41 +08:00
|
|
|
|
if event.position_code == 0x021D {
|
|
|
|
|
return events;
|
2023-02-08 09:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 21:35:59 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
try_file_win2win_hotkey(peer, event, &key_event, &mut events);
|
|
|
|
|
|
2023-03-22 08:17:11 +08:00
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
2023-04-01 21:35:59 +08:00
|
|
|
|
if events.is_empty() && is_press(event) {
|
2023-03-31 11:48:37 +08:00
|
|
|
|
try_fill_unicode(peer, event, &key_event, &mut events);
|
2023-02-08 09:48:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-04-01 21:35:59 +08:00
|
|
|
|
// If AltGr is down, no need to send events other than unicode.
|
2023-02-08 21:50:18 +08:00
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
unsafe {
|
|
|
|
|
if IS_0X021D_DOWN {
|
|
|
|
|
return events;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-14 15:42:02 +08:00
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
if !unsafe { IS_LEFT_OPTION_DOWN } {
|
2023-03-31 12:13:50 +08:00
|
|
|
|
try_fill_unicode(peer, event, &key_event, &mut events);
|
2023-02-14 15:42:02 +08:00
|
|
|
|
}
|
|
|
|
|
|
2023-02-03 10:41:47 +08:00
|
|
|
|
if events.is_empty() {
|
2023-04-01 18:09:53 +08:00
|
|
|
|
if let Some(evt) = map_keyboard_mode(peer, event, key_event) {
|
2023-02-02 22:27:11 +08:00
|
|
|
|
events.push(evt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
events
|
2022-12-15 21:30:49 +08:00
|
|
|
|
}
|
2023-03-29 15:40:05 +08:00
|
|
|
|
|
|
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
|
|
|
|
pub fn keycode_to_rdev_key(keycode: u32) -> Key {
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
|
return rdev::win_key_from_scancode(keycode);
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
|
return rdev::linux_key_from_code(keycode);
|
|
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
|
return rdev::macos_key_from_code(keycode.try_into().unwrap_or_default());
|
|
|
|
|
}
|