#include "app/mac/MacClient.h" #include "event/Input.hpp" #include "os/Compat.hpp" #include #include #include #include #include #include void* MacClient::s_currentKeyboardLayout = nullptr; KEY MacClient::s_specialKeyConversion[128] = { KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_1, // kVK_ANSI_1 (0x12) KEY_2, // kVK_ANSI_2 (0x13) KEY_3, // kVK_ANSI_3 (0x14) KEY_4, // kVK_ANSI_4 (0x15) KEY_6, // kVK_ANSI_6 (0x16) KEY_5, // kVK_ANSI_5 (0x17) KEY_NONE, KEY_9, // kVK_ANSI_9 (0x19) KEY_7, // kVK_ANSI_7 (0x1A) KEY_NONE, KEY_8, // kVK_ANSI_8 (0x1C) KEY_0, // kVK_ANSI_0 (0x1D) KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_ENTER, // kVK_Return (0x24) KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_TAB, // kVK_Tab (0x30) KEY_SPACE, // kVK_Space (0x31) KEY_NONE, KEY_BACKSPACE, // kVK_Delete (0x33) KEY_NONE, KEY_ESCAPE, // kVK_Escape (0x35) KEY_NONE, KEY_NONE, KEY_LSHIFT, // kVK_Shift (0x38) KEY_CAPSLOCK, // kVK_CapsLock (0x39) KEY_LALT, // kVK_Option (0x3A) KEY_LCONTROL, // kVK_Control (0x3B) KEY_RSHIFT, // kVK_RightShift (0x3C) KEY_RALT, // kVK_RightOption (0x3D) KEY_RCONTROL, // kVK_RightControl (0x3E) KEY_NONE, KEY_F17, // kVK_F17 (0x40) KEY_NUMPAD_DECIMAL, // kVK_ANSI_KeypadDecimal (0x41) KEY_NONE, KEY_NUMPAD_MULTIPLY, // kVK_ANSI_KeypadMultiply (0x43) KEY_NONE, KEY_NUMPAD_PLUS, // kVK_ANSI_KeypadPlus (0x45) KEY_NONE, KEY_NUMLOCK, // kVK_ANSI_KeypadClear (0x47) KEY_NONE, KEY_NONE, KEY_NONE, KEY_NUMPAD_DIVIDE, // kVK_ANSI_KeypadDivide (0x4B) KEY_ENTER, // kVK_ANSI_KeypadEnter (0x4C) KEY_NONE, KEY_NUMPAD_MINUS, // kVK_ANSI_KeypadMinus (0x4E) KEY_F18, // kVK_F18 (0x4F) KEY_F19, // kVK_F19 (0x50) KEY_NUMPAD_EQUALS, // kVK_ANSI_KeypadEquals (0x51) KEY_NUMPAD0, // kVK_ANSI_Keypad0 (0x52) KEY_NUMPAD1, // kVK_ANSI_Keypad1 (0x53) KEY_NUMPAD2, // kVK_ANSI_Keypad2 (0x54) KEY_NUMPAD3, // kVK_ANSI_Keypad3 (0x55) KEY_NUMPAD4, // kVK_ANSI_Keypad4 (0x56) KEY_NUMPAD5, // kVK_ANSI_Keypad5 (0x57) KEY_NUMPAD6, // kVK_ANSI_Keypad6 (0x58) KEY_NUMPAD7, // kVK_ANSI_Keypad7 (0x59) KEY_NONE, KEY_NUMPAD8, // kVK_ANSI_Keypad8 (0x5B) KEY_NUMPAD9, // kVK_ANSI_Keypad9 (0x5C) KEY_NONE, KEY_NONE, KEY_NONE, KEY_F5, // kVK_F5 (0x60) KEY_F6, // kVK_F6 (0x61) KEY_F7, // kVK_F7 (0x62) KEY_F3, // kVK_F3 (0x63) KEY_F8, // kVK_F8 (0x64) KEY_F9, // kVK_F9 (0x65) KEY_NONE, KEY_F11, // kVK_F11 (0x67) KEY_NONE, KEY_F13, // kVK_F13 (0x69) KEY_F16, // kVK_F16 (0x6A) KEY_F14, // kVK_F14 (0x6B) KEY_NONE, KEY_F10, // kVK_F10 (0x6D) KEY_NONE, KEY_F12, // kVK_F12 (0x6F) KEY_NONE, KEY_F15, // kVK_F15 (0x71) KEY_INSERT, // kVK_Help (0x72) KEY_HOME, // kVK_Home (0x73) KEY_PAGEUP, // kVK_PageUp (0x74) KEY_DELETE, // kVK_ForwardDelete (0x75) KEY_F4, // kVK_F4 (0x76) KEY_END, // kVK_End (0x77) KEY_F2, // kVK_F2 (0x78) KEY_PAGEDOWN, // kVK_PageDown (0x79) KEY_F1, // kVK_F1 (0x7A) KEY_LEFT, // kVK_LeftArrow (0x7B) KEY_RIGHT, // kVK_RightArrow (0x7C) KEY_DOWN, // kVK_DownArrow (0x7D) KEY_UP, // kVK_UpArrow (0x7E) KEY_NONE }; KEY MacClient::s_keyConversion[128]; void MacClient::CheckKeyboardLayout() { #if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_6 void* KCHR = reinterpret_cast(GetScriptManagerVariable(smKCHRCache)); if (MacClient::s_currentKeyboardLayout != KCHR) { MacClient::InitializeKeyConversion(); MacClient::s_currentKeyboardLayout = KCHR; } #endif #if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_6 TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource(); CFDataRef layoutData = static_cast(TISGetInputSourceProperty(inputSrc, kTISPropertyUnicodeKeyLayoutData)); const UCKeyboardLayout* keyboardLayout = reinterpret_cast(CFDataGetBytePtr(layoutData)); if (MacClient::s_currentKeyboardLayout != keyboardLayout) { MacClient::InitializeKeyConversion(); MacClient::s_currentKeyboardLayout = const_cast(keyboardLayout); } #endif } double MacClient::GetMouseSpeed() { #if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_12 double mouseSpeed = 1.0; NXEventHandle handle = NXOpenEventStatus(); if (handle) { IOHIDGetAccelerationWithKey(handle, CFSTR(kIOHIDMouseAccelerationType), &mouseSpeed); NXCloseEventStatus(handle); } return mouseSpeed; #endif #if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_12 double mouseSpeed = 1.0; io_service_t service = IORegistryEntryFromPath(kIOMasterPortDefault, kIOServicePlane ":/IOResources/IOHIDSystem"); if (service != MACH_PORT_NULL) { CFDictionaryRef parameters = static_cast(IORegistryEntryCreateCFProperty(service, CFSTR(kIOHIDParametersKey), kCFAllocatorDefault, kNilOptions)); CFNumberRef speedParameter = static_cast(CFDictionaryGetValue(parameters, CFSTR(kIOHIDMouseAccelerationType))); if (speedParameter) { int32_t number; if (CFNumberGetValue(static_cast(speedParameter), kCFNumberSInt32Type, &number)) { mouseSpeed = static_cast(number) / 65536.0; } } CFRelease(parameters); IOObjectRelease(service); } return mouseSpeed; #endif } bool MacClient::GetTextInputEnabled() { // TODO return false; } void MacClient::InitializeKeyConversion() { memcpy(MacClient::s_keyConversion, MacClient::s_specialKeyConversion, sizeof(MacClient::s_specialKeyConversion)); #if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_6 void* KCHR = reinterpret_cast(GetScriptManagerVariable(smKCHRCache)); if (KCHR) { for (uint16_t i = 0; i < 128; i++) { if (MacClient::s_keyConversion[i] == KEY_NONE) { uint16_t translate = i | (1 << 7); uint32_t state = 0; uint32_t value = KeyTranslate(KCHR, translate, &state); if (state) { value = KeyTranslate(KCHR, translate, &state); } if (value) { value = value - 97 <= 25 ? value - 32 : value; auto string = CFStringCreateWithBytes( nullptr, reinterpret_cast(&value), 1, 0, false ); if (string) { CFIndex len; CFRange range = CFRangeMake(0, 1); CFStringGetBytes( string, range, kCFStringEncodingISOLatin1, 0, 0, reinterpret_cast(&value), 1, &len ); if (len && value) { MacClient::s_keyConversion[i] = static_cast(value); } } } } } } #endif #if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_6 TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource(); CFDataRef layoutData = static_cast(TISGetInputSourceProperty(inputSrc, kTISPropertyUnicodeKeyLayoutData)); const UCKeyboardLayout* keyboardLayout = reinterpret_cast(CFDataGetBytePtr(layoutData)); const uint32_t keyboardType = LMGetKbdType(); if (keyboardLayout) { for (uint16_t i = 0; i < 128; i++) { if (MacClient::s_keyConversion[i] == KEY_NONE) { uint16_t vkey = i; uint32_t state = 0; UniChar buf[1]; UniCharCount len; OSStatus res = UCKeyTranslate( keyboardLayout, vkey, kUCKeyActionUp, 0, keyboardType, 0, &state, 1, &len, buf ); if (res != noErr) { continue; } if (state) { res = UCKeyTranslate( keyboardLayout, vkey, kUCKeyActionUp, 0, keyboardType, 0, &state, 1, &len, buf ); if (res != noErr) { continue; } } uint16_t value = buf[0]; if (len && value) { value = value >= 97 && value <= 122 ? value - 32 : value; MacClient::s_keyConversion[i] = static_cast(value); } } } } #endif } bool MacClient::IsUsingGLLayer() { return true; } void MacClient::PostClipboardKeyEvents(MacClient::ClipboardAction action) { int32_t v1; switch (action) { case ClipboardUndo: v1 = 90; break; case ClipboardCut: v1 = 88; break; case ClipboardCopy: v1 = 67; break; case ClipboardPaste: v1 = 86; break; case ClipboardSelectAll: v1 = 65; break; default: return; } OsInputPostEvent(OS_INPUT_KEY_DOWN, 2, 0, 0, 0); OsInputPostEvent(OS_INPUT_KEY_DOWN, v1, 0, 0, 0); OsInputPostEvent(OS_INPUT_KEY_UP, v1, 0, 0, 0); OsInputPostEvent(OS_INPUT_KEY_UP, 2, 0, 0, 0); } void MacClient::SetMouseCoalescingEnabled(bool enabled) { #if WHOA_SYSTEM_VERSION < WHOA_MACOS_10_5 bool prevEnabled = false; SetMouseCoalescingEnabled(true, &prevEnabled); #endif #if WHOA_SYSTEM_VERSION >= WHOA_MACOS_10_5 [NSEvent setMouseCoalescingEnabled: enabled]; #endif }