Remote side has a higher priority on mouse control

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-11-09 15:04:24 +08:00
parent 6bdb69f7bc
commit 60e8dd840f
5 changed files with 72 additions and 25 deletions

View File

@ -1,12 +1,8 @@
use hbb_common::{
anyhow::{self, bail},
tokio, ResultType,
};
use reqwest::blocking::Response; use reqwest::blocking::Response;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use serde_derive::Deserialize;
use serde_json::{Map, Value}; use serde_json::{Map, Value};
#[cfg(feature = "flutter")]
pub mod account; pub mod account;
#[derive(Debug)] #[derive(Debug)]

View File

@ -1,4 +1,5 @@
use super::*; use super::*;
#[cfg(target_os = "linux")]
use crate::common::IS_X11; use crate::common::IS_X11;
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use dispatch::Queue; use dispatch::Queue;
@ -7,6 +8,7 @@ use hbb_common::{config::COMPRESS_LEVEL, get_time, protobuf::EnumOrUnknown};
use rdev::{simulate, EventType, Key as RdevKey}; use rdev::{simulate, EventType, Key as RdevKey};
use std::{ use std::{
convert::TryFrom, convert::TryFrom,
ops::Sub,
sync::atomic::{AtomicBool, Ordering}, sync::atomic::{AtomicBool, Ordering},
time::Instant, time::Instant,
}; };
@ -100,8 +102,16 @@ pub fn new_pos() -> GenericService {
sp sp
} }
fn update_last_cursor_pos(x: i32, y: i32) {
let mut lock = LATEST_CURSOR_POS.lock().unwrap();
if lock.1 .0 != x || lock.1 .1 != y {
(lock.0, lock.1) = (Instant::now(), (x, y))
}
}
fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> { fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> {
if let Some((x, y)) = crate::get_cursor_pos() { if let Some((x, y)) = crate::get_cursor_pos() {
update_last_cursor_pos(x, y);
if state.cursor_pos.0 != x || state.cursor_pos.1 != y { if state.cursor_pos.0 != x || state.cursor_pos.1 != y {
state.cursor_pos = (x, y); state.cursor_pos = (x, y);
let mut msg_out = Message::new(); let mut msg_out = Message::new();
@ -112,7 +122,7 @@ fn run_pos(sp: GenericService, state: &mut StatePos) -> ResultType<()> {
}); });
let exclude = { let exclude = {
let now = get_time(); let now = get_time();
let lock = LATEST_INPUT.lock().unwrap(); let lock = LATEST_INPUT_CURSOR.lock().unwrap();
if now - lock.time < 300 { if now - lock.time < 300 {
lock.conn lock.conn
} else { } else {
@ -170,10 +180,15 @@ lazy_static::lazy_static! {
Arc::new(Mutex::new(Enigo::new())) Arc::new(Mutex::new(Enigo::new()))
}; };
static ref KEYS_DOWN: Arc<Mutex<HashMap<u64, Instant>>> = Default::default(); static ref KEYS_DOWN: Arc<Mutex<HashMap<u64, Instant>>> = Default::default();
static ref LATEST_INPUT: Arc<Mutex<Input>> = Default::default(); static ref LATEST_INPUT_CURSOR: Arc<Mutex<Input>> = Default::default();
static ref LATEST_INPUT_CURSOR_POS: Arc<Mutex<HashMap<i32, (i32, i32)>>> = Default::default();
static ref LATEST_CURSOR_POS: Arc<Mutex<(Instant, (i32, i32))>> = Arc::new(Mutex::new((Instant::now().sub(MOUSE_MOVE_PROTECTION_TIMEOUT), (0, 0))));
} }
static EXITING: AtomicBool = AtomicBool::new(false); static EXITING: AtomicBool = AtomicBool::new(false);
const MOUSE_MOVE_PROTECTION_TIMEOUT: Duration = Duration::from_millis(1_000);
const MOUSE_ACTIVE_DISTANCE: i32 = 5;
// mac key input must be run in main thread, otherwise crash on >= osx 10.15 // mac key input must be run in main thread, otherwise crash on >= osx 10.15
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
lazy_static::lazy_static! { lazy_static::lazy_static! {
@ -357,17 +372,43 @@ fn fix_modifiers(modifiers: &[EnumOrUnknown<ControlKey>], en: &mut Enigo, ck: i3
} }
} }
fn is_mouse_active_by_conn(conn: i32) -> bool {
if LATEST_CURSOR_POS.lock().unwrap().0.elapsed() > MOUSE_MOVE_PROTECTION_TIMEOUT {
return true;
}
match LATEST_INPUT_CURSOR_POS.lock().unwrap().get(&conn) {
Some((x, y)) => match crate::get_cursor_pos() {
Some((x2, y2)) => {
(x - x2).abs() < MOUSE_ACTIVE_DISTANCE && (y - y2).abs() < MOUSE_ACTIVE_DISTANCE
}
None => true,
},
None => true,
}
}
fn handle_mouse_(evt: &MouseEvent, conn: i32) { fn handle_mouse_(evt: &MouseEvent, conn: i32) {
if EXITING.load(Ordering::SeqCst) { if EXITING.load(Ordering::SeqCst) {
return; return;
} }
if !is_mouse_active_by_conn(conn) {
return;
}
#[cfg(windows)] #[cfg(windows)]
crate::platform::windows::try_change_desktop(); crate::platform::windows::try_change_desktop();
let buttons = evt.mask >> 3; let buttons = evt.mask >> 3;
let evt_type = evt.mask & 0x7; let evt_type = evt.mask & 0x7;
if evt_type == 0 { if evt_type == 0 {
let time = get_time(); let time = get_time();
*LATEST_INPUT.lock().unwrap() = Input { time, conn }; *LATEST_INPUT_CURSOR.lock().unwrap() = Input { time, conn };
LATEST_INPUT_CURSOR_POS
.lock()
.unwrap()
.insert(conn, (evt.x, evt.y));
} }
let mut en = ENIGO.lock().unwrap(); let mut en = ENIGO.lock().unwrap();
#[cfg(not(target_os = "macos"))] #[cfg(not(target_os = "macos"))]
@ -432,7 +473,10 @@ fn handle_mouse_(evt: &MouseEvent, conn: i32) {
// fix shift + scroll(down/up) // fix shift + scroll(down/up)
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
if evt.modifiers.contains(&EnumOrUnknown::new(ControlKey::Shift)){ if evt
.modifiers
.contains(&EnumOrUnknown::new(ControlKey::Shift))
{
x = y; x = y;
y = 0; y = 0;
} }
@ -653,16 +697,16 @@ fn sync_status(evt: &KeyEvent) -> (bool, bool) {
let code = evt.chr(); let code = evt.chr();
let key = rdev::get_win_key(code, 0); let key = rdev::get_win_key(code, 0);
match key { match key {
RdevKey::Home | RdevKey::Home
RdevKey::UpArrow | | RdevKey::UpArrow
RdevKey::PageUp | | RdevKey::PageUp
RdevKey::LeftArrow | | RdevKey::LeftArrow
RdevKey::RightArrow | | RdevKey::RightArrow
RdevKey::End | | RdevKey::End
RdevKey::DownArrow | | RdevKey::DownArrow
RdevKey::PageDown | | RdevKey::PageDown
RdevKey::Insert | | RdevKey::Insert
RdevKey::Delete => en.get_key_state(enigo::Key::NumLock), | RdevKey::Delete => en.get_key_state(enigo::Key::NumLock),
_ => click_numlock, _ => click_numlock,
} }
}; };

View File

@ -1,10 +1,13 @@
use hbb_common::log::{debug, error, info}; use hbb_common::log::debug;
#[cfg(target_os = "linux")]
use hbb_common::log::{error, info};
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
use libappindicator::AppIndicator; use libappindicator::AppIndicator;
#[cfg(target_os = "linux")]
use std::env::temp_dir; use std::env::temp_dir;
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{Arc, Mutex, RwLock}, sync::{Arc, Mutex},
}; };
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use trayicon::{MenuBuilder, TrayIconBuilder}; use trayicon::{MenuBuilder, TrayIconBuilder};

View File

@ -20,7 +20,9 @@ use hbb_common::{
tokio::{self, sync::mpsc, time}, tokio::{self, sync::mpsc, time},
}; };
use crate::{common::SOFTWARE_UPDATE_URL, hbbs_http::account, ipc, platform}; use crate::{common::SOFTWARE_UPDATE_URL, ipc, platform};
#[cfg(feature = "flutter")]
use crate::hbbs_http::account;
type Message = RendezvousMessage; type Message = RendezvousMessage;
@ -844,14 +846,17 @@ pub(crate) fn check_connect_status(reconnect: bool) -> mpsc::UnboundedSender<ipc
tx tx
} }
#[cfg(feature = "flutter")]
pub fn account_auth(op: String, id: String, uuid: String) { pub fn account_auth(op: String, id: String, uuid: String) {
account::OidcSession::account_auth(op, id, uuid); account::OidcSession::account_auth(op, id, uuid);
} }
#[cfg(feature = "flutter")]
pub fn account_auth_cancel() { pub fn account_auth_cancel() {
account::OidcSession::auth_cancel(); account::OidcSession::auth_cancel();
} }
#[cfg(feature = "flutter")]
pub fn account_auth_result() -> String { pub fn account_auth_result() -> String {
serde_json::to_string(&account::OidcSession::get_result()).unwrap_or_default() serde_json::to_string(&account::OidcSession::get_result()).unwrap_or_default()
} }

