Warning, file /frameworks/kwindowsystem/src/platforms/osx/kkeyserver.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-or-later
0005 */
0006 
0007 #include "kkeyserver_mac.h"
0008 
0009 #ifdef Q_OS_MAC // Only compile this module if we're compiling for Mac OS X
0010 
0011 #include <Carbon/Carbon.h>
0012 #include <QDebug>
0013 #include <QKeySequence>
0014 #include <QMultiMap>
0015 
0016 namespace KKeyServer
0017 {
0018 struct TransKey {
0019     int qt_code;
0020     int mac_code;
0021 };
0022 
0023 static TransKey qtKeyToChar[] = {{Qt::Key_Escape, kEscapeCharCode},
0024                                  {Qt::Key_Tab, kTabCharCode},
0025                                  {Qt::Key_Backtab, kTabCharCode}, // Backtab == tab with different modifiers
0026                                  {Qt::Key_Backspace, kBackspaceCharCode},
0027                                  {Qt::Key_Return, kReturnCharCode},
0028                                  {Qt::Key_Enter, kEnterCharCode},
0029                                  // Insert
0030                                  {Qt::Key_Delete, kDeleteCharCode},
0031                                  // Pause, Print, SysReq
0032                                  {Qt::Key_Clear, kClearCharCode},
0033                                  {Qt::Key_Home, kHomeCharCode},
0034                                  {Qt::Key_End, kEndCharCode},
0035                                  {Qt::Key_Left, kLeftArrowCharCode},
0036                                  {Qt::Key_Up, kUpArrowCharCode},
0037                                  {Qt::Key_Right, kRightArrowCharCode},
0038                                  {Qt::Key_Down, kDownArrowCharCode},
0039                                  {Qt::Key_PageUp, kPageUpCharCode},
0040                                  {Qt::Key_PageDown, kPageDownCharCode},
0041                                  // Shift, Control, Meta, Alt, CapsLock, NumLock, ScrollLock
0042                                  // Super_L, Super_R, Menu, Hyper_L, Hyper_R
0043                                  {Qt::Key_Help, kHelpCharCode},
0044                                  // Direction_L, Direction_R
0045                                  {Qt::Key_nobreakspace, kNonBreakingSpaceCharCode},
0046                                  {0, 0}};
0047 
0048 static QMultiMap<int, uint> scancodes;
0049 static long lastLayoutID = -1;
0050 #ifdef QT_MAC_USE_COCOA
0051 static TISInputSourceRef lastLayout = 0;
0052 #else
0053 static KeyboardLayoutRef lastLayout = NULL;
0054 #endif
0055 
0056 void updateScancodes()
0057 {
0058 #ifdef QT_MAC_USE_COCOA
0059     TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource();
0060     if (!layout) {
0061         qWarning() << "Error retrieving current layout";
0062         return;
0063     }
0064     if (layout == lastLayout) {
0065         CFRelease(layout);
0066     } else {
0067         // keyboard layout changed
0068 #ifndef NDEBUG
0069         const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName);
0070         qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
0071 #endif
0072         lastLayout = layout;
0073         scancodes.clear();
0074 
0075         CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout, kTISPropertyUnicodeKeyLayoutData));
0076         const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
0077 
0078         if (!ucData) {
0079             qWarning() << "Error retrieving current layout character data";
0080             return;
0081         }
0082 
0083         for (int i = 0; i < 128; ++i) {
0084             UInt32 tmpState = 0;
0085             UniChar str[4];
0086             UniCharCount actualLength = 0;
0087             OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str);
0088             if (err != noErr) {
0089                 qWarning() << "Error translating unicode key" << err;
0090             } else {
0091                 if (str[0] && str[0] != kFunctionKeyCharCode) {
0092                     scancodes.insert(str[0], i);
0093                 }
0094             }
0095         }
0096     }
0097 #else
0098     KeyboardLayoutRef layout;
0099     if (KLGetCurrentKeyboardLayout(&layout) != noErr) {
0100         qWarning() << "Error retrieving current layout";
0101     }
0102     if (layout != lastLayout) {
0103 #ifndef NDEBUG
0104         void *name;
0105         KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void **>(&name));
0106         qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
0107 #endif
0108         lastLayout = layout;
0109         scancodes.clear();
0110         void *kchr;
0111         if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void **>(&kchr)) != noErr) {
0112             qWarning() << "Couldn't load active keyboard layout";
0113         } else {
0114             for (int i = 0; i < 128; i++) {
0115                 UInt32 tmpState = 0;
0116                 UInt32 chr = KeyTranslate(kchr, i, &tmpState);
0117                 if (chr && chr != kFunctionKeyCharCode) {
0118                     scancodes.insert(chr, i);
0119                 }
0120             }
0121         }
0122     }
0123 #endif
0124 }
0125 
0126 #define SCANCODE(name, value)                                                                                                                                  \
0127     {                                                                                                                                                          \
0128         Qt::Key_##name, value                                                                                                                                  \
0129     }
0130 static TransKey functionKeys[] = {SCANCODE(F1, 122),
0131                                   SCANCODE(F2, 120),
0132                                   SCANCODE(F3, 99),
0133                                   SCANCODE(F4, 118),
0134                                   SCANCODE(F5, 96),
0135                                   SCANCODE(F6, 97),
0136                                   SCANCODE(F7, 98),
0137                                   SCANCODE(F8, 100),
0138                                   SCANCODE(F9, 101),
0139                                   SCANCODE(F10, 109),
0140                                   // TODO: figure out scancodes of other F* keys
0141                                   {0, 0}};
0142 #undef SCANCODE
0143 
0144 bool keyQtToSymMac(int keyQt, int &sym)
0145 {
0146     // Printable ascii values, before A
0147     if (keyQt >= 0x20 && keyQt < Qt::Key_A) {
0148         sym = keyQt;
0149         return true;
0150     }
0151     // Letters, return lower-case equivalent
0152     if (keyQt >= Qt::Key_A && keyQt <= Qt::Key_Z) {
0153         sym = keyQt - Qt::Key_A + 'a';
0154         return true;
0155     }
0156     // Printable ascii values up to lower-case a
0157     if (keyQt > Qt::Key_Z && keyQt <= 0x60) {
0158         sym = keyQt;
0159         return true;
0160     }
0161     // Remainder of printable ascii values
0162     if (keyQt >= 0x7B && keyQt < 0x7F) {
0163         sym = keyQt;
0164         return true;
0165     }
0166     // Function keys
0167     if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) {
0168         sym = kFunctionKeyCharCode;
0169         return true;
0170     }
0171     // Try to find in lookup table
0172     for (int i = 0; qtKeyToChar[i].qt_code; i++) {
0173         if (qtKeyToChar[i].qt_code == keyQt) {
0174             sym = qtKeyToChar[i].mac_code;
0175             return true;
0176         }
0177     }
0178 
0179     // Not found
0180     return false;
0181 }
0182 
0183 bool keyQtToCodeMac(int keyQt, QList<uint> &keyCodes)
0184 {
0185     updateScancodes();
0186     keyCodes.clear();
0187     keyQt &= ~Qt::KeyboardModifierMask;
0188     int chr;
0189     if (!keyQtToSymMac(keyQt, chr)) {
0190         return false;
0191     }
0192 
0193     if (chr == kFunctionKeyCharCode) {
0194         for (int i = 0; functionKeys[i].qt_code; i++) {
0195             if (functionKeys[i].qt_code == keyQt) {
0196                 keyCodes.append(functionKeys[i].mac_code);
0197             }
0198         }
0199     } else {
0200         keyCodes += scancodes.values(chr);
0201     }
0202 
0203     return keyCodes.count() > 0;
0204 }
0205 
0206 bool keyQtToModMac(int keyQt, uint &mod)
0207 {
0208     mod = 0;
0209     if (keyQt & Qt::ShiftModifier) {
0210         mod |= shiftKey;
0211     }
0212     if (keyQt & Qt::ControlModifier) {
0213         mod |= cmdKey;
0214     }
0215     if (keyQt & Qt::AltModifier) {
0216         mod |= optionKey;
0217     }
0218     if (keyQt & Qt::MetaModifier) {
0219         mod |= controlKey;
0220     }
0221     if (keyQt & Qt::KeypadModifier) {
0222         mod |= kEventKeyModifierNumLockMask;
0223     }
0224     // Special case for Qt::Key_Backtab
0225     if ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Backtab) {
0226         mod |= shiftKey;
0227     }
0228 
0229     return true;
0230 }
0231 } // end of namespace KKeyServer
0232 
0233 #endif // Q_OS_MAC