fix mac key mapping, https://github.com/rustdesk/rustdesk/issues/186, https://github.com/rustdesk/rustdesk/issues/86
This commit is contained in:
		
							parent
							
								
									39f0dd28b4
								
							
						
					
					
						commit
						eb76f7cecc
					
				| @ -71,3 +71,50 @@ pub const kVK_ANSI_KeypadEnter: u16 = 0x4C; | ||||
| pub const kVK_ANSI_KeypadMinus: u16 = 0x4E; | ||||
| pub const kVK_ANSI_KeypadEquals: u16 = 0x51; | ||||
| pub const kVK_RIGHT_COMMAND: u16 = 0x36; | ||||
| pub const kVK_ANSI_A                 : u16 = 0x00; | ||||
| pub const kVK_ANSI_S                 : u16 = 0x01; | ||||
| pub const kVK_ANSI_D                 : u16 = 0x02; | ||||
| pub const kVK_ANSI_F                 : u16 = 0x03; | ||||
| pub const kVK_ANSI_H                 : u16 = 0x04; | ||||
| pub const kVK_ANSI_G                 : u16 = 0x05; | ||||
| pub const kVK_ANSI_Z                 : u16 = 0x06; | ||||
| pub const kVK_ANSI_X                 : u16 = 0x07; | ||||
| pub const kVK_ANSI_C                 : u16 = 0x08; | ||||
| pub const kVK_ANSI_V                 : u16 = 0x09; | ||||
| pub const kVK_ANSI_B                 : u16 = 0x0B; | ||||
| pub const kVK_ANSI_Q                 : u16 = 0x0C; | ||||
| pub const kVK_ANSI_W                 : u16 = 0x0D; | ||||
| pub const kVK_ANSI_E                 : u16 = 0x0E; | ||||
| pub const kVK_ANSI_R                 : u16 = 0x0F; | ||||
| pub const kVK_ANSI_Y                 : u16 = 0x10; | ||||
| pub const kVK_ANSI_T                 : u16 = 0x11; | ||||
| pub const kVK_ANSI_1                 : u16 = 0x12; | ||||
| pub const kVK_ANSI_2                 : u16 = 0x13; | ||||
| pub const kVK_ANSI_3                 : u16 = 0x14; | ||||
| pub const kVK_ANSI_4                 : u16 = 0x15; | ||||
| pub const kVK_ANSI_6                 : u16 = 0x16; | ||||
| pub const kVK_ANSI_5                 : u16 = 0x17; | ||||
| pub const kVK_ANSI_Equal             : u16 = 0x18; | ||||
| pub const kVK_ANSI_9                 : u16 = 0x19; | ||||
| pub const kVK_ANSI_7                 : u16 = 0x1A; | ||||
| pub const kVK_ANSI_Minus             : u16 = 0x1B; | ||||
| pub const kVK_ANSI_8                 : u16 = 0x1C; | ||||
| pub const kVK_ANSI_0                 : u16 = 0x1D; | ||||
| pub const kVK_ANSI_RightBracket      : u16 = 0x1E; | ||||
| pub const kVK_ANSI_O                 : u16 = 0x1F; | ||||
| pub const kVK_ANSI_U                 : u16 = 0x20; | ||||
| pub const kVK_ANSI_LeftBracket       : u16 = 0x21; | ||||
| pub const kVK_ANSI_I                 : u16 = 0x22; | ||||
| pub const kVK_ANSI_P                 : u16 = 0x23; | ||||
| pub const kVK_ANSI_L                 : u16 = 0x25; | ||||
| pub const kVK_ANSI_J                 : u16 = 0x26; | ||||
| pub const kVK_ANSI_Quote             : u16 = 0x27; | ||||
| pub const kVK_ANSI_K                 : u16 = 0x28; | ||||
| pub const kVK_ANSI_Semicolon         : u16 = 0x29; | ||||
| pub const kVK_ANSI_Backslash         : u16 = 0x2A; | ||||
| pub const kVK_ANSI_Comma             : u16 = 0x2B; | ||||
| pub const kVK_ANSI_Slash             : u16 = 0x2C; | ||||
| pub const kVK_ANSI_N                 : u16 = 0x2D; | ||||
| pub const kVK_ANSI_M                 : u16 = 0x2E; | ||||
| pub const kVK_ANSI_Period            : u16 = 0x2F; | ||||
| pub const kVK_ANSI_Grave             : u16 = 0x32; | ||||
|  | ||||
| @ -9,12 +9,6 @@ use self::core_graphics::event_source::*; | ||||
| use crate::macos::keycodes::*; | ||||
| use crate::{Key, KeyboardControllable, MouseButton, MouseControllable}; | ||||
| use objc::runtime::Class; | ||||
| use std::ffi::CStr; | ||||
| use std::os::raw::*; | ||||
| 
 | ||||
