1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the plugins of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qcocoakeymapper.h"
41
42#include <QtCore/QDebug>
43#include <QtGui/QGuiApplication>
44
45QT_BEGIN_NAMESPACE
46
47// QCocoaKeyMapper debug facilities
48//#define DEBUG_KEY_BINDINGS
49//#define DEBUG_KEY_BINDINGS_MODIFIERS
50//#define DEBUG_KEY_MAPS
51
52// Possible modifier states.
53// NOTE: The order of these states match the order in updatePossibleKeyCodes()!
54static const Qt::KeyboardModifiers ModsTbl[] = {
55    Qt::NoModifier,                                             // 0
56    Qt::ShiftModifier,                                          // 1
57    Qt::ControlModifier,                                        // 2
58    Qt::ControlModifier | Qt::ShiftModifier,                    // 3
59    Qt::AltModifier,                                            // 4
60    Qt::AltModifier | Qt::ShiftModifier,                        // 5
61    Qt::AltModifier | Qt::ControlModifier,                      // 6
62    Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier,  // 7
63    Qt::MetaModifier,                                           // 8
64    Qt::MetaModifier | Qt::ShiftModifier,                       // 9
65    Qt::MetaModifier | Qt::ControlModifier,                    // 10
66    Qt::MetaModifier | Qt::ControlModifier | Qt::ShiftModifier,// 11
67    Qt::MetaModifier | Qt::AltModifier,                        // 12
68    Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier,    // 13
69    Qt::MetaModifier | Qt::AltModifier | Qt::ControlModifier,  // 14
70    Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier,  // 15
71};
72
73bool qt_mac_eat_unicode_key = false;
74
75
76/* key maps */
77struct qt_mac_enum_mapper
78{
79    int mac_code;
80    int qt_code;
81#if defined(DEBUG_KEY_BINDINGS)
82#   define QT_MAC_MAP_ENUM(x) x, #x
83    const char *desc;
84#else
85#   define QT_MAC_MAP_ENUM(x) x
86#endif
87};
88
89//modifiers
90static qt_mac_enum_mapper qt_mac_modifier_symbols[] = {
91    { shiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
92    { rightShiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
93    { controlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
94    { rightControlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
95    { cmdKey, QT_MAC_MAP_ENUM(Qt::ControlModifier) },
96    { optionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
97    { rightOptionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
98    { kEventKeyModifierNumLockMask, QT_MAC_MAP_ENUM(Qt::KeypadModifier) },
99    { 0, QT_MAC_MAP_ENUM(0) }
100};
101Qt::KeyboardModifiers qt_mac_get_modifiers(int keys)
102{
103#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
104    qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", keys, keys);
105#endif
106    Qt::KeyboardModifiers ret = Qt::NoModifier;
107    for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
108        if (keys & qt_mac_modifier_symbols[i].mac_code) {
109#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
110            qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
111#endif
112            ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code);
113        }
114    }
115    if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
116        Qt::KeyboardModifiers oldModifiers = ret;
117        ret &= ~(Qt::MetaModifier | Qt::ControlModifier);
118        if (oldModifiers & Qt::ControlModifier)
119            ret |= Qt::MetaModifier;
120        if (oldModifiers & Qt::MetaModifier)
121            ret |= Qt::ControlModifier;
122    }
123    return ret;
124}
125static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys)
126{
127#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
128    qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", (int)keys, (int)keys);
129#endif
130    int ret = 0;
131    for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
132        if (keys & qt_mac_modifier_symbols[i].qt_code) {
133#ifdef DEBUG_KEY_BINDINGS_MODIFIERS
134            qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
135#endif
136            ret |= qt_mac_modifier_symbols[i].mac_code;
137        }
138    }
139
140    if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
141        int oldModifiers = ret;
142        ret &= ~(controlKeyBit | cmdKeyBit);
143        if (oldModifiers & controlKeyBit)
144            ret |= cmdKeyBit;
145        if (oldModifiers & cmdKeyBit)
146            ret |= controlKeyBit;
147    }
148    return ret;
149}
150
151//keyboard keys (non-modifiers)
152static qt_mac_enum_mapper qt_mac_keyboard_symbols[] = {
153    { kHomeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Home) },
154    { kEnterCharCode, QT_MAC_MAP_ENUM(Qt::Key_Enter) },
155    { kEndCharCode, QT_MAC_MAP_ENUM(Qt::Key_End) },
156    { kBackspaceCharCode, QT_MAC_MAP_ENUM(Qt::Key_Backspace) },
157    { kTabCharCode, QT_MAC_MAP_ENUM(Qt::Key_Tab) },
158    { kPageUpCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },
159    { kPageDownCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },
160    { kReturnCharCode, QT_MAC_MAP_ENUM(Qt::Key_Return) },
161    { kEscapeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Escape) },
162    { kLeftArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Left) },
163    { kRightArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Right) },
164    { kUpArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Up) },
165    { kDownArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Down) },
166    { kHelpCharCode, QT_MAC_MAP_ENUM(Qt::Key_Help) },
167    { kDeleteCharCode, QT_MAC_MAP_ENUM(Qt::Key_Delete) },
168//ascii maps, for debug
169    { ':', QT_MAC_MAP_ENUM(Qt::Key_Colon) },
170    { ';', QT_MAC_MAP_ENUM(Qt::Key_Semicolon) },
171    { '<', QT_MAC_MAP_ENUM(Qt::Key_Less) },
172    { '=', QT_MAC_MAP_ENUM(Qt::Key_Equal) },
173    { '>', QT_MAC_MAP_ENUM(Qt::Key_Greater) },
174    { '?', QT_MAC_MAP_ENUM(Qt::Key_Question) },
175    { '@', QT_MAC_MAP_ENUM(Qt::Key_At) },
176    { ' ', QT_MAC_MAP_ENUM(Qt::Key_Space) },
177    { '!', QT_MAC_MAP_ENUM(Qt::Key_Exclam) },
178    { '"', QT_MAC_MAP_ENUM(Qt::Key_QuoteDbl) },
179    { '#', QT_MAC_MAP_ENUM(Qt::Key_NumberSign) },
180    { '$', QT_MAC_MAP_ENUM(Qt::Key_Dollar) },
181    { '%', QT_MAC_MAP_ENUM(Qt::Key_Percent) },
182    { '&', QT_MAC_MAP_ENUM(Qt::Key_Ampersand) },
183    { '\'', QT_MAC_MAP_ENUM(Qt::Key_Apostrophe) },
184    { '(', QT_MAC_MAP_ENUM(Qt::Key_ParenLeft) },
185    { ')', QT_MAC_MAP_ENUM(Qt::Key_ParenRight) },
186    { '*', QT_MAC_MAP_ENUM(Qt::Key_Asterisk) },
187    { '+', QT_MAC_MAP_ENUM(Qt::Key_Plus) },
188    { ',', QT_MAC_MAP_ENUM(Qt::Key_Comma) },
189    { '-', QT_MAC_MAP_ENUM(Qt::Key_Minus) },
190    { '.', QT_MAC_MAP_ENUM(Qt::Key_Period) },
191    { '/', QT_MAC_MAP_ENUM(Qt::Key_Slash) },
192    { '[', QT_MAC_MAP_ENUM(Qt::Key_BracketLeft) },
193    { ']', QT_MAC_MAP_ENUM(Qt::Key_BracketRight) },
194    { '\\', QT_MAC_MAP_ENUM(Qt::Key_Backslash) },
195    { '_', QT_MAC_MAP_ENUM(Qt::Key_Underscore) },
196    { '`', QT_MAC_MAP_ENUM(Qt::Key_QuoteLeft) },
197    { '{', QT_MAC_MAP_ENUM(Qt::Key_BraceLeft) },
198    { '}', QT_MAC_MAP_ENUM(Qt::Key_BraceRight) },
199    { '|', QT_MAC_MAP_ENUM(Qt::Key_Bar) },
200    { '~', QT_MAC_MAP_ENUM(Qt::Key_AsciiTilde) },
201    { '^', QT_MAC_MAP_ENUM(Qt::Key_AsciiCircum) },
202    {   0, QT_MAC_MAP_ENUM(0) }
203};
204
205static qt_mac_enum_mapper qt_mac_keyvkey_symbols[] = { //real scan codes
206    { kVK_F1, QT_MAC_MAP_ENUM(Qt::Key_F1) },
207    { kVK_F2, QT_MAC_MAP_ENUM(Qt::Key_F2) },
208    { kVK_F3, QT_MAC_MAP_ENUM(Qt::Key_F3) },
209    { kVK_F4, QT_MAC_MAP_ENUM(Qt::Key_F4) },
210    { kVK_F5, QT_MAC_MAP_ENUM(Qt::Key_F5) },
211    { kVK_F6, QT_MAC_MAP_ENUM(Qt::Key_F6) },
212    { kVK_F7, QT_MAC_MAP_ENUM(Qt::Key_F7) },
213    { kVK_F8, QT_MAC_MAP_ENUM(Qt::Key_F8) },
214    { kVK_F9, QT_MAC_MAP_ENUM(Qt::Key_F9) },
215    { kVK_F10, QT_MAC_MAP_ENUM(Qt::Key_F10) },
216    { kVK_F11, QT_MAC_MAP_ENUM(Qt::Key_F11) },
217    { kVK_F12, QT_MAC_MAP_ENUM(Qt::Key_F12) },
218    { kVK_F13, QT_MAC_MAP_ENUM(Qt::Key_F13) },
219    { kVK_F14, QT_MAC_MAP_ENUM(Qt::Key_F14) },
220    { kVK_F15, QT_MAC_MAP_ENUM(Qt::Key_F15) },
221    { kVK_F16, QT_MAC_MAP_ENUM(Qt::Key_F16) },
222    { kVK_Return, QT_MAC_MAP_ENUM(Qt::Key_Return) },
223    { kVK_Tab, QT_MAC_MAP_ENUM(Qt::Key_Tab) },
224    { kVK_Escape, QT_MAC_MAP_ENUM(Qt::Key_Escape) },
225    { kVK_Help, QT_MAC_MAP_ENUM(Qt::Key_Help) },
226    { kVK_UpArrow, QT_MAC_MAP_ENUM(Qt::Key_Up) },
227    { kVK_DownArrow, QT_MAC_MAP_ENUM(Qt::Key_Down) },
228    { kVK_LeftArrow, QT_MAC_MAP_ENUM(Qt::Key_Left) },
229    { kVK_RightArrow, QT_MAC_MAP_ENUM(Qt::Key_Right) },
230    { kVK_PageUp, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },
231    { kVK_PageDown, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },
232    {   0, QT_MAC_MAP_ENUM(0) }
233};
234
235static qt_mac_enum_mapper qt_mac_private_unicode[] = {
236    { 0xF700, QT_MAC_MAP_ENUM(Qt::Key_Up) },            //NSUpArrowFunctionKey
237    { 0xF701, QT_MAC_MAP_ENUM(Qt::Key_Down) },          //NSDownArrowFunctionKey
238    { 0xF702, QT_MAC_MAP_ENUM(Qt::Key_Left) },          //NSLeftArrowFunctionKey
239    { 0xF703, QT_MAC_MAP_ENUM(Qt::Key_Right) },         //NSRightArrowFunctionKey
240    { 0xF727, QT_MAC_MAP_ENUM(Qt::Key_Insert) },        //NSInsertFunctionKey
241    { 0xF728, QT_MAC_MAP_ENUM(Qt::Key_Delete) },        //NSDeleteFunctionKey
242    { 0xF729, QT_MAC_MAP_ENUM(Qt::Key_Home) },          //NSHomeFunctionKey
243    { 0xF72B, QT_MAC_MAP_ENUM(Qt::Key_End) },           //NSEndFunctionKey
244    { 0xF72C, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },        //NSPageUpFunctionKey
245    { 0xF72D, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },      //NSPageDownFunctionKey
246    { 0xF72E, QT_MAC_MAP_ENUM(Qt::Key_Print) },         //NSPrintScreenFunctionKey
247    { 0xF72F, QT_MAC_MAP_ENUM(Qt::Key_ScrollLock) },    //NSScrollLockFunctionKey
248    { 0xF730, QT_MAC_MAP_ENUM(Qt::Key_Pause) },         //NSPauseFunctionKey
249    { 0xF731, QT_MAC_MAP_ENUM(Qt::Key_SysReq) },        //NSSysReqFunctionKey
250    { 0xF735, QT_MAC_MAP_ENUM(Qt::Key_Menu) },          //NSMenuFunctionKey
251    { 0xF738, QT_MAC_MAP_ENUM(Qt::Key_Printer) },       //NSPrintFunctionKey
252    { 0xF73A, QT_MAC_MAP_ENUM(Qt::Key_Clear) },         //NSClearDisplayFunctionKey
253    { 0xF73D, QT_MAC_MAP_ENUM(Qt::Key_Insert) },        //NSInsertCharFunctionKey
254    { 0xF73E, QT_MAC_MAP_ENUM(Qt::Key_Delete) },        //NSDeleteCharFunctionKey
255    { 0xF741, QT_MAC_MAP_ENUM(Qt::Key_Select) },        //NSSelectFunctionKey
256    { 0xF742, QT_MAC_MAP_ENUM(Qt::Key_Execute) },       //NSExecuteFunctionKey
257    { 0xF743, QT_MAC_MAP_ENUM(Qt::Key_Undo) },          //NSUndoFunctionKey
258    { 0xF744, QT_MAC_MAP_ENUM(Qt::Key_Redo) },          //NSRedoFunctionKey
259    { 0xF745, QT_MAC_MAP_ENUM(Qt::Key_Find) },          //NSFindFunctionKey
260    { 0xF746, QT_MAC_MAP_ENUM(Qt::Key_Help) },          //NSHelpFunctionKey
261    { 0xF747, QT_MAC_MAP_ENUM(Qt::Key_Mode_switch) },   //NSModeSwitchFunctionKey
262    {   0,    QT_MAC_MAP_ENUM(0) }
263};
264
265static int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
266{
267#ifdef DEBUG_KEY_BINDINGS
268    qDebug("**Mapping key: %d (0x%04x) - %d (0x%04x)", key.unicode(), key.unicode(), virtualKey, virtualKey);
269#endif
270
271    if (key == kClearCharCode && virtualKey == 0x47)
272        return Qt::Key_Clear;
273
274    if (key.isDigit()) {
275#ifdef DEBUG_KEY_BINDINGS
276            qDebug("%d: got key: %d", __LINE__, key.digitValue());
277#endif
278        return key.digitValue() + Qt::Key_0;
279    }
280
281    if (key.isLetter()) {
282#ifdef DEBUG_KEY_BINDINGS
283        qDebug("%d: got key: %d", __LINE__, (key.toUpper().unicode() - 'A'));
284#endif
285        return (key.toUpper().unicode() - 'A') + Qt::Key_A;
286    }
287    if (key.isSymbol()) {
288#ifdef DEBUG_KEY_BINDINGS
289        qDebug("%d: got key: %d", __LINE__, (key.unicode()));
290#endif
291        return key.unicode();
292    }
293
294    for (int i = 0; qt_mac_keyboard_symbols[i].qt_code; i++) {
295        if (qt_mac_keyboard_symbols[i].mac_code == key) {
296            /* To work like Qt for X11 we issue Backtab when Shift + Tab are pressed */
297            if (qt_mac_keyboard_symbols[i].qt_code == Qt::Key_Tab && (modif & Qt::ShiftModifier)) {
298#ifdef DEBUG_KEY_BINDINGS
299                qDebug("%d: got key: Qt::Key_Backtab", __LINE__);
300#endif
301                return Qt::Key_Backtab;
302            }
303
304#ifdef DEBUG_KEY_BINDINGS
305            qDebug("%d: got key: %s", __LINE__, qt_mac_keyboard_symbols[i].desc);
306#endif
307            return qt_mac_keyboard_symbols[i].qt_code;
308        }
309    }
310
311    //last ditch try to match the scan code
312    for (int i = 0; qt_mac_keyvkey_symbols[i].qt_code; i++) {
313        if (qt_mac_keyvkey_symbols[i].mac_code == virtualKey) {
314#ifdef DEBUG_KEY_BINDINGS
315            qDebug("%d: got key: %s", __LINE__, qt_mac_keyvkey_symbols[i].desc);
316#endif
317            return qt_mac_keyvkey_symbols[i].qt_code;
318        }
319    }
320
321    // check if they belong to key codes in private unicode range
322    if (key >= 0xf700 && key <= 0xf747) {
323        if (key >= 0xf704 && key <= 0xf726) {
324            return Qt::Key_F1 + (key.unicode() - 0xf704) ;
325        }
326        for (int i = 0; qt_mac_private_unicode[i].qt_code; i++) {
327            if (qt_mac_private_unicode[i].mac_code == key) {
328                return qt_mac_private_unicode[i].qt_code;
329            }
330        }
331
332    }
333
334    //oh well
335#ifdef DEBUG_KEY_BINDINGS
336    qDebug("Unknown case.. %s:%d %d[%d] %d", __FILE__, __LINE__, key.unicode(), key.toLatin1(), virtualKey);
337#endif
338    return Qt::Key_unknown;
339}
340
341QCocoaKeyMapper::QCocoaKeyMapper()
342{
343    memset(keyLayout, 0, sizeof(keyLayout));
344}
345
346QCocoaKeyMapper::~QCocoaKeyMapper()
347{
348    deleteLayouts();
349}
350
351Qt::KeyboardModifiers QCocoaKeyMapper::queryKeyboardModifiers()
352{
353    return qt_mac_get_modifiers(GetCurrentKeyModifiers());
354}
355
356bool QCocoaKeyMapper::updateKeyboard()
357{
358    const UCKeyboardLayout *uchrData = nullptr;
359    QCFType<TISInputSourceRef> source = TISCopyInputMethodKeyboardLayoutOverride();
360    if (!source)
361        source = TISCopyCurrentKeyboardInputSource();
362    if (keyboard_mode != NullMode && source == currentInputSource) {
363        return false;
364    }
365    Q_ASSERT(source);
366    CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
367                                                                 kTISPropertyUnicodeKeyLayoutData));
368    uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : nullptr;
369
370    keyboard_kind = LMGetKbdType();
371    if (uchrData) {
372        keyboard_layout_format = uchrData;
373        keyboard_mode = UnicodeMode;
374    } else {
375        keyboard_layout_format = nullptr;
376        keyboard_mode = NullMode;
377    }
378    currentInputSource = source;
379    keyboard_dead = 0;
380
381    const auto newMode = keyboard_mode;
382    deleteLayouts();
383    keyboard_mode = newMode;
384
385    return true;
386}
387
388void QCocoaKeyMapper::deleteLayouts()
389{
390    keyboard_mode = NullMode;
391    for (int i = 0; i < 255; ++i) {
392        if (keyLayout[i]) {
393            delete keyLayout[i];
394            keyLayout[i] = nullptr;
395        }
396    }
397}
398
399void QCocoaKeyMapper::clearMappings()
400{
401    deleteLayouts();
402    updateKeyboard();
403}
404
405void QCocoaKeyMapper::updateKeyMap(unsigned short macVirtualKey, QChar unicodeKey)
406{
407    updateKeyboard();
408
409    if (keyLayout[macVirtualKey])
410        return;
411
412    UniCharCount buffer_size = 10;
413    UniChar buffer[buffer_size];
414    keyLayout[macVirtualKey] = new KeyboardLayoutItem;
415    for (int i = 0; i < 16; ++i) {
416        UniCharCount out_buffer_size = 0;
417        keyLayout[macVirtualKey]->qtKey[i] = 0;
418
419        const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
420        OSStatus err = UCKeyTranslate(keyboard_layout_format, macVirtualKey, kUCKeyActionDown, keyModifier,
421                                      keyboard_kind, 0, &keyboard_dead, buffer_size, &out_buffer_size, buffer);
422        if (err == noErr && out_buffer_size) {
423            const QChar unicode(buffer[0]);
424            int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
425            if (qtkey == Qt::Key_unknown)
426                qtkey = unicode.unicode();
427            keyLayout[macVirtualKey]->qtKey[i] = qtkey;
428        } else {
429            int qtkey = qt_mac_get_key(keyModifier, unicodeKey, macVirtualKey);
430            if (qtkey == Qt::Key_unknown)
431                qtkey = unicodeKey.unicode();
432            keyLayout[macVirtualKey]->qtKey[i] = qtkey;
433        }
434    }
435#ifdef DEBUG_KEY_MAPS
436    qDebug("updateKeyMap for virtual key = 0x%02x!", (uint)macVirtualKey);
437    for (int i = 0; i < 16; ++i) {
438        qDebug("    [%d] (%d,0x%02x,'%c')", i,
439               keyLayout[macVirtualKey]->qtKey[i],
440               keyLayout[macVirtualKey]->qtKey[i],
441               keyLayout[macVirtualKey]->qtKey[i]);
442    }
443#endif
444}
445
446QList<int> QCocoaKeyMapper::possibleKeys(const QKeyEvent *event) const
447{
448    QList<int> ret;
449    const_cast<QCocoaKeyMapper *>(this)->updateKeyMap(event->nativeVirtualKey(), QChar(event->key()));
450
451    KeyboardLayoutItem *kbItem = keyLayout[event->nativeVirtualKey()];
452
453    if (!kbItem) // Key is not in any keyboard layout (e.g. eisu-key on Japanese keyboard)
454        return ret;
455
456    int baseKey = kbItem->qtKey[0];
457    Qt::KeyboardModifiers keyMods = event->modifiers();
458
459    ret << int(baseKey + keyMods); // The base key is _always_ valid, of course
460
461    for (int i = 1; i < 8; ++i) {
462        Qt::KeyboardModifiers neededMods = ModsTbl[i];
463        int key = kbItem->qtKey[i];
464        if (key && key != baseKey && ((keyMods & neededMods) == neededMods)) {
465            ret << int(key + (keyMods & ~neededMods));
466        }
467    }
468    return ret;
469}
470
471QT_END_NAMESPACE
472