10#if defined(QT_PLATFORM_UIKIT)
11#include <UIKit/UIKit.h>
16#include <QtCore/qloggingcategory.h>
17#include <QtGui/QGuiApplication>
28 Qt::KeyboardModifiers swappedModifiers =
modifiers;
36 return swappedModifiers;
40static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaModifierMap[] = {
48Qt::KeyboardModifiers QAppleKeyMapper::fromCocoaModifiers(NSEventModifierFlags cocoaModifiers)
51 for (
const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
52 if (cocoaModifiers & cocoaModifier)
53 qtModifiers |= qtModifier;
59NSEventModifierFlags QAppleKeyMapper::toCocoaModifiers(Qt::KeyboardModifiers qtModifiers)
63 NSEventModifierFlags cocoaModifiers = 0;
64 for (
const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
65 if (qtModifiers & qtModifier)
66 cocoaModifiers |= cocoaModifier;
69 return cocoaModifiers;
72using CarbonModifiers = UInt32;
74static CarbonModifiers toCarbonModifiers(Qt::KeyboardModifiers qtModifiers)
78 static constexpr std::tuple<int, Qt::KeyboardModifier> carbonModifierMap[] = {
86 CarbonModifiers carbonModifiers = 0;
87 for (
const auto &[carbonModifier, qtModifier] : carbonModifierMap) {
88 if (qtModifiers & qtModifier)
89 carbonModifiers |= carbonModifier;
92 return carbonModifiers;
96static QHash<char16_t, Qt::Key> standardKeys = {
148static QHash<char16_t, Qt::Key> virtualKeys = {
177static QHash<char16_t, Qt::Key> functionKeys = {
209 qCDebug(lcQpaKeyMapperKeys,
"Mapping key: %d (0x%04x) / vk %d (0x%04x)",
210 key.unicode(),
key.unicode(), virtualKey, virtualKey);
212 if (
key ==
QChar(kClearCharCode) && virtualKey == 0x47)
216 qCDebug(lcQpaKeyMapperKeys,
"Got digit key: %d",
key.digitValue());
220 if (
key.isLetter()) {
221 qCDebug(lcQpaKeyMapperKeys,
"Got letter key: %d", (
key.toUpper().unicode() -
'A'));
224 if (
key.isSymbol()) {
225 qCDebug(lcQpaKeyMapperKeys,
"Got symbol key: %d", (
key.unicode()));
226 return key.unicode();
229 if (
auto qtKey = standardKeys.value(
key.unicode())) {
232 qCDebug(lcQpaKeyMapperKeys,
"Got key: Qt::Key_Backtab");
241 if (
auto qtKey = virtualKeys.value(virtualKey)) {
247 if (
key >=
QChar(NSUpArrowFunctionKey) &&
key <=
QChar(NSModeSwitchFunctionKey)) {
248 if (
auto qtKey = functionKeys.value(
key.unicode())) {
251 }
else if (
key >=
QChar(NSF1FunctionKey) &&
key <=
QChar(NSF35FunctionKey)) {
252 auto functionKey =
Qt::Key_F1 + (
key.unicode() - NSF1FunctionKey) ;
253 qCDebug(lcQpaKeyMapperKeys) <<
"Got" << functionKey;
258 qCDebug(lcQpaKeyMapperKeys,
"Unknown case.. %d[%d] %d",
key.unicode(),
key.toLatin1(), virtualKey);
264static const int NSEscapeCharacter = 27;
266static const QHash<char16_t, Qt::Key> cocoaKeys = {
332 return QChar(NSCarriageReturnCharacter);
334 return QChar(NSBackspaceCharacter);
336 Q_CONSTINIT
static QHash<Qt::Key, char16_t> reverseCocoaKeys;
337 if (reverseCocoaKeys.isEmpty()) {
338 reverseCocoaKeys.reserve(cocoaKeys.size());
340 reverseCocoaKeys.insert(
it.value(),
it.key());
343 return reverseCocoaKeys.value(
key);
348 if (
auto key = cocoaKeys.value(keyCode.unicode()))
351 return Qt::Key(keyCode.toUpper().unicode());
358 return fromCocoaModifiers(NSEvent.modifierFlags);
361bool QAppleKeyMapper::updateKeyboard()
363 QCFType<TISInputSourceRef>
source = TISCopyInputMethodKeyboardLayoutOverride();
365 source = TISCopyCurrentKeyboardInputSource();
367 if (m_keyboardMode != NullMode &&
source == m_currentInputSource)
371 m_currentInputSource =
source;
372 m_keyboardKind = LMGetKbdType();
376 if (
auto data = CFDataRef(TISGetInputSourceProperty(
source, kTISPropertyUnicodeKeyLayoutData))) {
377 const UCKeyboardLayout *uchrData =
reinterpret_cast<const UCKeyboardLayout *
>(CFDataGetBytePtr(
data));
379 m_keyboardLayoutFormat = uchrData;
380 m_keyboardMode = UnicodeMode;
382 m_keyboardLayoutFormat =
nullptr;
383 m_keyboardMode = NullMode;
386 qCDebug(lcQpaKeyMapper) <<
"Updated keyboard to"
387 << QString::fromCFString(CFStringRef(TISGetInputSourceProperty(
388 m_currentInputSource, kTISPropertyLocalizedName)));
393static constexpr Qt::KeyboardModifiers modifierCombinations[] = {
416const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey)
const
418 static_assert(
sizeof(modifierCombinations) /
sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations);
422 auto &
keyMap = m_keyMap[virtualKey];
426 qCDebug(lcQpaKeyMapper,
"Updating key map for virtual key 0x%02x", (
uint)virtualKey);
431 const bool canMapCocoaEvent = NSApp.currentEvent.type == NSEventTypeKeyDown;
433 if (!canMapCocoaEvent)
434 qCWarning(lcQpaKeyMapper) <<
"Could not map key to character for event" << NSApp.currentEvent;
436 for (
int i = 0;
i < kNumModifierCombinations; ++
i) {
439 auto qtModifiers = modifierCombinations[
i];
440 auto carbonModifiers = toCarbonModifiers(qtModifiers);
441 const UInt32 modifierKeyState = (carbonModifiers >> 8) & 0xFF;
443 UInt32 deadKeyState = 0;
444 static const UniCharCount maxStringLength = 10;
445 static UniChar unicodeString[maxStringLength];
446 UniCharCount actualStringLength = 0;
447 OSStatus err = UCKeyTranslate(m_keyboardLayoutFormat, virtualKey,
448 kUCKeyActionDown, modifierKeyState, m_keyboardKind,
449 kUCKeyTranslateNoDeadKeysMask, &deadKeyState,
450 maxStringLength, &actualStringLength,
454 QChar carbonUnicodeKey;
455 if (err == noErr && actualStringLength)
456 carbonUnicodeKey =
QChar(unicodeString[0]);
458 if (canMapCocoaEvent) {
462 auto cocoaModifiers = toCocoaModifiers(qtModifiers);
463 auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers];
465 QChar cocoaUnicodeKey;
466 if (charactersWithModifiers.length > 0)
467 cocoaUnicodeKey =
QChar([charactersWithModifiers characterAtIndex:0]);
469 if (cocoaUnicodeKey != carbonUnicodeKey) {
470 qCWarning(lcQpaKeyMapper) <<
"Mismatch between Cocoa" << cocoaUnicodeKey
471 <<
"and Carbon" << carbonUnicodeKey <<
"for virtual key" << virtualKey
472 <<
"with" << qtModifiers;
476 int qtKey = toKeyCode(carbonUnicodeKey, virtualKey, qtModifiers);
478 qtKey = carbonUnicodeKey.unicode();
482 qCDebug(lcQpaKeyMapper).verbosity(0) <<
"\t" << qtModifiers
510 QList<QKeyCombination>
ret;
512 const auto nativeVirtualKey =
event->nativeVirtualKey();
513 if (!nativeVirtualKey)
516 auto keyMap = keyMapForKey(nativeVirtualKey);
521 auto eventModifiers =
event->modifiers();
523 int startingModifierLayer = 0;
524 if (toCocoaModifiers(eventModifiers) & NSEventModifierFlagCommand) {
536 static constexpr int kCommandLayer = 2;
538 int(eventModifiers) +
int(
keyMap[kCommandLayer]));
559 if (unmodifiedKey <= 0xff)
560 startingModifierLayer = 1;
564 for (
int i = startingModifierLayer;
i < 15; ++
i) {
565 auto keyAfterApplyingModifiers =
keyMap[
i];
566 if (!keyAfterApplyingModifiers)
571 auto candidateModifiers = modifierCombinations[
i];
572 if ((eventModifiers & candidateModifiers) == candidateModifiers) {
575 auto additionalModifiers = eventModifiers & ~candidateModifiers;
578 int(additionalModifiers) +
int(keyAfterApplyingModifiers));
583 const auto existingCombination = std::find_if(
584 ret.begin(),
ret.end(), [&](
auto existingCombination) {
585 return existingCombination.key() == keyAfterApplyingModifiers;
588 if (existingCombination !=
ret.end()) {
603 if (replacementModifiers > existingModifiers)
604 *existingCombination = keyCombination;
607 ret << keyCombination;
620 NSString *charactersIgnoringModifiers,
QString &
text)
626 }
else if ([
characters isEqualToString:
@"\r"]) {
634 ([charactersIgnoringModifiers
length] != 0)) {
635 ch =
QChar([charactersIgnoringModifiers characterAtIndex:0]);
640 (
ch.unicode() < 0xf700 ||
ch.unicode() > 0xf8ff)) {
652 static QHash<NSString *, Qt::Key> uiKitKeys = {
676 if (
auto key = uiKitKeys.value(keyCode))
694 ulong nativeModifiers = 0;
696 if (qtModifiers & qtModifier)
697 nativeModifiers |= nativeModifier;
700 return nativeModifiers;
707 if (nativeModifiers & nativeModifier)
708 qtModifiers |= qtModifier;
static ulong toUIKitModifiers(Qt::KeyboardModifiers)
static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters, NSString *charactersIgnoringModifiers, QString &text)
static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers)
QList< QKeyCombination > possibleKeyCombinations(const QKeyEvent *event) const override
Qt::KeyboardModifiers queryKeyboardModifiers() const override
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
static constexpr QKeyCombination fromCombined(int combined)
The QKeyEvent class describes a key event.
The QKeySequence class encapsulates a key sequence as used by shortcuts.
QString toString(SequenceFormat format=PortableText) const
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
EGLImageKHR int int EGLuint64KHR * modifiers
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ AA_MacDontSwapCtrlAndMeta
API_AVAILABLE(ios(13.4)) Qt
static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers modifiers)
static constexpr std::tuple< ulong, Qt::KeyboardModifier > uiKitModifierMap[]
#define Q_LOGGING_CATEGORY(name,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLchar * source
static QString qtKey(CFStringRef cfkey)
#define qUtf8Printable(string)
static const struct @450 keyMap[]
QList< QChar > characters