| 1 | /****************************************************************************
|
|---|
| 2 | **
|
|---|
| 3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|---|
| 4 | ** Contact: Qt Software Information (qt-info@nokia.com)
|
|---|
| 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 qt-sales@nokia.com.
|
|---|
| 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 |
|
|---|
| 52 | QT_BEGIN_NAMESPACE
|
|---|
| 53 |
|
|---|
| 54 | QT_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 | *****************************************************************************/
|
|---|
| 66 | bool qt_mac_eat_unicode_key = false;
|
|---|
| 67 | extern bool qt_sendSpontaneousEvent(QObject *obj, QEvent *event); //qapplication_mac.cpp
|
|---|
| 68 |
|
|---|
| 69 | Q_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 | */
|
|---|
| 98 | struct 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()!
|
|---|
| 105 | static 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 */
|
|---|
| 125 | struct 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
|
|---|
| 138 | static 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 | };
|
|---|
| 149 | Qt::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 | }
|
|---|
| 165 | static 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 | }
|
|---|
| 181 | void 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)
|
|---|
| 235 | static 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 |
|
|---|
| 288 | static 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 |
|
|---|
| 308 | static 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 |
|
|---|
| 371 | static 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 |
|
|---|
| 378 | static 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 |
|
|---|
| 534 | QKeyMapperPrivate::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 |
|
|---|
| 545 | QKeyMapperPrivate::~QKeyMapperPrivate()
|
|---|
| 546 | {
|
|---|
| 547 | clearMappings();
|
|---|
| 548 | }
|
|---|
| 549 |
|
|---|
| 550 | bool
|
|---|
| 551 | QKeyMapperPrivate::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 |
|
|---|
| 641 | void
|
|---|
| 642 | QKeyMapperPrivate::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 |
|
|---|
| 654 | QList<int>
|
|---|
| 655 | QKeyMapperPrivate::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 |
|
|---|
| 677 | bool 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 |
|
|---|
| 815 | void
|
|---|
| 816 | QKeyMapperPrivate::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 |
|
|---|
| 873 | bool
|
|---|
| 874 | QKeyMapper::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
|
|---|
| 909 | Q_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 |
|
|---|
| 931 | QT_END_NAMESPACE
|
|---|