From 453948155a2df5ce4bbe989eab60c05f6ae6dbd1 Mon Sep 17 00:00:00 2001 From: shenleban tongying Date: Tue, 12 Nov 2024 07:33:28 -0500 Subject: [PATCH] clean: simplify macOS hotkey mapping code --- src/macos/machotkeywrapper.mm | 69 ++++++++++++++++------------------- 1 file changed, 32 insertions(+), 37 deletions(-) diff --git a/src/macos/machotkeywrapper.mm b/src/macos/machotkeywrapper.mm index c7f7750b..8ab0d7b5 100644 --- a/src/macos/machotkeywrapper.mm +++ b/src/macos/machotkeywrapper.mm @@ -6,7 +6,9 @@ #include #include #include + #include +#include #import @@ -31,70 +33,63 @@ struct ReverseMapEntry { UInt16 keyCode; }; -static struct ReverseMapEntry* mapping; -static int mapEntries = 0; +static std::vector mapping; +/// References: +/// * https://github.com/libsdl-org/SDL/blob/fc12cc6dfd859a4e01376162a58f12208e539ac6/src/video/cocoa/SDL_cocoakeyboard.m#L345 +/// * https://github.com/qt/qtbase/blob/922369844fcb75386237bca3eef59edd5093f58d/src/gui/platform/darwin/qapplekeymapper.mm#L449 +/// +/// Known possible flaws 1) UCKeyTranslate doesn't handle modifiers at all 2) Handling keyboard switching void createMapping() { - if (mapping == NULL) { - TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage(CFSTR("en")); - if (!inputSourceRef) { - inputSourceRef = TISCopyCurrentKeyboardInputSource(); - } + if (mapping.empty()) { + mapping.reserve(128); + + TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); if (!inputSourceRef) { return; } - CFDataRef dataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, - kTISPropertyUnicodeKeyLayoutData); - // this method returns null under macos Japanese input method(and also Chinese), which causes cmd+C+C not to be registered as a hotkey - if (!dataRef) { - // solve the null value under Japanese keyboard - inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); - dataRef = static_cast((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData))); - if (!dataRef) { - return; - } + CFDataRef uchrDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData); + + const UCKeyboardLayout* UCKeyboardLayoutPtr; + + if (uchrDataRef) { + UCKeyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(uchrDataRef); } - const UCKeyboardLayout* keyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(dataRef); - if (!keyboardLayoutPtr) { + if (!UCKeyboardLayoutPtr) { return; } - mapping = (struct ReverseMapEntry*)calloc(128, sizeof(struct ReverseMapEntry)); - if (!mapping) { - return; - } - - mapEntries = 0; - - for (int i = 0; i < 128; i++) { + for (UInt16 i = 0; i < 128; i++) { UInt32 theDeadKeyState = 0; UniCharCount theLength = 0; - if (UCKeyTranslate(keyboardLayoutPtr, i, kUCKeyActionDisplay, 0, LMGetKbdType(), + UniChar temp_char_buf; + if (UCKeyTranslate(UCKeyboardLayoutPtr, i, kUCKeyActionDown, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength, - &mapping[mapEntries].character) + &temp_char_buf) == noErr && theLength > 0) { - if (isprint(mapping[mapEntries].character)) { - mapping[mapEntries++].keyCode = i; + if (isprint(temp_char_buf)) { + mapping.emplace_back(ReverseMapEntry { temp_char_buf, i }); } } } + mapping.shrink_to_fit(); } } -quint32 qtKeyToNativeKey(quint32 key) +quint32 qtKeyToNativeKey(UniChar key) { createMapping(); - if (mapping == NULL) { + if (mapping.empty()) { return 0; } - for (int i = 0; i < mapEntries; i++) { - if (mapping[i].character == key) { - return mapping[i].keyCode; + for (auto& m : mapping) { + if (m.character == key) { + return m.keyCode; } } @@ -345,7 +340,7 @@ quint32 HotkeyWrapper::nativeKey(int key) return 0x72; default:; } - return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().toLatin1()); + return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().unicode()); } void HotkeyWrapper::sendCmdC()