Fixed crash in GL 2 paint engine on Intel Atom.
[profile/ivi/qtbase.git] / src / widgets / platforms / mac / qkeymapper_mac.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtGui module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <private/qt_mac_p.h>
43 #include <qdebug.h>
44 #include <qevent.h>
45 #include <private/qevent_p.h>
46 #include <qtextcodec.h>
47 #include <qapplication.h>
48 #include <qinputcontext.h>
49 #include <private/qkeymapper_p.h>
50 #include <private/qapplication_p.h>
51 #include <private/qmacinputcontext_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 QT_USE_NAMESPACE
56
57 /*****************************************************************************
58   QKeyMapper debug facilities
59  *****************************************************************************/
60 //#define DEBUG_KEY_BINDINGS
61 //#define DEBUG_KEY_BINDINGS_MODIFIERS
62 //#define DEBUG_KEY_MAPS
63
64 /*****************************************************************************
65   Internal variables and functions
66  *****************************************************************************/
67 bool qt_mac_eat_unicode_key = false;
68 extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); //qapplication_mac.cpp
69
70 Q_WIDGETS_EXPORT void qt_mac_secure_keyboard(bool b)
71 {
72     static bool secure = false;
73     if (b != secure){
74         b ? EnableSecureEventInput() : DisableSecureEventInput();
75         secure = b;
76     }
77 }
78
79 /*
80     \internal
81     A Mac KeyboardLayoutItem has 8 possible states:
82         1. Unmodified
83         2. Shift
84         3. Control
85         4. Control + Shift
86         5. Alt
87         6. Alt + Shift
88         7. Alt + Control
89         8. Alt + Control + Shift
90         9. Meta
91         10. Meta + Shift
92         11. Meta + Control
93         12. Meta + Control + Shift
94         13. Meta + Alt
95         14. Meta + Alt + Shift
96         15. Meta + Alt + Control
97         16. Meta + Alt + Control + Shift
98 */
99 struct KeyboardLayoutItem {
100     bool dirty;
101     quint32 qtKey[16]; // Can by any Qt::Key_<foo>, or unicode character
102 };
103
104 // Possible modifier states.
105 // NOTE: The order of these states match the order in QKeyMapperPrivate::updatePossibleKeyCodes()!
106 static const Qt::KeyboardModifiers ModsTbl[] = {
107     Qt::NoModifier,                                             // 0
108     Qt::ShiftModifier,                                          // 1
109     Qt::ControlModifier,                                        // 2
110     Qt::ControlModifier | Qt::ShiftModifier,                    // 3
111     Qt::AltModifier,                                            // 4
112     Qt::AltModifier | Qt::ShiftModifier,                        // 5
113     Qt::AltModifier | Qt::ControlModifier,                      // 6
114     Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier,  // 7
115     Qt::MetaModifier,                                           // 8
116     Qt::MetaModifier | Qt::ShiftModifier,                       // 9
117     Qt::MetaModifier | Qt::ControlModifier,                    // 10
118     Qt::MetaModifier | Qt::ControlModifier | Qt::ShiftModifier,// 11
119     Qt::MetaModifier | Qt::AltModifier,                        // 12
120     Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier,    // 13
121     Qt::MetaModifier | Qt::AltModifier | Qt::ControlModifier,  // 14
122     Qt::MetaModifier | Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier,  // 15
123 };
124
125 /* key maps */
126 struct qt_mac_enum_mapper
127 {
128     int mac_code;
129     int qt_code;
130 #if defined(DEBUG_KEY_BINDINGS)
131 #   define QT_MAC_MAP_ENUM(x) x, #x
132     const char *desc;
133 #else
134 #   define QT_MAC_MAP_ENUM(x) x
135 #endif
136 };
137
138 //modifiers
139 static qt_mac_enum_mapper qt_mac_modifier_symbols[] = {
140     { shiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
141     { rightShiftKey, QT_MAC_MAP_ENUM(Qt::ShiftModifier) },
142     { controlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
143     { rightControlKey, QT_MAC_MAP_ENUM(Qt::MetaModifier) },
144     { cmdKey, QT_MAC_MAP_ENUM(Qt::ControlModifier) },
145     { optionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
146     { rightOptionKey, QT_MAC_MAP_ENUM(Qt::AltModifier) },
147     { kEventKeyModifierNumLockMask, QT_MAC_MAP_ENUM(Qt::KeypadModifier) },
148     { 0, QT_MAC_MAP_ENUM(0) }
149 };
150 Qt::KeyboardModifiers qt_mac_get_modifiers(int keys)
151 {
152 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
153     qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", keys, keys);
154 #endif
155     Qt::KeyboardModifiers ret = Qt::NoModifier;
156     for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
157         if (keys & qt_mac_modifier_symbols[i].mac_code) {
158 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
159             qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
160 #endif
161             ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code);
162         }
163     }
164     if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
165         Qt::KeyboardModifiers oldModifiers = ret;
166         ret &= ~(Qt::MetaModifier | Qt::ControlModifier);
167         if (oldModifiers & Qt::ControlModifier)
168             ret |= Qt::MetaModifier;
169         if (oldModifiers & Qt::MetaModifier)
170             ret |= Qt::ControlModifier;
171     }
172     return ret;
173 }
174 static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys)
175 {
176 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
177     qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", (int)keys, (int)keys);
178 #endif
179     int ret = 0;
180     for (int i = 0; qt_mac_modifier_symbols[i].qt_code; i++) {
181         if (keys & qt_mac_modifier_symbols[i].qt_code) {
182 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
183             qDebug("Qt: internal: got modifier: %s", qt_mac_modifier_symbols[i].desc);
184 #endif
185             ret |= qt_mac_modifier_symbols[i].mac_code;
186         }
187     }
188
189     if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
190         int oldModifiers = ret;
191         ret &= ~(controlKeyBit | cmdKeyBit);
192         if (oldModifiers & controlKeyBit)
193             ret |= cmdKeyBit;
194         if (oldModifiers & cmdKeyBit)
195             ret |= controlKeyBit;
196     }
197     return ret;
198 }
199 void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object)
200 {
201     static quint32 cachedModifiers = 0;
202     quint32 lastModifiers = cachedModifiers,
203           changedModifiers = lastModifiers ^ modifiers;
204     cachedModifiers = modifiers;
205
206     //check the bits
207     static qt_mac_enum_mapper modifier_key_symbols[] = {
208         { shiftKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Shift) },
209         { rightShiftKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Shift) }, //???
210         { controlKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Meta) },
211         { rightControlKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Meta) }, //???
212         { cmdKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Control) },
213         { optionKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Alt) },
214         { rightOptionKeyBit, QT_MAC_MAP_ENUM(Qt::Key_Alt) }, //???
215         { alphaLockBit, QT_MAC_MAP_ENUM(Qt::Key_CapsLock) },
216         { kEventKeyModifierNumLockBit, QT_MAC_MAP_ENUM(Qt::Key_NumLock) },
217         {   0, QT_MAC_MAP_ENUM(0) } };
218     for (int i = 0; i <= 32; i++) { //just check each bit
219         if (!(changedModifiers & (1 << i)))
220             continue;
221         QEvent::Type etype = QEvent::KeyPress;
222         if (lastModifiers & (1 << i))
223             etype = QEvent::KeyRelease;
224         int key = 0;
225         for (uint x = 0; modifier_key_symbols[x].mac_code; x++) {
226             if (modifier_key_symbols[x].mac_code == i) {
227 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
228                 qDebug("got modifier changed: %s", modifier_key_symbols[x].desc);
229 #endif
230                 key = modifier_key_symbols[x].qt_code;
231                 break;
232             }
233         }
234         if (!key) {
235 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
236             qDebug("could not get modifier changed: %d", i);
237 #endif
238             continue;
239         }
240 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
241         qDebug("KeyEvent (modif): Sending %s to %s::%s: %d - 0x%08x",
242                etype == QEvent::KeyRelease ? "KeyRelease" : "KeyPress",
243                object ? object->metaObject()->className() : "none",
244                object ? object->objectName().toLatin1().constData() : "",
245                key, (int)modifiers);
246 #endif
247         QKeyEvent ke(etype, key, qt_mac_get_modifiers(modifiers ^ (1 << i)), QLatin1String(""));
248         qt_sendSpontaneousEvent(object, &ke);
249     }
250 }
251
252 //keyboard keys (non-modifiers)
253 static qt_mac_enum_mapper qt_mac_keyboard_symbols[] = {
254     { kHomeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Home) },
255     { kEnterCharCode, QT_MAC_MAP_ENUM(Qt::Key_Enter) },
256     { kEndCharCode, QT_MAC_MAP_ENUM(Qt::Key_End) },
257     { kBackspaceCharCode, QT_MAC_MAP_ENUM(Qt::Key_Backspace) },
258     { kTabCharCode, QT_MAC_MAP_ENUM(Qt::Key_Tab) },
259     { kPageUpCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },
260     { kPageDownCharCode, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },
261     { kReturnCharCode, QT_MAC_MAP_ENUM(Qt::Key_Return) },
262     { kEscapeCharCode, QT_MAC_MAP_ENUM(Qt::Key_Escape) },
263     { kLeftArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Left) },
264     { kRightArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Right) },
265     { kUpArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Up) },
266     { kDownArrowCharCode, QT_MAC_MAP_ENUM(Qt::Key_Down) },
267     { kHelpCharCode, QT_MAC_MAP_ENUM(Qt::Key_Help) },
268     { kDeleteCharCode, QT_MAC_MAP_ENUM(Qt::Key_Delete) },
269 //ascii maps, for debug
270     { ':', QT_MAC_MAP_ENUM(Qt::Key_Colon) },
271     { ';', QT_MAC_MAP_ENUM(Qt::Key_Semicolon) },
272     { '<', QT_MAC_MAP_ENUM(Qt::Key_Less) },
273     { '=', QT_MAC_MAP_ENUM(Qt::Key_Equal) },
274     { '>', QT_MAC_MAP_ENUM(Qt::Key_Greater) },
275     { '?', QT_MAC_MAP_ENUM(Qt::Key_Question) },
276     { '@', QT_MAC_MAP_ENUM(Qt::Key_At) },
277     { ' ', QT_MAC_MAP_ENUM(Qt::Key_Space) },
278     { '!', QT_MAC_MAP_ENUM(Qt::Key_Exclam) },
279     { '"', QT_MAC_MAP_ENUM(Qt::Key_QuoteDbl) },
280     { '#', QT_MAC_MAP_ENUM(Qt::Key_NumberSign) },
281     { '$', QT_MAC_MAP_ENUM(Qt::Key_Dollar) },
282     { '%', QT_MAC_MAP_ENUM(Qt::Key_Percent) },
283     { '&', QT_MAC_MAP_ENUM(Qt::Key_Ampersand) },
284     { '\'', QT_MAC_MAP_ENUM(Qt::Key_Apostrophe) },
285     { '(', QT_MAC_MAP_ENUM(Qt::Key_ParenLeft) },
286     { ')', QT_MAC_MAP_ENUM(Qt::Key_ParenRight) },
287     { '*', QT_MAC_MAP_ENUM(Qt::Key_Asterisk) },
288     { '+', QT_MAC_MAP_ENUM(Qt::Key_Plus) },
289     { ',', QT_MAC_MAP_ENUM(Qt::Key_Comma) },
290     { '-', QT_MAC_MAP_ENUM(Qt::Key_Minus) },
291     { '.', QT_MAC_MAP_ENUM(Qt::Key_Period) },
292     { '/', QT_MAC_MAP_ENUM(Qt::Key_Slash) },
293     { '[', QT_MAC_MAP_ENUM(Qt::Key_BracketLeft) },
294     { ']', QT_MAC_MAP_ENUM(Qt::Key_BracketRight) },
295     { '\\', QT_MAC_MAP_ENUM(Qt::Key_Backslash) },
296     { '_', QT_MAC_MAP_ENUM(Qt::Key_Underscore) },
297     { '`', QT_MAC_MAP_ENUM(Qt::Key_QuoteLeft) },
298     { '{', QT_MAC_MAP_ENUM(Qt::Key_BraceLeft) },
299     { '}', QT_MAC_MAP_ENUM(Qt::Key_BraceRight) },
300     { '|', QT_MAC_MAP_ENUM(Qt::Key_Bar) },
301     { '~', QT_MAC_MAP_ENUM(Qt::Key_AsciiTilde) },
302     { '^', QT_MAC_MAP_ENUM(Qt::Key_AsciiCircum) },
303     {   0, QT_MAC_MAP_ENUM(0) }
304 };
305
306 static qt_mac_enum_mapper qt_mac_keyvkey_symbols[] = { //real scan codes
307     { 122, QT_MAC_MAP_ENUM(Qt::Key_F1) },
308     { 120, QT_MAC_MAP_ENUM(Qt::Key_F2) },
309     { 99,  QT_MAC_MAP_ENUM(Qt::Key_F3) },
310     { 118, QT_MAC_MAP_ENUM(Qt::Key_F4) },
311     { 96,  QT_MAC_MAP_ENUM(Qt::Key_F5) },
312     { 97,  QT_MAC_MAP_ENUM(Qt::Key_F6) },
313     { 98,  QT_MAC_MAP_ENUM(Qt::Key_F7) },
314     { 100, QT_MAC_MAP_ENUM(Qt::Key_F8) },
315     { 101, QT_MAC_MAP_ENUM(Qt::Key_F9) },
316     { 109, QT_MAC_MAP_ENUM(Qt::Key_F10) },
317     { 103, QT_MAC_MAP_ENUM(Qt::Key_F11) },
318     { 111, QT_MAC_MAP_ENUM(Qt::Key_F12) },
319     { 105, QT_MAC_MAP_ENUM(Qt::Key_F13) },
320     { 107, QT_MAC_MAP_ENUM(Qt::Key_F14) },
321     { 113, QT_MAC_MAP_ENUM(Qt::Key_F15) },
322     { 106, QT_MAC_MAP_ENUM(Qt::Key_F16) },
323     {   0, QT_MAC_MAP_ENUM(0) }
324 };
325
326 static qt_mac_enum_mapper qt_mac_private_unicode[] = {
327     { 0xF700, QT_MAC_MAP_ENUM(Qt::Key_Up) },            //NSUpArrowFunctionKey
328     { 0xF701, QT_MAC_MAP_ENUM(Qt::Key_Down) },          //NSDownArrowFunctionKey
329     { 0xF702, QT_MAC_MAP_ENUM(Qt::Key_Left) },          //NSLeftArrowFunctionKey
330     { 0xF703, QT_MAC_MAP_ENUM(Qt::Key_Right) },         //NSRightArrowFunctionKey
331     { 0xF727, QT_MAC_MAP_ENUM(Qt::Key_Insert) },        //NSInsertFunctionKey
332     { 0xF728, QT_MAC_MAP_ENUM(Qt::Key_Delete) },        //NSDeleteFunctionKey
333     { 0xF729, QT_MAC_MAP_ENUM(Qt::Key_Home) },          //NSHomeFunctionKey
334     { 0xF72B, QT_MAC_MAP_ENUM(Qt::Key_End) },           //NSEndFunctionKey
335     { 0xF72C, QT_MAC_MAP_ENUM(Qt::Key_PageUp) },        //NSPageUpFunctionKey
336     { 0xF72D, QT_MAC_MAP_ENUM(Qt::Key_PageDown) },      //NSPageDownFunctionKey
337     { 0xF72F, QT_MAC_MAP_ENUM(Qt::Key_ScrollLock) },    //NSScrollLockFunctionKey
338     { 0xF730, QT_MAC_MAP_ENUM(Qt::Key_Pause) },         //NSPauseFunctionKey
339     { 0xF731, QT_MAC_MAP_ENUM(Qt::Key_SysReq) },        //NSSysReqFunctionKey
340     { 0xF735, QT_MAC_MAP_ENUM(Qt::Key_Menu) },          //NSMenuFunctionKey
341     { 0xF738, QT_MAC_MAP_ENUM(Qt::Key_Print) },         //NSPrintFunctionKey
342     { 0xF73A, QT_MAC_MAP_ENUM(Qt::Key_Clear) },         //NSClearDisplayFunctionKey
343     { 0xF73D, QT_MAC_MAP_ENUM(Qt::Key_Insert) },        //NSInsertCharFunctionKey
344     { 0xF73E, QT_MAC_MAP_ENUM(Qt::Key_Delete) },        //NSDeleteCharFunctionKey
345     { 0xF741, QT_MAC_MAP_ENUM(Qt::Key_Select) },        //NSSelectFunctionKey
346     { 0xF742, QT_MAC_MAP_ENUM(Qt::Key_Execute) },       //NSExecuteFunctionKey
347     { 0xF746, QT_MAC_MAP_ENUM(Qt::Key_Help) },          //NSHelpFunctionKey
348     { 0xF747, QT_MAC_MAP_ENUM(Qt::Key_Mode_switch) },   //NSModeSwitchFunctionKey
349     {   0,    QT_MAC_MAP_ENUM(0) }
350 };
351
352 static int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
353 {
354 #ifdef DEBUG_KEY_BINDINGS
355     qDebug("**Mapping key: %d (0x%04x) - %d (0x%04x)", key.unicode(), key.unicode(), virtualKey, virtualKey);
356 #endif
357
358     if (key == kClearCharCode && virtualKey == 0x47)
359         return Qt::Key_Clear;
360
361     if (key.isDigit()) {
362 #ifdef DEBUG_KEY_BINDINGS
363             qDebug("%d: got key: %d", __LINE__, key.digitValue());
364 #endif
365         return key.digitValue() + Qt::Key_0;
366     }
367
368     if (key.isLetter()) {
369 #ifdef DEBUG_KEY_BINDINGS
370         qDebug("%d: got key: %d", __LINE__, (key.toUpper().unicode() - 'A'));
371 #endif
372         return (key.toUpper().unicode() - 'A') + Qt::Key_A;
373     }
374     if (key.isSymbol()) {
375 #ifdef DEBUG_KEY_BINDINGS
376         qDebug("%d: got key: %d", __LINE__, (key.unicode()));
377 #endif
378         return key.unicode();
379     }
380
381     for (int i = 0; qt_mac_keyboard_symbols[i].qt_code; i++) {
382         if (qt_mac_keyboard_symbols[i].mac_code == key) {
383             /* To work like Qt for X11 we issue Backtab when Shift + Tab are pressed */
384             if (qt_mac_keyboard_symbols[i].qt_code == Qt::Key_Tab && (modif & Qt::ShiftModifier)) {
385 #ifdef DEBUG_KEY_BINDINGS
386                 qDebug("%d: got key: Qt::Key_Backtab", __LINE__);
387 #endif
388                 return Qt::Key_Backtab;
389             }
390
391 #ifdef DEBUG_KEY_BINDINGS
392             qDebug("%d: got key: %s", __LINE__, qt_mac_keyboard_symbols[i].desc);
393 #endif
394             return qt_mac_keyboard_symbols[i].qt_code;
395         }
396     }
397
398     //last ditch try to match the scan code
399     for (int i = 0; qt_mac_keyvkey_symbols[i].qt_code; i++) {
400         if (qt_mac_keyvkey_symbols[i].mac_code == virtualKey) {
401 #ifdef DEBUG_KEY_BINDINGS
402             qDebug("%d: got key: %s", __LINE__, qt_mac_keyvkey_symbols[i].desc);
403 #endif
404             return qt_mac_keyvkey_symbols[i].qt_code;
405         }
406     }
407
408     // check if they belong to key codes in private unicode range
409     if (key >= 0xf700 && key <= 0xf747) {
410         if (key >= 0xf704 && key <= 0xf726) {
411             return Qt::Key_F1 + (key.unicode() - 0xf704) ;
412         }
413         for (int i = 0; qt_mac_private_unicode[i].qt_code; i++) {
414             if (qt_mac_private_unicode[i].mac_code == key) {
415                 return qt_mac_private_unicode[i].qt_code;
416             }
417         }
418
419     }
420
421     //oh well
422 #ifdef DEBUG_KEY_BINDINGS
423     qDebug("Unknown case.. %s:%d %d[%d] %d", __FILE__, __LINE__, key.unicode(), key.toLatin1(), virtualKey);
424 #endif
425     return Qt::Key_unknown;
426 }
427
428 static Boolean qt_KeyEventComparatorProc(EventRef inEvent, void *data)
429 {
430     UInt32 ekind = GetEventKind(inEvent),
431            eclass = GetEventClass(inEvent);
432     return (eclass == kEventClassKeyboard && (void *)ekind == data);
433 }
434
435 static bool translateKeyEventInternal(EventHandlerCallRef er, EventRef keyEvent, int *qtKey,
436                                       QChar *outChar, Qt::KeyboardModifiers *outModifiers, bool *outHandled)
437 {
438     const UInt32 ekind = GetEventKind(keyEvent);
439     {
440         UInt32 mac_modifiers = 0;
441         GetEventParameter(keyEvent, kEventParamKeyModifiers, typeUInt32, 0,
442                           sizeof(mac_modifiers), 0, &mac_modifiers);
443 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
444         qDebug("************ Mapping modifiers and key ***********");
445 #endif
446         *outModifiers = qt_mac_get_modifiers(mac_modifiers);
447 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
448         qDebug("------------ Mapping modifiers and key -----------");
449 #endif
450     }
451
452     //get keycode
453     UInt32 keyCode = 0;
454     GetEventParameter(keyEvent, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode);
455
456     //get mac mapping
457     static UInt32 tmp_unused_state = 0L;
458     const UCKeyboardLayout *uchrData = 0;
459 #if defined(Q_OS_MAC32)
460     KeyboardLayoutRef keyLayoutRef = 0;
461     KLGetCurrentKeyboardLayout(&keyLayoutRef);
462     OSStatus err;
463     if (keyLayoutRef != 0) {
464         err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
465                                   (reinterpret_cast<const void **>(&uchrData)));
466         if (err != noErr) {
467             qWarning("Qt::internal::unable to get keyboardlayout %ld %s:%d",
468                      long(err), __FILE__, __LINE__);
469         }
470     }
471 #else
472     QCFType<TISInputSourceRef> inputSource = TISCopyCurrentKeyboardInputSource();
473     Q_ASSERT(inputSource != 0);
474     CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSource,
475                                                                  kTISPropertyUnicodeKeyLayoutData));
476     uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
477 #endif
478     *qtKey = Qt::Key_unknown;
479     if (uchrData) {
480         // The easy stuff; use the unicode stuff!
481         UniChar string[4];
482         UniCharCount actualLength;
483         UInt32 currentModifiers = GetCurrentEventKeyModifiers();
484         UInt32 currentModifiersWOAltOrControl = currentModifiers & ~(controlKey | optionKey);
485         int keyAction;
486         switch (ekind) {
487         default:
488         case kEventRawKeyDown:
489             keyAction = kUCKeyActionDown;
490             break;
491         case kEventRawKeyUp:
492             keyAction = kUCKeyActionUp;
493             break;
494         case kEventRawKeyRepeat:
495             keyAction = kUCKeyActionAutoKey;
496             break;
497         }
498         OSStatus err = UCKeyTranslate(uchrData, keyCode, keyAction,
499                                   ((currentModifiersWOAltOrControl >> 8) & 0xff), LMGetKbdType(),
500                                   kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
501                                   string);
502         if (err == noErr) {
503             *outChar = QChar(string[0]);
504             *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
505             if (currentModifiersWOAltOrControl != currentModifiers) {
506                 // Now get the real char.
507                 err = UCKeyTranslate(uchrData, keyCode, keyAction,
508                                      ((currentModifiers >> 8) & 0xff), LMGetKbdType(),
509                                       kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
510                                       string);
511                 if (err == noErr)
512                     *outChar = QChar(string[0]);
513             }
514         } else {
515             qWarning("Qt::internal::UCKeyTranslate is returnining %ld %s:%d",
516                      long(err), __FILE__, __LINE__);
517         }
518     }
519 #ifdef Q_OS_MAC32
520     else {
521         // The road less travelled; use KeyTranslate
522         const void *keyboard_layout;
523         KeyboardLayoutRef keyLayoutRef = 0;
524         KLGetCurrentKeyboardLayout(&keyLayoutRef);
525         err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
526                                   reinterpret_cast<const void **>(&keyboard_layout));
527
528         int translatedChar = KeyTranslate(keyboard_layout, (GetCurrentEventKeyModifiers() &
529                                                              (kEventKeyModifierNumLockMask|shiftKey|cmdKey|
530                                                               rightShiftKey|alphaLock)) | keyCode,
531                                            &tmp_unused_state);
532         if (!translatedChar) {
533             if (outHandled) {
534                 qt_mac_eat_unicode_key = false;
535                 if (er)
536                     CallNextEventHandler(er, keyEvent);
537                 *outHandled = qt_mac_eat_unicode_key;
538             }
539             return false;
540         }
541
542         //map it into qt keys
543         *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
544         if (*outModifiers & (Qt::AltModifier | Qt::ControlModifier)) {
545             if (translatedChar & (1 << 7)) //high ascii
546                 translatedChar = 0;
547         } else {          //now get the real ascii value
548             UInt32 tmp_mod = 0L;
549             static UInt32 tmp_state = 0L;
550             if (*outModifiers & Qt::ShiftModifier)
551                 tmp_mod |= shiftKey;
552             if (*outModifiers & Qt::MetaModifier)
553                 tmp_mod |= controlKey;
554             if (*outModifiers & Qt::ControlModifier)
555                 tmp_mod |= cmdKey;
556             if (GetCurrentEventKeyModifiers() & alphaLock) //no Qt mapper
557                 tmp_mod |= alphaLock;
558             if (*outModifiers & Qt::AltModifier)
559                 tmp_mod |= optionKey;
560             if (*outModifiers & Qt::KeypadModifier)
561                 tmp_mod |= kEventKeyModifierNumLockMask;
562             translatedChar = KeyTranslate(keyboard_layout, tmp_mod | keyCode, &tmp_state);
563         }
564         {
565             ByteCount unilen = 0;
566             if (GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, 0, &unilen, 0)
567                     == noErr && unilen == 2) {
568                 GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, unilen, 0, outChar);
569             } else if (translatedChar) {
570                 static QTextCodec *c = 0;
571                 if (!c)
572                     c = QTextCodec::codecForName("Apple Roman");
573                 char tmpChar = (char)translatedChar; // **sigh**
574                 *outChar = c->toUnicode(&tmpChar, 1).at(0);
575             } else {
576                 *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
577             }
578         }
579     }
580 #endif
581     if (*qtKey == Qt::Key_unknown)
582         *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
583     return true;
584 }
585
586 QKeyMapperPrivate::QKeyMapperPrivate()
587 {
588     memset(keyLayout, 0, sizeof(keyLayout));
589     keyboard_layout_format.unicode = 0;
590 #ifdef Q_OS_MAC32
591     keyboard_mode = NullMode;
592 #else
593     currentInputSource = 0;
594 #endif
595 }
596
597 QKeyMapperPrivate::~QKeyMapperPrivate()
598 {
599     deleteLayouts();
600 }
601
602 bool
603 QKeyMapperPrivate::updateKeyboard()
604 {
605     const UCKeyboardLayout *uchrData = 0;
606 #ifdef Q_OS_MAC32
607     KeyboardLayoutRef keyLayoutRef = 0;
608     KLGetCurrentKeyboardLayout(&keyLayoutRef);
609
610     if (keyboard_mode != NullMode && currentKeyboardLayout == keyLayoutRef)
611         return false;
612
613     OSStatus err;
614     if (keyLayoutRef != 0) {
615         err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
616                                   const_cast<const void **>(reinterpret_cast<const void **>(&uchrData)));
617         if (err != noErr) {
618             qWarning("Qt::internal::unable to get unicode keyboardlayout %ld %s:%d",
619                      long(err), __FILE__, __LINE__);
620         }
621     }
622 #else
623     QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
624     if (keyboard_mode != NullMode && source == currentInputSource) {
625         return false;
626     }
627     Q_ASSERT(source != 0);
628     CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
629                                                                  kTISPropertyUnicodeKeyLayoutData));
630     uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
631 #endif
632
633     keyboard_kind = LMGetKbdType();
634     if (uchrData) {
635         keyboard_layout_format.unicode = uchrData;
636         keyboard_mode = UnicodeMode;
637     }
638 #ifdef Q_OS_MAC32
639     else {
640         void *happy;
641         err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
642                                   const_cast<const void **>(reinterpret_cast<void **>(&happy)));
643         if (err != noErr) {
644             qFatal("Qt::internal::unable to get non-unicode layout, cannot procede %ld %s:%d",
645                      long(err), __FILE__, __LINE__);
646         }
647         keyboard_layout_format.other = happy;
648         keyboard_mode = OtherMode;
649     }
650
651     currentKeyboardLayout = keyLayoutRef;
652 #else
653     currentInputSource = source;
654 #endif
655     keyboard_dead = 0;
656     CFStringRef iso639Code;
657 #ifdef Q_OS_MAC32
658 # ifndef kKLLanguageCode
659 # define kKLLanguageCode 9
660 # endif
661     KLGetKeyboardLayoutProperty(currentKeyboardLayout, kKLLanguageCode,
662                                 reinterpret_cast<const void **>(&iso639Code));
663 #else
664     CFArrayRef array = static_cast<CFArrayRef>(TISGetInputSourceProperty(currentInputSource, kTISPropertyInputSourceLanguages));
665     iso639Code = static_cast<CFStringRef>(CFArrayGetValueAtIndex(array, 0)); // Actually a RFC3066bis, but it's close enough
666 #endif
667     if (iso639Code) {
668         keyboardInputLocale = QLocale(QCFString::toQString(iso639Code));
669         keyboardInputDirection = keyboardInputLocale.textDirection();
670     } else {
671         keyboardInputLocale = QLocale::c();
672         keyboardInputDirection = Qt::LeftToRight;
673     }
674     return true;
675 }
676
677 void
678 QKeyMapperPrivate::deleteLayouts()
679 {
680     keyboard_mode = NullMode;
681     for (int i = 0; i < 255; ++i) {
682         if (keyLayout[i]) {
683             delete keyLayout[i];
684             keyLayout[i] = 0;
685         }
686     }
687 }
688
689 void
690 QKeyMapperPrivate::clearMappings()
691 {
692     deleteLayouts();
693     updateKeyboard();
694 }
695
696 QList<int>
697 QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
698 {
699     QList<int> ret;
700
701     KeyboardLayoutItem *kbItem = keyLayout[e->nativeVirtualKey()];
702     if (!kbItem) // Key is not in any keyboard layout (e.g. eisu-key on Japanese keyboard) 
703         return ret;
704
705     int baseKey = kbItem->qtKey[0];
706     Qt::KeyboardModifiers keyMods = e->modifiers();
707     ret << int(baseKey + keyMods); // The base key is _always_ valid, of course
708
709     for (int i = 1; i < 8; ++i) {
710         Qt::KeyboardModifiers neededMods = ModsTbl[i];
711         int key = kbItem->qtKey[i];
712         if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
713             ret << int(key + (keyMods & ~neededMods));
714     }
715
716     return ret;
717 }
718
719 bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef er, EventRef event,
720                                           void *info, bool grab)
721 {
722     Q_ASSERT(GetEventClass(event) == kEventClassKeyboard);
723     bool handled_event=true;
724     UInt32 ekind = GetEventKind(event);
725
726     // unfortunately modifiers changed event looks quite different, so I have a separate
727     // code path
728     if (ekind == kEventRawKeyModifiersChanged) {
729         //figure out changed modifiers, wish Apple would just send a delta
730         UInt32 modifiers = 0;
731         GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
732                           sizeof(modifiers), 0, &modifiers);
733         qt_mac_send_modifiers_changed(modifiers, widget);
734         return true;
735     }
736
737     QInputContext *currentContext = qApp->inputContext();
738     if (currentContext && currentContext->isComposing()) {
739         if (ekind == kEventRawKeyDown) {
740             QMacInputContext *context = qobject_cast<QMacInputContext*>(currentContext);
741             if (context)
742                 context->setLastKeydownEvent(event);
743         }
744         return false;
745     }
746     // Once we process the key down , we don't need to send the saved event again from
747     // kEventTextInputUnicodeForKeyEvent, so clear it.
748     if (currentContext && ekind == kEventRawKeyDown) {
749         QMacInputContext *context = qobject_cast<QMacInputContext*>(currentContext);
750         if (context)
751             context->setLastKeydownEvent(0);
752     }
753
754     //get modifiers
755     Qt::KeyboardModifiers modifiers;
756     int qtKey;
757     QChar ourChar;
758     if (translateKeyEventInternal(er, event, &qtKey, &ourChar, &modifiers,
759                                   &handled_event) == false)
760         return handled_event;
761     QString text(ourChar);
762     /* This is actually wrong - but unfortunately it is the best that can be
763        done for now because of the Control/Meta mapping problems */
764     if (modifiers & (Qt::ControlModifier | Qt::MetaModifier)
765         && !qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
766         text = QString();
767     }
768
769
770     if (widget) {
771         // Try to compress key events.
772         if (!text.isEmpty() && widget->testAttribute(Qt::WA_KeyCompression)) {
773             EventTime lastTime = GetEventTime(event);
774             for (;;) {
775                 EventRef releaseEvent = FindSpecificEventInQueue(GetMainEventQueue(),
776                                                                  qt_KeyEventComparatorProc,
777                                                                  (void*)kEventRawKeyUp);
778                 if (!releaseEvent)
779                     break;
780                 const EventTime releaseTime = GetEventTime(releaseEvent);
781                 if (releaseTime < lastTime)
782                     break;
783                 lastTime = releaseTime;
784
785                 EventRef pressEvent = FindSpecificEventInQueue(GetMainEventQueue(),
786                                                                qt_KeyEventComparatorProc,
787                                                                (void*)kEventRawKeyDown);
788                 if (!pressEvent)
789                     break;
790                 const EventTime pressTime = GetEventTime(pressEvent);
791                 if (pressTime < lastTime)
792                     break;
793                 lastTime = pressTime;
794
795                 Qt::KeyboardModifiers compressMod;
796                 int compressQtKey = 0;
797                 QChar compressChar;
798                 if (translateKeyEventInternal(er, pressEvent,
799                                               &compressQtKey, &compressChar, &compressMod, 0)
800                     == false) {
801                     break;
802                 }
803                 // Copied from qapplication_x11.cpp (change both).
804
805                 bool stopCompression =
806                     // 1) misc keys
807                     (compressQtKey >= Qt::Key_Escape && compressQtKey <= Qt::Key_SysReq)
808                     // 2) cursor movement
809                     || (compressQtKey >= Qt::Key_Home && compressQtKey <= Qt::Key_PageDown)
810                     // 3) extra keys
811                     || (compressQtKey >= Qt::Key_Super_L && compressQtKey <= Qt::Key_Direction_R)
812                     // 4) something that a) doesn't translate to text or b) translates
813                     //    to newline text
814                     || (compressQtKey == 0)
815                     || (compressChar == QLatin1Char('\n'))
816                     || (compressQtKey == Qt::Key_unknown);
817
818                 if (compressMod == modifiers && !compressChar.isNull() && !stopCompression) {
819 #ifdef DEBUG_KEY_BINDINGS
820                     qDebug("compressing away %c", compressChar.toLatin1());
821 #endif
822                     text += compressChar;
823                     // Clean up
824                     RemoveEventFromQueue(GetMainEventQueue(), releaseEvent);
825                     RemoveEventFromQueue(GetMainEventQueue(), pressEvent);
826                 } else {
827 #ifdef DEBUG_KEY_BINDINGS
828                     qDebug("stoping compression..");
829 #endif
830                     break;
831                 }
832             }
833         }
834
835         // There is no way to get the scan code from carbon. But we cannot use the value 0, since
836         // it indicates that the event originates from somewhere else than the keyboard
837         UInt32 macScanCode = 1;
838         UInt32 macVirtualKey = 0;
839         GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
840         UInt32 macModifiers = 0;
841         GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
842                           sizeof(macModifiers), 0, &macModifiers);
843         // The unicode characters in the range 0xF700-0xF747 are reserved
844         // by Mac OS X for transient use as keyboard function keys. We
845         // wont send 'text' for such key events. This is done to match
846         // behavior on other platforms.
847         unsigned int *unicodeKey = (unsigned int*)info;
848         if (*unicodeKey >= 0xf700 && *unicodeKey <= 0xf747)
849             text = QString();
850         bool isAccepted;
851         handled_event = QKeyMapper::sendKeyEvent(widget, grab,
852                                                  (ekind == kEventRawKeyUp) ? QEvent::KeyRelease : QEvent::KeyPress,
853                                                  qtKey, modifiers, text, ekind == kEventRawKeyRepeat, 0,
854                                                  macScanCode, macVirtualKey, macModifiers
855                                                  ,&isAccepted
856                                                  );
857         *unicodeKey = (unsigned int)isAccepted;
858     }
859     return handled_event;
860 }
861
862 void
863 QKeyMapperPrivate::updateKeyMap(EventHandlerCallRef, EventRef event, void *
864                                 unicodeKey // unicode character from NSEvent (modifiers applied)
865                                 )
866 {
867     UInt32 macVirtualKey = 0;
868     GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
869     if (updateKeyboard())
870        QKeyMapper::changeKeyboard();
871     else if (keyLayout[macVirtualKey])
872         return;
873
874     UniCharCount buffer_size = 10;
875     UniChar buffer[buffer_size];
876     keyLayout[macVirtualKey] = new KeyboardLayoutItem;
877     for (int i = 0; i < 16; ++i) {
878         UniCharCount out_buffer_size = 0;
879         keyLayout[macVirtualKey]->qtKey[i] = 0;
880 #ifdef Q_WS_MAC32
881         if (keyboard_mode == UnicodeMode) {
882 #endif
883             const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
884             OSStatus err = UCKeyTranslate(keyboard_layout_format.unicode, macVirtualKey, kUCKeyActionDown, keyModifier,
885                                           keyboard_kind, 0, &keyboard_dead, buffer_size, &out_buffer_size, buffer);
886             if (err == noErr && out_buffer_size) {
887                 const QChar unicode(buffer[0]);
888                 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
889                 if (qtkey == Qt::Key_unknown)
890                     qtkey = unicode.unicode();
891                 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
892             }
893 #ifndef Q_WS_MAC32
894             else {
895                 const QChar unicode(*((UniChar *)unicodeKey));
896                 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
897                 if (qtkey == Qt::Key_unknown)
898                     qtkey = unicode.unicode();
899                 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
900             }
901 #endif
902 #ifdef Q_WS_MAC32            
903         } else {
904             const UInt32 keyModifier = (qt_mac_get_mac_modifiers(ModsTbl[i]));
905
906             uchar translatedChar = KeyTranslate(keyboard_layout_format.other, keyModifier | macVirtualKey, &keyboard_dead);
907             if (translatedChar) {
908                 static QTextCodec *c = 0;
909                 if (!c)
910                     c = QTextCodec::codecForName("Apple Roman");
911                 const QChar unicode(c->toUnicode((const char *)&translatedChar, 1).at(0));
912                 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
913                 if (qtkey == Qt::Key_unknown)
914                     qtkey = unicode.unicode();
915                 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
916             }
917         }
918 #endif
919     }
920 #ifdef DEBUG_KEY_MAPS
921     qDebug("updateKeyMap for virtual key = 0x%02x!", (uint)macVirtualKey);
922     for (int i = 0; i < 16; ++i) {
923         qDebug("    [%d] (%d,0x%02x,'%c')", i,
924                keyLayout[macVirtualKey]->qtKey[i],
925                keyLayout[macVirtualKey]->qtKey[i],
926                keyLayout[macVirtualKey]->qtKey[i]);
927     }
928 #endif
929 }
930
931 bool
932 QKeyMapper::sendKeyEvent(QWidget *widget, bool grab,
933                          QEvent::Type type, int code, Qt::KeyboardModifiers modifiers,
934                          const QString &text, bool autorepeat, int count,
935                          quint32 nativeScanCode, quint32 nativeVirtualKey,
936                          quint32 nativeModifiers, bool *isAccepted)
937 {
938     Q_UNUSED(count);
939     Q_UNUSED(grab);
940
941     if (widget && widget->isEnabled()) {
942         bool key_event = true;
943         if (key_event) {
944 #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
945             qDebug("KeyEvent: Sending %s to %s::%s: %s 0x%08x%s",
946                    type == QEvent::KeyRelease ? "KeyRelease" : "KeyPress",
947                    widget ? widget->metaObject()->className() : "none",
948                    widget ? widget->objectName().toLatin1().constData() : "",
949                    text.toLatin1().constData(), int(modifiers),
950                    autorepeat ? " Repeat" : "");
951 #endif
952             QKeyEventEx ke(type, code, modifiers, text, autorepeat, qMax(1, text.length()),
953                            nativeScanCode, nativeVirtualKey, nativeModifiers);
954             bool retMe = qt_sendSpontaneousEvent(widget,&ke);
955             if (isAccepted)
956                 *isAccepted = ke.isAccepted();
957             return retMe;
958         }
959     }
960     return false;
961 }
962
963 QT_END_NAMESPACE