1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** Contact: Qt Software Information ([email protected])
|
---|
5 | **
|
---|
6 | ** Copyright (C) 2009 netlabs.org. OS/2 parts.
|
---|
7 | **
|
---|
8 | ** This file is part of the QtGui module of the Qt Toolkit.
|
---|
9 | **
|
---|
10 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
11 | ** Commercial Usage
|
---|
12 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
13 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
14 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
15 | ** a written agreement between you and Nokia.
|
---|
16 | **
|
---|
17 | ** GNU Lesser General Public License Usage
|
---|
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
19 | ** General Public License version 2.1 as published by the Free Software
|
---|
20 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
21 | ** packaging of this file. Please review the following information to
|
---|
22 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
23 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
24 | **
|
---|
25 | ** In addition, as a special exception, Nokia gives you certain
|
---|
26 | ** additional rights. These rights are described in the Nokia Qt LGPL
|
---|
27 | ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
|
---|
28 | ** package.
|
---|
29 | **
|
---|
30 | ** GNU General Public License Usage
|
---|
31 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
32 | ** General Public License version 3.0 as published by the Free Software
|
---|
33 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
34 | ** packaging of this file. Please review the following information to
|
---|
35 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
36 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
37 | **
|
---|
38 | ** If you are unsure which license is appropriate for your use, please
|
---|
39 | ** contact the sales department at [email protected].
|
---|
40 | ** $QT_END_LICENSE$
|
---|
41 | **
|
---|
42 | ****************************************************************************/
|
---|
43 |
|
---|
44 | #include "qkeymapper_p.h"
|
---|
45 | #include "qapplication_p.h"
|
---|
46 | #include "qevent_p.h"
|
---|
47 | #include "qwidget.h"
|
---|
48 |
|
---|
49 | #include "qt_os2.h"
|
---|
50 |
|
---|
51 | QT_BEGIN_NAMESPACE
|
---|
52 |
|
---|
53 | //#define DEBUG_KEYMAPPER
|
---|
54 |
|
---|
55 | // Key recorder ----------------------------------------------------[ start ] --
|
---|
56 | struct KeyRecord {
|
---|
57 | KeyRecord(int _scan, int _code, int _state, const QString &_text)
|
---|
58 | : scan(_scan), code(_code), state(_state), text(_text) {}
|
---|
59 | KeyRecord() {}
|
---|
60 |
|
---|
61 | int scan;
|
---|
62 | int code;
|
---|
63 | int state;
|
---|
64 | QString text;
|
---|
65 | };
|
---|
66 |
|
---|
67 | static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
|
---|
68 |
|
---|
69 | struct KeyRecorder
|
---|
70 | {
|
---|
71 | KeyRecorder() : nrecs(0) {}
|
---|
72 |
|
---|
73 | inline KeyRecord *findKey(int code, bool remove);
|
---|
74 | inline void storeKey(int scan, int code, int state, const QString& text);
|
---|
75 | inline void clearKeys();
|
---|
76 |
|
---|
77 | int nrecs;
|
---|
78 | KeyRecord deleted_record; // A copy of last entry removed from records[]
|
---|
79 | KeyRecord records[QT_MAX_KEY_RECORDINGS];
|
---|
80 | };
|
---|
81 | static KeyRecorder key_recorder;
|
---|
82 |
|
---|
83 | KeyRecord *KeyRecorder::findKey(int scan, bool remove)
|
---|
84 | {
|
---|
85 | KeyRecord *result = 0;
|
---|
86 | for (int i = 0; i < nrecs; ++i) {
|
---|
87 | if (records[i].scan == scan) {
|
---|
88 | if (remove) {
|
---|
89 | deleted_record = records[i];
|
---|
90 | // Move rest down, and decrease count
|
---|
91 | while (i + 1 < nrecs) {
|
---|
92 | records[i] = records[i + 1];
|
---|
93 | ++i;
|
---|
94 | }
|
---|
95 | --nrecs;
|
---|
96 | result = &deleted_record;
|
---|
97 | } else {
|
---|
98 | result = &records[i];
|
---|
99 | }
|
---|
100 | break;
|
---|
101 | }
|
---|
102 | }
|
---|
103 | return result;
|
---|
104 | }
|
---|
105 |
|
---|
106 | void KeyRecorder::storeKey(int scan, int code, int state, const QString& text)
|
---|
107 | {
|
---|
108 | Q_ASSERT_X(nrecs != QT_MAX_KEY_RECORDINGS,
|
---|
109 | "Internal KeyRecorder",
|
---|
110 | "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
|
---|
111 |
|
---|
112 | if (nrecs == QT_MAX_KEY_RECORDINGS) {
|
---|
113 | qWarning("Qt: Internal keyboard buffer overflow");
|
---|
114 | return;
|
---|
115 | }
|
---|
116 | records[nrecs++] = KeyRecord(scan, code, state, text);
|
---|
117 | }
|
---|
118 |
|
---|
119 | void KeyRecorder::clearKeys()
|
---|
120 | {
|
---|
121 | nrecs = 0;
|
---|
122 | }
|
---|
123 | // Key recorder ------------------------------------------------------[ end ] --
|
---|
124 |
|
---|
125 | // Key translation -------------------------------------------------[ start ] --
|
---|
126 | // Meaning of values:
|
---|
127 | // 0 = Character output key, needs keyboard driver mapping
|
---|
128 | // Key_unknown = Unknown Virtual Key, no translation possible, ignore
|
---|
129 | static const uint KeyTbl[] = { // Keyboard mapping table
|
---|
130 | // Dec | Hex | PM Virtual key
|
---|
131 | Qt::Key_unknown, // 0 0x00
|
---|
132 | Qt::Key_unknown, // 1 0x01 VK_BUTTON1 | Mouse button 1
|
---|
133 | Qt::Key_unknown, // 2 0x02 VK_BUTTON2 | Mouse button 2
|
---|
134 | Qt::Key_unknown, // 3 0x03 VK_BUTTON3 | Mouse button 3
|
---|
135 | Qt::Key_Cancel, // 4 0x04 VK_BREAK | Control-Break processing
|
---|
136 | Qt::Key_Backspace, // 5 0x05 VK_BACKSPACE | BackSpace key
|
---|
137 | Qt::Key_Tab, // 6 0x06 VK_TAB | Tab key
|
---|
138 | Qt::Key_Backtab, // 7 0x07 VK_BACKTAB | Shift+Tab key
|
---|
139 | Qt::Key_Return, // 8 0x08 VK_RETURN | Enter key
|
---|
140 | Qt::Key_Shift, // 9 0x09 VK_SHIFT | Shift key
|
---|
141 | Qt::Key_Control, // 10 0x0A VK_CTRL | Ctrl key
|
---|
142 | Qt::Key_Alt, // 11 0x0B VK_ALT | Alt key
|
---|
143 | Qt::Key_Alt, // 12 0x0C VK_ALTGRAF | AltGr key
|
---|
144 | Qt::Key_Pause, // 13 0x0D VK_PAUSE | Pause key
|
---|
145 | Qt::Key_CapsLock, // 14 0x0E VK_CAPSLOCK | Caps-Lock
|
---|
146 | Qt::Key_Escape, // 15 0x0F VK_ESC | Esc key
|
---|
147 | Qt::Key_Space, // 16 0x10 VK_SPACE | Spacebar
|
---|
148 | Qt::Key_PageUp, // 17 0x11 VK_PAGEUP | Page Up key
|
---|
149 | Qt::Key_PageDown, // 18 0x12 VK_PAGEDOWN | Page Down key
|
---|
150 | Qt::Key_End, // 19 0x13 VK_END | End key
|
---|
151 | Qt::Key_Home, // 20 0x14 VK_HOME | Home key
|
---|
152 | Qt::Key_Left, // 21 0x15 VK_LEFT | Left arrow key
|
---|
153 | Qt::Key_Up, // 22 0x16 VK_UP | Up arrow key
|
---|
154 | Qt::Key_Right, // 23 0x17 VK_RIGHT | Right arrow key
|
---|
155 | Qt::Key_Down, // 24 0x18 VK_DOWN | Down arrow key
|
---|
156 | Qt::Key_Print, // 25 0x19 VK_PRINTSCRN | Print Screen key
|
---|
157 | Qt::Key_Insert, // 26 0x1A VK_INSERT | Ins key
|
---|
158 | Qt::Key_Delete, // 27 0x1B VK_DELETE | Del key
|
---|
159 | Qt::Key_NumLock, // 28 0x1C VK_SCROLL | Scroll Lock key
|
---|
160 | Qt::Key_ScrollLock, // 29 0x1D VK_NUMLOCK | Num Lock key
|
---|
161 | Qt::Key_Enter, // 30 0x1E VK_ENTER | Enter (Numpad) key
|
---|
162 | Qt::Key_SysReq, // 31 0x1F VK_SYSRQ | SysReq key
|
---|
163 | Qt::Key_F1, // 32 0x20 VK_F1 | F1 key
|
---|
164 | Qt::Key_F2, // 33 0x21 VK_F2 | F2 key
|
---|
165 | Qt::Key_F3, // 34 0x22 VK_F3 | F3 key
|
---|
166 | Qt::Key_F4, // 35 0x23 VK_F4 | F4 key
|
---|
167 | Qt::Key_F5, // 36 0x24 VK_F5 | F5 key
|
---|
168 | Qt::Key_F6, // 37 0x25 VK_F6 | F6 key
|
---|
169 | Qt::Key_F7, // 38 0x26 VK_F7 | F7 key
|
---|
170 | Qt::Key_F8, // 39 0x27 VK_F8 | F8 key
|
---|
171 | Qt::Key_F9, // 40 0x28 VK_F9 | F9 key
|
---|
172 | Qt::Key_F10, // 41 0x29 VK_F10 | F10 key
|
---|
173 | Qt::Key_F11, // 42 0x2A VK_F11 | F11 key
|
---|
174 | Qt::Key_F12, // 43 0x2B VK_F12 | F12 key
|
---|
175 | Qt::Key_F13, // 44 0x2C VK_F13 | F13 key
|
---|
176 | Qt::Key_F14, // 45 0x2D VK_F14 | F14 key
|
---|
177 | Qt::Key_F15, // 46 0x2E VK_F15 | F15 key
|
---|
178 | Qt::Key_F16, // 47 0x2F VK_F16 | F16 key
|
---|
179 | Qt::Key_F17, // 48 0x30 VK_F17 | F17 key
|
---|
180 | Qt::Key_F18, // 49 0x31 VK_F18 | F18 key
|
---|
181 | Qt::Key_F19, // 50 0x32 VK_F19 | F19 key
|
---|
182 | Qt::Key_F20, // 51 0x33 VK_F20 | F20 key
|
---|
183 | Qt::Key_F21, // 52 0x34 VK_F21 | F21 key
|
---|
184 | Qt::Key_F22, // 53 0x35 VK_F22 | F22 key
|
---|
185 | Qt::Key_F23, // 54 0x36 VK_F23 | F23 key
|
---|
186 | Qt::Key_F24, // 55 0x37 VK_F24 | F24 key
|
---|
187 | Qt::Key_unknown, // 56 0x38 VK_ENDDRAG | ???
|
---|
188 | Qt::Key_Clear, // 57 0x39 VK_CLEAR | Clear key
|
---|
189 | Qt::Key_unknown, // 58 0x3A VK_EREOF | ???
|
---|
190 | Qt::Key_unknown, // 59 0x3B VK_PA1 | ???
|
---|
191 | Qt::Key_unknown, // 60 0x3C VK_ATTN | ???
|
---|
192 | Qt::Key_unknown, // 61 0x3D VK_CRSEL | ???
|
---|
193 | Qt::Key_unknown, // 62 0x3E VK_EXSEL | ???
|
---|
194 | Qt::Key_unknown, // 63 0x3F VK_COPY | ???
|
---|
195 | Qt::Key_unknown, // 64 0x40 VK_BLK1 | ???
|
---|
196 | Qt::Key_unknown, // 65 0x41 VK_BLK2 | ???
|
---|
197 | };
|
---|
198 |
|
---|
199 | // Converts known accent symbols to their Key_Dead_ equivalents.
|
---|
200 | static inline int deadCharToDeadKeyCode(const QChar &ch)
|
---|
201 | {
|
---|
202 | switch (ch.unicode()) {
|
---|
203 | case 0x0060: return Qt::Key_Dead_Grave;
|
---|
204 | case 0x00B4: return Qt::Key_Dead_Acute;
|
---|
205 | case 0x005E: return Qt::Key_Dead_Circumflex;
|
---|
206 | case 0x007E: return Qt::Key_Dead_Tilde;
|
---|
207 | case 0x00AF: return Qt::Key_Dead_Macron;
|
---|
208 | case 0x02D8: return Qt::Key_Dead_Breve;
|
---|
209 | case 0x02D9: return Qt::Key_Dead_Abovedot;
|
---|
210 | case 0x00A8: return Qt::Key_Dead_Diaeresis;
|
---|
211 | case 0x02DA: return Qt::Key_Dead_Abovering;
|
---|
212 | case 0x02DD: return Qt::Key_Dead_Doubleacute;
|
---|
213 | case 0x02C7: return Qt::Key_Dead_Caron;
|
---|
214 | case 0x00B8: return Qt::Key_Dead_Cedilla;
|
---|
215 | case 0x02DB: return Qt::Key_Dead_Ogonek;
|
---|
216 | case 0x1DA5: return Qt::Key_Dead_Iota; // @todo is that correct???
|
---|
217 | case 0x3099: return Qt::Key_Dead_Voiced_Sound;
|
---|
218 | case 0x309A: return Qt::Key_Dead_Semivoiced_Sound;
|
---|
219 | case 0x0323: return Qt::Key_Dead_Belowdot;
|
---|
220 | case 0x02DE: return Qt::Key_Dead_Hook;
|
---|
221 | case 0x031B: return Qt::Key_Dead_Horn;
|
---|
222 | default: break;
|
---|
223 | }
|
---|
224 |
|
---|
225 | // otherwise, return unmodified uppercase unicode value (similar to other
|
---|
226 | // cases)
|
---|
227 | return ch.unicode();
|
---|
228 | }
|
---|
229 |
|
---|
230 | // Key translation ---------------------------------------------------[ end ]---
|
---|
231 |
|
---|
232 | // QETWidget class is only for accessing the sendSpontaneousEvent function in QApplication
|
---|
233 | class QETWidget : public QWidget {
|
---|
234 | public:
|
---|
235 | static bool sendSpontaneousEvent(QObject *r, QEvent *e)
|
---|
236 | { return QApplication::sendSpontaneousEvent(r, e); }
|
---|
237 | };
|
---|
238 |
|
---|
239 | // Keyboard map private --------------------------------------------[ start ]---
|
---|
240 |
|
---|
241 | QKeyMapperPrivate::QKeyMapperPrivate()
|
---|
242 | {
|
---|
243 | // State holder for LWIN/RWIN and ALTGr keys
|
---|
244 | // (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
|
---|
245 | extraKeyState = 0;
|
---|
246 |
|
---|
247 | // @todo implement
|
---|
248 | }
|
---|
249 |
|
---|
250 | QKeyMapperPrivate::~QKeyMapperPrivate()
|
---|
251 | {
|
---|
252 | clearMappings();
|
---|
253 | }
|
---|
254 |
|
---|
255 | void QKeyMapperPrivate::clearMappings()
|
---|
256 | {
|
---|
257 | // @todo implement
|
---|
258 | }
|
---|
259 |
|
---|
260 | QList<int> QKeyMapperPrivate::possibleKeys(QKeyEvent *e)
|
---|
261 | {
|
---|
262 | QList<int> result;
|
---|
263 |
|
---|
264 | // @todo implement; so far do the same as QKeyMapper::possibleKeys()
|
---|
265 | if (e->key() && (e->key() != Qt::Key_unknown))
|
---|
266 | result << int(e->key() + e->modifiers());
|
---|
267 | else if (!e->text().isEmpty())
|
---|
268 | result << int(e->text().at(0).unicode() + e->modifiers());
|
---|
269 | return result;
|
---|
270 | }
|
---|
271 |
|
---|
272 | bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const QMSG &qmsg, bool grab)
|
---|
273 | {
|
---|
274 | Q_Q(QKeyMapper);
|
---|
275 |
|
---|
276 | bool k0 = false;
|
---|
277 | bool k1 = false;
|
---|
278 |
|
---|
279 | CHRMSG chm = *CHARMSG(&qmsg.msg);
|
---|
280 |
|
---|
281 | // we combine the flags from the message with the raw chr value and pass
|
---|
282 | // them as QKeyEvent::nativeModifiers(). Together with chr.vkey passed as
|
---|
283 | // nativeVirtualKey() and chr.scancode as nativeScanCode(), the Qt
|
---|
284 | // application gets the full key message details (except the repeat count).
|
---|
285 | quint32 nativeMods = chm.fs | chm.chr << 16;
|
---|
286 |
|
---|
287 | // Get the modifier states (may be altered later, depending on key code)
|
---|
288 | int state = 0;
|
---|
289 | if (chm.fs & KC_SHIFT)
|
---|
290 | state |= Qt::ShiftModifier;
|
---|
291 | if (chm.fs & KC_CTRL)
|
---|
292 | state |= Qt::ControlModifier;
|
---|
293 | if (chm.fs & KC_ALT)
|
---|
294 | state |= Qt::AltModifier;
|
---|
295 |
|
---|
296 | // Translate VK_* (native) -> Key_* (Qt) keys
|
---|
297 | int code = 0;
|
---|
298 | if ((chm.fs & KC_VIRTUALKEY)) {
|
---|
299 | if (chm.vkey == 0) {
|
---|
300 | // The only known situation when KC_VIRTUALKEY is present but
|
---|
301 | // vkey is zero is when Alt+Shift is pressed to switch the
|
---|
302 | // keyboard layout state from latin to national and back.
|
---|
303 | // It seems that this way the system informs applications about
|
---|
304 | // layout changes: chm.chr is 0xF1 when the user switches
|
---|
305 | // to the national layout (i.e. presses Alt + Left Shift)
|
---|
306 | // and 0xF0 when he switches back (presses Alt + Right Shift).
|
---|
307 | // We assume this and restore fs, vkey, scancode and chr accordingly.
|
---|
308 | if (chm.chr == 0xF0 || chm.chr == 0xF1) {
|
---|
309 | chm.fs |= KC_ALT | KC_SHIFT;
|
---|
310 | chm.vkey = VK_SHIFT;
|
---|
311 | chm.scancode = chm.chr == 0xF1 ? 0x2A : 0x36;
|
---|
312 | chm.chr = 0;
|
---|
313 | state |= Qt::AltModifier | Qt::ShiftModifier;
|
---|
314 | // code will be assigned by the normal procedure below
|
---|
315 | }
|
---|
316 | } else if (chm.vkey == VK_ALTGRAF) {
|
---|
317 | if (!(chm.fs & KC_KEYUP))
|
---|
318 | extraKeyState |= Qt::AltModifier;
|
---|
319 | else
|
---|
320 | extraKeyState &= ~Qt::AltModifier;
|
---|
321 | }
|
---|
322 | if (chm.vkey < sizeof(KeyTbl))
|
---|
323 | code = KeyTbl[chm.vkey];
|
---|
324 | }
|
---|
325 |
|
---|
326 | // detect some special keys that don't have a virtual key but have a pseudo
|
---|
327 | // char code in the high byte of chm.chr (probably this is less
|
---|
328 | // device-dependent than scancode)
|
---|
329 | switch (chm.chr) {
|
---|
330 | case 0xEC00: // LWIN
|
---|
331 | case 0xED00: // RWIN
|
---|
332 | code = Qt::Key_Meta;
|
---|
333 | if (!(chm.fs & KC_KEYUP))
|
---|
334 | extraKeyState |= Qt::MetaModifier;
|
---|
335 | else
|
---|
336 | extraKeyState &= ~Qt::MetaModifier;
|
---|
337 | break;
|
---|
338 | case 0xEE00: // WINAPP (menu with arrow)
|
---|
339 | code = Qt::Key_Menu;
|
---|
340 | break;
|
---|
341 | case 0x5600: // additional '\' (0x56 is actually its scancode)
|
---|
342 | chm.chr = state & Qt::ShiftModifier ? '|' : '\\';
|
---|
343 | break;
|
---|
344 | }
|
---|
345 |
|
---|
346 | // update state after updating extraKeyState
|
---|
347 | if (extraKeyState & Qt::AltModifier)
|
---|
348 | state |= Qt::AltModifier;
|
---|
349 | if (extraKeyState & Qt::MetaModifier)
|
---|
350 | state |= Qt::MetaModifier;
|
---|
351 |
|
---|
352 | // Invert state logic:
|
---|
353 | // If the key actually pressed is a modifier key, then we remove its modifier key from the
|
---|
354 | // state, since a modifier-key can't have itself as a modifier
|
---|
355 | //
|
---|
356 | // ### QKeyEvent::modifiers() already does this inversion which in result
|
---|
357 | // cancels the inversion we do below and therefore makes the above statement
|
---|
358 | // incorrect! It looks like the inversion block should be removed from this
|
---|
359 | // function but it is left here for compatibility with other platforms which
|
---|
360 | // also have this bug.
|
---|
361 | //
|
---|
362 | if (code == Qt::Key_Control)
|
---|
363 | state = state ^ Qt::ControlModifier;
|
---|
364 | else if (code == Qt::Key_Shift)
|
---|
365 | state = state ^ Qt::ShiftModifier;
|
---|
366 | else if (code == Qt::Key_Alt)
|
---|
367 | state = state ^ Qt::AltModifier;
|
---|
368 | else if (code == Qt::Key_Meta)
|
---|
369 | state = state ^ Qt::MetaModifier;
|
---|
370 |
|
---|
371 | // KEYDOWN -----------------------------------------------------------------
|
---|
372 | if (!(chm.fs & KC_KEYUP)) {
|
---|
373 | // Get the last record of this key press, so we can validate the current state
|
---|
374 | // The record is not removed from the list
|
---|
375 | KeyRecord *rec = key_recorder.findKey(chm.scancode, false);
|
---|
376 |
|
---|
377 | // If rec's state doesn't match the current state, something has changed behind our back
|
---|
378 | // (Consumed by modal widget is one possibility) So, remove the record from the list
|
---|
379 | // This will stop the auto-repeat of the key, should a modifier change, for example
|
---|
380 | if (rec && rec->state != state) {
|
---|
381 | key_recorder.findKey(chm.scancode, true);
|
---|
382 | rec = 0;
|
---|
383 | }
|
---|
384 |
|
---|
385 | // If we have a record, it means that the key is already pressed, the state is the same
|
---|
386 | // so, we have an auto-repeating key
|
---|
387 | if (rec) {
|
---|
388 | Q_ASSERT(!code || code == rec->code);
|
---|
389 | if (rec->code < Qt::Key_Shift || rec->code > Qt::Key_ScrollLock) {
|
---|
390 | k0 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, rec->code,
|
---|
391 | Qt::KeyboardModifier(state), rec->text, true, 0,
|
---|
392 | chm.scancode, chm.vkey, nativeMods);
|
---|
393 | k1 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, rec->code,
|
---|
394 | Qt::KeyboardModifier(state), rec->text, true, 0,
|
---|
395 | chm.scancode, chm.vkey, nativeMods);
|
---|
396 | }
|
---|
397 | }
|
---|
398 | // No record of the key being previous pressed, so we now send a QEvent::KeyPress event,
|
---|
399 | // and store the key data into our records.
|
---|
400 | else {
|
---|
401 | QString text;
|
---|
402 | // we assume that we have a correct 8-bit character not only when
|
---|
403 | // KC_CHAR is set but also when there are one or more modifiers
|
---|
404 | // (in which case KC_CHAR is not present) but no KC_VIRTUALKEY.
|
---|
405 | // The latter is in particular important for Alt+Letter combos
|
---|
406 | // processing Alt+Letter shortcuts for non-ASCII letters in widgets
|
---|
407 | // (e.g. QPushButton) depends on that.
|
---|
408 | if (((chm.fs & KC_CHAR) ||
|
---|
409 | (!(chm.fs & KC_VIRTUALKEY) && (chm.fs & (KC_CTRL | KC_ALT | KC_SHIFT)))) &&
|
---|
410 | chm.chr) {
|
---|
411 | if (chm.chr & 0xFF00) {
|
---|
412 | // We assume we get a DBCS char if the above condition is met.
|
---|
413 | text = QString::fromLocal8Bit((char *)&chm.chr, 2);
|
---|
414 | } else {
|
---|
415 | text = QString::fromLocal8Bit((char*)&chm.chr, 1);
|
---|
416 | }
|
---|
417 |
|
---|
418 | if (chm.fs & KC_DEADKEY) {
|
---|
419 | // convert dead keys to Key_Dead_* codes and set text to
|
---|
420 | // null to avoid interpreting them as normal chars
|
---|
421 | Q_ASSERT(text.size() == 1);
|
---|
422 | code = deadCharToDeadKeyCode(text[0]);
|
---|
423 | text = QString();
|
---|
424 | } else if (chm.fs & KC_INVALIDCOMP) {
|
---|
425 | // if the pressed letter is invalid for the given dead
|
---|
426 | // key, we set text to null as well (to meet the PM
|
---|
427 | // behavior) and set the code to the uppercase unicode
|
---|
428 | // value (similar to other cases) to have it recognized
|
---|
429 | Q_ASSERT(text.size() == 1);
|
---|
430 | code = text[0].toUpper().unicode();
|
---|
431 | text = QString();
|
---|
432 | }
|
---|
433 |
|
---|
434 | Q_ASSERT(code || !text.isEmpty()); // we must provide the key code
|
---|
435 | if (!code && !text.isEmpty()) {
|
---|
436 | code = text[0].toUpper().unicode();
|
---|
437 | }
|
---|
438 |
|
---|
439 | if ((state & Qt::ControlModifier) &&
|
---|
440 | !(state & Qt::KeypadModifier) && !(state & Qt::AltModifier) &&
|
---|
441 | !text.isEmpty() && !text[0].row()) {
|
---|
442 | // Ctrl + A..Z etc. produce ascii from 0x01 to 0x1F
|
---|
443 | int ascii = text[0].toUpper().cell();
|
---|
444 | if (ascii >= 0x41 && ascii <= 0x5F)
|
---|
445 | ascii -= 0x40;
|
---|
446 | // the below emulates OS/2 functionality. It differs from
|
---|
447 | // e.g. Win32.
|
---|
448 | else if (ascii == 0x36 && !(state & Qt::KeypadModifier))
|
---|
449 | ascii = 0x1E;
|
---|
450 | else if (ascii == 0x2D)
|
---|
451 | ascii = 0x1F;
|
---|
452 | else if (ascii >= 0x7B && ascii <= 0x7D)
|
---|
453 | ascii -= 0x60;
|
---|
454 | text = QChar(ascii);
|
---|
455 | }
|
---|
456 | }
|
---|
457 | key_recorder.storeKey(chm.scancode, code, state, text);
|
---|
458 | k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, code,
|
---|
459 | Qt::KeyboardModifier(state), text, false, 0,
|
---|
460 | chm.scancode, chm.vkey, nativeMods);
|
---|
|
---|