View File

@ -22,7 +22,6 @@ use std::collections::{HashMap, HashSet};
use std::ops::{Deref, DerefMut}; use std::ops::{Deref, DerefMut};
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex, RwLock}; use std::sync::{Arc, Mutex, RwLock};
use std::time::Duration;
/// IS_IN KEYBOARD_HOOKED sciter only /// IS_IN KEYBOARD_HOOKED sciter only
pub static IS_IN: AtomicBool = AtomicBool::new(false); pub static IS_IN: AtomicBool = AtomicBool::new(false);
@ -1323,7 +1322,7 @@ impl<T: InvokeUiSession> Session<T> {
#[cfg(any(target_os = "windows", target_os = "macos"))] #[cfg(any(target_os = "windows", target_os = "macos"))]
std::thread::spawn(move || { std::thread::spawn(move || {
let func = move |event: Event| match event.event_type { let func = move |event: Event| match event.event_type {
EventType::KeyPress(key) | EventType::KeyRelease(key) => { EventType::KeyPress(..) | EventType::KeyRelease(..) => {
// grab all keys // grab all keys
if !IS_IN.load(Ordering::SeqCst) if !IS_IN.load(Ordering::SeqCst)
|| !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst) || !SERVER_KEYBOARD_ENABLED.load(Ordering::SeqCst)