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