| // required for pressedMouseButtons on NSEvent
 | ||||
| #[link(name = "AppKit", kind = "framework")] | ||||
| extern "C" {} | ||||
| 
 | ||||
| struct MyCGEvent; | ||||
| 
 | ||||
| @ -34,8 +28,6 @@ extern "C" { | ||||
|     fn CGEventSourceKeyState(stateID: i32, key: u16) -> bool; | ||||
| } | ||||
| 
 | ||||
| pub type CFDataRef = *const c_void; | ||||
| 
 | ||||
| #[repr(C)] | ||||
| #[derive(Clone, Copy)] | ||||
| struct NSPoint { | ||||
| @ -43,162 +35,6 @@ struct NSPoint { | ||||
|     y: f64, | ||||
| } | ||||
| 
 | ||||
| #[repr(C)] | ||||
| pub struct __TISInputSource; | ||||
| pub type TISInputSourceRef = *const __TISInputSource; | ||||
| 
 | ||||
| #[repr(C)] | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub struct __CFString([u8; 0]); | ||||
| pub type CFStringRef = *const __CFString; | ||||
| pub type Boolean = c_uchar; | ||||
| pub type UInt8 = c_uchar; | ||||
| pub type SInt32 = c_int; | ||||
| pub type UInt16 = c_ushort; | ||||
| pub type UInt32 = c_uint; | ||||
| pub type UniChar = UInt16; | ||||
| pub type UniCharCount = c_ulong; | ||||
| 
 | ||||
| pub type OptionBits = UInt32; | ||||
| pub type OSStatus = SInt32; | ||||
| 
 | ||||
| pub type CFStringEncoding = UInt32; | ||||
| 
 | ||||
| #[allow(non_upper_case_globals)] | ||||
| pub const kUCKeyActionDisplay: _bindgen_ty_702 = _bindgen_ty_702::kUCKeyActionDisplay; | ||||
| 
 | ||||
| #[allow(non_camel_case_types)] | ||||
| #[repr(u32)] | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum _bindgen_ty_702 { | ||||
|     // kUCKeyActionDown = 0,
 | ||||
|     // kUCKeyActionUp = 1,
 | ||||
|     // kUCKeyActionAutoKey = 2,
 | ||||
|     kUCKeyActionDisplay = 3, | ||||
| } | ||||
| 
 | ||||
| #[allow(non_snake_case)] | ||||
| #[repr(C)] | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub struct UCKeyboardTypeHeader { | ||||
|     pub keyboardTypeFirst: UInt32, | ||||
|     pub keyboardTypeLast: UInt32, | ||||
|     pub keyModifiersToTableNumOffset: UInt32, | ||||
|     pub keyToCharTableIndexOffset: UInt32, | ||||
|     pub keyStateRecordsIndexOffset: UInt32, | ||||
|     pub keyStateTerminatorsOffset: UInt32, | ||||
|     pub keySequenceDataIndexOffset: UInt32, | ||||
| } | ||||
| 
 | ||||
