Refactor simulate to support switching keyboard modes
This commit is contained in:
parent
7c24f6bb12
commit
5dab7bd9a2
@ -3,7 +3,6 @@ use libc;
|
|||||||
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
|
use crate::{Key, KeyboardControllable, MouseButton, MouseControllable};
|
||||||
|
|
||||||
use self::libc::{c_char, c_int, c_void, useconds_t};
|
use self::libc::{c_char, c_int, c_void, useconds_t};
|
||||||
use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError};
|
|
||||||
use std::{borrow::Cow, ffi::CString, io::prelude::*, ptr, sync::mpsc, thread, time};
|
use std::{borrow::Cow, ffi::CString, io::prelude::*, ptr, sync::mpsc, thread, time};
|
||||||
const CURRENT_WINDOW: c_int = 0;
|
const CURRENT_WINDOW: c_int = 0;
|
||||||
const DEFAULT_DELAY: u64 = 12000;
|
const DEFAULT_DELAY: u64 = 12000;
|
||||||
@ -104,26 +103,6 @@ impl Enigo {
|
|||||||
self.tx.send((PyMsg::Char('\0'), true)).ok();
|
self.tx.send((PyMsg::Char('\0'), true)).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool {
|
|
||||||
if let Key::Raw(keycode) = key {
|
|
||||||
let event_type = match is_press {
|
|
||||||
// todo: Acccodding to client type
|
|
||||||
true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
};
|
|
||||||
|
|
||||||
match simulate(event_type) {
|
|
||||||
Ok(()) => true,
|
|
||||||
Err(SimulateError) => false,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn send_pynput(&mut self, key: &Key, is_press: bool) -> bool {
|
fn send_pynput(&mut self, key: &Key, is_press: bool) -> bool {
|
||||||
@ -459,12 +438,9 @@ impl KeyboardControllable for Enigo {
|
|||||||
if self.xdo.is_null() {
|
if self.xdo.is_null() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
if self.send_rdev(&key, true) {
|
// if self.send_pynput(&key, true) {
|
||||||
return Ok(());
|
// return Ok(());
|
||||||
}
|
// }
|
||||||
if self.send_pynput(&key, true) {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let string = CString::new(&*keysequence(key))?;
|
let string = CString::new(&*keysequence(key))?;
|
||||||
unsafe {
|
unsafe {
|
||||||
xdo_send_keysequence_window_down(
|
xdo_send_keysequence_window_down(
|
||||||
@ -480,14 +456,9 @@ impl KeyboardControllable for Enigo {
|
|||||||
if self.xdo.is_null() {
|
if self.xdo.is_null() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// todo
|
// if self.send_pynput(&key, false) {
|
||||||
let keyboard_mode = 1;
|
// return;
|
||||||
if keyboard_mode == 1 && self.send_rdev(&key, false) {
|
// }
|
||||||
return;
|
|
||||||
}
|
|
||||||
if self.send_pynput(&key, false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if let Ok(string) = CString::new(&*keysequence(key)) {
|
if let Ok(string) = CString::new(&*keysequence(key)) {
|
||||||
unsafe {
|
unsafe {
|
||||||
xdo_send_keysequence_window_up(
|
xdo_send_keysequence_window_up(
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use core_graphics;
|
use core_graphics;
|
||||||
use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError};
|
|
||||||
// TODO(dustin): use only the things i need
|
// TODO(dustin): use only the things i need
|
||||||
|
|
||||||
use self::core_graphics::display::*;
|
use self::core_graphics::display::*;
|
||||||
@ -354,11 +353,6 @@ impl KeyboardControllable for Enigo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
||||||
let keyboard_mode = 1;
|
|
||||||
if keyboard_mode == 1 {
|
|
||||||
self.send_rdev(&key, true);
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
let code = self.key_to_keycode(key);
|
let code = self.key_to_keycode(key);
|
||||||
if code == u16::MAX {
|
if code == u16::MAX {
|
||||||
return Err("".into());
|
return Err("".into());
|
||||||
@ -374,11 +368,6 @@ impl KeyboardControllable for Enigo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_up(&mut self, key: Key) {
|
fn key_up(&mut self, key: Key) {
|
||||||
let keyboard_mode = 1;
|
|
||||||
if keyboard_mode == 1 {
|
|
||||||
self.send_rdev(&key, true);
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
if let Some(src) = self.event_source.as_ref() {
|
if let Some(src) = self.event_source.as_ref() {
|
||||||
if let Ok(event) =
|
if let Ok(event) =
|
||||||
CGEvent::new_keyboard_event(src.clone(), self.key_to_keycode(key), false)
|
CGEvent::new_keyboard_event(src.clone(), self.key_to_keycode(key), false)
|
||||||
@ -431,27 +420,6 @@ impl Enigo {
|
|||||||
(x, (display_height as i32) - y_inv)
|
(x, (display_height as i32) - y_inv)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool {
|
|
||||||
if let Key::Raw(keycode) = key {
|
|
||||||
let event_type = match is_press {
|
|
||||||
// todo: Acccodding to client type
|
|
||||||
true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
};
|
|
||||||
|
|
||||||
match simulate(event_type) {
|
|
||||||
Ok(()) => true,
|
|
||||||
Err(SimulateError) => false,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_to_keycode(&mut self, key: Key) -> CGKeyCode {
|
fn key_to_keycode(&mut self, key: Key) -> CGKeyCode {
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
// I mean duh, we still need to support deprecated keys until they're removed
|
// I mean duh, we still need to support deprecated keys until they're removed
|
||||||
|
@ -2,7 +2,6 @@ use self::winapi::ctypes::c_int;
|
|||||||
use self::winapi::shared::{basetsd::ULONG_PTR, minwindef::*, windef::*};
|
use self::winapi::shared::{basetsd::ULONG_PTR, minwindef::*, windef::*};
|
||||||
use self::winapi::um::winbase::*;
|
use self::winapi::um::winbase::*;
|
||||||
use self::winapi::um::winuser::*;
|
use self::winapi::um::winuser::*;
|
||||||
use rdev::{simulate, EventType, Key as RdevKey, SimulateError};
|
|
||||||
use winapi;
|
use winapi;
|
||||||
|
|
||||||
use crate::win::keycodes::*;
|
use crate::win::keycodes::*;
|
||||||
@ -198,11 +197,6 @@ impl KeyboardControllable for Enigo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
fn key_down(&mut self, key: Key) -> crate::ResultType {
|
||||||
let keyboard_mode = 1;
|
|
||||||
if keyboard_mode == 1 {
|
|
||||||
self.send_rdev(&key, true);
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
let code = self.key_to_keycode(key);
|
let code = self.key_to_keycode(key);
|
||||||
if code == 0 || code == 65535 {
|
if code == 0 || code == 65535 {
|
||||||
return Err("".into());
|
return Err("".into());
|
||||||
@ -218,11 +212,6 @@ impl KeyboardControllable for Enigo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn key_up(&mut self, key: Key) {
|
fn key_up(&mut self, key: Key) {
|
||||||
let keyboard_mode = 1;
|
|
||||||
if keyboard_mode == 1 {
|
|
||||||
self.send_rdev(&key, false);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
keybd_event(KEYEVENTF_KEYUP, self.key_to_keycode(key), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,27 +272,6 @@ impl Enigo {
|
|||||||
keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char);
|
keybd_event(KEYEVENTF_UNICODE | KEYEVENTF_KEYUP, 0, unicode_char);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_rdev(&mut self, key: &Key, is_press: bool) -> bool {
|
|
||||||
if let Key::Raw(keycode) = key {
|
|
||||||
let event_type = match is_press {
|
|
||||||
// todo: Acccodding to client type
|
|
||||||
true => Box::leak(Box::new(EventType::KeyPress(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
false => Box::leak(Box::new(EventType::KeyRelease(RdevKey::Unknown(
|
|
||||||
(*keycode).into(),
|
|
||||||
)))),
|
|
||||||
};
|
|
||||||
|
|
||||||
match simulate(event_type) {
|
|
||||||
Ok(()) => true,
|
|
||||||
Err(SimulateError) => false,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn key_to_keycode(&self, key: Key) -> u16 {
|
fn key_to_keycode(&self, key: Key) -> u16 {
|
||||||
unsafe {
|
unsafe {
|
||||||
LAYOUT = std::ptr::null_mut();
|
LAYOUT = std::ptr::null_mut();
|
||||||
|
@ -419,15 +419,8 @@ impl Connection {
|
|||||||
handle_mouse(&msg, id);
|
handle_mouse(&msg, id);
|
||||||
}
|
}
|
||||||
MessageInput::Key((mut msg, press)) => {
|
MessageInput::Key((mut msg, press)) => {
|
||||||
if press {
|
// todo: press and down have similar meanings.
|
||||||
msg.down = true;
|
|
||||||
}
|
|
||||||
handle_key(&msg);
|
handle_key(&msg);
|
||||||
let keyboard_mode = 1;
|
|
||||||
if press && keyboard_mode != 1{
|
|
||||||
msg.down = false;
|
|
||||||
handle_key(&msg);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
MessageInput::BlockOn => {
|
MessageInput::BlockOn => {
|
||||||
if crate::platform::block_input(true) {
|
if crate::platform::block_input(true) {
|
||||||
|
@ -3,6 +3,7 @@ use super::*;
|
|||||||
use dispatch::Queue;
|
use dispatch::Queue;
|
||||||
use enigo::{Enigo, Key, KeyboardControllable, MouseButton, MouseControllable};
|
use enigo::{Enigo, Key, KeyboardControllable, MouseButton, MouseControllable};
|
||||||
use hbb_common::{config::COMPRESS_LEVEL, protobuf::ProtobufEnumOrUnknown};
|
use hbb_common::{config::COMPRESS_LEVEL, protobuf::ProtobufEnumOrUnknown};
|
||||||
|
use rdev::{simulate, EventType, EventType::*, Key as RdevKey, SimulateError};
|
||||||
use std::{
|
use std::{
|
||||||
convert::TryFrom,
|
convert::TryFrom,
|
||||||
sync::atomic::{AtomicBool, Ordering},
|
sync::atomic::{AtomicBool, Ordering},
|
||||||
@ -578,24 +579,27 @@ pub fn handle_key(evt: &KeyEvent) {
|
|||||||
handle_key_(evt);
|
handle_key_(evt);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key_(evt: &KeyEvent) {
|
fn map_keyboard_map(evt: &KeyEvent) {
|
||||||
if EXITING.load(Ordering::SeqCst) {
|
// map mode(1): Send keycode according to the peer platform.
|
||||||
return;
|
let event_type = match evt.down {
|
||||||
|
true => EventType::KeyPress(RdevKey::Unknown(evt.get_chr())),
|
||||||
|
false => EventType::KeyRelease(RdevKey::Unknown(evt.get_chr())),
|
||||||
|
};
|
||||||
|
|
||||||
|
match simulate(&event_type) {
|
||||||
|
Ok(()) => (),
|
||||||
|
Err(_simulate_error) => {
|
||||||
|
// todo
|
||||||
|
log::error!("rdev could not send {:?}", event_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn legacy_keyboard_map(evt: &KeyEvent) {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
crate::platform::windows::try_change_desktop();
|
crate::platform::windows::try_change_desktop();
|
||||||
let mut en = ENIGO.lock().unwrap();
|
let mut en = ENIGO.lock().unwrap();
|
||||||
let keyboard_mode = 1;
|
|
||||||
if keyboard_mode == 1 {
|
|
||||||
if let Some(key_event::Union::chr(chr)) = evt.union {
|
|
||||||
if evt.down {
|
|
||||||
en.key_down(Key::Raw(chr.try_into().unwrap()));
|
|
||||||
} else {
|
|
||||||
en.key_up(Key::Raw(chr.try_into().unwrap()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// disable numlock if press home etc when numlock is on,
|
// disable numlock if press home etc when numlock is on,
|
||||||
// because we will get numpad value (7,8,9 etc) if not
|
// because we will get numpad value (7,8,9 etc) if not
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -740,9 +744,67 @@ fn handle_key_(evt: &KeyEvent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_key_(evt: &KeyEvent) {
|
||||||
|
if EXITING.load(Ordering::SeqCst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
match evt.mode {
|
||||||
|
1 => {
|
||||||
|
map_keyboard_map(evt);
|
||||||
|
}
|
||||||
|
3 => {
|
||||||
|
legacy_keyboard_map(evt);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
map_keyboard_map(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::main(flavor = "current_thread")]
|
#[tokio::main(flavor = "current_thread")]
|
||||||
async fn send_sas() -> ResultType<()> {
|
async fn send_sas() -> ResultType<()> {
|
||||||
let mut stream = crate::ipc::connect(1000, crate::POSTFIX_SERVICE).await?;
|
let mut stream = crate::ipc::connect(1000, crate::POSTFIX_SERVICE).await?;
|
||||||
timeout(1000, stream.send(&crate::ipc::Data::SAS)).await??;
|
timeout(1000, stream.send(&crate::ipc::Data::SAS)).await??;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::*;
|
||||||
|
use rdev::{listen, simulate, Event, EventType, Key};
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::thread;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_handle_key() {
|
||||||
|
// listen
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
std::env::set_var("KEYBOARD_ONLY", "y");
|
||||||
|
let func = move |event: Event| {
|
||||||
|
tx.send(event).ok();
|
||||||
|
};
|
||||||
|
if let Err(error) = listen(func) {
|
||||||
|
println!("Error: {:?}", error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// set key/char base on char
|
||||||
|
let mut evt = KeyEvent::new();
|
||||||
|
evt.set_chr(49);
|
||||||
|
evt.mode = 3;
|
||||||
|
|
||||||
|
// press
|
||||||
|
evt.down = true;
|
||||||
|
handle_key(&evt);
|
||||||
|
if let Ok(listen_evt) = rx.recv() {
|
||||||
|
assert_eq!(listen_evt.event_type, EventType::KeyPress(Key::Num1))
|
||||||
|
}
|
||||||
|
// release
|
||||||
|
evt.down = false;
|
||||||
|
handle_key(&evt);
|
||||||
|
if let Ok(listen_evt) = rx.recv() {
|
||||||
|
assert_eq!(listen_evt.event_type, EventType::KeyRelease(Key::Num1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user