10#if defined(QT_PLATFORM_UIKIT)
11#include <UIKit/UIKit.h>
16#include <QtCore/qloggingcategory.h>
17#include <QtGui/QGuiApplication>
29 Qt::KeyboardModifiers swappedModifiers =
modifiers;
37 return swappedModifiers;
41 NSString *charactersIgnoringModifiers,
QString &
text)
47 }
else if ([
characters isEqualToString:
@"\r"]) {
55 ([charactersIgnoringModifiers
length] != 0)) {
56 ch =
QChar([charactersIgnoringModifiers characterAtIndex:0]);
61 (
ch.unicode() < 0xf700 ||
ch.unicode() > 0xf8ff)) {
71static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaModifierMap[] = {
79Qt::KeyboardModifiers QAppleKeyMapper::fromCocoaModifiers(NSEventModifierFlags cocoaModifiers)
82 for (
const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
83 if (cocoaModifiers & cocoaModifier)
84 qtModifiers |= qtModifier;
90NSEventModifierFlags QAppleKeyMapper::toCocoaModifiers(Qt::KeyboardModifiers qtModifiers)
94 NSEventModifierFlags cocoaModifiers = 0;
95 for (
const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
96 if (qtModifiers & qtModifier)
97 cocoaModifiers |= cocoaModifier;
100 return cocoaModifiers;
103using CarbonModifiers = UInt32;
105static CarbonModifiers toCarbonModifiers(Qt::KeyboardModifiers qtModifiers)
109 static constexpr std::tuple<int, Qt::KeyboardModifier> carbonModifierMap[] = {
117 CarbonModifiers carbonModifiers = 0;
118 for (
const auto &[carbonModifier, qtModifier] : carbonModifierMap) {
119 if (qtModifiers & qtModifier)
120 carbonModifiers |= carbonModifier;
123 return carbonModifiers;
240 qCDebug(lcQpaKeyMapperKeys,
"Mapping key: %d (0x%04x) / vk %d (0x%04x)",
241 key.unicode(),
key.unicode(), virtualKey, virtualKey);
243 if (
key ==
QChar(kClearCharCode) && virtualKey == 0x47)
247 qCDebug(lcQpaKeyMapperKeys,
"Got digit key: %d",
key.digitValue());
251 if (
key.isLetter()) {
252 qCDebug(lcQpaKeyMapperKeys,
"Got letter key: %d", (
key.toUpper().unicode() -
'A'));
255 if (
key.isSymbol()) {
256 qCDebug(lcQpaKeyMapperKeys,
"Got symbol key: %d", (
key.unicode()));
257 return key.unicode();
263 qCDebug(lcQpaKeyMapperKeys,
"Got key: Qt::Key_Backtab");
272 if (
auto qtKey = virtualKeys.
value(virtualKey)) {
278 if (
key >=
QChar(NSUpArrowFunctionKey) &&
key <=
QChar(NSModeSwitchFunctionKey)) {
282 }
else if (
key >=
QChar(NSF1FunctionKey) &&
key <=
QChar(NSF35FunctionKey)) {
283 auto functionKey =
Qt::Key_F1 + (
key.unicode() - NSF1FunctionKey) ;
284 qCDebug(lcQpaKeyMapperKeys) <<
"Got" << functionKey;
289 qCDebug(lcQpaKeyMapperKeys,
"Unknown case.. %d[%d] %d",
key.unicode(),
key.toLatin1(), virtualKey);
295static const int NSEscapeCharacter = 27;
363 return QChar(NSCarriageReturnCharacter);
365 return QChar(NSBackspaceCharacter);
368 if (reverseCocoaKeys.isEmpty()) {
371 reverseCocoaKeys.insert(
it.value(),
it.key());
374 return reverseCocoaKeys.value(
key);
389 return fromCocoaModifiers(NSEvent.modifierFlags);
392bool QAppleKeyMapper::updateKeyboard()
396 source = TISCopyCurrentKeyboardInputSource();
398 if (m_keyboardMode != NullMode &&
source == m_currentInputSource)
402 m_currentInputSource =
source;
403 m_keyboardKind = LMGetKbdType();
407 if (
auto data = CFDataRef(TISGetInputSourceProperty(
source, kTISPropertyUnicodeKeyLayoutData))) {
408 const UCKeyboardLayout *uchrData =
reinterpret_cast<const UCKeyboardLayout *
>(CFDataGetBytePtr(
data));
410 m_keyboardLayoutFormat = uchrData;
411 m_keyboardMode = UnicodeMode;
413 m_keyboardLayoutFormat =
nullptr;
414 m_keyboardMode = NullMode;
417 qCDebug(lcQpaKeyMapper) <<
"Updated keyboard to"
418 << QString::fromCFString(CFStringRef(TISGetInputSourceProperty(
419 m_currentInputSource, kTISPropertyLocalizedName)));
424static constexpr Qt::KeyboardModifiers modifierCombinations[] = {
447const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey)
const
449 static_assert(
sizeof(modifierCombinations) /
sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations);
453 auto &
keyMap = m_keyMap[virtualKey];
457 qCDebug(lcQpaKeyMapper,
"Updating key map for virtual key 0x%02x", (
uint)virtualKey);
462 const bool canMapCocoaEvent = NSApp.currentEvent.type == NSEventTypeKeyDown;
464 if (!canMapCocoaEvent)
465 qCWarning(lcQpaKeyMapper) <<
"Could not map key to character for event" << NSApp.currentEvent;
467 for (
int i = 0;
i < kNumModifierCombinations; ++
i) {
470 auto qtModifiers = modifierCombinations[
i];
471 auto carbonModifiers = toCarbonModifiers(qtModifiers);
472 const UInt32 modifierKeyState = (carbonModifiers >> 8) & 0xFF;
474 UInt32 deadKeyState = 0;
475 static const UniCharCount maxStringLength = 10;
476 static UniChar unicodeString[maxStringLength];
477 UniCharCount actualStringLength = 0;
478 OSStatus err = UCKeyTranslate(m_keyboardLayoutFormat, virtualKey,
479 kUCKeyActionDown, modifierKeyState, m_keyboardKind,
480 kUCKeyTranslateNoDeadKeysMask, &deadKeyState,
481 maxStringLength, &actualStringLength,
485 QChar carbonUnicodeKey;
486 if (err == noErr && actualStringLength)
487 carbonUnicodeKey =
QChar(unicodeString[0]);
489 if (@available(macOS 10.15, *)) {
490 if (canMapCocoaEvent) {
494 auto cocoaModifiers = toCocoaModifiers(qtModifiers);
495 auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers];
497 QChar cocoaUnicodeKey;
498 if (charactersWithModifiers.length > 0)
499 cocoaUnicodeKey =
QChar([charactersWithModifiers characterAtIndex:0]);
501 if (cocoaUnicodeKey != carbonUnicodeKey) {
502 qCWarning(lcQpaKeyMapper) <<
"Mismatch between Cocoa" << cocoaUnicodeKey
503 <<
"and Carbon" << carbonUnicodeKey <<
"for virtual key" << virtualKey
504 <<
"with" << qtModifiers;
509 int qtKey = toKeyCode(carbonUnicodeKey, virtualKey, qtModifiers);
515 qCDebug(lcQpaKeyMapper).verbosity(0) <<
"\t" << qtModifiers
545 qCDebug(lcQpaKeyMapper) <<
"Computing possible keys for" <<
event;
547 const auto nativeVirtualKey =
event->nativeVirtualKey();
548 if (!nativeVirtualKey)
551 auto keyMap = keyMapForKey(nativeVirtualKey);
556 auto eventModifiers =
event->modifiers();
561 ret << int(eventModifiers) + int(unmodifiedKey);
564 for (
int i = 1;
i < 8; ++
i) {
565 auto keyAfterApplyingModifiers =
keyMap[
i];
566 if (keyAfterApplyingModifiers == unmodifiedKey)
568 if (!keyAfterApplyingModifiers)
573 auto candidateModifiers = modifierCombinations[
i];
574 if ((eventModifiers & candidateModifiers) == candidateModifiers) {
577 auto additionalModifiers = eventModifiers & ~candidateModifiers;
578 ret << int(additionalModifiers) + int(keyAfterApplyingModifiers);
582 if (lcQpaKeyMapper().isDebugEnabled()) {
583 qCDebug(lcQpaKeyMapper) <<
"Possible keys:";
584 for (
int keyAndModifiers :
ret) {
587 qCDebug(lcQpaKeyMapper).verbosity(0) <<
"\t-"
588 << keyCombination <<
"/" << keySequence <<
"/"
627 if (
auto key = uiKitKeys.
value(keyCode))
645 ulong nativeModifiers = 0;
647 if (qtModifiers & qtModifier)
648 nativeModifiers |= nativeModifier;
651 return nativeModifiers;
658 if (nativeModifiers & nativeModifier)
659 qtModifiers |= qtModifier;
static ulong toUIKitModifiers(Qt::KeyboardModifiers)
static Qt::Key fromNSString(Qt::KeyboardModifiers qtMods, NSString *characters, NSString *charactersIgnoringModifiers, QString &text)
QList< int > possibleKeys(const QKeyEvent *event) const
static Qt::KeyboardModifiers fromUIKitModifiers(ulong uikitModifiers)
static Qt::KeyboardModifiers queryKeyboardModifiers()
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
QChar toUpper() const noexcept
Returns the uppercase equivalent if the character is lowercase or titlecase; otherwise returns the ch...
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
qsizetype size() const noexcept
Returns the number of items in the hash.
void reserve(qsizetype size)
Ensures that the QHash's internal hash table has space to store at least size items without having to...
T value(const Key &key) const noexcept
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
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 @437 keyMap[]
QList< QChar > characters