1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtGui module of the Qt Toolkit.
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.
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.
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.
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.
40 ****************************************************************************/
42 #include <private/qt_mac_p.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>
57 /*****************************************************************************
58 QKeyMapper debug facilities
59 *****************************************************************************/
60 //#define DEBUG_KEY_BINDINGS
61 //#define DEBUG_KEY_BINDINGS_MODIFIERS
62 //#define DEBUG_KEY_MAPS
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
70 Q_WIDGETS_EXPORT void qt_mac_secure_keyboard(bool b)
72 static bool secure = false;
74 b ? EnableSecureEventInput() : DisableSecureEventInput();
81 A Mac KeyboardLayoutItem has 8 possible states:
89 8. Alt + Control + Shift
93 12. Meta + Control + Shift
95 14. Meta + Alt + Shift
96 15. Meta + Alt + Control
97 16. Meta + Alt + Control + Shift
99 struct KeyboardLayoutItem {
101 quint32 qtKey[16]; // Can by any Qt::Key_<foo>, or unicode character
104 // Possible modifier states.
105 // NOTE: The order of these states match the order in QKeyMapperPrivate::updatePossibleKeyCodes()!
106 static const Qt::KeyboardModifiers ModsTbl[] = {
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
126 struct qt_mac_enum_mapper
130 #if defined(DEBUG_KEY_BINDINGS)
131 # define QT_MAC_MAP_ENUM(x) x, #x
134 # define QT_MAC_MAP_ENUM(x) x
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) }
150 Qt::KeyboardModifiers qt_mac_get_modifiers(int keys)
152 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
153 qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", keys, keys);
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);
161 ret |= Qt::KeyboardModifier(qt_mac_modifier_symbols[i].qt_code);
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;
174 static int qt_mac_get_mac_modifiers(Qt::KeyboardModifiers keys)
176 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
177 qDebug("Qt: internal: **Mapping modifiers: %d (0x%04x)", (int)keys, (int)keys);
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);
185 ret |= qt_mac_modifier_symbols[i].mac_code;
189 if (qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
190 int oldModifiers = ret;
191 ret &= ~(controlKeyBit | cmdKeyBit);
192 if (oldModifiers & controlKeyBit)
194 if (oldModifiers & cmdKeyBit)
195 ret |= controlKeyBit;
199 void qt_mac_send_modifiers_changed(quint32 modifiers, QObject *object)
201 static quint32 cachedModifiers = 0;
202 quint32 lastModifiers = cachedModifiers,
203 changedModifiers = lastModifiers ^ modifiers;
204 cachedModifiers = modifiers;
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)))
221 QEvent::Type etype = QEvent::KeyPress;
222 if (lastModifiers & (1 << i))
223 etype = QEvent::KeyRelease;
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);
230 key = modifier_key_symbols[x].qt_code;
235 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
236 qDebug("could not get modifier changed: %d", i);
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);
247 QKeyEvent ke(etype, key, qt_mac_get_modifiers(modifiers ^ (1 << i)), QLatin1String(""));
248 qt_sendSpontaneousEvent(object, &ke);
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) }
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) }
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) }
352 static int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
354 #ifdef DEBUG_KEY_BINDINGS
355 qDebug("**Mapping key: %d (0x%04x) - %d (0x%04x)", key.unicode(), key.unicode(), virtualKey, virtualKey);
358 if (key == kClearCharCode && virtualKey == 0x47)
359 return Qt::Key_Clear;
362 #ifdef DEBUG_KEY_BINDINGS
363 qDebug("%d: got key: %d", __LINE__, key.digitValue());
365 return key.digitValue() + Qt::Key_0;
368 if (key.isLetter()) {
369 #ifdef DEBUG_KEY_BINDINGS
370 qDebug("%d: got key: %d", __LINE__, (key.toUpper().unicode() - 'A'));
372 return (key.toUpper().unicode() - 'A') + Qt::Key_A;
374 if (key.isSymbol()) {
375 #ifdef DEBUG_KEY_BINDINGS
376 qDebug("%d: got key: %d", __LINE__, (key.unicode()));
378 return key.unicode();
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__);
388 return Qt::Key_Backtab;
391 #ifdef DEBUG_KEY_BINDINGS
392 qDebug("%d: got key: %s", __LINE__, qt_mac_keyboard_symbols[i].desc);
394 return qt_mac_keyboard_symbols[i].qt_code;
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);
404 return qt_mac_keyvkey_symbols[i].qt_code;
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) ;
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;
422 #ifdef DEBUG_KEY_BINDINGS
423 qDebug("Unknown case.. %s:%d %d[%d] %d", __FILE__, __LINE__, key.unicode(), key.toLatin1(), virtualKey);
425 return Qt::Key_unknown;
428 static Boolean qt_KeyEventComparatorProc(EventRef inEvent, void *data)
430 UInt32 ekind = GetEventKind(inEvent),
431 eclass = GetEventClass(inEvent);
432 return (eclass == kEventClassKeyboard && (void *)ekind == data);
435 static bool translateKeyEventInternal(EventHandlerCallRef er, EventRef keyEvent, int *qtKey,
436 QChar *outChar, Qt::KeyboardModifiers *outModifiers, bool *outHandled)
438 #if !defined(QT_MAC_USE_COCOA) || defined(Q_OS_MAC64)
440 Q_UNUSED(outHandled);
442 const UInt32 ekind = GetEventKind(keyEvent);
444 UInt32 mac_modifiers = 0;
445 GetEventParameter(keyEvent, kEventParamKeyModifiers, typeUInt32, 0,
446 sizeof(mac_modifiers), 0, &mac_modifiers);
447 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
448 qDebug("************ Mapping modifiers and key ***********");
450 *outModifiers = qt_mac_get_modifiers(mac_modifiers);
451 #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
452 qDebug("------------ Mapping modifiers and key -----------");
458 GetEventParameter(keyEvent, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode);
461 static UInt32 tmp_unused_state = 0L;
462 const UCKeyboardLayout *uchrData = 0;
463 #if defined(Q_OS_MAC32)
464 KeyboardLayoutRef keyLayoutRef = 0;
465 KLGetCurrentKeyboardLayout(&keyLayoutRef);
467 if (keyLayoutRef != 0) {
468 err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
469 (reinterpret_cast<const void **>(&uchrData)));
471 qWarning("Qt::internal::unable to get keyboardlayout %ld %s:%d",
472 long(err), __FILE__, __LINE__);
476 QCFType<TISInputSourceRef> inputSource = TISCopyCurrentKeyboardInputSource();
477 Q_ASSERT(inputSource != 0);
478 CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSource,
479 kTISPropertyUnicodeKeyLayoutData));
480 uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
482 *qtKey = Qt::Key_unknown;
484 // The easy stuff; use the unicode stuff!
486 UniCharCount actualLength;
487 UInt32 currentModifiers = GetCurrentEventKeyModifiers();
488 UInt32 currentModifiersWOAltOrControl = currentModifiers & ~(controlKey | optionKey);
492 case kEventRawKeyDown:
493 keyAction = kUCKeyActionDown;
496 keyAction = kUCKeyActionUp;
498 case kEventRawKeyRepeat:
499 keyAction = kUCKeyActionAutoKey;
502 OSStatus err = UCKeyTranslate(uchrData, keyCode, keyAction,
503 ((currentModifiersWOAltOrControl >> 8) & 0xff), LMGetKbdType(),
504 kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
507 *outChar = QChar(string[0]);
508 *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
509 if (currentModifiersWOAltOrControl != currentModifiers) {
510 // Now get the real char.
511 err = UCKeyTranslate(uchrData, keyCode, keyAction,
512 ((currentModifiers >> 8) & 0xff), LMGetKbdType(),
513 kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
516 *outChar = QChar(string[0]);
519 qWarning("Qt::internal::UCKeyTranslate is returnining %ld %s:%d",
520 long(err), __FILE__, __LINE__);
525 // The road less travelled; use KeyTranslate
526 const void *keyboard_layout;
527 KeyboardLayoutRef keyLayoutRef = 0;
528 KLGetCurrentKeyboardLayout(&keyLayoutRef);
529 err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
530 reinterpret_cast<const void **>(&keyboard_layout));
532 int translatedChar = KeyTranslate(keyboard_layout, (GetCurrentEventKeyModifiers() &
533 (kEventKeyModifierNumLockMask|shiftKey|cmdKey|
534 rightShiftKey|alphaLock)) | keyCode,
536 if (!translatedChar) {
537 #ifdef QT_MAC_USE_COCOA
539 qt_mac_eat_unicode_key = false;
541 CallNextEventHandler(er, keyEvent);
542 *outHandled = qt_mac_eat_unicode_key;
548 //map it into qt keys
549 *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
550 if (*outModifiers & (Qt::AltModifier | Qt::ControlModifier)) {
551 if (translatedChar & (1 << 7)) //high ascii
553 } else { //now get the real ascii value
555 static UInt32 tmp_state = 0L;
556 if (*outModifiers & Qt::ShiftModifier)
558 if (*outModifiers & Qt::MetaModifier)
559 tmp_mod |= controlKey;
560 if (*outModifiers & Qt::ControlModifier)
562 if (GetCurrentEventKeyModifiers() & alphaLock) //no Qt mapper
563 tmp_mod |= alphaLock;
564 if (*outModifiers & Qt::AltModifier)
565 tmp_mod |= optionKey;
566 if (*outModifiers & Qt::KeypadModifier)
567 tmp_mod |= kEventKeyModifierNumLockMask;
568 translatedChar = KeyTranslate(keyboard_layout, tmp_mod | keyCode, &tmp_state);
571 ByteCount unilen = 0;
572 if (GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, 0, &unilen, 0)
573 == noErr && unilen == 2) {
574 GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, unilen, 0, outChar);
575 } else if (translatedChar) {
576 static QTextCodec *c = 0;
578 c = QTextCodec::codecForName("Apple Roman");
579 char tmpChar = (char)translatedChar; // **sigh**
580 *outChar = c->toUnicode(&tmpChar, 1).at(0);
582 *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
587 if (*qtKey == Qt::Key_unknown)
588 *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
592 QKeyMapperPrivate::QKeyMapperPrivate()
594 memset(keyLayout, 0, sizeof(keyLayout));
595 keyboard_layout_format.unicode = 0;
597 keyboard_mode = NullMode;
599 currentInputSource = 0;
603 QKeyMapperPrivate::~QKeyMapperPrivate()
609 QKeyMapperPrivate::updateKeyboard()
611 const UCKeyboardLayout *uchrData = 0;
613 KeyboardLayoutRef keyLayoutRef = 0;
614 KLGetCurrentKeyboardLayout(&keyLayoutRef);
616 if (keyboard_mode != NullMode && currentKeyboardLayout == keyLayoutRef)
620 if (keyLayoutRef != 0) {
621 err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
622 const_cast<const void **>(reinterpret_cast<const void **>(&uchrData)));
624 qWarning("Qt::internal::unable to get unicode keyboardlayout %ld %s:%d",
625 long(err), __FILE__, __LINE__);
629 QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
630 if (keyboard_mode != NullMode && source == currentInputSource) {
633 Q_ASSERT(source != 0);
634 CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
635 kTISPropertyUnicodeKeyLayoutData));
636 uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
639 keyboard_kind = LMGetKbdType();
641 keyboard_layout_format.unicode = uchrData;
642 keyboard_mode = UnicodeMode;
647 err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
648 const_cast<const void **>(reinterpret_cast<void **>(&happy)));
650 qFatal("Qt::internal::unable to get non-unicode layout, cannot procede %ld %s:%d",
651 long(err), __FILE__, __LINE__);
653 keyboard_layout_format.other = happy;
654 keyboard_mode = OtherMode;
657 currentKeyboardLayout = keyLayoutRef;
659 currentInputSource = source;
662 CFStringRef iso639Code;
664 # ifndef kKLLanguageCode
665 # define kKLLanguageCode 9
667 KLGetKeyboardLayoutProperty(currentKeyboardLayout, kKLLanguageCode,
668 reinterpret_cast<const void **>(&iso639Code));
670 CFArrayRef array = static_cast<CFArrayRef>(TISGetInputSourceProperty(currentInputSource, kTISPropertyInputSourceLanguages));
671 iso639Code = static_cast<CFStringRef>(CFArrayGetValueAtIndex(array, 0)); // Actually a RFC3066bis, but it's close enough
674 keyboardInputLocale = QLocale(QCFString::toQString(iso639Code));
675 keyboardInputDirection = keyboardInputLocale.textDirection();
677 keyboardInputLocale = QLocale::c();
678 keyboardInputDirection = Qt::LeftToRight;
684 QKeyMapperPrivate::deleteLayouts()
686 keyboard_mode = NullMode;
687 for (int i = 0; i < 255; ++i) {
696 QKeyMapperPrivate::clearMappings()
703 QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
707 KeyboardLayoutItem *kbItem = keyLayout[e->nativeVirtualKey()];
708 if (!kbItem) // Key is not in any keyboard layout (e.g. eisu-key on Japanese keyboard)
711 int baseKey = kbItem->qtKey[0];
712 Qt::KeyboardModifiers keyMods = e->modifiers();
713 ret << int(baseKey + keyMods); // The base key is _always_ valid, of course
715 for (int i = 1; i < 8; ++i) {
716 Qt::KeyboardModifiers neededMods = ModsTbl[i];
717 int key = kbItem->qtKey[i];
718 if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
719 ret << int(key + (keyMods & ~neededMods));
725 bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef er, EventRef event,
726 void *info, bool grab)
728 Q_ASSERT(GetEventClass(event) == kEventClassKeyboard);
729 bool handled_event=true;
730 UInt32 ekind = GetEventKind(event);
732 // unfortunately modifiers changed event looks quite different, so I have a separate
734 if (ekind == kEventRawKeyModifiersChanged) {
735 //figure out changed modifiers, wish Apple would just send a delta
736 UInt32 modifiers = 0;
737 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
738 sizeof(modifiers), 0, &modifiers);
739 qt_mac_send_modifiers_changed(modifiers, widget);
743 QInputContext *currentContext = qApp->inputContext();
744 if (currentContext && currentContext->isComposing()) {
745 if (ekind == kEventRawKeyDown) {
746 QMacInputContext *context = qobject_cast<QMacInputContext*>(currentContext);
748 context->setLastKeydownEvent(event);
752 // Once we process the key down , we don't need to send the saved event again from
753 // kEventTextInputUnicodeForKeyEvent, so clear it.
754 if (currentContext && ekind == kEventRawKeyDown) {
755 QMacInputContext *context = qobject_cast<QMacInputContext*>(currentContext);
757 context->setLastKeydownEvent(0);
761 Qt::KeyboardModifiers modifiers;
764 if (translateKeyEventInternal(er, event, &qtKey, &ourChar, &modifiers,
765 &handled_event) == false)
766 return handled_event;
767 QString text(ourChar);
768 /* This is actually wrong - but unfortunately it is the best that can be
769 done for now because of the Control/Meta mapping problems */
770 if (modifiers & (Qt::ControlModifier | Qt::MetaModifier)
771 && !qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
777 #ifndef QT_MAC_USE_COCOA
779 // Try not to call "other" event handlers if we have a popup,
780 // However, if the key has text
781 // then we should pass it along because otherwise then people
782 // can use input method stuff.
783 if (!qApp->activePopupWidget()
784 || (qApp->activePopupWidget() && !text.isEmpty())) {
785 //Find out if someone else wants the event, namely
786 //is it of use to text services? If so we won't bother
788 qt_mac_eat_unicode_key = false;
790 CallNextEventHandler(er, event);
791 extern bool qt_mac_menubar_is_open();
792 if (qt_mac_eat_unicode_key || qt_mac_menubar_is_open()) {
797 // Try to compress key events.
798 if (!text.isEmpty() && widget->testAttribute(Qt::WA_KeyCompression)) {
799 EventTime lastTime = GetEventTime(event);
801 EventRef releaseEvent = FindSpecificEventInQueue(GetMainEventQueue(),
802 qt_KeyEventComparatorProc,
803 (void*)kEventRawKeyUp);
806 const EventTime releaseTime = GetEventTime(releaseEvent);
807 if (releaseTime < lastTime)
809 lastTime = releaseTime;
811 EventRef pressEvent = FindSpecificEventInQueue(GetMainEventQueue(),
812 qt_KeyEventComparatorProc,
813 (void*)kEventRawKeyDown);
816 const EventTime pressTime = GetEventTime(pressEvent);
817 if (pressTime < lastTime)
819 lastTime = pressTime;
821 Qt::KeyboardModifiers compressMod;
822 int compressQtKey = 0;
824 if (translateKeyEventInternal(er, pressEvent,
825 &compressQtKey, &compressChar, &compressMod, 0)
829 // Copied from qapplication_x11.cpp (change both).
831 bool stopCompression =
833 (compressQtKey >= Qt::Key_Escape && compressQtKey <= Qt::Key_SysReq)
834 // 2) cursor movement
835 || (compressQtKey >= Qt::Key_Home && compressQtKey <= Qt::Key_PageDown)
837 || (compressQtKey >= Qt::Key_Super_L && compressQtKey <= Qt::Key_Direction_R)
838 // 4) something that a) doesn't translate to text or b) translates
840 || (compressQtKey == 0)
841 || (compressChar == QLatin1Char('\n'))
842 || (compressQtKey == Qt::Key_unknown);
844 if (compressMod == modifiers && !compressChar.isNull() && !stopCompression) {
845 #ifdef DEBUG_KEY_BINDINGS
846 qDebug("compressing away %c", compressChar.toLatin1());
848 text += compressChar;
850 RemoveEventFromQueue(GetMainEventQueue(), releaseEvent);
851 RemoveEventFromQueue(GetMainEventQueue(), pressEvent);
853 #ifdef DEBUG_KEY_BINDINGS
854 qDebug("stoping compression..");
861 // There is no way to get the scan code from carbon. But we cannot use the value 0, since
862 // it indicates that the event originates from somewhere else than the keyboard
863 UInt32 macScanCode = 1;
864 UInt32 macVirtualKey = 0;
865 GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
866 UInt32 macModifiers = 0;
867 GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
868 sizeof(macModifiers), 0, &macModifiers);
869 #ifdef QT_MAC_USE_COCOA
870 // The unicode characters in the range 0xF700-0xF747 are reserved
871 // by Mac OS X for transient use as keyboard function keys. We
872 // wont send 'text' for such key events. This is done to match
873 // behavior on other platforms.
874 unsigned int *unicodeKey = (unsigned int*)info;
875 if (*unicodeKey >= 0xf700 && *unicodeKey <= 0xf747)
879 handled_event = QKeyMapper::sendKeyEvent(widget, grab,
880 (ekind == kEventRawKeyUp) ? QEvent::KeyRelease : QEvent::KeyPress,
881 qtKey, modifiers, text, ekind == kEventRawKeyRepeat, 0,
882 macScanCode, macVirtualKey, macModifiers
883 #ifdef QT_MAC_USE_COCOA
887 #ifdef QT_MAC_USE_COCOA
888 *unicodeKey = (unsigned int)isAccepted;
891 return handled_event;
895 QKeyMapperPrivate::updateKeyMap(EventHandlerCallRef, EventRef event, void *
896 #if defined(QT_MAC_USE_COCOA)
897 unicodeKey // unicode character from NSEvent (modifiers applied)
901 UInt32 macVirtualKey = 0;
902 GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
903 if (updateKeyboard())
904 QKeyMapper::changeKeyboard();
905 else if (keyLayout[macVirtualKey])
908 UniCharCount buffer_size = 10;
909 UniChar buffer[buffer_size];
910 keyLayout[macVirtualKey] = new KeyboardLayoutItem;
911 for (int i = 0; i < 16; ++i) {
912 UniCharCount out_buffer_size = 0;
913 keyLayout[macVirtualKey]->qtKey[i] = 0;
915 if (keyboard_mode == UnicodeMode) {
917 const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
918 OSStatus err = UCKeyTranslate(keyboard_layout_format.unicode, macVirtualKey, kUCKeyActionDown, keyModifier,
919 keyboard_kind, 0, &keyboard_dead, buffer_size, &out_buffer_size, buffer);
920 if (err == noErr && out_buffer_size) {
921 const QChar unicode(buffer[0]);
922 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
923 if (qtkey == Qt::Key_unknown)
924 qtkey = unicode.unicode();
925 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
929 const QChar unicode(*((UniChar *)unicodeKey));
930 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
931 if (qtkey == Qt::Key_unknown)
932 qtkey = unicode.unicode();
933 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
938 const UInt32 keyModifier = (qt_mac_get_mac_modifiers(ModsTbl[i]));
940 uchar translatedChar = KeyTranslate(keyboard_layout_format.other, keyModifier | macVirtualKey, &keyboard_dead);
941 if (translatedChar) {
942 static QTextCodec *c = 0;
944 c = QTextCodec::codecForName("Apple Roman");
945 const QChar unicode(c->toUnicode((const char *)&translatedChar, 1).at(0));
946 int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
947 if (qtkey == Qt::Key_unknown)
948 qtkey = unicode.unicode();
949 keyLayout[macVirtualKey]->qtKey[i] = qtkey;
954 #ifdef DEBUG_KEY_MAPS
955 qDebug("updateKeyMap for virtual key = 0x%02x!", (uint)macVirtualKey);
956 for (int i = 0; i < 16; ++i) {
957 qDebug(" [%d] (%d,0x%02x,'%c')", i,
958 keyLayout[macVirtualKey]->qtKey[i],
959 keyLayout[macVirtualKey]->qtKey[i],
960 keyLayout[macVirtualKey]->qtKey[i]);
966 QKeyMapper::sendKeyEvent(QWidget *widget, bool grab,
967 QEvent::Type type, int code, Qt::KeyboardModifiers modifiers,
968 const QString &text, bool autorepeat, int count,
969 quint32 nativeScanCode, quint32 nativeVirtualKey,
970 quint32 nativeModifiers, bool *isAccepted)
973 if (widget && widget->isEnabled()) {
974 bool key_event = true;
975 #if defined(QT3_SUPPORT) && !defined(QT_NO_SHORTCUT)
976 if (type == QEvent::KeyPress && !grab
977 && QApplicationPrivate::instance()->use_compat()) {
978 QKeyEventEx accel_ev(type, code, modifiers,
979 text, autorepeat, qMax(1, int(text.length())),
980 nativeScanCode, nativeVirtualKey, nativeModifiers);
981 if (QApplicationPrivate::instance()->qt_tryAccelEvent(widget, &accel_ev)) {
982 #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
983 qDebug("KeyEvent: %s::%s consumed Accel: %s",
984 widget ? widget->metaObject()->className() : "none",
985 widget ? widget->objectName().toLatin1().constData() : "",
986 text.toLatin1().constData());
990 if (accel_ev.isAccepted()) {
991 #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
992 qDebug("KeyEvent: %s::%s overrode Accel: %s",
993 widget ? widget->metaObject()->className() : "none",
994 widget ? widget->objectName().toLatin1().constData() : "",
995 text.toLatin1().constData());
1002 #endif // QT3_SUPPORT && !QT_NO_SHORTCUT
1004 #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
1005 qDebug("KeyEvent: Sending %s to %s::%s: %s 0x%08x%s",
1006 type == QEvent::KeyRelease ? "KeyRelease" : "KeyPress",
1007 widget ? widget->metaObject()->className() : "none",
1008 widget ? widget->objectName().toLatin1().constData() : "",
1009 text.toLatin1().constData(), int(modifiers),
1010 autorepeat ? " Repeat" : "");
1012 QKeyEventEx ke(type, code, modifiers, text, autorepeat, qMax(1, text.length()),
1013 nativeScanCode, nativeVirtualKey, nativeModifiers);
1014 bool retMe = qt_sendSpontaneousEvent(widget,&ke);
1016 *isAccepted = ke.isAccepted();