| #[allow(non_snake_case)] | ||||
| #[repr(C)] | ||||
| #[derive(Debug, Clone, Copy)] | ||||
| pub struct UCKeyboardLayout { | ||||
|     pub keyLayoutHeaderFormat: UInt16, | ||||
|     pub keyLayoutDataVersion: UInt16, | ||||
|     pub keyLayoutFeatureInfoOffset: UInt32, | ||||
|     pub keyboardTypeCount: UInt32, | ||||
|     pub keyboardTypeList: [UCKeyboardTypeHeader; 1usize], | ||||
| } | ||||
| 
 | ||||
| #[allow(non_upper_case_globals)] | ||||
| pub const kUCKeyTranslateNoDeadKeysBit: _bindgen_ty_703 = | ||||
|     _bindgen_ty_703::kUCKeyTranslateNoDeadKeysBit; | ||||
| 
 | ||||
| #[allow(non_camel_case_types)] | ||||
| #[repr(u32)] | ||||
| #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum _bindgen_ty_703 { | ||||
|     kUCKeyTranslateNoDeadKeysBit = 0, | ||||
| } | ||||
| 
 | ||||
| #[repr(C)] | ||||
| #[derive(Debug, Copy, Clone)] | ||||
| pub struct __CFAllocator([u8; 0]); | ||||
| pub type CFAllocatorRef = *const __CFAllocator; | ||||
| 
 | ||||
| // #[repr(u32)]
 | ||||
| // #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 | ||||
| // pub enum _bindgen_ty_15 {
 | ||||
| //     kCFStringEncodingMacRoman = 0,
 | ||||
| //     kCFStringEncodingWindowsLatin1 = 1280,
 | ||||
| //     kCFStringEncodingISOLatin1 = 513,
 | ||||
| //     kCFStringEncodingNextStepLatin = 2817,
 | ||||
| //     kCFStringEncodingASCII = 1536,
 | ||||
| //     kCFStringEncodingUnicode = 256,
 | ||||
| //     kCFStringEncodingUTF8 = 134217984,
 | ||||
| //     kCFStringEncodingNonLossyASCII = 3071,
 | ||||
| //     kCFStringEncodingUTF16BE = 268435712,
 | ||||
| //     kCFStringEncodingUTF16LE = 335544576,
 | ||||
| //     kCFStringEncodingUTF32 = 201326848,
 | ||||
| //     kCFStringEncodingUTF32BE = 402653440,
 | ||||
| //     kCFStringEncodingUTF32LE = 469762304,
 | ||||
| // }
 | ||||
| 
 | ||||
| #[allow(non_upper_case_globals)] | ||||
| pub const kCFStringEncodingUTF8: u32 = 134_217_984; | ||||
| 
 | ||||
