sciter input & conn_type and other InvokeUi impl
This commit is contained in:
parent
2891c1b148
commit
ee83987523
@ -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<u8>, // 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<OptionMessage> {
|
||||
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<OptionMessage> {
|
||||
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
|
||||
|
@ -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<FlutterHandler> = 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<EventToUI>) -> 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(())
|
||||
|
@ -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::<HashMap<String, String>>(&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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
265
src/ui/remote.rs
265
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<video_destination>;
|
||||
@ -38,9 +38,6 @@ lazy_static::lazy_static! {
|
||||
static ref VIDEO: Arc<Mutex<Option<Video>>> = 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<String>) -> Self {
|
||||
let session: Session<SciterHandler> = 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);
|
||||
}
|
||||
|
@ -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<T: InvokeUi> {
|
||||
pub cmd: String,
|
||||
@ -219,7 +224,7 @@ impl<T: InvokeUi> Session<T> {
|
||||
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<T: InvokeUi> Session<T> {
|
||||
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<T: InvokeUi> Session<T> {
|
||||
}
|
||||
|
||||
pub fn send_mouse(
|
||||
&mut self,
|
||||
&self,
|
||||
mask: i32,
|
||||
x: i32,
|
||||
y: i32,
|
||||
@ -588,19 +593,16 @@ impl<T: InvokeUi> Interface for Session<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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<T: InvokeUi> Interface for Session<T> {
|
||||
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<T: InvokeUi> Interface for Session<T> {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use event callbcak
|
||||
// sciter only
|
||||
impl<T: InvokeUi> Session<T> {
|
||||
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<T: InvokeUi>(handler: Session<T>) {
|
||||
let (sender, mut receiver) = mpsc::unbounded_channel::<Data>();
|
||||
|
Loading…
x
Reference in New Issue
Block a user