clean: simplify macOS hotkey mapping code
Some checks are pending
SonarCloud / Build and analyze (push) Waiting to run

This commit is contained in:
shenleban tongying 2024-11-12 07:33:28 -05:00 committed by GitHub
parent 8fc71c9586
commit 453948155a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -6,7 +6,9 @@
#include <QObject> #include <QObject>
#include <QPushButton> #include <QPushButton>
#include <QTimer> #include <QTimer>
#include <memory> #include <memory>
#include <vector>
#import <Appkit/Appkit.h> #import <Appkit/Appkit.h>
@ -31,70 +33,63 @@ struct ReverseMapEntry {
UInt16 keyCode; UInt16 keyCode;
}; };
static struct ReverseMapEntry* mapping; static std::vector<ReverseMapEntry> mapping;
static int mapEntries = 0;
/// 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() void createMapping()
{ {
if (mapping == NULL) { if (mapping.empty()) {
TISInputSourceRef inputSourceRef = TISCopyInputSourceForLanguage(CFSTR("en")); mapping.reserve(128);
if (!inputSourceRef) {
inputSourceRef = TISCopyCurrentKeyboardInputSource(); TISInputSourceRef inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource();
}
if (!inputSourceRef) { if (!inputSourceRef) {
return; return;
} }
CFDataRef dataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, CFDataRef uchrDataRef = (CFDataRef)TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData);
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 const UCKeyboardLayout* UCKeyboardLayoutPtr;
if (!dataRef) {
// solve the null value under Japanese keyboard if (uchrDataRef) {
inputSourceRef = TISCopyCurrentKeyboardLayoutInputSource(); UCKeyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(uchrDataRef);
dataRef = static_cast<CFDataRef>((TISGetInputSourceProperty(inputSourceRef, kTISPropertyUnicodeKeyLayoutData)));
if (!dataRef) {
return;
}
} }
const UCKeyboardLayout* keyboardLayoutPtr = (const UCKeyboardLayout*)CFDataGetBytePtr(dataRef); if (!UCKeyboardLayoutPtr) {
if (!keyboardLayoutPtr) {
return; return;
} }
mapping = (struct ReverseMapEntry*)calloc(128, sizeof(struct ReverseMapEntry)); for (UInt16 i = 0; i < 128; i++) {
if (!mapping) {
return;
}
mapEntries = 0;
for (int i = 0; i < 128; i++) {
UInt32 theDeadKeyState = 0; UInt32 theDeadKeyState = 0;
UniCharCount theLength = 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, kUCKeyTranslateNoDeadKeysBit, &theDeadKeyState, 1, &theLength,
&mapping[mapEntries].character) &temp_char_buf)
== noErr == noErr
&& theLength > 0) { && theLength > 0) {
if (isprint(mapping[mapEntries].character)) { if (isprint(temp_char_buf)) {
mapping[mapEntries++].keyCode = i; mapping.emplace_back(ReverseMapEntry { temp_char_buf, i });
} }
} }
} }
mapping.shrink_to_fit();
} }
} }
quint32 qtKeyToNativeKey(quint32 key) quint32 qtKeyToNativeKey(UniChar key)
{ {
createMapping(); createMapping();
if (mapping == NULL) { if (mapping.empty()) {
return 0; return 0;
} }
for (int i = 0; i < mapEntries; i++) { for (auto& m : mapping) {
if (mapping[i].character == key) { if (m.character == key) {
return mapping[i].keyCode; return m.keyCode;
} }
} }
@ -345,7 +340,7 @@ quint32 HotkeyWrapper::nativeKey(int key)
return 0x72; return 0x72;
default:; default:;
} }
return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().toLatin1()); return MacKeyMapping::qtKeyToNativeKey(QChar(key).toLower().unicode());
} }
void HotkeyWrapper::sendCmdC() void HotkeyWrapper::sendCmdC()