| #[allow(improper_ctypes)] | ||||
| #[link(name = "Carbon", kind = "framework")] | ||||
| extern "C" { | ||||
|     fn TISCopyCurrentKeyboardInputSource() -> TISInputSourceRef; | ||||
|     fn TISCopyCurrentKeyboardLayoutInputSource() -> TISInputSourceRef; | ||||
|     fn TISCopyCurrentASCIICapableKeyboardLayoutInputSource() -> TISInputSourceRef; | ||||
| 
 | ||||
|     //     extern void *
 | ||||
|     // TISGetInputSourceProperty(
 | ||||
|     //   TISInputSourceRef   inputSource,
 | ||||
|     //   CFStringRef         propertyKey)
 | ||||
| 
 | ||||
|     #[allow(non_upper_case_globals)] | ||||
|     #[link_name = "kTISPropertyUnicodeKeyLayoutData"] | ||||
|     pub static kTISPropertyUnicodeKeyLayoutData: CFStringRef; | ||||
| 
 | ||||
|     #[allow(non_snake_case)] | ||||
|     pub fn TISGetInputSourceProperty( | ||||
|         inputSource: TISInputSourceRef, | ||||
|         propertyKey: CFStringRef, | ||||
|     ) -> *mut c_void; | ||||
| 
 | ||||
|     #[allow(non_snake_case)] | ||||
|     pub fn CFDataGetBytePtr(theData: CFDataRef) -> *const UInt8; | ||||
| 
 | ||||
|     #[allow(non_snake_case)] | ||||
|     pub fn UCKeyTranslate( | ||||
|         keyLayoutPtr: *const UInt8, //*const UCKeyboardLayout,
 | ||||
|         virtualKeyCode: UInt16, | ||||
|         keyAction: UInt16, | ||||
|         modifierKeyState: UInt32, | ||||
|         keyboardType: UInt32, | ||||
|         keyTranslateOptions: OptionBits, | ||||
|         deadKeyState: *mut UInt32, | ||||
|         maxStringLength: UniCharCount, | ||||
|         actualStringLength: *mut UniCharCount, | ||||
|         unicodeString: *mut UniChar, | ||||
|     ) -> OSStatus; | ||||
| 
 | ||||
|     pub fn LMGetKbdType() -> UInt8; | ||||
| 
 | ||||
|     #[allow(non_snake_case)] | ||||
|     pub fn CFStringCreateWithCharacters( | ||||
|         alloc: CFAllocatorRef, | ||||
|         chars: *const UniChar, | ||||
|         numChars: CFIndex, | ||||
|     ) -> CFStringRef; | ||||
| 
 | ||||
|     #[allow(non_upper_case_globals)] | ||||
|     #[link_name = "kCFAllocatorDefault"] | ||||
|     pub static kCFAllocatorDefault: CFAllocatorRef; | ||||
| 
 | ||||
|     #[allow(non_snake_case)] | ||||
|     pub fn CFStringGetCString( | ||||
|         theString: CFStringRef, | ||||
|         buffer: *mut c_char, | ||||
|         bufferSize: CFIndex, | ||||
|         encoding: CFStringEncoding, | ||||
|     ) -> Boolean; | ||||
| } | ||||
| 
 | ||||
| // not present in servo/core-graphics
 | ||||
