source: trunk/src/gui/kernel/qkeymapper_pm.cpp@ 147

Last change on this file since 147 was 137, checked in by Dmitry A. Kuminov, 16 years ago

gui: Dummy QKeyMapperPrivate::possibleKeys() implementation.

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