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