source: trunk/src/gui/kernel/qkeymapper_mac.cpp@ 187

Last change on this file since 187 was 2, checked in by Dmitry A. Kuminov, 16 years ago

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

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