KWindowSystem

platforms/osx/kkeyserver.cpp
1 /*
2  SPDX-FileCopyrightText: 2006 Marijn Kruisselbrink <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6 
7 #include "kkeyserver_mac.h"
8 
9 #ifdef Q_OS_MAC // Only compile this module if we're compiling for Mac OS X
10 
11 #include <Carbon/Carbon.h>
12 #include <QDebug>
13 #include <QKeySequence>
14 #include <QMultiMap>
15 
16 namespace KKeyServer
17 {
18 struct TransKey {
19  int qt_code;
20  int mac_code;
21 };
22 
23 static TransKey qtKeyToChar[] = {{Qt::Key_Escape, kEscapeCharCode},
24  {Qt::Key_Tab, kTabCharCode},
25  {Qt::Key_Backtab, kTabCharCode}, // Backtab == tab with different modifiers
26  {Qt::Key_Backspace, kBackspaceCharCode},
27  {Qt::Key_Return, kReturnCharCode},
28  {Qt::Key_Enter, kEnterCharCode},
29  // Insert
30  {Qt::Key_Delete, kDeleteCharCode},
31  // Pause, Print, SysReq
32  {Qt::Key_Clear, kClearCharCode},
33  {Qt::Key_Home, kHomeCharCode},
34  {Qt::Key_End, kEndCharCode},
35  {Qt::Key_Left, kLeftArrowCharCode},
36  {Qt::Key_Up, kUpArrowCharCode},
37  {Qt::Key_Right, kRightArrowCharCode},
38  {Qt::Key_Down, kDownArrowCharCode},
39  {Qt::Key_PageUp, kPageUpCharCode},
40  {Qt::Key_PageDown, kPageDownCharCode},
41  // Shift, Control, Meta, Alt, CapsLock, NumLock, ScrollLock
42  // Super_L, Super_R, Menu, Hyper_L, Hyper_R
43  {Qt::Key_Help, kHelpCharCode},
44  // Direction_L, Direction_R
45  {Qt::Key_nobreakspace, kNonBreakingSpaceCharCode},
46  {0, 0}};
47 
48 static QMultiMap<int, uint> scancodes;
49 static long lastLayoutID = -1;
50 #ifdef QT_MAC_USE_COCOA
51 static TISInputSourceRef lastLayout = 0;
52 #else
53 static KeyboardLayoutRef lastLayout = NULL;
54 #endif
55 
56 void updateScancodes()
57 {
58 #ifdef QT_MAC_USE_COCOA
59  TISInputSourceRef layout = TISCopyCurrentKeyboardLayoutInputSource();
60  if (!layout) {
61  qWarning() << "Error retrieving current layout";
62  return;
63  }
64  if (layout == lastLayout) {
65  CFRelease(layout);
66  } else {
67  // keyboard layout changed
68 #ifndef NDEBUG
69  const void *name = TISGetInputSourceProperty(layout, kTISPropertyLocalizedName);
70  qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
71 #endif
72  lastLayout = layout;
73  scancodes.clear();
74 
75  CFDataRef data = static_cast<CFDataRef>(TISGetInputSourceProperty(layout, kTISPropertyUnicodeKeyLayoutData));
76  const UCKeyboardLayout *ucData = data ? reinterpret_cast<const UCKeyboardLayout *>(CFDataGetBytePtr(data)) : 0;
77 
78  if (!ucData) {
79  qWarning() << "Error retrieving current layout character data";
80  return;
81  }
82 
83  for (int i = 0; i < 128; ++i) {
84  UInt32 tmpState = 0;
85  UniChar str[4];
86  UniCharCount actualLength = 0;
87  OSStatus err = UCKeyTranslate(ucData, i, kUCKeyActionDown, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysMask, &tmpState, 4, &actualLength, str);
88  if (err != noErr) {
89  qWarning() << "Error translating unicode key" << err;
90  } else {
91  if (str[0] && str[0] != kFunctionKeyCharCode) {
92  scancodes.insert(str[0], i);
93  }
94  }
95  }
96  }
97 #else
98  KeyboardLayoutRef layout;
99  if (KLGetCurrentKeyboardLayout(&layout) != noErr) {
100  qWarning() << "Error retrieving current layout";
101  }
102  if (layout != lastLayout) {
103 #ifndef NDEBUG
104  void *name;
105  KLGetKeyboardLayoutProperty(layout, kKLName, const_cast<const void **>(&name));
106  qDebug() << "Layout changed to: " << CFStringGetCStringPtr((CFStringRef)name, 0);
107 #endif
108  lastLayout = layout;
109  scancodes.clear();
110  void *kchr;
111  if (KLGetKeyboardLayoutProperty(layout, kKLKCHRData, const_cast<const void **>(&kchr)) != noErr) {
112  qWarning() << "Couldn't load active keyboard layout";
113  } else {
114  for (int i = 0; i < 128; i++) {
115  UInt32 tmpState = 0;
116  UInt32 chr = KeyTranslate(kchr, i, &tmpState);
117  if (chr && chr != kFunctionKeyCharCode) {
118  scancodes.insert(chr, i);
119  }
120  }
121  }
122  }
123 #endif
124 }
125 
126 #define SCANCODE(name, value) \
127  { \
128  Qt::Key_##name, value \
129  }
130 static TransKey functionKeys[] = {SCANCODE(F1, 122),
131  SCANCODE(F2, 120),
132  SCANCODE(F3, 99),
133  SCANCODE(F4, 118),
134  SCANCODE(F5, 96),
135  SCANCODE(F6, 97),
136  SCANCODE(F7, 98),
137  SCANCODE(F8, 100),
138  SCANCODE(F9, 101),
139  SCANCODE(F10, 109),
140  // TODO: figure out scancodes of other F* keys
141  {0, 0}};
142 #undef SCANCODE
143 
144 bool keyQtToSymMac(int keyQt, int &sym)
145 {
146  // Printable ascii values, before A
147  if (keyQt >= 0x20 && keyQt < Qt::Key_A) {
148  sym = keyQt;
149  return true;
150  }
151  // Letters, return lower-case equivalent
152  if (keyQt >= Qt::Key_A && keyQt <= Qt::Key_Z) {
153  sym = keyQt - Qt::Key_A + 'a';
154  return true;
155  }
156  // Printable ascii values up to lower-case a
157  if (keyQt > Qt::Key_Z && keyQt <= 0x60) {
158  sym = keyQt;
159  return true;
160  }
161  // Remainder of printable ascii values
162  if (keyQt >= 0x7B && keyQt < 0x7F) {
163  sym = keyQt;
164  return true;
165  }
166  // Function keys
167  if (keyQt >= Qt::Key_F1 && keyQt <= Qt::Key_F35) {
168  sym = kFunctionKeyCharCode;
169  return true;
170  }
171  // Try to find in lookup table
172  for (int i = 0; qtKeyToChar[i].qt_code; i++) {
173  if (qtKeyToChar[i].qt_code == keyQt) {
174  sym = qtKeyToChar[i].mac_code;
175  return true;
176  }
177  }
178 
179  // Not found
180  return false;
181 }
182 
183 bool keyQtToCodeMac(int keyQt, QList<uint> &keyCodes)
184 {
185  updateScancodes();
186  keyCodes.clear();
187  keyQt &= ~Qt::KeyboardModifierMask;
188  int chr;
189  if (!keyQtToSymMac(keyQt, chr)) {
190  return false;
191  }
192 
193  if (chr == kFunctionKeyCharCode) {
194  for (int i = 0; functionKeys[i].qt_code; i++) {
195  if (functionKeys[i].qt_code == keyQt) {
196  keyCodes.append(functionKeys[i].mac_code);
197  }
198  }
199  } else {
200  keyCodes += scancodes.values(chr);
201  }
202 
203  return keyCodes.count() > 0;
204 }
205 
206 bool keyQtToModMac(int keyQt, uint &mod)
207 {
208  mod = 0;
209  if (keyQt & Qt::ShiftModifier) {
210  mod |= shiftKey;
211  }
212  if (keyQt & Qt::ControlModifier) {
213  mod |= cmdKey;
214  }
215  if (keyQt & Qt::AltModifier) {
216  mod |= optionKey;
217  }
218  if (keyQt & Qt::MetaModifier) {
219  mod |= controlKey;
220  }
221  if (keyQt & Qt::KeypadModifier) {
222  mod |= kEventKeyModifierNumLockMask;
223  }
224  // Special case for Qt::Key_Backtab
225  if ((keyQt & ~Qt::KeyboardModifierMask) == Qt::Key_Backtab) {
226  mod |= shiftKey;
227  }
228 
229  return true;
230 }
231 } // end of namespace KKeyServer
232 
233 #endif // Q_OS_MAC
void clear()
ShiftModifier
QString name(const QVariant &location)
A collection of functions for the conversion of key presses and their modifiers from the window syste...
Definition: kkeyserver.cpp:14
void clear()
KWINDOWSYSTEM_EXPORT bool keyQtToSymMac(int keyQt, int &sym)
Extracts the symbol from the given Qt key, and converts it to an OSX symbol.
int count(const T &value) const const
void append(const T &value)
typename QMap< Key, T >::iterator insert(const Key &key, const T &value)
KWINDOWSYSTEM_EXPORT bool keyQtToCodeMac(int keyQt, QList< uint > &keyCodes)
Extracts all the scancodes from the given Qt key.
KWINDOWSYSTEM_EXPORT bool keyQtToModMac(int keyQt, uint &mod)
Extracts the modifiers from the given Qt key and converts them in a mask of OSX modifiers.
Key_Escape
QList< T > values(const Key &key) const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Oct 15 2021 22:41:49 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.