| #[allow(dead_code)] | ||||
| #[derive(Debug)] | ||||
| @ -211,7 +47,6 @@ enum ScrollUnit { | ||||
| /// The main struct for handling the event emitting
 | ||||
| pub struct Enigo { | ||||
|     event_source: Option<CGEventSource>, | ||||
|     keycode_to_string_map: std::collections::HashMap<String, CGKeyCode>, | ||||
|     double_click_interval: u32, | ||||
|     last_click_time: Option<std::time::Instant>, | ||||
|     multiple_click: i64, | ||||
| @ -263,7 +98,6 @@ impl Default for Enigo { | ||||
|             } else { | ||||
|                 None | ||||
|             }, | ||||
|             keycode_to_string_map: Default::default(), | ||||
|             double_click_interval, | ||||
|             multiple_click: 1, | ||||
|             last_click_time: None, | ||||
| @ -591,129 +425,63 @@ impl Enigo { | ||||
|             Key::RightAlt => kVK_RightOption, | ||||
| 
 | ||||
|             Key::Raw(raw_keycode) => raw_keycode, | ||||
|             Key::Layout(c) => self.get_layoutdependent_keycode(c.to_string()), | ||||
|             Key::Layout(c) => self.map_key_board(c), | ||||
| 
 | ||||
|             Key::Super | Key::Command | Key::Windows | Key::Meta => kVK_Command, | ||||
|             _ => 0, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn get_layoutdependent_keycode(&mut self, string: String) -> CGKeyCode { | ||||
|         if self.keycode_to_string_map.is_empty() { | ||||
|             self.init_map(); | ||||
|     fn map_key_board(&self, ch: char) -> CGKeyCode { | ||||
|         match ch { | ||||
|             'a' => kVK_ANSI_A, | ||||
|             'b' => kVK_ANSI_B, | ||||
|             'c' => kVK_ANSI_C, | ||||
|             'd' => kVK_ANSI_D, | ||||
|             'e' => kVK_ANSI_E, | ||||
|             'f' => kVK_ANSI_F, | ||||
|             'g' => kVK_ANSI_G, | ||||
|             'h' => kVK_ANSI_H, | ||||
|             'i' => kVK_ANSI_I, | ||||
|             'j' => kVK_ANSI_J, | ||||
|             'k' => kVK_ANSI_K, | ||||
|             'l' => kVK_ANSI_L, | ||||
|             'm' => kVK_ANSI_M, | ||||
|             'n' => kVK_ANSI_N, | ||||
|             'o' => kVK_ANSI_O, | ||||
|             'p' => kVK_ANSI_P, | ||||
|             'q' => kVK_ANSI_Q, | ||||
|             'r' => kVK_ANSI_R, | ||||
|             's' => kVK_ANSI_S, | ||||
|             't' => kVK_ANSI_T, | ||||
|             'u' => kVK_ANSI_U, | ||||
|             'v' => kVK_ANSI_V, | ||||
|             'w' => kVK_ANSI_W, | ||||
|             'x' => kVK_ANSI_X, | ||||
|             'y' => kVK_ANSI_Y, | ||||
|             'z' => kVK_ANSI_Z, | ||||
|             '0' => kVK_ANSI_0, | ||||
|             '1' => kVK_ANSI_1, | ||||
|             '2' => kVK_ANSI_2, | ||||
|             '3' => kVK_ANSI_3, | ||||
|             '4' => kVK_ANSI_4, | ||||
|             '5' => kVK_ANSI_5, | ||||
|             '6' => kVK_ANSI_6, | ||||
|             '7' => kVK_ANSI_7, | ||||
|             '8' => kVK_ANSI_8, | ||||
|             '9' => kVK_ANSI_9, | ||||
|             '-' => kVK_ANSI_Minus, | ||||
|             '=' => kVK_ANSI_Equal, | ||||
|             '[' => kVK_ANSI_LeftBracket, | ||||
|             ']' => kVK_ANSI_RightBracket, | ||||
|             '\\' => kVK_ANSI_Backslash, | ||||
|             ';' => kVK_ANSI_Semicolon, | ||||
|             '\'' => kVK_ANSI_Quote, | ||||
|             ',' => kVK_ANSI_Comma, | ||||
|             '.' => kVK_ANSI_Period, | ||||
|             '/' => kVK_ANSI_Slash, | ||||
|             '`' => kVK_ANSI_Grave, | ||||
|             _ => 0, | ||||
|         } | ||||
|         *self.keycode_to_string_map.get(&string).unwrap_or(&0) | ||||
|     } | ||||
| 
 | ||||
|     fn init_map(&mut self) { | ||||
|         println!("init_map"); | ||||
|         self.keycode_to_string_map.insert("".to_owned(), 0); | ||||
|         // loop through every keycode (0 - 127)
 | ||||
|         for keycode in 0..128 { | ||||
|             // no modifier
 | ||||
|             if let Some(key_string) = self.keycode_to_string(keycode, 0x100) { | ||||
|                 self.keycode_to_string_map.insert(key_string, keycode); | ||||
|             } | ||||
| 
 | ||||
|             // shift modifier
 | ||||
|             if let Some(key_string) = self.keycode_to_string(keycode, 0x20102) { | ||||
|                 self.keycode_to_string_map.insert(key_string, keycode); | ||||
|             } | ||||
| 
 | ||||
|             // alt modifier
 | ||||
|             // if let Some(string) = self.keycode_to_string(keycode, 0x80120) {
 | ||||
|             //     println!("{:?}", string);
 | ||||
|             // }
 | ||||
|             // alt + shift modifier
 | ||||
|             // if let Some(string) = self.keycode_to_string(keycode, 0xa0122) {
 | ||||
|             //     println!("{:?}", string);
 | ||||
|             // }
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn keycode_to_string(&self, keycode: u16, modifier: u32) -> Option<String> { | ||||
|         let cf_string = self.create_string_for_key(keycode, modifier); | ||||
|         unsafe { | ||||
|             if !cf_string.is_null() { | ||||
|                 let mut buf: [i8; 255] = [0; 255]; | ||||
|                 let success = CFStringGetCString( | ||||
|                     cf_string, | ||||
|                     buf.as_mut_ptr(), | ||||
|                     buf.len() as _, | ||||
|                     kCFStringEncodingUTF8, | ||||
|                 ); | ||||
|                 if success != 0 { | ||||
|                     let name: &CStr = CStr::from_ptr(buf.as_ptr()); | ||||
|                     if let Ok(name) = name.to_str() { | ||||
|                         return Some(name.to_owned()); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         None | ||||
|     } | ||||
| 
 | ||||
|     fn create_string_for_key(&self, keycode: u16, modifier: u32) -> CFStringRef { | ||||
|         let current_keyboard = unsafe { TISCopyCurrentKeyboardInputSource() }; | ||||
|         let mut layout_data = std::ptr::null_mut(); | ||||
|         if !current_keyboard.is_null() { | ||||
|             layout_data = unsafe { | ||||
|                 TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData) | ||||
|             }; | ||||
|         } | ||||
|         if layout_data.is_null() { | ||||
|             // https://github.com/microsoft/vscode/issues/23833
 | ||||
|             let current_keyboard = unsafe { TISCopyCurrentKeyboardLayoutInputSource() }; | ||||
|             if !current_keyboard.is_null() { | ||||
|                 layout_data = unsafe { | ||||
|                     TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData) | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|         if layout_data.is_null() { | ||||
|             let current_keyboard = unsafe { TISCopyCurrentASCIICapableKeyboardLayoutInputSource() }; | ||||
|             if !current_keyboard.is_null() { | ||||
|                 layout_data = unsafe { | ||||
|                     TISGetInputSourceProperty(current_keyboard, kTISPropertyUnicodeKeyLayoutData) | ||||
|                 }; | ||||
|             } | ||||
|         } | ||||
|         if layout_data.is_null() { | ||||
|             // to-do: try out manual mapping in https://github.com/stweil/OSXvnc
 | ||||
| 			// we do see crash like this, also not easy to reproduce, no sure if it related
 | ||||
| /* | ||||
| 0   rustdesk                      	0x000000010f921bc9 std::collections::hash::map::HashMap$LT$K$C$V$C$S$GT$::insert::h84e28c51a3292e7a + 473 | ||||
| 1   rustdesk                      	0x000000010f921884 enigo::macos::macos_impl::Enigo::key_to_keycode::h85ead82e9b1075ae + 1428 | ||||
| 2   rustdesk                      	0x000000010f922a8c _$LT$enigo..macos..macos_impl..Enigo$u20$as$u20$enigo..KeyboardControllable$GT$::key_down::h54f24da6d274b948 + 44 | ||||
| */ | ||||
|             return std::ptr::null() as _; | ||||
|         } | ||||
|         let keyboard_layout = unsafe { CFDataGetBytePtr(layout_data) }; | ||||
|         if keyboard_layout.is_null() { | ||||
|             return std::ptr::null() as _; | ||||
|         } | ||||
| 
 | ||||
|         let mut keys_down: UInt32 = 0; | ||||
|         let mut chars: u16 = 0; | ||||
|         // let mut chars: *mut c_void;//[UniChar; 4];
 | ||||
|         let mut real_length: UniCharCount = 0; | ||||
|         unsafe { | ||||
|             UCKeyTranslate( | ||||
|                 keyboard_layout, | ||||
|                 keycode, | ||||
|                 kUCKeyActionDisplay as u16, | ||||
|                 modifier, | ||||
|                 LMGetKbdType() as u32, | ||||
|                 kUCKeyTranslateNoDeadKeysBit as u32, | ||||
|                 &mut keys_down, | ||||
|                 8, // sizeof(chars) / sizeof(chars[0]),
 | ||||
|                 &mut real_length, | ||||
|                 &mut chars, | ||||
|             ); | ||||
|         } | ||||
| 
 | ||||
|         unsafe { CFStringCreateWithCharacters(kCFAllocatorDefault, &chars, 1) } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user