KDEUI
kkeyserver_mac.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (C) 2006 Marijn Kruisselbrink <m.kruisselbrink@student.tue.nl> 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Library General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public License 00015 along with this library; see the file COPYING.LIB. If not, write to 00016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00017 Boston, MA 02110-1301, USA. 00018 */ 00019 00020 #include "kkeyserver_mac.h" 00021 00022 #include <config.h> 00023 00024 #include <QtCore/QCOORD> 00025 00026 #ifdef Q_WS_MACX // Only compile this module if we're compiling for Mac OS X 00027 00028 #include "kshortcut.h" 00029 #include <kdebug.h> 00030 #include <QMultiMap> 00031 #include <Carbon/Carbon.h> 00032 00033 namespace KKeyServer { 00034 struct TransKey { 00035 int qt_code; 00036 int mac_code; 00037 }; 00038 00039 static TransKey qtKeyToChar[] = { 00040 {Qt::Key_Escape, kEscapeCharCode}, 00041 {Qt::Key_Tab, kTabCharCode}, 00042 {Qt::Key_Backtab, kTabCharCode}, // Backtab == tab with different modifiers 00043 {Qt::Key_Backspace, kBackspaceCharCode}, 00044 {Qt::Key_Return, kReturnCharCode}, 00045 {Qt::Key_Enter, kEnterCharCode}, 00046 // Insert 00047 {Qt::Key_Delete, kDeleteCharCode}, 00048 // Pause, Print, SysReq 00049 {Qt::Key_Clear, kClearCharCode}, 00050 {Qt::Key_Home, kHomeCharCode}, 00051 {Qt::Key_End, kEndCharCode}, 00052 {Qt::Key_Left, kLeftArrowCharCode}, 00053 {Qt::Key_Up, kUpArrowCharCode}, 00054 {Qt::Key_Right, kRightArrowCharCode}, 00055 {Qt::Key_Down, kDownArrowCharCode}, 00056 {Qt::Key_PageUp, kPageUpCharCode}, 00057 {Qt::Key_PageDown, kPageDownCharCode}, 00058 // Shift, Control, Meta, Alt, CapsLock, NumLock, ScrollLock 00059 // Super_L, Super_R, Menu, Hyper_L, Hyper_R 00060 {Qt::Key_Help, kHelpCharCode}, 00061 // Direction_L, Direction_R 00062 {Qt::Key_nobreakspace, kNonBreakingSpaceCharCode}, 00063 {0, 0} 00064 }; 00065 00066 static QMultiMap<int, uint> scancodes; 00067 static long lastLayoutID = -1; 00068 #ifdef QT_MAC_USE_COCOA 00069 static TISInputSourceRef lastLayout = 0; 00070 #else 00071 static KeyboardLayoutRef lastLayout = NULL; 00072 #endif 00073 00074 void updateScancodes() { 00075 #ifdef QT_MAC_USE_COCOA 00076 TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource(); 00077 if (!layout) { 00078 kWarning() << "Error retrieving current layout"; 00079 return; 00080 } 00081 if (layout == lastLayout) { 00082 CFRelease(layout); 00083 } else { 00084 // keyboard layout changed 00085 #ifndef NDEBUG 00086 const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName); 00087 kDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0); 00088 #endif 00089 lastLayout = layout; 00090 scancodes.clear(); 00091 00092 CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout, 00093 kTISPropertyUnicodeKeyLayoutData)); 00094 const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0; 00095 00096 if (!ucData) { 00097 kWarning() << "Error retrieving current layout character data"; 00098 return; 00099 } 00100 00101 for (int i = 0; i < 128; ++i) { 00102 UInt32 tmpState = 0; 00103 UniChar str[4]; 00104 UniCharCount actualLength = 0; 00105 OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(), 00106 kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str); 00107 if (err != noErr) { 00108 kWarning() << "Error translating unicode key" << err; 00109 } else { 00110 if (str[0] && str[0] != kFunctionKeyCharCode) 00111 scancodes.insert(str[0], i); 00112 } 00113 } 00114 } 00115 #else 00116 KeyboardLayoutRef layout; 00117 if (KLGetCurrentKeyboardLayout(&layout) != noErr) { 00118 kWarning() << "Error retrieving current layout"; 00119 } 00120 if (layout != lastLayout) { 00121 #ifndef NDEBUG 00122 void *name; 00123 KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void**>(&name)); 00124 kDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef) name, 0); 00125 #endif 00126 lastLayout = layout; 00127 scancodes.clear(); 00128 void *kchr; 00129 if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void**>(&kchr)) != noErr) { 00130 kWarning() << "Couldn't load active keyboard layout"; 00131 } else { 00132 for (int i = 0; i < 128; i++) { 00133 UInt32 tmpState = 0; 00134 UInt32 chr = KeyTranslate(kchr, i, &tmpState); 00135 if (chr && chr != kFunctionKeyCharCode) { 00136 scancodes.insert(chr, i); 00137 } 00138 } 00139 } 00140 } 00141 #endif 00142 } 00143 00144 #define SCANCODE(name, value) { Qt::Key_ ## name, value } 00145 static TransKey functionKeys[] = { 00146 SCANCODE(F1, 122), 00147 SCANCODE(F2, 120), 00148 SCANCODE(F3, 99), 00149 SCANCODE(F4, 118), 00150 SCANCODE(F5, 96), 00151 SCANCODE(F6, 97), 00152 SCANCODE(F7, 98), 00153 SCANCODE(F8, 100), 00154 SCANCODE(F9, 101), 00155 SCANCODE(F10, 109), 00156 //TODO: figure out scancodes of other F* keys 00157 { 0, 0 } 00158 }; 00159 #undef SCANCODE 00160 00161 bool keyQtToSymMac( int keyQt, int& sym ) 00162 { 00163 // Printable ascii values, before A 00164 if (keyQt >= 0x20 && keyQt < Qt::Key_A) { 00165 sym = keyQt; 00166 return true; 00167 } 00168 // Letters, return lower-case equivalent 00169 if (keyQt >= Qt::Key_A && keyQt <= Qt::Key_Z) { 00170 sym = keyQt - Qt::Key_A + 'a'; 00171 return true; 00172 } 00173 // Printable ascii values up to lower-case a 00174 if (keyQt > Qt::Key_Z && keyQt <= 0x60) { 00175 sym = keyQt; 00176 return true; 00177 } 00178 // Remainder of printable ascii values 00179 if (keyQt >= 0x7B && keyQt < 0x7F) { 00180 sym = keyQt; 00181 return true; 00182 } 00183 // Function keys 00184 if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) { 00185 sym = kFunctionKeyCharCode; 00186 return true; 00187 } 00188 // Try to find in lookup table 00189 for (int i = 0; qtKeyToChar[i].qt_code; i++) { 00190 if (qtKeyToChar[i].qt_code == keyQt) { 00191 sym = qtKeyToChar[i].mac_code; 00192 return true; 00193 } 00194 } 00195 00196 // Not found 00197 return false; 00198 } 00199 00200 bool keyQtToCodeMac( int keyQt, QList<uint>& keyCodes ) 00201 { 00202 updateScancodes(); 00203 keyCodes.clear(); 00204 keyQt &= ~Qt::KeyboardModifierMask; 00205 int chr; 00206 if (!keyQtToSymMac( keyQt, chr ) ) return false; 00207 00208 if (chr == kFunctionKeyCharCode) { 00209 for (int i = 0; functionKeys[i].qt_code; i++) { 00210 if (functionKeys[i].qt_code == keyQt) { 00211 keyCodes.append(functionKeys[i].mac_code); 00212 } 00213 } 00214 } else { 00215 keyCodes += scancodes.values(chr); 00216 } 00217 00218 return keyCodes.count() > 0; 00219 } 00220 00221 bool keyQtToModMac( int keyQt, uint& mod ) 00222 { 00223 mod = 0; 00224 if (keyQt & Qt::ShiftModifier) { 00225 mod |= shiftKey; 00226 } 00227 if (keyQt & Qt::ControlModifier) { 00228 mod |= cmdKey; 00229 } 00230 if (keyQt & Qt::AltModifier) { 00231 mod |= optionKey; 00232 } 00233 if (keyQt & Qt::MetaModifier) { 00234 mod |= controlKey; 00235 } 00236 if (keyQt & Qt::KeypadModifier) { 00237 mod |= kEventKeyModifierNumLockMask; 00238 } 00239 // Special case for Qt::Key_Backtab 00240 if ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Backtab) { 00241 mod |= shiftKey; 00242 } 00243 00244 return true; 00245 } 00246 } // end of namespace KKeyServer 00247 00248 #endif // Q_WS_MACX 00249
KDE 4.6 API Reference