legacy mode, win, fix layout code simulation

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2023-04-06 17:53:07 +08:00
parent 1bc0dd791e
commit ac74ed1914
3 changed files with 73 additions and 34 deletions

View File

@ -156,7 +156,7 @@ impl MouseControllable for Enigo {
match button { match button {
MouseButton::Back => XBUTTON1 as _, MouseButton::Back => XBUTTON1 as _,
MouseButton::Forward => XBUTTON2 as _, MouseButton::Forward => XBUTTON2 as _,
_ => 0, _ => 0,
}, },
0, 0,
0, 0,
@ -186,7 +186,7 @@ impl MouseControllable for Enigo {
match button { match button {
MouseButton::Back => XBUTTON1 as _, MouseButton::Back => XBUTTON1 as _,
MouseButton::Forward => XBUTTON2 as _, MouseButton::Forward => XBUTTON2 as _,
_ => 0, _ => 0,
}, },
0, 0,
0, 0,
@ -215,7 +215,7 @@ impl KeyboardControllable for Enigo {
fn as_mut_any(&mut self) -> &mut dyn std::any::Any { fn as_mut_any(&mut self) -> &mut dyn std::any::Any {
self self
} }
fn key_sequence(&mut self, sequence: &str) { fn key_sequence(&mut self, sequence: &str) {
let mut buffer = [0; 2]; let mut buffer = [0; 2];
@ -247,15 +247,51 @@ impl KeyboardControllable for Enigo {
} }
fn key_down(&mut self, key: Key) -> crate::ResultType { fn key_down(&mut self, key: Key) -> crate::ResultType {
let code = self.key_to_keycode(key); match &key {
if code == 0 || code == 65535 { Key::Layout(c) => {
return Err("".into()); // to-do: dup code
} // https://github.com/rustdesk/rustdesk/blob/1bc0dd791ed8344997024dc46626bd2ca7df73d2/src/server/input_service.rs#L1348
let res = keybd_event(0, code, 0); let code = self.get_layoutdependent_keycode(*c);
if res == 0 { if code as u16 != 0xFFFF {
let err = get_error(); let vk = code & 0x00FF;
if !err.is_empty() { let flag = code >> 8;
return Err(err.into()); let modifiers = [Key::Shift, Key::Control, Key::Alt];
let mod_len = modifiers.len();
for pos in 0..mod_len {
if flag & (0x0001 << pos) != 0 {
self.key_down(modifiers[pos])?;
}
}
let res = keybd_event(0, vk, 0);
let err = if res == 0 { get_error() } else { "".to_owned() };
for pos in 0..mod_len {
let rpos = mod_len - 1 - pos;
if flag & (0x0001 << rpos) != 0 {
self.key_up(modifiers[pos]);
}
}
if !err.is_empty() {
return Err(err.into());
}
} else {
return Err(format!("Failed to get keycode of {}", c).into());
}
}
_ => {
let code = self.key_to_keycode(key);
if code == 0 || code == 65535 {
return Err("".into());
}
let res = keybd_event(0, code, 0);
if res == 0 {
let err = get_error();
if !err.is_empty() {
return Err(err.into());
}
}
} }
} }
Ok(()) Ok(())
@ -411,30 +447,27 @@ impl Enigo {
Key::RightAlt => EVK_RMENU, Key::RightAlt => EVK_RMENU,
Key::Raw(raw_keycode) => raw_keycode, Key::Raw(raw_keycode) => raw_keycode,
Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()),
Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN, Key::Super | Key::Command | Key::Windows | Key::Meta => EVK_LWIN,
Key::Layout(..) => {
// unreachable
0
}
} }
} }
fn get_layoutdependent_keycode(&self, string: String) -> u16 { fn get_layoutdependent_keycode(&self, chr: char) -> u16 {
// get the first char from the string ignore the rest // NOTE VkKeyScanW uses the current keyboard LAYOUT
// ensure its not a multybyte char // to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout
if let Some(chr) = string.chars().nth(0) { // or load one with LoadKeyboardLayoutW
// NOTE VkKeyScanW uses the current keyboard LAYOUT let current_window_thread_id =
// to specify a LAYOUT use VkKeyScanExW and GetKeyboardLayout unsafe { GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut()) };
// or load one with LoadKeyboardLayoutW unsafe { LAYOUT = GetKeyboardLayout(current_window_thread_id) };
let current_window_thread_id = let keycode_and_shiftstate = unsafe { VkKeyScanExW(chr as _, LAYOUT) };
unsafe { GetWindowThreadProcessId(GetForegroundWindow(), std::ptr::null_mut()) }; if keycode_and_shiftstate == (EVK_DECIMAL as i16) && chr == '.' {
unsafe { LAYOUT = GetKeyboardLayout(current_window_thread_id) }; // a workaround of italian keyboard shift + '.' issue
let keycode_and_shiftstate = unsafe { VkKeyScanExW(chr as _, LAYOUT) }; EVK_PERIOD as _
if keycode_and_shiftstate == (EVK_DECIMAL as i16) && chr == '.' {
// a workaround of italian keyboard shift + '.' issue
EVK_PERIOD as _
} else {
keycode_and_shiftstate as _
}
} else { } else {
0 keycode_and_shiftstate as _
} }
} }
} }

View File

@ -4,11 +4,15 @@ pub mod linux;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
pub mod macos; pub mod macos;
#[cfg(not(debug_assertions))]
use crate::{config::Config, log}; use crate::{config::Config, log};
#[cfg(not(debug_assertions))]
use std::process::exit; use std::process::exit;
#[cfg(not(debug_assertions))]
static mut GLOBAL_CALLBACK: Option<Box<dyn Fn()>> = None; static mut GLOBAL_CALLBACK: Option<Box<dyn Fn()>> = None;
#[cfg(not(debug_assertions))]
extern "C" fn breakdown_signal_handler(sig: i32) { extern "C" fn breakdown_signal_handler(sig: i32) {
let mut stack = vec![]; let mut stack = vec![];
backtrace::trace(|frame| { backtrace::trace(|frame| {
@ -61,13 +65,13 @@ extern "C" fn breakdown_signal_handler(sig: i32) {
exit(0); exit(0);
} }
pub fn register_breakdown_handler<T>(_callback: T) #[cfg(not(debug_assertions))]
pub fn register_breakdown_handler<T>(callback: T)
where where
T: Fn() + 'static, T: Fn() + 'static,
{ {
#[cfg(not(debug_assertions))]
unsafe { unsafe {
GLOBAL_CALLBACK = Some(Box::new(_callback)); GLOBAL_CALLBACK = Some(Box::new(callback));
libc::signal(libc::SIGSEGV, breakdown_signal_handler as _); libc::signal(libc::SIGSEGV, breakdown_signal_handler as _);
} }
} }

View File

@ -1,5 +1,6 @@
use crate::platform::breakdown_callback; use crate::platform::breakdown_callback;
use hbb_common::log; use hbb_common::log;
#[cfg(not(debug_assertions))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use hbb_common::platform::register_breakdown_handler; use hbb_common::platform::register_breakdown_handler;
@ -39,6 +40,7 @@ pub fn core_main() -> Option<Vec<String>> {
} }
i += 1; i += 1;
} }
#[cfg(not(debug_assertions))]
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
register_breakdown_handler(breakdown_callback); register_breakdown_handler(breakdown_callback);
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]