Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qapplekeymapper.mm
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qglobal.h>
5
6#ifdef Q_OS_MACOS
7#include <AppKit/AppKit.h>
8#endif
9
10#if defined(QT_PLATFORM_UIKIT)
11#include <UIKit/UIKit.h>
12#endif
13
14#include "qapplekeymapper_p.h"
15
16#include <QtCore/qloggingcategory.h>
17#include <QtGui/QGuiApplication>
18
20
21Q_LOGGING_CATEGORY(lcQpaKeyMapper, "qt.qpa.keymapper");
22Q_LOGGING_CATEGORY(lcQpaKeyMapperKeys, "qt.qpa.keymapper.keys");
23
24static Qt::KeyboardModifiers swapModifiersIfNeeded(const Qt::KeyboardModifiers modifiers)
25{
27 return modifiers;
28
29 Qt::KeyboardModifiers swappedModifiers = modifiers;
30 swappedModifiers &= ~(Qt::MetaModifier | Qt::ControlModifier);
31
33 swappedModifiers |= Qt::MetaModifier;
35 swappedModifiers |= Qt::ControlModifier;
36
37 return swappedModifiers;
38}
39
40Qt::Key QAppleKeyMapper::fromNSString(Qt::KeyboardModifiers qtModifiers, NSString *characters,
41 NSString *charactersIgnoringModifiers, QString &text)
42{
43 if ([characters isEqualToString:@"\t"]) {
44 if (qtModifiers & Qt::ShiftModifier)
45 return Qt::Key_Backtab;
46 return Qt::Key_Tab;
47 } else if ([characters isEqualToString:@"\r"]) {
48 if (qtModifiers & Qt::KeypadModifier)
49 return Qt::Key_Enter;
50 return Qt::Key_Return;
51 }
52 if ([characters length] != 0 || [charactersIgnoringModifiers length] != 0) {
53 QChar ch;
54 if (((qtModifiers & Qt::MetaModifier) || (qtModifiers & Qt::AltModifier)) &&
55 ([charactersIgnoringModifiers length] != 0)) {
56 ch = QChar([charactersIgnoringModifiers characterAtIndex:0]);
57 } else if ([characters length] != 0) {
58 ch = QChar([characters characterAtIndex:0]);
59 }
60 if (!(qtModifiers & (Qt::ControlModifier | Qt::MetaModifier)) &&
61 (ch.unicode() < 0xf700 || ch.unicode() > 0xf8ff)) {
62 text = QString::fromNSString(characters);
63 }
64 if (!ch.isNull())
65 return Qt::Key(ch.toUpper().unicode());
66 }
67 return Qt::Key_unknown;
68}
69
70#ifdef Q_OS_MACOS
71static constexpr std::tuple<NSEventModifierFlags, Qt::KeyboardModifier> cocoaModifierMap[] = {
72 { NSEventModifierFlagShift, Qt::ShiftModifier },
73 { NSEventModifierFlagControl, Qt::ControlModifier },
74 { NSEventModifierFlagCommand, Qt::MetaModifier },
75 { NSEventModifierFlagOption, Qt::AltModifier },
76 { NSEventModifierFlagNumericPad, Qt::KeypadModifier }
77};
78
79Qt::KeyboardModifiers QAppleKeyMapper::fromCocoaModifiers(NSEventModifierFlags cocoaModifiers)
80{
81 Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
82 for (const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
83 if (cocoaModifiers & cocoaModifier)
84 qtModifiers |= qtModifier;
85 }
86
87 return swapModifiersIfNeeded(qtModifiers);
88}
89
90NSEventModifierFlags QAppleKeyMapper::toCocoaModifiers(Qt::KeyboardModifiers qtModifiers)
91{
92 qtModifiers = swapModifiersIfNeeded(qtModifiers);
93
94 NSEventModifierFlags cocoaModifiers = 0;
95 for (const auto &[cocoaModifier, qtModifier] : cocoaModifierMap) {
96 if (qtModifiers & qtModifier)
97 cocoaModifiers |= cocoaModifier;
98 }
99
100 return cocoaModifiers;
101}
102
103using CarbonModifiers = UInt32; // As opposed to EventModifiers which is UInt16
104
105static CarbonModifiers toCarbonModifiers(Qt::KeyboardModifiers qtModifiers)
106{
107 qtModifiers = swapModifiersIfNeeded(qtModifiers);
108
109 static constexpr std::tuple<int, Qt::KeyboardModifier> carbonModifierMap[] = {
110 { shiftKey, Qt::ShiftModifier },
111 { controlKey, Qt::ControlModifier },
112 { cmdKey, Qt::MetaModifier },
113 { optionKey, Qt::AltModifier },
114 { kEventKeyModifierNumLockMask, Qt::KeypadModifier }
115 };
116
117 CarbonModifiers carbonModifiers = 0;
118 for (const auto &[carbonModifier, qtModifier] : carbonModifierMap) {
119 if (qtModifiers & qtModifier)
120 carbonModifiers |= carbonModifier;
121 }
122
123 return carbonModifiers;
124}
125
126// Keyboard keys (non-modifiers)
127static QHash<char16_t, Qt::Key> standardKeys = {
128 { kHomeCharCode, Qt::Key_Home },
129 { kEnterCharCode, Qt::Key_Enter },
130 { kEndCharCode, Qt::Key_End },
131 { kBackspaceCharCode, Qt::Key_Backspace },
132 { kTabCharCode, Qt::Key_Tab },
133 { kPageUpCharCode, Qt::Key_PageUp },
134 { kPageDownCharCode, Qt::Key_PageDown },
135 { kReturnCharCode, Qt::Key_Return },
136 { kEscapeCharCode, Qt::Key_Escape },
137 { kLeftArrowCharCode, Qt::Key_Left },
138 { kRightArrowCharCode, Qt::Key_Right },
139 { kUpArrowCharCode, Qt::Key_Up },
140 { kDownArrowCharCode, Qt::Key_Down },
141 { kHelpCharCode, Qt::Key_Help },
142 { kDeleteCharCode, Qt::Key_Delete },
143 // ASCII maps, for debugging
144 { ':', Qt::Key_Colon },
145 { ';', Qt::Key_Semicolon },
146 { '<', Qt::Key_Less },
147 { '=', Qt::Key_Equal },
148 { '>', Qt::Key_Greater },
149 { '?', Qt::Key_Question },
150 { '@', Qt::Key_At },
151 { ' ', Qt::Key_Space },
152 { '!', Qt::Key_Exclam },
153 { '"', Qt::Key_QuoteDbl },
154 { '#', Qt::Key_NumberSign },
155 { '$', Qt::Key_Dollar },
156 { '%', Qt::Key_Percent },
157 { '&', Qt::Key_Ampersand },
158 { '\'', Qt::Key_Apostrophe },
159 { '(', Qt::Key_ParenLeft },
160 { ')', Qt::Key_ParenRight },
161 { '*', Qt::Key_Asterisk },
162 { '+', Qt::Key_Plus },
163 { ',', Qt::Key_Comma },
164 { '-', Qt::Key_Minus },
165 { '.', Qt::Key_Period },
166 { '/', Qt::Key_Slash },
167 { '[', Qt::Key_BracketLeft },
168 { ']', Qt::Key_BracketRight },
169 { '\\', Qt::Key_Backslash },
170 { '_', Qt::Key_Underscore },
171 { '`', Qt::Key_QuoteLeft },
172 { '{', Qt::Key_BraceLeft },
173 { '}', Qt::Key_BraceRight },
174 { '|', Qt::Key_Bar },
175 { '~', Qt::Key_AsciiTilde },
176 { '^', Qt::Key_AsciiCircum }
177};
178
179static QHash<char16_t, Qt::Key> virtualKeys = {
180 { kVK_F1, Qt::Key_F1 },
181 { kVK_F2, Qt::Key_F2 },
182 { kVK_F3, Qt::Key_F3 },
183 { kVK_F4, Qt::Key_F4 },
184 { kVK_F5, Qt::Key_F5 },
185 { kVK_F6, Qt::Key_F6 },
186 { kVK_F7, Qt::Key_F7 },
187 { kVK_F8, Qt::Key_F8 },
188 { kVK_F9, Qt::Key_F9 },
189 { kVK_F10, Qt::Key_F10 },
190 { kVK_F11, Qt::Key_F11 },
191 { kVK_F12, Qt::Key_F12 },
192 { kVK_F13, Qt::Key_F13 },
193 { kVK_F14, Qt::Key_F14 },
194 { kVK_F15, Qt::Key_F15 },
195 { kVK_F16, Qt::Key_F16 },
196 { kVK_Return, Qt::Key_Return },
197 { kVK_Tab, Qt::Key_Tab },
198 { kVK_Escape, Qt::Key_Escape },
199 { kVK_Help, Qt::Key_Help },
200 { kVK_UpArrow, Qt::Key_Up },
201 { kVK_DownArrow, Qt::Key_Down },
202 { kVK_LeftArrow, Qt::Key_Left },
203 { kVK_RightArrow, Qt::Key_Right },
204 { kVK_PageUp, Qt::Key_PageUp },
205 { kVK_PageDown, Qt::Key_PageDown }
206};
207
208static QHash<char16_t, Qt::Key> functionKeys = {
209 { NSUpArrowFunctionKey, Qt::Key_Up },
210 { NSDownArrowFunctionKey, Qt::Key_Down },
211 { NSLeftArrowFunctionKey, Qt::Key_Left },
212 { NSRightArrowFunctionKey, Qt::Key_Right },
213 // F1-35 function keys handled manually below
214 { NSInsertFunctionKey, Qt::Key_Insert },
215 { NSDeleteFunctionKey, Qt::Key_Delete },
216 { NSHomeFunctionKey, Qt::Key_Home },
217 { NSEndFunctionKey, Qt::Key_End },
218 { NSPageUpFunctionKey, Qt::Key_PageUp },
219 { NSPageDownFunctionKey, Qt::Key_PageDown },
220 { NSPrintScreenFunctionKey, Qt::Key_Print },
221 { NSScrollLockFunctionKey, Qt::Key_ScrollLock },
222 { NSPauseFunctionKey, Qt::Key_Pause },
223 { NSSysReqFunctionKey, Qt::Key_SysReq },
224 { NSMenuFunctionKey, Qt::Key_Menu },
225 { NSPrintFunctionKey, Qt::Key_Printer },
226 { NSClearDisplayFunctionKey, Qt::Key_Clear },
227 { NSInsertCharFunctionKey, Qt::Key_Insert },
228 { NSDeleteCharFunctionKey, Qt::Key_Delete },
229 { NSSelectFunctionKey, Qt::Key_Select },
230 { NSExecuteFunctionKey, Qt::Key_Execute },
231 { NSUndoFunctionKey, Qt::Key_Undo },
232 { NSRedoFunctionKey, Qt::Key_Redo },
233 { NSFindFunctionKey, Qt::Key_Find },
234 { NSHelpFunctionKey, Qt::Key_Help },
235 { NSModeSwitchFunctionKey, Qt::Key_Mode_switch }
236};
237
238static int toKeyCode(const QChar &key, int virtualKey, int modifiers)
239{
240 qCDebug(lcQpaKeyMapperKeys, "Mapping key: %d (0x%04x) / vk %d (0x%04x)",
241 key.unicode(), key.unicode(), virtualKey, virtualKey);
242
243 if (key == QChar(kClearCharCode) && virtualKey == 0x47)
244 return Qt::Key_Clear;
245
246 if (key.isDigit()) {
247 qCDebug(lcQpaKeyMapperKeys, "Got digit key: %d", key.digitValue());
248 return key.digitValue() + Qt::Key_0;
249 }
250
251 if (key.isLetter()) {
252 qCDebug(lcQpaKeyMapperKeys, "Got letter key: %d", (key.toUpper().unicode() - 'A'));
253 return (key.toUpper().unicode() - 'A') + Qt::Key_A;
254 }
255 if (key.isSymbol()) {
256 qCDebug(lcQpaKeyMapperKeys, "Got symbol key: %d", (key.unicode()));
257 return key.unicode();
258 }
259
260 if (auto qtKey = standardKeys.value(key.unicode())) {
261 // To work like Qt for X11 we issue Backtab when Shift + Tab are pressed
263 qCDebug(lcQpaKeyMapperKeys, "Got key: Qt::Key_Backtab");
264 return Qt::Key_Backtab;
265 }
266
267 qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey;
268 return qtKey;
269 }
270
271 // Last ditch try to match the scan code
272 if (auto qtKey = virtualKeys.value(virtualKey)) {
273 qCDebug(lcQpaKeyMapperKeys) << "Got scancode" << qtKey;
274 return qtKey;
275 }
276
277 // Check if they belong to key codes in private unicode range
278 if (key >= QChar(NSUpArrowFunctionKey) && key <= QChar(NSModeSwitchFunctionKey)) {
279 if (auto qtKey = functionKeys.value(key.unicode())) {
280 qCDebug(lcQpaKeyMapperKeys) << "Got" << qtKey;
281 return qtKey;
282 } else if (key >= QChar(NSF1FunctionKey) && key <= QChar(NSF35FunctionKey)) {
283 auto functionKey = Qt::Key_F1 + (key.unicode() - NSF1FunctionKey) ;
284 qCDebug(lcQpaKeyMapperKeys) << "Got" << functionKey;
285 return functionKey;
286 }
287 }
288
289 qCDebug(lcQpaKeyMapperKeys, "Unknown case.. %d[%d] %d", key.unicode(), key.toLatin1(), virtualKey);
290 return Qt::Key_unknown;
291}
292
293// --------- Cocoa key mapping moved from Qt Core ---------
294
295static const int NSEscapeCharacter = 27; // not defined by Cocoa headers
296
297static const QHash<char16_t, Qt::Key> cocoaKeys = {
298 { NSEnterCharacter, Qt::Key_Enter },
299 { NSBackspaceCharacter, Qt::Key_Backspace },
300 { NSTabCharacter, Qt::Key_Tab },
301 { NSNewlineCharacter, Qt::Key_Return },
302 { NSCarriageReturnCharacter, Qt::Key_Return },
303 { NSBackTabCharacter, Qt::Key_Backtab },
304 { NSEscapeCharacter, Qt::Key_Escape },
305 { NSDeleteCharacter, Qt::Key_Backspace },
306 { NSUpArrowFunctionKey, Qt::Key_Up },
307 { NSDownArrowFunctionKey, Qt::Key_Down },
308 { NSLeftArrowFunctionKey, Qt::Key_Left },
309 { NSRightArrowFunctionKey, Qt::Key_Right },
310 { NSF1FunctionKey, Qt::Key_F1 },
311 { NSF2FunctionKey, Qt::Key_F2 },
312 { NSF3FunctionKey, Qt::Key_F3 },
313 { NSF4FunctionKey, Qt::Key_F4 },
314 { NSF5FunctionKey, Qt::Key_F5 },
315 { NSF6FunctionKey, Qt::Key_F6 },
316 { NSF7FunctionKey, Qt::Key_F7 },
317 { NSF8FunctionKey, Qt::Key_F8 },
318 { NSF9FunctionKey, Qt::Key_F9 },
319 { NSF10FunctionKey, Qt::Key_F10 },
320 { NSF11FunctionKey, Qt::Key_F11 },
321 { NSF12FunctionKey, Qt::Key_F12 },
322 { NSF13FunctionKey, Qt::Key_F13 },
323 { NSF14FunctionKey, Qt::Key_F14 },
324 { NSF15FunctionKey, Qt::Key_F15 },
325 { NSF16FunctionKey, Qt::Key_F16 },
326 { NSF17FunctionKey, Qt::Key_F17 },
327 { NSF18FunctionKey, Qt::Key_F18 },
328 { NSF19FunctionKey, Qt::Key_F19 },
329 { NSF20FunctionKey, Qt::Key_F20 },
330 { NSF21FunctionKey, Qt::Key_F21 },
331 { NSF22FunctionKey, Qt::Key_F22 },
332 { NSF23FunctionKey, Qt::Key_F23 },
333 { NSF24FunctionKey, Qt::Key_F24 },
334 { NSF25FunctionKey, Qt::Key_F25 },
335 { NSF26FunctionKey, Qt::Key_F26 },
336 { NSF27FunctionKey, Qt::Key_F27 },
337 { NSF28FunctionKey, Qt::Key_F28 },
338 { NSF29FunctionKey, Qt::Key_F29 },
339 { NSF30FunctionKey, Qt::Key_F30 },
340 { NSF31FunctionKey, Qt::Key_F31 },
341 { NSF32FunctionKey, Qt::Key_F32 },
342 { NSF33FunctionKey, Qt::Key_F33 },
343 { NSF34FunctionKey, Qt::Key_F34 },
344 { NSF35FunctionKey, Qt::Key_F35 },
345 { NSInsertFunctionKey, Qt::Key_Insert },
346 { NSDeleteFunctionKey, Qt::Key_Delete },
347 { NSHomeFunctionKey, Qt::Key_Home },
348 { NSEndFunctionKey, Qt::Key_End },
349 { NSPageUpFunctionKey, Qt::Key_PageUp },
350 { NSPageDownFunctionKey, Qt::Key_PageDown },
351 { NSPrintScreenFunctionKey, Qt::Key_Print },
352 { NSScrollLockFunctionKey, Qt::Key_ScrollLock },
353 { NSPauseFunctionKey, Qt::Key_Pause },
354 { NSSysReqFunctionKey, Qt::Key_SysReq },
355 { NSMenuFunctionKey, Qt::Key_Menu },
356 { NSHelpFunctionKey, Qt::Key_Help },
357};
358
359QChar QAppleKeyMapper::toCocoaKey(Qt::Key key)
360{
361 // Prioritize overloaded keys
362 if (key == Qt::Key_Return)
363 return QChar(NSCarriageReturnCharacter);
364 if (key == Qt::Key_Backspace)
365 return QChar(NSBackspaceCharacter);
366
367 Q_CONSTINIT static QHash<Qt::Key, char16_t> reverseCocoaKeys;
368 if (reverseCocoaKeys.isEmpty()) {
369 reverseCocoaKeys.reserve(cocoaKeys.size());
370 for (auto it = cocoaKeys.begin(); it != cocoaKeys.end(); ++it)
371 reverseCocoaKeys.insert(it.value(), it.key());
372 }
373
374 return reverseCocoaKeys.value(key);
375}
376
377Qt::Key QAppleKeyMapper::fromCocoaKey(QChar keyCode)
378{
379 if (auto key = cocoaKeys.value(keyCode.unicode()))
380 return key;
381
382 return Qt::Key(keyCode.toUpper().unicode());
383}
384
385// ------------------------------------------------
386
387Qt::KeyboardModifiers QAppleKeyMapper::queryKeyboardModifiers()
388{
389 return fromCocoaModifiers(NSEvent.modifierFlags);
390}
391
392bool QAppleKeyMapper::updateKeyboard()
393{
394 QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride();
395 if (!source)
396 source = TISCopyCurrentKeyboardInputSource();
397
398 if (m_keyboardMode != NullMode && source == m_currentInputSource)
399 return false;
400
402 m_currentInputSource = source;
403 m_keyboardKind = LMGetKbdType();
404
405 m_keyMap.clear();
406
407 if (auto data = CFDataRef(TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData))) {
408 const UCKeyboardLayout *uchrData = reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data));
409 Q_ASSERT(uchrData);
410 m_keyboardLayoutFormat = uchrData;
411 m_keyboardMode = UnicodeMode;
412 } else {
413 m_keyboardLayoutFormat = nullptr;
414 m_keyboardMode = NullMode;
415 }
416
417 qCDebug(lcQpaKeyMapper) << "Updated keyboard to"
418 << QString::fromCFString(CFStringRef(TISGetInputSourceProperty(
419 m_currentInputSource, kTISPropertyLocalizedName)));
420
421 return true;
422}
423
424static constexpr Qt::KeyboardModifiers modifierCombinations[] = {
425 Qt::NoModifier, // 0
429 Qt::AltModifier, // 4
433 Qt::MetaModifier, // 8
441};
442
443/*
444 Returns a key map for the given \virtualKey based on all
445 possible modifier combinations.
446*/
447const QAppleKeyMapper::KeyMap &QAppleKeyMapper::keyMapForKey(VirtualKeyCode virtualKey) const
448{
449 static_assert(sizeof(modifierCombinations) / sizeof(Qt::KeyboardModifiers) == kNumModifierCombinations);
450
451 const_cast<QAppleKeyMapper *>(this)->updateKeyboard();
452
453 auto &keyMap = m_keyMap[virtualKey];
455 return keyMap; // Already filled
456
457 qCDebug(lcQpaKeyMapper, "Updating key map for virtual key 0x%02x", (uint)virtualKey);
458
459 // Key mapping via [NSEvent charactersByApplyingModifiers:] only works for key down
460 // events, but we might (wrongly) get into this code path for other key events such
461 // as NSEventTypeFlagsChanged.
462 const bool canMapCocoaEvent = NSApp.currentEvent.type == NSEventTypeKeyDown;
463
464 if (!canMapCocoaEvent)
465 qCWarning(lcQpaKeyMapper) << "Could not map key to character for event" << NSApp.currentEvent;
466
467 for (int i = 0; i < kNumModifierCombinations; ++i) {
468 Q_ASSERT(!i || keyMap[i] == 0);
469
470 auto qtModifiers = modifierCombinations[i];
471 auto carbonModifiers = toCarbonModifiers(qtModifiers);
472 const UInt32 modifierKeyState = (carbonModifiers >> 8) & 0xFF;
473
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,
482 unicodeString);
483
484 // Use translated Unicode key if valid
485 QChar carbonUnicodeKey;
486 if (err == noErr && actualStringLength)
487 carbonUnicodeKey = QChar(unicodeString[0]);
488
489 if (@available(macOS 10.15, *)) {
490 if (canMapCocoaEvent) {
491 // Until we've verified that the Cocoa API works as expected
492 // we first run the event through the Carbon APIs and then
493 // compare the results to Cocoa.
494 auto cocoaModifiers = toCocoaModifiers(qtModifiers);
495 auto *charactersWithModifiers = [NSApp.currentEvent charactersByApplyingModifiers:cocoaModifiers];
496
497 QChar cocoaUnicodeKey;
498 if (charactersWithModifiers.length > 0)
499 cocoaUnicodeKey = QChar([charactersWithModifiers characterAtIndex:0]);
500
501 if (cocoaUnicodeKey != carbonUnicodeKey) {
502 qCWarning(lcQpaKeyMapper) << "Mismatch between Cocoa" << cocoaUnicodeKey
503 << "and Carbon" << carbonUnicodeKey << "for virtual key" << virtualKey
504 << "with" << qtModifiers;
505 }
506 }
507 }
508
509 int qtKey = toKeyCode(carbonUnicodeKey, virtualKey, qtModifiers);
510 if (qtKey == Qt::Key_unknown)
511 qtKey = carbonUnicodeKey.unicode();
512
513 keyMap[i] = qtKey;
514
515 qCDebug(lcQpaKeyMapper).verbosity(0) << "\t" << qtModifiers
516 << "+" << qUtf8Printable(QString::asprintf("0x%02x", virtualKey))
517 << "=" << qUtf8Printable(QString::asprintf("%d / 0x%02x /", qtKey, qtKey))
519 }
520
521 return keyMap;
522}
523
524/*
525 Compute the possible key combinations that can map to the event's
526 virtual key and modifiers, in the current keyboard layout.
527
528 For example, given a normal US keyboard layout, the virtual key
529 23 combined with the Alt (⌥) and Shift (⇧) modifiers, can map
530 to the following key combinations:
531
532 - Alt+Shift+5
533 - Alt+%
534 - Shift+∞
535 - fi
536
537 The function builds on a key map produced by keyMapForKey(),
538 where each modifier-key combination has been mapped to the
539 key it will produce.
540*/
542{
544
545 qCDebug(lcQpaKeyMapper) << "Computing possible keys for" << event;
546
547 const auto nativeVirtualKey = event->nativeVirtualKey();
548 if (!nativeVirtualKey)
549 return ret;
550
551 auto keyMap = keyMapForKey(nativeVirtualKey);
552
553 auto unmodifiedKey = keyMap[Qt::NoModifier];
554 Q_ASSERT(unmodifiedKey != Qt::Key_unknown);
555
556 auto eventModifiers = event->modifiers();
557
558 // The complete set of event modifiers, along with the
559 // unmodified key, is always a valid key combination,
560 // and the first priority.
561 ret << int(eventModifiers) + int(unmodifiedKey);
562
563 // FIXME: We only compute the first 8 combinations. Why?
564 for (int i = 1; i < 8; ++i) {
565 auto keyAfterApplyingModifiers = keyMap[i];
566 if (keyAfterApplyingModifiers == unmodifiedKey)
567 continue;
568 if (!keyAfterApplyingModifiers)
569 continue;
570
571 // Include key if the event modifiers match exactly,
572 // or are a superset of the current candidate modifiers.
573 auto candidateModifiers = modifierCombinations[i];
574 if ((eventModifiers & candidateModifiers) == candidateModifiers) {
575 // If the event includes more modifiers than the candidate they
576 // will need to be included in the resulting key combination.
577 auto additionalModifiers = eventModifiers & ~candidateModifiers;
578 ret << int(additionalModifiers) + int(keyAfterApplyingModifiers);
579 }
580 }
581
582 if (lcQpaKeyMapper().isDebugEnabled()) {
583 qCDebug(lcQpaKeyMapper) << "Possible keys:";
584 for (int keyAndModifiers : ret) {
585 auto keyCombination = QKeyCombination::fromCombined(keyAndModifiers);
586 auto keySequence = QKeySequence(keyCombination);
587 qCDebug(lcQpaKeyMapper).verbosity(0) << "\t-"
588 << keyCombination << "/" << keySequence << "/"
589 << qUtf8Printable(keySequence.toString(QKeySequence::NativeText));
590 }
591 }
592
593 return ret;
594}
595
596
597
598#else // iOS
599
600// Keyboard keys (non-modifiers)
601API_AVAILABLE(ios(13.4)) Qt::Key QAppleKeyMapper::fromUIKitKey(NSString *keyCode)
602{
603 static QHash<NSString *, Qt::Key> uiKitKeys = {
604 { UIKeyInputF1, Qt::Key_F1 },
605 { UIKeyInputF2, Qt::Key_F2 },
606 { UIKeyInputF3, Qt::Key_F3 },
607 { UIKeyInputF4, Qt::Key_F4 },
608 { UIKeyInputF5, Qt::Key_F5 },
609 { UIKeyInputF6, Qt::Key_F6 },
610 { UIKeyInputF7, Qt::Key_F7 },
611 { UIKeyInputF8, Qt::Key_F8 },
612 { UIKeyInputF9, Qt::Key_F9 },
613 { UIKeyInputF10, Qt::Key_F10 },
614 { UIKeyInputF11, Qt::Key_F11 },
615 { UIKeyInputF12, Qt::Key_F12 },
616 { UIKeyInputHome, Qt::Key_Home },
617 { UIKeyInputEnd, Qt::Key_End },
618 { UIKeyInputPageUp, Qt::Key_PageUp },
619 { UIKeyInputPageDown, Qt::Key_PageDown },
620 { UIKeyInputEscape, Qt::Key_Escape },
621 { UIKeyInputUpArrow, Qt::Key_Up },
622 { UIKeyInputDownArrow, Qt::Key_Down },
623 { UIKeyInputLeftArrow, Qt::Key_Left },
624 { UIKeyInputRightArrow, Qt::Key_Right }
625 };
626
627 if (auto key = uiKitKeys.value(keyCode))
628 return key;
629
630 return Qt::Key_unknown;
631}
632
633static constexpr std::tuple<ulong, Qt::KeyboardModifier> uiKitModifierMap[] = {
634 { UIKeyModifierShift, Qt::ShiftModifier },
635 { UIKeyModifierControl, Qt::ControlModifier },
636 { UIKeyModifierCommand, Qt::MetaModifier },
637 { UIKeyModifierAlternate, Qt::AltModifier },
638 { UIKeyModifierNumericPad, Qt::KeypadModifier }
639};
640
641ulong QAppleKeyMapper::toUIKitModifiers(Qt::KeyboardModifiers qtModifiers)
642{
643 qtModifiers = swapModifiersIfNeeded(qtModifiers);
644
645 ulong nativeModifiers = 0;
646 for (const auto &[nativeModifier, qtModifier] : uiKitModifierMap) {
647 if (qtModifiers & qtModifier)
648 nativeModifiers |= nativeModifier;
649 }
650
651 return nativeModifiers;
652}
653
654Qt::KeyboardModifiers QAppleKeyMapper::fromUIKitModifiers(ulong nativeModifiers)
655{
656 Qt::KeyboardModifiers qtModifiers = Qt::NoModifier;
657 for (const auto &[nativeModifier, qtModifier] : uiKitModifierMap) {
658 if (nativeModifiers & nativeModifier)
659 qtModifiers |= qtModifier;
660 }
661
662 return swapModifiersIfNeeded(qtModifiers);
663}
664#endif
665
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()
\inmodule QtCore
Definition qchar.h:48
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
QChar toUpper() const noexcept
Returns the uppercase equivalent if the character is lowercase or titlecase; otherwise returns the ch...
Definition qchar.h:449
static bool testAttribute(Qt::ApplicationAttribute attribute)
Returns true if attribute attribute is set; otherwise returns false.
\inmodule QtCore
Definition qhash.h:818
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1202
qsizetype size() const noexcept
Returns the number of items in the hash.
Definition qhash.h:925
void reserve(qsizetype size)
Ensures that the QHash's internal hash table has space to store at least size items without having to...
Definition qhash.h:929
T value(const Key &key) const noexcept
Definition qhash.h:1044
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1206
static constexpr QKeyCombination fromCombined(int combined)
The QKeyEvent class describes a key event.
Definition qevent.h:423
The QKeySequence class encapsulates a key sequence as used by shortcuts.
QString toString(SequenceFormat format=PortableText) const
Definition qlist.h:74
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
EGLImageKHR int int EGLuint64KHR * modifiers
QString text
QSet< QString >::iterator it
Combined button and popup list for selecting options.
@ Key_Escape
Definition qnamespace.h:658
@ Key_F20
Definition qnamespace.h:704
@ Key_Tab
Definition qnamespace.h:659
@ Key_Select
@ Key_ParenRight
Definition qnamespace.h:522
@ Key_F30
Definition qnamespace.h:714
@ Key_Plus
Definition qnamespace.h:524
@ Key_Return
Definition qnamespace.h:662
@ Key_QuoteLeft
Definition qnamespace.h:577
@ Key_Right
Definition qnamespace.h:674
@ Key_Greater
Definition qnamespace.h:543
@ Key_Enter
Definition qnamespace.h:663
@ Key_F7
Definition qnamespace.h:691
@ Key_PageUp
Definition qnamespace.h:676
@ Key_Printer
@ Key_F22
Definition qnamespace.h:706
@ Key_Execute
@ Key_F23
Definition qnamespace.h:707
@ Key_Space
Definition qnamespace.h:512
@ Key_F29
Definition qnamespace.h:713
@ Key_F24
Definition qnamespace.h:708
@ Key_F32
Definition qnamespace.h:716
@ Key_F17
Definition qnamespace.h:701
@ Key_At
Definition qnamespace.h:545
@ Key_F21
Definition qnamespace.h:705
@ Key_QuoteDbl
Definition qnamespace.h:515
@ Key_Undo
@ Key_Colon
Definition qnamespace.h:539
@ Key_F35
Definition qnamespace.h:719
@ Key_Backspace
Definition qnamespace.h:661
@ Key_Backtab
Definition qnamespace.h:660
@ Key_F6
Definition qnamespace.h:690
@ Key_Insert
Definition qnamespace.h:664
@ Key_BracketRight
Definition qnamespace.h:574
@ Key_Left
Definition qnamespace.h:672
@ Key_BracketLeft
Definition qnamespace.h:572
@ Key_A
Definition qnamespace.h:546
@ Key_NumberSign
Definition qnamespace.h:516
@ Key_0
Definition qnamespace.h:529
@ Key_F9
Definition qnamespace.h:693
@ Key_F27
Definition qnamespace.h:711
@ Key_Redo
@ Key_AsciiCircum
Definition qnamespace.h:575
@ Key_Question
Definition qnamespace.h:544
@ Key_Find
@ Key_Dollar
Definition qnamespace.h:517
@ Key_SysReq
Definition qnamespace.h:668
@ Key_F11
Definition qnamespace.h:695
@ Key_Equal
Definition qnamespace.h:542
@ Key_Exclam
Definition qnamespace.h:514
@ Key_Print
Definition qnamespace.h:667
@ Key_Pause
Definition qnamespace.h:666
@ Key_F26
Definition qnamespace.h:710
@ Key_Up
Definition qnamespace.h:673
@ Key_Minus
Definition qnamespace.h:526
@ Key_F3
Definition qnamespace.h:687
@ Key_F16
Definition qnamespace.h:700
@ Key_Down
Definition qnamespace.h:675
@ Key_F18
Definition qnamespace.h:702
@ Key_F33
Definition qnamespace.h:717
@ Key_ParenLeft
Definition qnamespace.h:521
@ Key_F4
Definition qnamespace.h:688
@ Key_Percent
Definition qnamespace.h:518
@ Key_Underscore
Definition qnamespace.h:576
@ Key_F2
Definition qnamespace.h:686
@ Key_Delete
Definition qnamespace.h:665
@ Key_AsciiTilde
Definition qnamespace.h:581
@ Key_Backslash
Definition qnamespace.h:573
@ Key_Less
Definition qnamespace.h:541
@ Key_F28
Definition qnamespace.h:712
@ Key_Help
Definition qnamespace.h:725
@ Key_ScrollLock
Definition qnamespace.h:684
@ Key_F31
Definition qnamespace.h:715
@ Key_F1
Definition qnamespace.h:685
@ Key_Semicolon
Definition qnamespace.h:540
@ Key_F14
Definition qnamespace.h:698
@ Key_Slash
Definition qnamespace.h:528
@ Key_Period
Definition qnamespace.h:527
@ Key_Menu
Definition qnamespace.h:722
@ Key_PageDown
Definition qnamespace.h:677
@ Key_Bar
Definition qnamespace.h:579
@ Key_F19
Definition qnamespace.h:703
@ Key_F5
Definition qnamespace.h:689
@ Key_Home
Definition qnamespace.h:670
@ Key_F10
Definition qnamespace.h:694
@ Key_Clear
Definition qnamespace.h:669
@ Key_F34
Definition qnamespace.h:718
@ Key_F25
Definition qnamespace.h:709
@ Key_BraceRight
Definition qnamespace.h:580
@ Key_Mode_switch
Definition qnamespace.h:742
@ Key_Comma
Definition qnamespace.h:525
@ Key_F8
Definition qnamespace.h:692
@ Key_F13
Definition qnamespace.h:697
@ Key_BraceLeft
Definition qnamespace.h:578
@ Key_Asterisk
Definition qnamespace.h:523
@ Key_Apostrophe
Definition qnamespace.h:520
@ Key_F12
Definition qnamespace.h:696
@ Key_unknown
@ Key_F15
Definition qnamespace.h:699
@ Key_End
Definition qnamespace.h:671
@ Key_Ampersand
Definition qnamespace.h:519
@ ShiftModifier
@ ControlModifier
@ MetaModifier
@ KeypadModifier
@ NoModifier
@ AltModifier
@ AA_MacDontSwapCtrlAndMeta
Definition qnamespace.h:431
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,...)
return ret
GLuint64 key
GLenum GLuint GLenum GLsizei length
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLsizei GLsizei GLchar * source
struct _cl_event * event
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static QString qtKey(CFStringRef cfkey)
#define qUtf8Printable(string)
Definition qstring.h:1395
unsigned long ulong
Definition qtypes.h:30
unsigned int uint
Definition qtypes.h:29
static const struct @437 keyMap[]
QList< QChar > characters