rustdesk 2022-01-09 19:56:24 +08:00
parent 089acaa6e7
commit 0a294d9ff3
6 changed files with 325 additions and 164 deletions

121
Cargo.lock generated
View File

@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d76e1fe0171b6d0857afca5671db12a44e71e80823db13ab39f776fb09ad079"
dependencies = [
"clipboard-win",
"core-graphics",
"core-graphics 0.22.3",
"image",
"log",
"objc",
@ -416,6 +416,21 @@ dependencies = [
"cc",
]
[[package]]
name = "cocoa"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "667fdc068627a2816b9ff831201dd9864249d6ee8d190b9532357f1fc0f61ea7"
dependencies = [
"bitflags",
"block",
"core-foundation 0.9.2",
"core-graphics 0.21.0",
"foreign-types",
"libc",
"objc",
]
[[package]]
name = "cocoa"
version = "0.24.0"
@ -425,8 +440,8 @@ dependencies = [
"bitflags",
"block",
"cocoa-foundation",
"core-foundation",
"core-graphics",
"core-foundation 0.9.2",
"core-graphics 0.22.3",
"foreign-types",
"libc",
"objc",
@ -440,7 +455,7 @@ checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318"
dependencies = [
"bitflags",
"block",
"core-foundation",
"core-foundation 0.9.2",
"core-graphics-types",
"foreign-types",
"libc",
@ -473,22 +488,62 @@ dependencies = [
"toml",
]
[[package]]
name = "core-foundation"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171"
dependencies = [
"core-foundation-sys 0.7.0",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
dependencies = [
"core-foundation-sys",
"core-foundation-sys 0.8.3",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac"
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]]
name = "core-graphics"
version = "0.19.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3889374e6ea6ab25dba90bb5d96202f61108058361f6dc72e8b03e6f8bbe923"
dependencies = [
"bitflags",
"core-foundation 0.7.0",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52a67c4378cf203eace8fb6567847eb641fd6ff933c1145a115c6ee820ebb978"
dependencies = [
"bitflags",
"core-foundation 0.9.2",
"foreign-types",
"libc",
]
[[package]]
name = "core-graphics"
version = "0.22.3"
@ -496,7 +551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2581bbab3b8ffc6fcbd550bf46c355135d16e9ff2a6ea032ad6b9bf1d7efe4fb"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation 0.9.2",
"core-graphics-types",
"foreign-types",
"libc",
@ -509,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation 0.9.2",
"foreign-types",
"libc",
]
@ -539,7 +594,7 @@ version = "0.13.4"
source = "git+https://github.com/open-trade/cpal#3a30569687271c2d5d67279c4883d63f4003d34c"
dependencies = [
"alsa",
"core-foundation-sys",
"core-foundation-sys 0.8.3",
"coreaudio-rs",
"jni",
"js-sys",
@ -922,7 +977,7 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
name = "enigo"
version = "0.0.14"
dependencies = [
"core-graphics",
"core-graphics 0.22.3",
"libc",
"log",
"objc",
@ -2891,6 +2946,21 @@ dependencies = [
"rand_core 0.3.1",
]
[[package]]
name = "rdev"
version = "0.5.0"
source = "git+https://github.com/open-trade/rdev#faeef84bf2edfa457e9e32c0c96b63f44e494fff"
dependencies = [
"cocoa 0.22.0",
"core-foundation 0.7.0",
"core-foundation-sys 0.7.0",
"core-graphics 0.19.2",
"lazy_static",
"libc",
"winapi 0.3.9",
"x11",
]
[[package]]
name = "rdrand"
version = "0.4.0"
@ -3055,9 +3125,9 @@ dependencies = [
"cfg-if 1.0.0",
"clap",
"clipboard-master",
"cocoa",
"core-foundation",
"core-graphics",
"cocoa 0.24.0",
"core-foundation 0.9.2",
"core-graphics 0.22.3",
"cpal",
"crc32fast",
"ctrlc",
@ -3077,6 +3147,7 @@ dependencies = [
"objc",
"parity-tokio-ipc",
"psutil",
"rdev",
"repng",
"rpassword 5.0.1",
"rubato",
@ -3091,7 +3162,6 @@ dependencies = [
"sha2",
"sys-locale",
"systray",
"tigervnc",
"uuid",
"whoami",
"winapi 0.3.9",
@ -3243,8 +3313,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"core-foundation 0.9.2",
"core-foundation-sys 0.8.3",
"libc",
"security-framework-sys",
]
@ -3255,7 +3325,7 @@ version = "2.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e"
dependencies = [
"core-foundation-sys",
"core-foundation-sys 0.8.3",
"libc",
]
@ -3604,15 +3674,6 @@ dependencies = [
"weezl",
]
[[package]]
name = "tigervnc"
version = "1.0.1"
source = "git+https://github.com/open-trade/tigervnc#254ad243c5a22887ddf0e79def58b8251b108d08"
dependencies = [
"cc",
"cfg-if 1.0.0",
]
[[package]]
name = "time"
version = "0.3.5"
@ -4126,6 +4187,16 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "x11"
version = "2.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dd0565fa8bfba8c5efe02725b14dff114c866724eff2cfd44d76cea74bcd87a"
dependencies = [
"libc",
"pkg-config",
]
[[package]]
name = "x11-clipboard"
version = "0.5.3"

View File

@ -54,7 +54,10 @@ sciter-rs = { git = "https://github.com/open-trade/rust-sciter", branch = "dyn"
ctrlc = "3.2"
arboard = "2.0"
clipboard-master = "3.1"
tigervnc = { git = "https://github.com/open-trade/tigervnc" }
#tigervnc = { path = "../tigervnc" }
#tigervnc = { git = "https://github.com/open-trade/tigervnc" }
#rdev = { path = "../rdev" }
rdev = { git = "https://github.com/open-trade/rdev" }
[target.'cfg(target_os = "windows")'.dependencies]
systray = { git = "https://github.com/liyue201/systray-rs" }

View File

@ -83,6 +83,7 @@ message MouseEvent {
}
enum ControlKey {
Unknown = 0;
Alt = 1;
Backspace = 2;
CapsLock = 3;

View File

@ -1,3 +1,12 @@
var last_key_time = 0;
var keymap = {};
for (var (k, v) in Event) {
k = k + ""
if (k[0] == "V" && k[1] == "K") {
keymap[v] = k;
}
}
class Grid: Behavior {
const TABLE_HEADER_CLICK = 0x81;
const TABLE_ROW_CLICK = 0x82;
@ -144,7 +153,7 @@ class Grid: Behavior {
function onKey(evt)
{
last_key_time = getTime();
if (evt.type != Event.KEY_DOWN)
return false;

View File

@ -48,6 +48,10 @@ fn get_key_state(key: enigo::Key) -> bool {
ENIGO.lock().unwrap().get_key_state(key)
}
static mut IS_IN: bool = false;
static mut KEYBOARD_HOOKED: bool = false;
static mut KEYBOARD_ENABLED: bool = true;
#[derive(Default)]
pub struct HandlerInner {
element: Option<Element>,
@ -153,7 +157,8 @@ impl sciter::EventHandler for Handler {
fn login(String, bool);
fn new_rdp();
fn send_mouse(i32, i32, i32, bool, bool, bool, bool);
fn key_down_or_up(bool, String, i32, bool, bool, bool, bool, bool);
fn enter();
fn leave();
fn ctrl_alt_del();
fn transfer_file();
fn tunnel();
@ -214,6 +219,130 @@ impl Handler {
me
}
fn start_keyboard_hook(&self) {
if self.is_port_forward() || self.is_file_transfer() {
return;
}
if unsafe { KEYBOARD_HOOKED } {
return;
}
unsafe {
KEYBOARD_HOOKED = true;
}
log::info!("keyboard hooked");
let mut me = self.clone();
let peer = self.peer_platform();
let is_win = peer == "Windows";
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 unsafe { !IS_IN || !KEYBOARD_ENABLED } {
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);
let ctrl = get_key_state(enigo::Key::Control);
let shift = get_key_state(enigo::Key::Shift);
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 => 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 | Key::KpDelete => {
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::Snapshot => Some(ControlKey::Snapshot),
Key::Help => Some(ControlKey::Help),
Key::Sleep => Some(ControlKey::Sleep),
Key::Separator => Some(ControlKey::Separator),
Key::KpReturn => Some(ControlKey::NumpadEnter),
Key::CapsLock | Key::NumLock | Key::ScrollLock => {
return;
}
_ => None,
};
let mut key_event = KeyEvent::new();
if let Some(k) = control_key {
key_event.set_control_key(k);
} else {
let chr = match evt.name {
Some(ref s) => {
if s.len() == 1 {
s.chars().next().unwrap()
} else {
'\0'
}
}
_ => '\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);
};
if let Err(error) = rdev::listen(func) {
log::error!("rdev: {:?}", error);
}
});
}
fn get_view_style(&mut self) -> String {
return self.lc.read().unwrap().view_style.clone();
}
@ -632,6 +761,18 @@ impl Handler {
self.send(Data::NewRDP);
}
fn enter(&mut self) {
unsafe {
IS_IN = true;
}
}
fn leave(&mut self) {
unsafe {
IS_IN = false;
}
}
fn send_mouse(
&mut self,
mask: i32,
@ -814,18 +955,20 @@ impl Handler {
fn ctrl_alt_del(&mut self) {
if self.peer_platform() == "Windows" {
let del = "CTRL_ALT_DEL".to_owned();
self.key_down_or_up(1, del, 0, false, false, false, false, false);
let mut key_event = KeyEvent::new();
key_event.set_control_key(ControlKey::CtrlAltDel);
self.key_down_or_up(1, key_event, false, false, false, false);
} else {
let del = "VK_DELETE".to_owned();
self.key_down_or_up(1, del.clone(), 0, true, true, false, false, false);
self.key_down_or_up(0, del, 0, true, true, false, false, false);
let mut key_event = KeyEvent::new();
key_event.set_control_key(ControlKey::Delete);
self.key_down_or_up(3, key_event, true, true, false, false);
}
}
fn lock_screen(&mut self) {
let lock = "LOCK_SCREEN".to_owned();
self.key_down_or_up(1, lock, 0, false, false, false, false, false);
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);
}
fn transfer_file(&mut self) {
@ -847,106 +990,61 @@ impl Handler {
fn key_down_or_up(
&mut self,
down_or_up: i32,
name: String,
code: i32,
evt: KeyEvent,
alt: bool,
ctrl: bool,
shift: bool,
command: bool,
extended: bool,
) {
if self.peer_platform() == "Windows" {
if ctrl && alt && name == "VK_DELETE" {
self.ctrl_alt_del();
return;
}
if command && name == "VK_L" {
self.lock_screen();
let mut key_event = evt;
if alt
&& !crate::is_control_key(&key_event, &ControlKey::Alt)
&& !crate::is_control_key(&key_event, &ControlKey::RAlt)
{
key_event.modifiers.push(ControlKey::Alt.into());
}
if shift
&& !crate::is_control_key(&key_event, &ControlKey::Shift)
&& !crate::is_control_key(&key_event, &ControlKey::RShift)
{
key_event.modifiers.push(ControlKey::Shift.into());
}
if ctrl
&& !crate::is_control_key(&key_event, &ControlKey::Control)
&& !crate::is_control_key(&key_event, &ControlKey::RControl)
{
key_event.modifiers.push(ControlKey::Control.into());
}
if command
&& !crate::is_control_key(&key_event, &ControlKey::Meta)
&& !crate::is_control_key(&key_event, &ControlKey::RWin)
{
key_event.modifiers.push(ControlKey::Meta.into());
}
/*
if crate::is_control_key(&key_event, &ControlKey::CapsLock) {
return;
} else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event) {
key_event.modifiers.push(ControlKey::CapsLock.into());
}
if self.peer_platform() != "Mac OS" {
if crate::is_control_key(&key_event, &ControlKey::NumLock) {
return;
} else if get_key_state(enigo::Key::NumLock) && common::valid_for_numlock(&key_event) {
key_event.modifiers.push(ControlKey::NumLock.into());
}
}
// extended: e.g. ctrl key on right side, https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-keybd_event
// not found api of osx and xdo
log::debug!(
"{:?} {} {} {} {} {} {} {} {}",
std::time::SystemTime::now(),
down_or_up,
name,
code,
alt,
ctrl,
shift,
command,
extended,
);
let mut name = name;
#[cfg(target_os = "linux")]
if code == 65383 {
// VK_MENU
name = "Apps".to_owned();
}
if extended {
match name.as_ref() {
"VK_CONTROL" => name = "RControl".to_owned(),
"VK_MENU" => name = "RAlt".to_owned(),
"VK_SHIFT" => name = "RShift".to_owned(),
_ => {}
}
}
if let Some(mut key_event) = self.get_key_event(down_or_up, &name, code) {
if alt
&& !crate::is_control_key(&key_event, &ControlKey::Alt)
&& !crate::is_control_key(&key_event, &ControlKey::RAlt)
{
key_event.modifiers.push(ControlKey::Alt.into());
}
if shift
&& !crate::is_control_key(&key_event, &ControlKey::Shift)
&& !crate::is_control_key(&key_event, &ControlKey::RShift)
{
key_event.modifiers.push(ControlKey::Shift.into());
}
if ctrl
&& !crate::is_control_key(&key_event, &ControlKey::Control)
&& !crate::is_control_key(&key_event, &ControlKey::RControl)
{
key_event.modifiers.push(ControlKey::Control.into());
}
if command
&& !crate::is_control_key(&key_event, &ControlKey::Meta)
&& !crate::is_control_key(&key_event, &ControlKey::RWin)
{
key_event.modifiers.push(ControlKey::Meta.into());
}
if crate::is_control_key(&key_event, &ControlKey::CapsLock) {
return;
} else if get_key_state(enigo::Key::CapsLock) && common::valid_for_capslock(&key_event)
{
key_event.modifiers.push(ControlKey::CapsLock.into());
}
if self.peer_platform() != "Mac OS" {
if crate::is_control_key(&key_event, &ControlKey::NumLock) {
return;
} else if get_key_state(enigo::Key::NumLock)
&& common::valid_for_numlock(&key_event)
{
key_event.modifiers.push(ControlKey::NumLock.into());
}
}
if down_or_up == 1 {
key_event.down = true;
} else if down_or_up == 3 {
key_event.press = true;
}
let mut msg_out = Message::new();
msg_out.set_key_event(key_event);
log::debug!("{:?}", msg_out);
self.send(Data::Message(msg_out));
*/
if down_or_up == 1 {
key_event.down = true;
} else if down_or_up == 3 {
key_event.press = true;
}
let mut msg_out = Message::new();
msg_out.set_key_event(key_event);
log::debug!("{:?}", msg_out);
self.send(Data::Message(msg_out));
}
#[inline]
@ -1123,6 +1221,9 @@ impl Remote {
};
match Client::start(&self.handler.id, conn_type).await {
Ok((mut peer, direct)) => {
unsafe {
KEYBOARD_ENABLED = true;
}
self.handler
.call("setConnectionType", &make_args!(peer.is_secured(), direct));
loop {
@ -1182,6 +1283,9 @@ impl Remote {
if let Some(stop) = stop_clipboard {
stop.send(()).ok();
}
unsafe {
KEYBOARD_ENABLED = false;
}
}
fn handle_job_status(&mut self, id: i32, file_num: i32, err: Option<String>) {
@ -1577,6 +1681,9 @@ impl Remote {
log::info!("Change permission {:?} -> {}", p.permission, p.enabled);
match p.permission.enum_value_or_default() {
Permission::Keyboard => {
unsafe {
KEYBOARD_ENABLED = p.enabled;
}
self.handler
.call("setPermission", &make_args!("keyboard", p.enabled));
}
@ -1729,6 +1836,7 @@ impl Interface for Handler {
crate::platform::windows::add_recent_document(&path);
}
}
self.start_keyboard_hook();
}
async fn handle_hash(&mut self, hash: Hash, peer: &mut Stream) {

View File

@ -1,5 +1,4 @@
var cursor_img = $(img#cursor);
var last_key_time = 0;
is_file_transfer = handler.is_file_transfer();
var is_port_forward = handler.is_port_forward();
var display_width = 0;
@ -72,46 +71,14 @@ function adaptDisplay() {
// https://sciter.com/docs/content/sciter/Event.htm
var entered = false;
var keymap = {};
for (var (k, v) in Event) {
k = k + ""
if (k[0] == "V" && k[1] == "K") {
keymap[v] = k;
if (!is_file_transfer && !is_port_forward) {
self.onKey = function(evt) {
if (!entered) return false;
// so that arrow key not move scrollbar
return true;
}
}
// VK_ENTER = VK_RETURN
// somehow, handler.onKey and view.onKey not working
function self.onKey(evt) {
last_key_time = getTime();
if (is_file_transfer || is_port_forward) return false;
if (!entered) return false;
if (!keyboard_enabled) return false;
switch (evt.type) {
case Event.KEY_DOWN:
handler.key_down_or_up(1, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey,
evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey);
if (is_osx && evt.commandKey) {
handler.key_down_or_up(0, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey,
evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey);
}
break;
case Event.KEY_UP:
handler.key_down_or_up(0, keymap[evt.keyCode] || "", evt.keyCode, evt.altKey,
evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey);
break;
case Event.KEY_CHAR:
// the keypress event is fired when the element receives character value. Event.keyCode is a UNICODE code point of the character
handler.key_down_or_up(2, "", evt.keyCode, evt.altKey,
evt.ctrlKey, evt.shiftKey, evt.commandKey, evt.extendedKey);
break;
default:
return false;
}
return true;
}
var wait_window_toolbar = false;
var last_mouse_mask;
var acc_wheel_delta_x = 0;
@ -284,10 +251,12 @@ function handler.onMouse(evt)
case Event.MOUSE_ENTER:
entered = true;
stdout.println("enter");
handler.enter();
return keyboard_enabled;
case Event.MOUSE_LEAVE:
entered = false;
stdout.println("leave");
handler.leave();
return keyboard_enabled;
default:
return false;