macos, use private CGEventSource

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-12-29 17:11:10 +08:00
parent 01ade73304
commit 94cecb1860
3 changed files with 56 additions and 14 deletions

2
Cargo.lock generated
View File

@ -4305,7 +4305,7 @@ dependencies = [
[[package]]
name = "rdev"
version = "0.5.0-2"
source = "git+https://github.com/fufesou/rdev#edddb71a88bd8a4737ef4216861b426490c49f2e"
source = "git+https://github.com/fufesou/rdev#196b589573f90703a601e6b105dd7c917fc388f9"
dependencies = [
"cocoa",
"core-foundation 0.9.3",

View File

@ -523,6 +523,8 @@ impl Connection {
rdev::set_dw_mouse_extra_info(enigo::ENIGO_INPUT_EXTRA_VALUE);
rdev::set_dw_keyboard_extra_info(enigo::ENIGO_INPUT_EXTRA_VALUE);
}
#[cfg(target_os = "macos")]
reset_input_ondisconn();
loop {
match receiver.recv_timeout(std::time::Duration::from_millis(500)) {
Ok(v) => match v {

View File

@ -5,7 +5,9 @@ use crate::common::IS_X11;
use dispatch::Queue;
use enigo::{Enigo, Key, KeyboardControllable, MouseButton, MouseControllable};
use hbb_common::{config::COMPRESS_LEVEL, get_time, protobuf::EnumOrUnknown};
use rdev::{self, simulate, EventType, Key as RdevKey, RawKey};
use rdev::{self, EventType, Key as RdevKey, RawKey};
#[cfg(target_os = "macos")]
use rdev::{CGEventSourceStateID, CGEventTapLocation, VirtualInput};
use std::time::Duration;
use std::{
convert::TryFrom,
@ -221,6 +223,10 @@ lazy_static::lazy_static! {
static ref IS_SERVER: bool = std::env::args().nth(1) == Some("--server".to_owned());
}
// virtual_input must be used in main thread.
// No need to wrap mutex.
static mut VIRTUAL_INPUT: Option<VirtualInput> = None;
// First call set_uinput() will create keyboard and mouse clients.
// The clients are ipc connections that must live shorter than tokio runtime.
// Thus this function must not be called in a temporary runtime.
@ -392,13 +398,15 @@ fn record_key_to_key(record_key: u64) -> Option<Key> {
fn release_record_key(record_key: u64) {
let func = move || {
if record_key_is_rdev_layout(record_key) {
rdev_key_down_or_up(RdevKey::Unknown((record_key - KEY_RDEV_START) as _), false);
simulate_(&EventType::KeyRelease(RdevKey::Unknown(
(record_key - KEY_RDEV_START) as _,
)));
} else if let Some(key) = record_key_to_key(record_key) {
ENIGO.lock().unwrap().key_up(key);
log::debug!("Fixed {:?} timeout", key);
}
};
#[cfg(target_os = "macos")]
QUEUE.exec_async(func);
#[cfg(not(target_os = "macos"))]
@ -687,7 +695,27 @@ pub fn handle_key(evt: &KeyEvent) {
handle_key_(evt);
}
fn sim_rdev_rawkey(code: u32, down_or_up: bool) {
#[inline]
fn reset_input() {
unsafe {
VIRTUAL_INPUT = VirtualInput::new(
CGEventSourceStateID::Private,
CGEventTapLocation::AnnotatedSession,
)
.ok();
}
}
#[cfg(target_os = "macos")]
pub fn reset_input_ondisconn() {
if !*IS_SERVER {
QUEUE.exec_async(reset_input);
} else {
reset_input();
}
}
fn sim_rdev_rawkey(code: u32, keydown: bool) {
#[cfg(target_os = "windows")]
let rawkey = RawKey::ScanCode(code);
#[cfg(target_os = "linux")]
@ -698,22 +726,34 @@ fn sim_rdev_rawkey(code: u32, down_or_up: bool) {
#[cfg(target_os = "macos")]
let rawkey = RawKey::MacVirtualKeycode(code);
rdev_key_down_or_up(RdevKey::RawKey(rawkey), down_or_up);
let event_type = if keydown {
EventType::KeyPress(RdevKey::RawKey(rawkey))
} else {
EventType::KeyRelease(RdevKey::RawKey(rawkey))
};
simulate_(&event_type);
}
fn rdev_key_down_or_up(key: RdevKey, down_or_up: bool) {
let event_type = match down_or_up {
true => EventType::KeyPress(key),
false => EventType::KeyRelease(key),
};
match simulate(&event_type) {
#[cfg(target_os = "macos")]
#[inline]
fn simulate_(event_type: &EventType) {
unsafe {
if let Some(virtual_input) = &VIRTUAL_INPUT {
let _ = virtual_input.simulate(&event_type);
std::thread::sleep(Duration::from_millis(20));
}
}
}
#[cfg(not(target_os = "macos"))]
#[inline]
fn simulate_(event_type: &EventType) {
match rdev::simulate(&event_type) {
Ok(()) => (),
Err(_simulate_error) => {
log::error!("Could not send {:?}", &event_type);
}
}
#[cfg(target_os = "macos")]
std::thread::sleep(Duration::from_millis(20));
}
fn is_modifier_in_key_event(control_key: ControlKey, key_event: &KeyEvent) -> bool {