| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** All rights reserved.
|
|---|
| 5 | ** Contact: Nokia Corporation ([email protected])
|
|---|
| 6 | **
|
|---|
| 7 | ** This file is part of the QtGui module of the Qt Toolkit.
|
|---|
| 8 | **
|
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$
|
|---|
| 10 | ** Commercial Usage
|
|---|
| 11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
|---|
| 12 | ** accordance with the Qt Commercial License Agreement provided with the
|
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in
|
|---|
| 14 | ** a written agreement between you and Nokia.
|
|---|
| 15 | **
|
|---|
| 16 | ** GNU Lesser General Public License Usage
|
|---|
| 17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
|---|
| 18 | ** General Public License version 2.1 as published by the Free Software
|
|---|
| 19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
|---|
| 20 | ** packaging of this file. Please review the following information to
|
|---|
| 21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
|---|
| 22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|---|
| 23 | **
|
|---|
| 24 | ** In addition, as a special exception, Nokia gives you certain additional
|
|---|
| 25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
|---|
| 26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 have questions regarding the use of this file, please contact
|
|---|
| 37 | ** Nokia 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 | #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_GUI_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 int qt_mac_get_key(int modif, const QChar &key, int virtualKey)
|
|---|
| 327 | {
|
|---|
| 328 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 329 | qDebug("**Mapping key: %d (0x%04x) - %d (0x%04x)", key.unicode(), key.unicode(), virtualKey, virtualKey);
|
|---|
| 330 | #endif
|
|---|
| 331 |
|
|---|
| 332 | if (key == kClearCharCode && virtualKey == 0x47)
|
|---|
| 333 | return Qt::Key_Clear;
|
|---|
| 334 |
|
|---|
| 335 | if (key.isDigit()) {
|
|---|
| 336 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 337 | qDebug("%d: got key: %d", __LINE__, key.digitValue());
|
|---|
| 338 | #endif
|
|---|
| 339 | return key.digitValue() + Qt::Key_0;
|
|---|
| 340 | }
|
|---|
| 341 |
|
|---|
| 342 | if (key.isLetter()) {
|
|---|
| 343 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 344 | qDebug("%d: got key: %d", __LINE__, (key.toUpper().unicode() - 'A'));
|
|---|
| 345 | #endif
|
|---|
| 346 | return (key.toUpper().unicode() - 'A') + Qt::Key_A;
|
|---|
| 347 | }
|
|---|
| 348 | if (key.isSymbol()) {
|
|---|
| 349 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 350 | qDebug("%d: got key: %d", __LINE__, (key.unicode()));
|
|---|
| 351 | #endif
|
|---|
| 352 | return key.unicode();
|
|---|
| 353 | }
|
|---|
| 354 |
|
|---|
| 355 | for (int i = 0; qt_mac_keyboard_symbols[i].qt_code; i++) {
|
|---|
| 356 | if (qt_mac_keyboard_symbols[i].mac_code == key) {
|
|---|
| 357 | /* To work like Qt for X11 we issue Backtab when Shift + Tab are pressed */
|
|---|
| 358 | if (qt_mac_keyboard_symbols[i].qt_code == Qt::Key_Tab && (modif & Qt::ShiftModifier)) {
|
|---|
| 359 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 360 | qDebug("%d: got key: Qt::Key_Backtab", __LINE__);
|
|---|
| 361 | #endif
|
|---|
| 362 | return Qt::Key_Backtab;
|
|---|
| 363 | }
|
|---|
| 364 |
|
|---|
| 365 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 366 | qDebug("%d: got key: %s", __LINE__, qt_mac_keyboard_symbols[i].desc);
|
|---|
| 367 | #endif
|
|---|
| 368 | return qt_mac_keyboard_symbols[i].qt_code;
|
|---|
| 369 | }
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | //last ditch try to match the scan code
|
|---|
| 373 | for (int i = 0; qt_mac_keyvkey_symbols[i].qt_code; i++) {
|
|---|
| 374 | if (qt_mac_keyvkey_symbols[i].mac_code == virtualKey) {
|
|---|
| 375 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 376 | qDebug("%d: got key: %s", __LINE__, qt_mac_keyvkey_symbols[i].desc);
|
|---|
| 377 | #endif
|
|---|
| 378 | return qt_mac_keyvkey_symbols[i].qt_code;
|
|---|
| 379 | }
|
|---|
| 380 | }
|
|---|
| 381 |
|
|---|
| 382 | //oh well
|
|---|
| 383 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 384 | qDebug("Unknown case.. %s:%d %d[%d] %d", __FILE__, __LINE__, key.unicode(), key.toLatin1(), virtualKey);
|
|---|
| 385 | #endif
|
|---|
| 386 | return Qt::Key_unknown;
|
|---|
| 387 | }
|
|---|
| 388 |
|
|---|
| 389 | static Boolean qt_KeyEventComparatorProc(EventRef inEvent, void *data)
|
|---|
| 390 | {
|
|---|
| 391 | UInt32 ekind = GetEventKind(inEvent),
|
|---|
| 392 | eclass = GetEventClass(inEvent);
|
|---|
| 393 | return (eclass == kEventClassKeyboard && (void *)ekind == data);
|
|---|
| 394 | }
|
|---|
| 395 |
|
|---|
| 396 | static bool translateKeyEventInternal(EventHandlerCallRef er, EventRef keyEvent, int *qtKey,
|
|---|
| 397 | QChar *outChar, Qt::KeyboardModifiers *outModifiers, bool *outHandled)
|
|---|
| 398 | {
|
|---|
| 399 | #if !defined(QT_MAC_USE_COCOA) || defined(Q_OS_MAC64)
|
|---|
| 400 | Q_UNUSED(er);
|
|---|
| 401 | Q_UNUSED(outHandled);
|
|---|
| 402 | #endif
|
|---|
| 403 | const UInt32 ekind = GetEventKind(keyEvent);
|
|---|
| 404 | {
|
|---|
| 405 | UInt32 mac_modifiers = 0;
|
|---|
| 406 | GetEventParameter(keyEvent, kEventParamKeyModifiers, typeUInt32, 0,
|
|---|
| 407 | sizeof(mac_modifiers), 0, &mac_modifiers);
|
|---|
| 408 | #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
|
|---|
| 409 | qDebug("************ Mapping modifiers and key ***********");
|
|---|
| 410 | #endif
|
|---|
| 411 | *outModifiers = qt_mac_get_modifiers(mac_modifiers);
|
|---|
| 412 | #ifdef DEBUG_KEY_BINDINGS_MODIFIERS
|
|---|
| 413 | qDebug("------------ Mapping modifiers and key -----------");
|
|---|
| 414 | #endif
|
|---|
| 415 | }
|
|---|
| 416 |
|
|---|
| 417 | //get keycode
|
|---|
| 418 | UInt32 keyCode = 0;
|
|---|
| 419 | GetEventParameter(keyEvent, kEventParamKeyCode, typeUInt32, 0, sizeof(keyCode), 0, &keyCode);
|
|---|
| 420 |
|
|---|
| 421 | //get mac mapping
|
|---|
| 422 | static UInt32 tmp_unused_state = 0L;
|
|---|
| 423 | const UCKeyboardLayout *uchrData = 0;
|
|---|
| 424 | #if defined(Q_OS_MAC32)
|
|---|
| 425 | KeyboardLayoutRef keyLayoutRef = 0;
|
|---|
| 426 | KLGetCurrentKeyboardLayout(&keyLayoutRef);
|
|---|
| 427 | OSStatus err;
|
|---|
| 428 | if (keyLayoutRef != 0) {
|
|---|
| 429 | err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
|
|---|
| 430 | (reinterpret_cast<const void **>(&uchrData)));
|
|---|
| 431 | if (err != noErr) {
|
|---|
| 432 | qWarning("Qt::internal::unable to get keyboardlayout %ld %s:%d",
|
|---|
| 433 | long(err), __FILE__, __LINE__);
|
|---|
| 434 | }
|
|---|
| 435 | }
|
|---|
| 436 | #else
|
|---|
| 437 | QCFType<TISInputSourceRef> inputSource = TISCopyCurrentKeyboardInputSource();
|
|---|
| 438 | Q_ASSERT(inputSource != 0);
|
|---|
| 439 | CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(inputSource,
|
|---|
| 440 | kTISPropertyUnicodeKeyLayoutData));
|
|---|
| 441 | uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
|
|---|
| 442 | #endif
|
|---|
| 443 | *qtKey = Qt::Key_unknown;
|
|---|
| 444 | if (uchrData) {
|
|---|
| 445 | // The easy stuff; use the unicode stuff!
|
|---|
| 446 | UniChar string[4];
|
|---|
| 447 | UniCharCount actualLength;
|
|---|
| 448 | UInt32 currentModifiers = GetCurrentEventKeyModifiers();
|
|---|
| 449 | UInt32 currentModifiersWOAltOrControl = currentModifiers & ~(controlKey | optionKey);
|
|---|
| 450 | int keyAction;
|
|---|
| 451 | switch (ekind) {
|
|---|
| 452 | default:
|
|---|
| 453 | case kEventRawKeyDown:
|
|---|
| 454 | keyAction = kUCKeyActionDown;
|
|---|
| 455 | break;
|
|---|
| 456 | case kEventRawKeyUp:
|
|---|
| 457 | keyAction = kUCKeyActionUp;
|
|---|
| 458 | break;
|
|---|
| 459 | case kEventRawKeyRepeat:
|
|---|
| 460 | keyAction = kUCKeyActionAutoKey;
|
|---|
| 461 | break;
|
|---|
| 462 | }
|
|---|
| 463 | OSStatus err = UCKeyTranslate(uchrData, keyCode, keyAction,
|
|---|
| 464 | ((currentModifiersWOAltOrControl >> 8) & 0xff), LMGetKbdType(),
|
|---|
| 465 | kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
|
|---|
| 466 | string);
|
|---|
| 467 | if (err == noErr) {
|
|---|
| 468 | *outChar = QChar(string[0]);
|
|---|
| 469 | *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
|
|---|
| 470 | if (currentModifiersWOAltOrControl != currentModifiers) {
|
|---|
| 471 | // Now get the real char.
|
|---|
| 472 | err = UCKeyTranslate(uchrData, keyCode, keyAction,
|
|---|
| 473 | ((currentModifiers >> 8) & 0xff), LMGetKbdType(),
|
|---|
| 474 | kUCKeyTranslateNoDeadKeysMask, &tmp_unused_state, 4, &actualLength,
|
|---|
| 475 | string);
|
|---|
| 476 | if (err == noErr)
|
|---|
| 477 | *outChar = QChar(string[0]);
|
|---|
| 478 | }
|
|---|
| 479 | } else {
|
|---|
| 480 | qWarning("Qt::internal::UCKeyTranslate is returnining %ld %s:%d",
|
|---|
| 481 | long(err), __FILE__, __LINE__);
|
|---|
| 482 | }
|
|---|
| 483 | }
|
|---|
| 484 | #ifdef Q_OS_MAC32
|
|---|
| 485 | else {
|
|---|
| 486 | // The road less travelled; use KeyTranslate
|
|---|
| 487 | const void *keyboard_layout;
|
|---|
| 488 | KeyboardLayoutRef keyLayoutRef = 0;
|
|---|
| 489 | KLGetCurrentKeyboardLayout(&keyLayoutRef);
|
|---|
| 490 | err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
|
|---|
| 491 | reinterpret_cast<const void **>(&keyboard_layout));
|
|---|
| 492 |
|
|---|
| 493 | int translatedChar = KeyTranslate(keyboard_layout, (GetCurrentEventKeyModifiers() &
|
|---|
| 494 | (kEventKeyModifierNumLockMask|shiftKey|cmdKey|
|
|---|
| 495 | rightShiftKey|alphaLock)) | keyCode,
|
|---|
| 496 | &tmp_unused_state);
|
|---|
| 497 | if (!translatedChar) {
|
|---|
| 498 | #ifdef QT_MAC_USE_COCOA
|
|---|
| 499 | if (outHandled) {
|
|---|
| 500 | qt_mac_eat_unicode_key = false;
|
|---|
| 501 | if (er)
|
|---|
| 502 | CallNextEventHandler(er, keyEvent);
|
|---|
| 503 | *outHandled = qt_mac_eat_unicode_key;
|
|---|
| 504 | }
|
|---|
| 505 | #endif
|
|---|
| 506 | return false;
|
|---|
| 507 | }
|
|---|
| 508 |
|
|---|
| 509 | //map it into qt keys
|
|---|
| 510 | *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
|
|---|
| 511 | if (*outModifiers & (Qt::AltModifier | Qt::ControlModifier)) {
|
|---|
| 512 | if (translatedChar & (1 << 7)) //high ascii
|
|---|
| 513 | translatedChar = 0;
|
|---|
| 514 | } else { //now get the real ascii value
|
|---|
| 515 | UInt32 tmp_mod = 0L;
|
|---|
| 516 | static UInt32 tmp_state = 0L;
|
|---|
| 517 | if (*outModifiers & Qt::ShiftModifier)
|
|---|
| 518 | tmp_mod |= shiftKey;
|
|---|
| 519 | if (*outModifiers & Qt::MetaModifier)
|
|---|
| 520 | tmp_mod |= controlKey;
|
|---|
| 521 | if (*outModifiers & Qt::ControlModifier)
|
|---|
| 522 | tmp_mod |= cmdKey;
|
|---|
| 523 | if (GetCurrentEventKeyModifiers() & alphaLock) //no Qt mapper
|
|---|
| 524 | tmp_mod |= alphaLock;
|
|---|
| 525 | if (*outModifiers & Qt::AltModifier)
|
|---|
| 526 | tmp_mod |= optionKey;
|
|---|
| 527 | if (*outModifiers & Qt::KeypadModifier)
|
|---|
| 528 | tmp_mod |= kEventKeyModifierNumLockMask;
|
|---|
| 529 | translatedChar = KeyTranslate(keyboard_layout, tmp_mod | keyCode, &tmp_state);
|
|---|
| 530 | }
|
|---|
| 531 | {
|
|---|
| 532 | ByteCount unilen = 0;
|
|---|
| 533 | if (GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, 0, &unilen, 0)
|
|---|
| 534 | == noErr && unilen == 2) {
|
|---|
| 535 | GetEventParameter(keyEvent, kEventParamKeyUnicodes, typeUnicodeText, 0, unilen, 0, outChar);
|
|---|
| 536 | } else if (translatedChar) {
|
|---|
| 537 | static QTextCodec *c = 0;
|
|---|
| 538 | if (!c)
|
|---|
| 539 | c = QTextCodec::codecForName("Apple Roman");
|
|---|
| 540 | char tmpChar = (char)translatedChar; // **sigh**
|
|---|
| 541 | *outChar = c->toUnicode(&tmpChar, 1).at(0);
|
|---|
| 542 | } else {
|
|---|
| 543 | *qtKey = qt_mac_get_key(*outModifiers, QChar(translatedChar), keyCode);
|
|---|
| 544 | }
|
|---|
| 545 | }
|
|---|
| 546 | }
|
|---|
| 547 | #endif
|
|---|
| 548 | if (*qtKey == Qt::Key_unknown)
|
|---|
| 549 | *qtKey = qt_mac_get_key(*outModifiers, *outChar, keyCode);
|
|---|
| 550 | return true;
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | QKeyMapperPrivate::QKeyMapperPrivate()
|
|---|
| 554 | {
|
|---|
| 555 | memset(keyLayout, 0, sizeof(keyLayout));
|
|---|
| 556 | keyboard_layout_format.unicode = 0;
|
|---|
| 557 | #ifdef Q_OS_MAC32
|
|---|
| 558 | keyboard_mode = NullMode;
|
|---|
| 559 | #else
|
|---|
| 560 | currentInputSource = 0;
|
|---|
| 561 | #endif
|
|---|
| 562 | }
|
|---|
| 563 |
|
|---|
| 564 | QKeyMapperPrivate::~QKeyMapperPrivate()
|
|---|
| 565 | {
|
|---|
| 566 | deleteLayouts();
|
|---|
| 567 | }
|
|---|
| 568 |
|
|---|
| 569 | bool
|
|---|
| 570 | QKeyMapperPrivate::updateKeyboard()
|
|---|
| 571 | {
|
|---|
| 572 | const UCKeyboardLayout *uchrData = 0;
|
|---|
| 573 | #ifdef Q_OS_MAC32
|
|---|
| 574 | KeyboardLayoutRef keyLayoutRef = 0;
|
|---|
| 575 | KLGetCurrentKeyboardLayout(&keyLayoutRef);
|
|---|
| 576 |
|
|---|
| 577 | if (keyboard_mode != NullMode && currentKeyboardLayout == keyLayoutRef)
|
|---|
| 578 | return false;
|
|---|
| 579 |
|
|---|
| 580 | OSStatus err;
|
|---|
| 581 | if (keyLayoutRef != 0) {
|
|---|
| 582 | err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLuchrData,
|
|---|
| 583 | const_cast<const void **>(reinterpret_cast<const void **>(&uchrData)));
|
|---|
| 584 | if (err != noErr) {
|
|---|
| 585 | qWarning("Qt::internal::unable to get unicode keyboardlayout %ld %s:%d",
|
|---|
| 586 | long(err), __FILE__, __LINE__);
|
|---|
| 587 | }
|
|---|
| 588 | }
|
|---|
| 589 | #else
|
|---|
| 590 | QCFType<TISInputSourceRef> source = TISCopyCurrentKeyboardInputSource();
|
|---|
| 591 | if (keyboard_mode != NullMode && source == currentInputSource) {
|
|---|
| 592 | return false;
|
|---|
| 593 | }
|
|---|
| 594 | Q_ASSERT(source != 0);
|
|---|
| 595 | CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(source,
|
|---|
| 596 | kTISPropertyUnicodeKeyLayoutData));
|
|---|
| 597 | uchrData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
|
|---|
| 598 | #endif
|
|---|
| 599 |
|
|---|
| 600 | keyboard_kind = LMGetKbdType();
|
|---|
| 601 | if (uchrData) {
|
|---|
| 602 | keyboard_layout_format.unicode = uchrData;
|
|---|
| 603 | keyboard_mode = UnicodeMode;
|
|---|
| 604 | }
|
|---|
| 605 | #ifdef Q_OS_MAC32
|
|---|
| 606 | else {
|
|---|
| 607 | void *happy;
|
|---|
| 608 | err = KLGetKeyboardLayoutProperty(keyLayoutRef, kKLKCHRData,
|
|---|
| 609 | const_cast<const void **>(reinterpret_cast<void **>(&happy)));
|
|---|
| 610 | if (err != noErr) {
|
|---|
| 611 | qFatal("Qt::internal::unable to get non-unicode layout, cannot procede %ld %s:%d",
|
|---|
| 612 | long(err), __FILE__, __LINE__);
|
|---|
| 613 | }
|
|---|
| 614 | keyboard_layout_format.other = happy;
|
|---|
| 615 | keyboard_mode = OtherMode;
|
|---|
| 616 | }
|
|---|
| 617 |
|
|---|
| 618 | currentKeyboardLayout = keyLayoutRef;
|
|---|
| 619 | #else
|
|---|
| 620 | currentInputSource = source;
|
|---|
| 621 | #endif
|
|---|
| 622 | keyboard_dead = 0;
|
|---|
| 623 | CFStringRef iso639Code;
|
|---|
| 624 | #ifdef Q_OS_MAC32
|
|---|
| 625 | # ifndef kKLLanguageCode
|
|---|
| 626 | # define kKLLanguageCode 9
|
|---|
| 627 | # endif
|
|---|
| 628 | KLGetKeyboardLayoutProperty(currentKeyboardLayout, kKLLanguageCode,
|
|---|
| 629 | reinterpret_cast<const void **>(&iso639Code));
|
|---|
| 630 | #else
|
|---|
| 631 | CFArrayRef array = static_cast<CFArrayRef>(TISGetInputSourceProperty(currentInputSource, kTISPropertyInputSourceLanguages));
|
|---|
| 632 | iso639Code = static_cast<CFStringRef>(CFArrayGetValueAtIndex(array, 0)); // Actually a RFC3066bis, but it's close enough
|
|---|
| 633 | #endif
|
|---|
| 634 | if (iso639Code) {
|
|---|
| 635 | keyboardInputLocale = QLocale(QCFString::toQString(iso639Code));
|
|---|
| 636 | QString monday = keyboardInputLocale.dayName(1);
|
|---|
| 637 | bool rtl = false;
|
|---|
| 638 | for (int i = 0; i < monday.length(); ++i) {
|
|---|
| 639 | switch (monday.at(i).direction()) {
|
|---|
| 640 | default:
|
|---|
| 641 | break;
|
|---|
| 642 | case QChar::DirR:
|
|---|
| 643 | case QChar::DirAL:
|
|---|
| 644 | case QChar::DirRLE:
|
|---|
| 645 | case QChar::DirRLO:
|
|---|
| 646 | rtl = true;
|
|---|
| 647 | break;
|
|---|
| 648 | }
|
|---|
| 649 | if (rtl)
|
|---|
| 650 | break;
|
|---|
| 651 | }
|
|---|
| 652 | keyboardInputDirection = rtl ? Qt::RightToLeft : Qt::LeftToRight;
|
|---|
| 653 | } else {
|
|---|
| 654 | keyboardInputLocale = QLocale::c();
|
|---|
| 655 | keyboardInputDirection = Qt::LeftToRight;
|
|---|
| 656 | }
|
|---|
| 657 | return true;
|
|---|
| 658 | }
|
|---|
| 659 |
|
|---|
| 660 | void
|
|---|
| 661 | QKeyMapperPrivate::deleteLayouts()
|
|---|
| 662 | {
|
|---|
| 663 | keyboard_mode = NullMode;
|
|---|
| 664 | for (int i = 0; i < 255; ++i) {
|
|---|
| 665 | if (keyLayout[i]) {
|
|---|
| 666 | delete keyLayout[i];
|
|---|
| 667 | keyLayout[i] = 0;
|
|---|
| 668 | }
|
|---|
| 669 | }
|
|---|
| 670 | }
|
|---|
| 671 |
|
|---|
| 672 | void
|
|---|
| 673 | QKeyMapperPrivate::clearMappings()
|
|---|
| 674 | {
|
|---|
| 675 | deleteLayouts();
|
|---|
| 676 | updateKeyboard();
|
|---|
| 677 | }
|
|---|
| 678 |
|
|---|
| 679 | QList<int>
|
|---|
| 680 | QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
|
|---|
| 681 | {
|
|---|
| 682 | QList<int> ret;
|
|---|
| 683 |
|
|---|
| 684 | KeyboardLayoutItem *kbItem = keyLayout[e->nativeVirtualKey()];
|
|---|
| 685 | if (!kbItem) // Key is not in any keyboard layout (e.g. eisu-key on Japanese keyboard)
|
|---|
| 686 | return ret;
|
|---|
| 687 |
|
|---|
| 688 | int baseKey = kbItem->qtKey[0];
|
|---|
| 689 | Qt::KeyboardModifiers keyMods = e->modifiers();
|
|---|
| 690 | ret << int(baseKey + keyMods); // The base key is _always_ valid, of course
|
|---|
| 691 |
|
|---|
| 692 | for (int i = 1; i < 8; ++i) {
|
|---|
| 693 | Qt::KeyboardModifiers neededMods = ModsTbl[i];
|
|---|
| 694 | int key = kbItem->qtKey[i];
|
|---|
| 695 | if (key && key != baseKey && ((keyMods & neededMods) == neededMods))
|
|---|
| 696 | ret << int(key + (keyMods & ~neededMods));
|
|---|
| 697 | }
|
|---|
| 698 |
|
|---|
| 699 | return ret;
|
|---|
| 700 | }
|
|---|
| 701 |
|
|---|
| 702 | bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, EventHandlerCallRef er, EventRef event,
|
|---|
| 703 | void *info, bool grab)
|
|---|
| 704 | {
|
|---|
| 705 | Q_ASSERT(GetEventClass(event) == kEventClassKeyboard);
|
|---|
| 706 | bool handled_event=true;
|
|---|
| 707 | UInt32 ekind = GetEventKind(event);
|
|---|
| 708 |
|
|---|
| 709 | // unfortunately modifiers changed event looks quite different, so I have a separate
|
|---|
| 710 | // code path
|
|---|
| 711 | if (ekind == kEventRawKeyModifiersChanged) {
|
|---|
| 712 | //figure out changed modifiers, wish Apple would just send a delta
|
|---|
| 713 | UInt32 modifiers = 0;
|
|---|
| 714 | GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
|
|---|
| 715 | sizeof(modifiers), 0, &modifiers);
|
|---|
| 716 | qt_mac_send_modifiers_changed(modifiers, widget);
|
|---|
| 717 | return true;
|
|---|
| 718 | }
|
|---|
| 719 |
|
|---|
| 720 | if (qApp->inputContext() && qApp->inputContext()->isComposing()) {
|
|---|
| 721 | if (ekind == kEventRawKeyDown) {
|
|---|
| 722 | QMacInputContext *context = qobject_cast<QMacInputContext*>(qApp->inputContext());
|
|---|
| 723 | if (context)
|
|---|
| 724 | context->setLastKeydownEvent(event);
|
|---|
| 725 | }
|
|---|
| 726 | return false;
|
|---|
| 727 | }
|
|---|
| 728 | //get modifiers
|
|---|
| 729 | Qt::KeyboardModifiers modifiers;
|
|---|
| 730 | int qtKey;
|
|---|
| 731 | QChar ourChar;
|
|---|
| 732 | if (translateKeyEventInternal(er, event, &qtKey, &ourChar, &modifiers,
|
|---|
| 733 | &handled_event) == false)
|
|---|
| 734 | return handled_event;
|
|---|
| 735 | QString text(ourChar);
|
|---|
| 736 | /* This is actually wrong - but unfortunatly it is the best that can be
|
|---|
| 737 | done for now because of the Control/Meta mapping problems */
|
|---|
| 738 | if (modifiers & (Qt::ControlModifier | Qt::MetaModifier)
|
|---|
| 739 | && !qApp->testAttribute(Qt::AA_MacDontSwapCtrlAndMeta)) {
|
|---|
| 740 | text = QString();
|
|---|
| 741 | }
|
|---|
| 742 |
|
|---|
| 743 |
|
|---|
| 744 | if (widget) {
|
|---|
| 745 | #ifndef QT_MAC_USE_COCOA
|
|---|
| 746 | Q_UNUSED(info);
|
|---|
| 747 | // Try not to call "other" event handlers if we have a popup,
|
|---|
| 748 | // However, if the key has text
|
|---|
| 749 | // then we should pass it along because otherwise then people
|
|---|
| 750 | // can use input method stuff.
|
|---|
| 751 | if (!qApp->activePopupWidget()
|
|---|
| 752 | || (qApp->activePopupWidget() && !text.isEmpty())) {
|
|---|
| 753 | //Find out if someone else wants the event, namely
|
|---|
| 754 | //is it of use to text services? If so we won't bother
|
|---|
| 755 | //with a QKeyEvent.
|
|---|
| 756 | qt_mac_eat_unicode_key = false;
|
|---|
| 757 | if (er)
|
|---|
| 758 | CallNextEventHandler(er, event);
|
|---|
| 759 | extern bool qt_mac_menubar_is_open();
|
|---|
| 760 | if (qt_mac_eat_unicode_key || qt_mac_menubar_is_open()) {
|
|---|
| 761 | return true;
|
|---|
| 762 | }
|
|---|
| 763 | }
|
|---|
| 764 | #endif
|
|---|
| 765 | // Try to compress key events.
|
|---|
| 766 | if (!text.isEmpty() && widget->testAttribute(Qt::WA_KeyCompression)) {
|
|---|
| 767 | EventTime lastTime = GetEventTime(event);
|
|---|
| 768 | for (;;) {
|
|---|
| 769 | EventRef releaseEvent = FindSpecificEventInQueue(GetMainEventQueue(),
|
|---|
| 770 | qt_KeyEventComparatorProc,
|
|---|
| 771 | (void*)kEventRawKeyUp);
|
|---|
| 772 | if (!releaseEvent)
|
|---|
| 773 | break;
|
|---|
| 774 | const EventTime releaseTime = GetEventTime(releaseEvent);
|
|---|
| 775 | if (releaseTime < lastTime)
|
|---|
| 776 | break;
|
|---|
| 777 | lastTime = releaseTime;
|
|---|
| 778 |
|
|---|
| 779 | EventRef pressEvent = FindSpecificEventInQueue(GetMainEventQueue(),
|
|---|
| 780 | qt_KeyEventComparatorProc,
|
|---|
| 781 | (void*)kEventRawKeyDown);
|
|---|
| 782 | if (!pressEvent)
|
|---|
| 783 | break;
|
|---|
| 784 | const EventTime pressTime = GetEventTime(pressEvent);
|
|---|
| 785 | if (pressTime < lastTime)
|
|---|
| 786 | break;
|
|---|
| 787 | lastTime = pressTime;
|
|---|
| 788 |
|
|---|
| 789 | Qt::KeyboardModifiers compressMod;
|
|---|
| 790 | int compressQtKey = 0;
|
|---|
| 791 | QChar compressChar;
|
|---|
| 792 | if (translateKeyEventInternal(er, pressEvent,
|
|---|
| 793 | &compressQtKey, &compressChar, &compressMod, 0)
|
|---|
| 794 | == false) {
|
|---|
| 795 | break;
|
|---|
| 796 | }
|
|---|
| 797 | // Copied from qapplication_x11.cpp (change both).
|
|---|
| 798 |
|
|---|
| 799 | bool stopCompression =
|
|---|
| 800 | // 1) misc keys
|
|---|
| 801 | (compressQtKey >= Qt::Key_Escape && compressQtKey <= Qt::Key_SysReq)
|
|---|
| 802 | // 2) cursor movement
|
|---|
| 803 | || (compressQtKey >= Qt::Key_Home && compressQtKey <= Qt::Key_PageDown)
|
|---|
| 804 | // 3) extra keys
|
|---|
| 805 | || (compressQtKey >= Qt::Key_Super_L && compressQtKey <= Qt::Key_Direction_R)
|
|---|
| 806 | // 4) something that a) doesn't translate to text or b) translates
|
|---|
| 807 | // to newline text
|
|---|
| 808 | || (compressQtKey == 0)
|
|---|
| 809 | || (compressChar == QLatin1Char('\n'))
|
|---|
| 810 | || (compressQtKey == Qt::Key_unknown);
|
|---|
| 811 |
|
|---|
| 812 | if (compressMod == modifiers && !compressChar.isNull() && !stopCompression) {
|
|---|
| 813 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 814 | qDebug("compressing away %c", compressChar.toLatin1());
|
|---|
| 815 | #endif
|
|---|
| 816 | text += compressChar;
|
|---|
| 817 | // Clean up
|
|---|
| 818 | RemoveEventFromQueue(GetMainEventQueue(), releaseEvent);
|
|---|
| 819 | RemoveEventFromQueue(GetMainEventQueue(), pressEvent);
|
|---|
| 820 | } else {
|
|---|
| 821 | #ifdef DEBUG_KEY_BINDINGS
|
|---|
| 822 | qDebug("stoping compression..");
|
|---|
| 823 | #endif
|
|---|
| 824 | break;
|
|---|
| 825 | }
|
|---|
| 826 | }
|
|---|
| 827 | }
|
|---|
| 828 |
|
|---|
| 829 | // There is no way to get the scan code from carbon. But we cannot use the value 0, since
|
|---|
| 830 | // it indicates that the event originates from somewhere else than the keyboard
|
|---|
| 831 | UInt32 macScanCode = 1;
|
|---|
| 832 | UInt32 macVirtualKey = 0;
|
|---|
| 833 | GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
|
|---|
| 834 | UInt32 macModifiers = 0;
|
|---|
| 835 | GetEventParameter(event, kEventParamKeyModifiers, typeUInt32, 0,
|
|---|
| 836 | sizeof(macModifiers), 0, &macModifiers);
|
|---|
| 837 | handled_event = QKeyMapper::sendKeyEvent(widget, grab,
|
|---|
| 838 | (ekind == kEventRawKeyUp) ? QEvent::KeyRelease : QEvent::KeyPress,
|
|---|
| 839 | qtKey, modifiers, text, ekind == kEventRawKeyRepeat, 0,
|
|---|
| 840 | macScanCode, macVirtualKey, macModifiers
|
|---|
| 841 | #ifdef QT_MAC_USE_COCOA
|
|---|
| 842 | ,static_cast<bool *>(info)
|
|---|
| 843 | #endif
|
|---|
| 844 | );
|
|---|
| 845 | }
|
|---|
| 846 | return handled_event;
|
|---|
| 847 | }
|
|---|
| 848 |
|
|---|
| 849 | void
|
|---|
| 850 | QKeyMapperPrivate::updateKeyMap(EventHandlerCallRef, EventRef event, void *)
|
|---|
| 851 | {
|
|---|
| 852 | UInt32 macVirtualKey = 0;
|
|---|
| 853 | GetEventParameter(event, kEventParamKeyCode, typeUInt32, 0, sizeof(macVirtualKey), 0, &macVirtualKey);
|
|---|
| 854 | if (updateKeyboard())
|
|---|
| 855 | QKeyMapper::changeKeyboard();
|
|---|
| 856 | else if (keyLayout[macVirtualKey])
|
|---|
| 857 | return;
|
|---|
| 858 |
|
|---|
| 859 | UniCharCount buffer_size = 10;
|
|---|
| 860 | UniChar buffer[buffer_size];
|
|---|
| 861 | keyLayout[macVirtualKey] = new KeyboardLayoutItem;
|
|---|
| 862 | for (int i = 0; i < 16; ++i) {
|
|---|
| 863 | UniCharCount out_buffer_size = 0;
|
|---|
| 864 | keyLayout[macVirtualKey]->qtKey[i] = 0;
|
|---|
| 865 | #ifdef Q_WS_MAC32
|
|---|
| 866 | if (keyboard_mode == UnicodeMode) {
|
|---|
| 867 | #endif
|
|---|
| 868 | const UInt32 keyModifier = ((qt_mac_get_mac_modifiers(ModsTbl[i]) >> 8) & 0xFF);
|
|---|
| 869 | OSStatus err = UCKeyTranslate(keyboard_layout_format.unicode, macVirtualKey, kUCKeyActionDown, keyModifier,
|
|---|
| 870 | keyboard_kind, 0, &keyboard_dead, buffer_size, &out_buffer_size, buffer);
|
|---|
| 871 | if (err == noErr && out_buffer_size) {
|
|---|
| 872 | const QChar unicode(buffer[0]);
|
|---|
| 873 | int qtkey = qt_mac_get_key(keyModifier, unicode, macVirtualKey);
|
|---|
| 874 | if (qtkey == Qt::Key_unknown)
|
|---|
| 875 | qtkey = unicode.unicode();
|
|---|
| 876 | keyLayout[macVirtualKey]->qtKey[i] = qtkey;
|
|---|
| 877 | }
|
|---|
| 878 | #ifdef Q_WS_MAC32
|
|---|
| 879 | } else {
|
|---|
| 880 | const UInt32 keyModifier = (qt_mac_get_mac_modifiers(ModsTbl[i]));
|
|---|
| 881 |
|
|---|
| 882 | uchar translatedChar = KeyTranslate(keyboard_layout_format.other, keyModifier | macVirtualKey, &keyboard_dead);
|
|---|
| 883 | if (translatedChar) {
|
|---|
| 884 | static QTextCodec *c = 0;
|
|---|
| 885 | if (!c)
|
|---|
| 886 | c = QTextCodec::codecForName("Apple Roman");
|
|---|
| 887 | const QChar unicode(c->toUnicode((const char *)&translatedChar, 1).at(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 | }
|
|---|
| 894 | #endif
|
|---|
| 895 | }
|
|---|
| 896 | #ifdef DEBUG_KEY_MAPS
|
|---|
| 897 | qDebug("updateKeyMap for virtual key = 0x%02x!", (uint)macVirtualKey);
|
|---|
| 898 | for (int i = 0; i < 16; ++i) {
|
|---|
| 899 | qDebug(" [%d] (%d,0x%02x,'%c')", i,
|
|---|
| 900 | keyLayout[macVirtualKey]->qtKey[i],
|
|---|
| 901 | keyLayout[macVirtualKey]->qtKey[i],
|
|---|
| 902 | keyLayout[macVirtualKey]->qtKey[i]);
|
|---|
| 903 | }
|
|---|
| 904 | #endif
|
|---|
| 905 | }
|
|---|
| 906 |
|
|---|
| 907 | bool
|
|---|
| 908 | QKeyMapper::sendKeyEvent(QWidget *widget, bool grab,
|
|---|
| 909 | QEvent::Type type, int code, Qt::KeyboardModifiers modifiers,
|
|---|
| 910 | const QString &text, bool autorepeat, int count,
|
|---|
| 911 | quint32 nativeScanCode, quint32 nativeVirtualKey,
|
|---|
| 912 | quint32 nativeModifiers, bool *isAccepted)
|
|---|
| 913 | {
|
|---|
| 914 | Q_UNUSED(count);
|
|---|
| 915 | if (widget && widget->isEnabled()) {
|
|---|
| 916 | bool key_event = true;
|
|---|
| 917 | #if defined(QT3_SUPPORT) && !defined(QT_NO_SHORTCUT)
|
|---|
| 918 | if (type == QEvent::KeyPress && !grab
|
|---|
| 919 | && QApplicationPrivate::instance()->use_compat()) {
|
|---|
| 920 | QKeyEventEx accel_ev(type, code, modifiers,
|
|---|
| 921 | text, autorepeat, qMax(1, int(text.length())),
|
|---|
| 922 | nativeScanCode, nativeVirtualKey, nativeModifiers);
|
|---|
| 923 | if (QApplicationPrivate::instance()->qt_tryAccelEvent(widget, &accel_ev)) {
|
|---|
| 924 | #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
|
|---|
| 925 | qDebug("KeyEvent: %s::%s consumed Accel: %s",
|
|---|
| 926 | widget ? widget->metaObject()->className() : "none",
|
|---|
| 927 | widget ? widget->objectName().toLatin1().constData() : "",
|
|---|
| 928 | text.toLatin1().constData());
|
|---|
| 929 | #endif
|
|---|
| 930 | key_event = false;
|
|---|
| 931 | } else {
|
|---|
| 932 | if (accel_ev.isAccepted()) {
|
|---|
| 933 | #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
|
|---|
| 934 | qDebug("KeyEvent: %s::%s overrode Accel: %s",
|
|---|
| 935 | widget ? widget->metaObject()->className() : "none",
|
|---|
| 936 | widget ? widget->objectName().toLatin1().constData() : "",
|
|---|
| 937 | text.toLatin1().constData());
|
|---|
| 938 | #endif
|
|---|
| 939 | }
|
|---|
| 940 | }
|
|---|
| 941 | }
|
|---|
| 942 | #else
|
|---|
| 943 | Q_UNUSED(grab);
|
|---|
| 944 | #endif // QT3_SUPPORT && !QT_NO_SHORTCUT
|
|---|
| 945 | if (key_event) {
|
|---|
| 946 | #if defined(DEBUG_KEY_BINDINGS) || defined(DEBUG_KEY_BINDINGS_MODIFIERS)
|
|---|
| 947 | qDebug("KeyEvent: Sending %s to %s::%s: %s 0x%08x%s",
|
|---|
| 948 | type == QEvent::KeyRelease ? "KeyRelease" : "KeyPress",
|
|---|
| 949 | widget ? widget->metaObject()->className() : "none",
|
|---|
| 950 | widget ? widget->objectName().toLatin1().constData() : "",
|
|---|
| 951 | text.toLatin1().constData(), int(modifiers),
|
|---|
| 952 | autorepeat ? " Repeat" : "");
|
|---|
| 953 | #endif
|
|---|
| 954 | QKeyEventEx ke(type, code, modifiers, text, autorepeat, qMax(1, text.length()),
|
|---|
| 955 | nativeScanCode, nativeVirtualKey, nativeModifiers);
|
|---|
| 956 | bool retMe = qt_sendSpontaneousEvent(widget,&ke);
|
|---|
| 957 | if (isAccepted)
|
|---|
| 958 | *isAccepted = ke.isAccepted();
|
|---|
| 959 | return retMe;
|
|---|
| 960 | }
|
|---|
| 961 | }
|
|---|
| 962 | return false;
|
|---|
| 963 | }
|
|---|
| 964 |
|
|---|
| 965 | QT_END_NAMESPACE
|
|---|