diff --git a/src/client.rs b/src/client.rs index 184170e4a..8f6cb12bb 100644 --- a/src/client.rs +++ b/src/client.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, net::SocketAddr, ops::{Deref, Not}, - sync::{mpsc, Arc, Mutex, RwLock, atomic::AtomicBool}, + sync::{atomic::AtomicBool, mpsc, Arc, Mutex, RwLock}, }; pub use async_trait::async_trait; @@ -864,8 +864,7 @@ impl VideoHandler { #[derive(Default)] pub struct LoginConfigHandler { id: String, - pub is_file_transfer: bool, - pub is_port_forward: bool, + pub conn_type: ConnType, hash: Hash, password: Vec, // remember password for reconnect pub remember: bool, @@ -904,12 +903,10 @@ impl LoginConfigHandler { /// # Arguments /// /// * `id` - id of peer - /// * `is_file_transfer` - Whether the connection is file transfer. - /// * `is_port_forward` - Whether the connection is port forward. - pub fn initialize(&mut self, id: String, is_file_transfer: bool, is_port_forward: bool) { + /// * `conn_type` - Connection type enum. + pub fn initialize(&mut self, id: String, conn_type: ConnType) { self.id = id; - self.is_file_transfer = is_file_transfer; - self.is_port_forward = is_port_forward; + self.conn_type = conn_type; let config = self.load_config(); self.remember = !config.password.is_empty(); self.config = config; @@ -1066,7 +1063,8 @@ impl LoginConfigHandler { /// /// * `ignore_default` - If `true`, ignore the default value of the option. fn get_option_message(&self, ignore_default: bool) -> Option { - if self.is_port_forward || self.is_file_transfer { + if self.conn_type.eq(&ConnType::FILE_TRANSFER) || self.conn_type.eq(&ConnType::PORT_FORWARD) + { return None; } let mut n = 0; @@ -1112,7 +1110,8 @@ impl LoginConfigHandler { } pub fn get_option_message_after_login(&self) -> Option { - if self.is_port_forward || self.is_file_transfer { + if self.conn_type.eq(&ConnType::FILE_TRANSFER) || self.conn_type.eq(&ConnType::PORT_FORWARD) + { return None; } let mut n = 0; @@ -1348,19 +1347,20 @@ impl LoginConfigHandler { version: crate::VERSION.to_string(), ..Default::default() }; - if self.is_file_transfer { - lr.set_file_transfer(FileTransfer { + match self.conn_type { + ConnType::FILE_TRANSFER => lr.set_file_transfer(FileTransfer { dir: self.get_remote_dir(), show_hidden: !self.get_option("remote_show_hidden").is_empty(), ..Default::default() - }); - } else if self.is_port_forward { - lr.set_port_forward(PortForward { + }), + ConnType::PORT_FORWARD => lr.set_port_forward(PortForward { host: self.port_forward.0.clone(), port: self.port_forward.1, ..Default::default() - }); + }), + _ => {} } + let mut msg_out = Message::new(); msg_out.set_login_request(lr); msg_out diff --git a/src/flutter.rs b/src/flutter.rs index 1244e521a..b84e91ce8 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -5,7 +5,7 @@ use std::{ use flutter_rust_bridge::{StreamSink, ZeroCopyBuffer}; -use hbb_common::{bail, config::LocalConfig, message_proto::*, ResultType}; +use hbb_common::{bail, config::LocalConfig, message_proto::*, ResultType, rendezvous_proto::ConnType}; use crate::ui_session_interface::{io_loop, InvokeUi, Session}; @@ -74,9 +74,8 @@ impl InvokeUi for FlutterHandler { ); } - fn set_display(&self, x: i32, y: i32, w: i32, h: i32) { - // todo!() - } + /// unused in flutter, use switch_display or set_peer_info + fn set_display(&self, _x: i32, _y: i32, _w: i32, _h: i32) {} fn update_privacy_mode(&self) { self.push_event("update_privacy_mode", [].into()); @@ -86,9 +85,7 @@ impl InvokeUi for FlutterHandler { self.push_event("permission", vec![(name, &value.to_string())]); } - fn close_success(&self) { - // todo!() - } + fn close_success(&self) {} fn update_quality_status(&self, status: QualityStatus) { const NULL: String = String::new(); @@ -179,9 +176,7 @@ impl InvokeUi for FlutterHandler { ); } - fn adapt_size(&self) { - // todo!() - } + fn adapt_size(&self) {} fn on_rgba(&self, data: &[u8]) { if let Some(stream) = &*self.event_stream.read().unwrap() { @@ -265,27 +260,37 @@ impl InvokeUi for FlutterHandler { /// * `is_file_transfer` - If the session is used for file transfer. /// * `is_port_forward` - If the session is used for port forward. pub fn session_add(id: &str, is_file_transfer: bool, is_port_forward: bool) -> ResultType<()> { - // TODO check same id let session_id = get_session_id(id.to_owned()); LocalConfig::set_remote_id(&session_id); - // TODO close - // Self::close(); - // TODO cmd passwd args let session: Session = Session { id: session_id.clone(), ..Default::default() }; + // TODO rdp + let conn_type = if is_file_transfer { + ConnType::FILE_TRANSFER + } else if is_port_forward { + ConnType::PORT_FORWARD + } else { + ConnType::DEFAULT_CONN + }; + session .lc .write() .unwrap() - .initialize(session_id.clone(), is_file_transfer, is_port_forward); - SESSIONS + .initialize(session_id, conn_type); + + if let Some(same_id_session) = SESSIONS .write() .unwrap() - .insert(id.to_owned(), session.clone()); + .insert(id.to_owned(), session) + { + same_id_session.close(); + } + Ok(()) } @@ -300,10 +305,6 @@ pub fn session_start_(id: &str, event_stream: StreamSink) -> ResultTy *session.event_stream.write().unwrap() = Some(event_stream); let session = session.clone(); std::thread::spawn(move || { - // TODO is_file_transfer is_port_forward - // let is_file_transfer = session.lc.read().unwrap().is_file_transfer; - // let is_port_forward = session.lc.read().unwrap().is_port_forward; - // Connection::start(session, is_file_transfer, is_port_forward); io_loop(session); }); Ok(()) diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 5226416b2..69da5f540 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -190,20 +190,20 @@ pub fn session_toggle_option(id: String, value: String) { } pub fn session_set_image_quality(id: String, value: String) { - if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.set_image_quality(value); + if let Some(session) = SESSIONS.write().unwrap().get_mut(&id) { + session.save_image_quality(value); } } pub fn session_lock_screen(id: String) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.lock_screen(); + session.lock_screen(); } } pub fn session_ctrl_alt_del(id: String) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.ctrl_alt_del(); + session.ctrl_alt_del(); } } @@ -224,13 +224,13 @@ pub fn session_input_key( command: bool, ) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.input_key(&name, down, press, alt, ctrl, shift, command); + session.input_key(&name, down, press, alt, ctrl, shift, command); } } pub fn session_input_string(id: String, value: String) { if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.input_string(&value); + session.input_string(&value); } } @@ -686,7 +686,6 @@ pub fn main_has_hwcodec() -> bool { has_hwcodec() } -// TODO pub fn session_send_mouse(id: String, msg: String) { if let Ok(m) = serde_json::from_str::>(&msg) { let alt = m.get("alt").is_some(); @@ -719,7 +718,7 @@ pub fn session_send_mouse(id: String, msg: String) { } << 3; } if let Some(session) = SESSIONS.read().unwrap().get(&id) { - // session.send_mouse(mask, x, y, alt, ctrl, shift, command); + session.send_mouse(mask, x, y, alt, ctrl, shift, command); } } } diff --git a/src/ui/remote.rs b/src/ui/remote.rs index 4310f64bf..7e2c5cd9c 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -22,14 +22,14 @@ use clipboard::{ cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, get_rx_clip_client, server_clip_file, }; -use enigo::{self}; -use hbb_common::{allow_err, log, message_proto::*}; + +use hbb_common::{allow_err, log, message_proto::*, rendezvous_proto::ConnType}; #[cfg(windows)] use crate::clipboard_file::*; use crate::{ client::*, - ui_session_interface::{InvokeUi, Session}, + ui_session_interface::{InvokeUi, Session, IS_IN}, }; type Video = AssetPtr; @@ -38,9 +38,6 @@ lazy_static::lazy_static! { static ref VIDEO: Arc>> = Default::default(); } -static IS_IN: AtomicBool = AtomicBool::new(false); -static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false); - #[cfg(windows)] static mut IS_ALT_GR: bool = false; @@ -397,255 +394,28 @@ impl sciter::EventHandler for SciterSession { impl SciterSession { pub fn new(cmd: String, id: String, password: String, args: Vec) -> Self { let session: Session = Session { - cmd, + cmd: cmd.clone(), id: id.clone(), password: password.clone(), args, ..Default::default() }; - session.lc.write().unwrap().initialize( - id, - session.is_file_transfer(), - session.is_port_forward(), - ); + + let conn_type = if cmd.eq("--file-transfer") { + ConnType::FILE_TRANSFER + } else if cmd.eq("--port-forward") { + ConnType::PORT_FORWARD + } else if cmd.eq("--rdp") { + ConnType::RDP + } else { + ConnType::DEFAULT_CONN + }; + + session.lc.write().unwrap().initialize(id, conn_type); Self(session) } - // TODO - fn start_keyboard_hook(&'static self) { - if self.is_port_forward() || self.is_file_transfer() { - return; - } - if KEYBOARD_HOOKED.swap(true, Ordering::SeqCst) { - return; - } - log::info!("keyboard hooked"); - let me = self.clone(); - let peer = self.peer_platform(); - let is_win = peer == "Windows"; - #[cfg(windows)] - crate::platform::windows::enable_lowlevel_keyboard(std::ptr::null_mut() as _); - std::thread::spawn(move || { - // This will block. - std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev - use rdev::{EventType::*, *}; - let func = move |evt: Event| { - if !IS_IN.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst) - { - return; - } - let (key, down) = match evt.event_type { - KeyPress(k) => (k, 1), - KeyRelease(k) => (k, 0), - _ => return, - }; - let alt = get_key_state(enigo::Key::Alt); - #[cfg(windows)] - let ctrl = { - let mut tmp = get_key_state(enigo::Key::Control); - unsafe { - if IS_ALT_GR { - if alt || key == Key::AltGr { - if tmp { - tmp = false; - } - } else { - IS_ALT_GR = false; - } - } - } - tmp - }; - #[cfg(not(windows))] - let ctrl = get_key_state(enigo::Key::Control); - let shift = get_key_state(enigo::Key::Shift); - #[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)] - if evt.scan_code & 0x200 != 0 { - unsafe { - IS_ALT_GR = true; - } - return; - } - 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 { - // me.ctrl_alt_del(); // TODO - return; - } - 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 => { - return; - } - 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, - }; - let mut key_event = KeyEvent::new(); - if let Some(k) = control_key { - key_event.set_control_key(k); - } else { - let mut chr = match evt.name { - Some(ref s) => { - if s.len() <= 2 { - // exclude chinese characters - s.chars().next().unwrap_or('\0') - } else { - '\0' - } - } - _ => '\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::BackSlash => '\\', - Key::Minus => '-', - Key::Equal => '=', - Key::BackQuote => '`', - _ => '\0', - } - } - if chr != '\0' { - if chr == 'l' && is_win && command { - // me.lock_screen(); // TODO - return; - } - key_event.set_chr(chr as _); - } else { - log::error!("Unknown key {:?}", evt); - return; - } - } - // me.key_down_or_up(down, key_event, alt, ctrl, shift, command); // TODO - }; - if let Err(error) = rdev::listen(func) { - log::error!("rdev: {:?}", error); - } - }); - } - - // TODO fn get_custom_image_quality(&mut self) -> Value { let mut v = Value::array(0); for x in self.lc.read().unwrap().custom_image_quality.iter() { @@ -654,7 +424,6 @@ impl SciterSession { v } - // TODO fn supported_hwcodec(&self) -> Value { #[cfg(feature = "hwcodec")] { @@ -679,7 +448,6 @@ impl SciterSession { } } - // TODO fn save_size(&mut self, x: i32, y: i32, w: i32, h: i32) { let size = (x, y, w, h); let mut config = self.load_config(); @@ -765,7 +533,6 @@ impl SciterSession { pi } - // close_state sciter only fn save_close_state(&mut self, k: String, v: String) { self.close_state.insert(k, v); } diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index 2f401e26f..c08cc09ce 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -2,7 +2,7 @@ use crate::client::io_loop::Remote; use crate::client::{ check_if_retry, get_key_state, handle_hash, handle_login_from_ui, handle_test_delay, input_os_password, load_config, send_mouse, start_video_audio_threads, FileManager, Key, - LoginConfigHandler, QualityStatus, KEY_MAP, + LoginConfigHandler, QualityStatus, KEY_MAP, SERVER_KEYBOARD_ENABLED, }; use crate::common; @@ -11,15 +11,20 @@ use async_trait::async_trait; use hbb_common::config::{Config, LocalConfig, PeerConfig}; +use hbb_common::rendezvous_proto::ConnType; use hbb_common::tokio::{self, sync::mpsc}; use hbb_common::{allow_err, message_proto::*}; use hbb_common::{fs, get_version_number, log, Stream}; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering, AtomicBool}; use std::sync::{Arc, Mutex, RwLock}; +/// IS_IN KEYBOARD_HOOKED sciter only +pub static IS_IN: AtomicBool = AtomicBool::new(false); +static KEYBOARD_HOOKED: AtomicBool = AtomicBool::new(false); + #[derive(Clone, Default)] pub struct Session { pub cmd: String, @@ -219,7 +224,7 @@ impl Session { self.lc.read().unwrap().info.platform.clone() } - pub fn ctrl_alt_del(&mut self) { + pub fn ctrl_alt_del(&self) { if self.peer_platform() == "Windows" { let mut key_event = KeyEvent::new(); key_event.set_control_key(ControlKey::CtrlAltDel); @@ -339,7 +344,7 @@ impl Session { self.send(Data::Message(msg_out)); } - pub fn lock_screen(&mut self) { + pub fn lock_screen(&self) { let mut key_event = KeyEvent::new(); key_event.set_control_key(ControlKey::LockScreen); self.key_down_or_up(1, key_event, false, false, false, false); @@ -422,7 +427,7 @@ impl Session { } pub fn send_mouse( - &mut self, + &self, mask: i32, x: i32, y: i32, @@ -588,19 +593,16 @@ impl Interface for Session { } } - // TODO flutter fn is_file_transfer(&self) -> bool { - self.cmd == "--file-transfer" + self.lc.read().unwrap().conn_type.eq(&ConnType::FILE_TRANSFER) } - // TODO flutter fn is_port_forward(&self) -> bool { - self.cmd == "--port-forward" || self.is_rdp() + self.lc.read().unwrap().conn_type.eq(&ConnType::PORT_FORWARD) } - // TODO flutter fn is_rdp(&self) -> bool { - self.cmd == "--rdp" + self.lc.read().unwrap().conn_type.eq(&ConnType::RDP) } fn msgbox(&self, msgtype: &str, title: &str, text: &str) { @@ -658,7 +660,8 @@ impl Interface for Session { crate::platform::windows::add_recent_document(&path); } } - // self.start_keyboard_hook(); // TODO + // TODO use event callbcak + self.start_keyboard_hook(); } async fn handle_hash(&mut self, pass: &str, hash: Hash, peer: &mut Stream) { @@ -699,6 +702,242 @@ impl Interface for Session { } } +// TODO use event callbcak +// sciter only +impl Session { + fn start_keyboard_hook(&self) { + if self.is_port_forward() || self.is_file_transfer() { + return; + } + if KEYBOARD_HOOKED.swap(true, Ordering::SeqCst) { + return; + } + log::info!("keyboard hooked"); + let me = self.clone(); + let peer = self.peer_platform(); + let is_win = peer == "Windows"; + #[cfg(windows)] + crate::platform::windows::enable_lowlevel_keyboard(std::ptr::null_mut() as _); + std::thread::spawn(move || { + // This will block. + std::env::set_var("KEYBOARD_ONLY", "y"); // pass to rdev + use rdev::{EventType::*, *}; + let func = move |evt: Event| { + if !IS_IN.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst) + { + return; + } + let (key, down) = match evt.event_type { + KeyPress(k) => (k, 1), + KeyRelease(k) => (k, 0), + _ => return, + }; + let alt = get_key_state(enigo::Key::Alt); + #[cfg(windows)] + let ctrl = { + let mut tmp = get_key_state(enigo::Key::Control); + unsafe { + if IS_ALT_GR { + if alt || key == Key::AltGr { + if tmp { + tmp = false; + } + } else { + IS_ALT_GR = false; + } + } + } + tmp + }; + #[cfg(not(windows))] + let ctrl = get_key_state(enigo::Key::Control); + let shift = get_key_state(enigo::Key::Shift); + #[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)] + if evt.scan_code & 0x200 != 0 { + unsafe { + IS_ALT_GR = true; + } + return; + } + 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 { + me.ctrl_alt_del(); + return; + } + 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 => { + return; + } + 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, + }; + let mut key_event = KeyEvent::new(); + if let Some(k) = control_key { + key_event.set_control_key(k); + } else { + let mut chr = match evt.name { + Some(ref s) => { + if s.len() <= 2 { + // exclude chinese characters + s.chars().next().unwrap_or('\0') + } else { + '\0' + } + } + _ => '\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::BackSlash => '\\', + Key::Minus => '-', + Key::Equal => '=', + Key::BackQuote => '`', + _ => '\0', + } + } + if chr != '\0' { + if chr == 'l' && is_win && command { + me.lock_screen(); + return; + } + key_event.set_chr(chr as _); + } else { + log::error!("Unknown key {:?}", evt); + return; + } + } + me.key_down_or_up(down, key_event, alt, ctrl, shift, command); // TODO + }; + if let Err(error) = rdev::listen(func) { + log::error!("rdev: {:?}", error); + } + }); + } +} + #[tokio::main(flavor = "current_thread")] pub async fn io_loop(handler: Session) { let (sender, mut receiver) = mpsc::unbounded_channel::();