From ba4945f598a095cf43f587eb98910db0ac09fa9d Mon Sep 17 00:00:00 2001 From: asur4s Date: Sat, 18 Mar 2023 20:57:19 -0700 Subject: [PATCH] Get char when hot key is pressed --- src/keyboard.rs | 18 ++++++++++--- src/platform/windows.rs | 58 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 71 insertions(+), 5 deletions(-) diff --git a/src/keyboard.rs b/src/keyboard.rs index bfff9ff86..f613a06ef 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -3,11 +3,13 @@ use crate::client::get_key_state; use crate::common::GrabState; #[cfg(feature = "flutter")] use crate::flutter::{CUR_SESSION_ID, SESSIONS}; +#[cfg(target_os = "windows")] +use crate::platform::windows::get_char_by_vk; #[cfg(not(any(feature = "flutter", feature = "cli")))] use crate::ui::CUR_SESSION; -use hbb_common::message_proto::*; #[cfg(not(any(target_os = "android", target_os = "ios")))] use hbb_common::log; +use hbb_common::message_proto::*; use rdev::{Event, EventType, Key}; #[cfg(any(target_os = "windows", target_os = "macos"))] use std::sync::atomic::{AtomicBool, Ordering}; @@ -789,8 +791,18 @@ fn try_fill_unicode(event: &Event, key_event: &KeyEvent, events: &mut Vec {} + None => { + #[cfg(target_os = "windows")] + if is_hot_key_modifiers_down() && unsafe { !IS_0X021D_DOWN }{ + if let Some(chr) = get_char_by_vk(event.code as u32) { + let mut evt = key_event.clone(); + evt.set_seq(chr.to_string()); + events.push(evt); + } + } + } } + } #[cfg(target_os = "windows")] @@ -857,7 +869,7 @@ pub fn translate_keyboard_mode(peer: &str, event: &Event, key_event: KeyEvent) - } #[cfg(target_os = "windows")] - if unsafe { IS_0X021D_DOWN } || !is_hot_key_modifiers_down() { + if matches!(event.event_type, EventType::KeyPress(_)) { try_fill_unicode(event, &key_event, &mut events); } diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 696a18ab9..ac3dc4e1d 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -10,6 +10,7 @@ use hbb_common::{ sleep, timeout, tokio, }; use std::io::prelude::*; +use std::ptr::null_mut; use std::{ ffi::OsString, fs, io, mem, @@ -26,8 +27,8 @@ use winapi::{ handleapi::CloseHandle, minwinbase::STILL_ACTIVE, processthreadsapi::{ - GetCurrentProcess, GetCurrentProcessId, GetExitCodeProcess, OpenProcess, - OpenProcessToken, PROCESS_INFORMATION, STARTUPINFOW, + GetCurrentProcess, GetCurrentProcessId, GetCurrentThreadId, GetExitCodeProcess, + OpenProcess, OpenProcessToken, PROCESS_INFORMATION, STARTUPINFOW, }, securitybaseapi::GetTokenInformation, shellapi::ShellExecuteW, @@ -2072,6 +2073,51 @@ mod cert { } } +pub fn get_char_by_vk(vk: u32) -> Option { + let mut buff = [0_u16; BUF_LEN as usize]; + let buff_ptr = buff.as_mut_ptr(); + const BUF_LEN: i32 = 32; + let len = unsafe { + let current_window_thread_id = GetWindowThreadProcessId(GetForegroundWindow(), null_mut()); + let layout = GetKeyboardLayout(current_window_thread_id); + + // refs: https://github.com/fufesou/rdev/blob/25a99ce71ab42843ad253dd51e6a35e83e87a8a4/src/windows/keyboard.rs#L115 + let press_state = 129; + let mut state: [BYTE; 256] = [0; 256]; + let shift_left = rdev::get_modifier(rdev::Key::ShiftLeft); + let shift_right = rdev::get_modifier(rdev::Key::ShiftRight); + if shift_left { + state[VK_LSHIFT as usize] = press_state; + } + if shift_right { + state[VK_RSHIFT as usize] = press_state; + } + if shift_left || shift_right { + state[VK_SHIFT as usize] = press_state; + } + buff = [0; 32]; + let buff_ptr = buff.as_mut_ptr(); + ToUnicodeEx(vk, 0x00, &state as _, buff_ptr, BUF_LEN, 0, layout) + }; + if len == 1 { + if let Some(chr) = String::from_utf16(&buff[..len as usize]) + .ok()? + .chars() + .next() + { + if chr.is_control() { + return None; + } else { + Some(chr) + } + } else { + None + } + } else { + None + } +} + #[cfg(test)] mod tests { use super::*; @@ -2084,4 +2130,12 @@ mod tests { fn test_uninstall_cert() { println!("uninstall driver certs: {:?}", cert::uninstall_certs()); } + + #[test] + fn test_get_char_by_vk() { + let chr = get_char_by_vk(0x41); // VK_A + assert_eq!(chr, Some('a')); + let chr = get_char_by_vk(VK_ESCAPE as u32); // VK_ESC + assert_eq!(chr, None) + } }