1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this 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 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qkbd_qws.h"
43 #include "qkbd_qws_p.h"
44
45 #ifndef QT_NO_QWS_KEYBOARD
46
47 #include <QFile>
48 #include <QDataStream>
49 #include <QStringList>
50
51 #ifdef Q_WS_QWS
52 #include "qwindowsystem_qws.h"
53 #include "qscreen_qws.h"
54 #endif
55
56 #ifdef Q_WS_QPA
57 #include <QWindowSystemInterface>
58 #include <QKeyEvent>
59 #endif
60
61 #include "qtimer.h"
62 #include <stdlib.h>
63
64 //#define QT_DEBUG_KEYMAP
65
66
67 QT_BEGIN_NAMESPACE
68
69 class QWSKbPrivate : public QObject
70 {
71 Q_OBJECT
72 public:
QWSKbPrivate(QWSKeyboardHandler * h,const QString & device)73 QWSKbPrivate(QWSKeyboardHandler *h, const QString &device)
74 : m_handler(h), m_modifiers(0), m_composing(0), m_dead_unicode(0xffff),
75 m_no_zap(false), m_do_compose(false),
76 m_keymap(0), m_keymap_size(0), m_keycompose(0), m_keycompose_size(0)
77 {
78 m_ar_timer = new QTimer(this);
79 m_ar_timer->setSingleShot(true);
80 connect(m_ar_timer, SIGNAL(timeout()), SLOT(autoRepeat()));
81 m_ar_delay = 400;
82 m_ar_period = 80;
83
84 memset(m_locks, 0, sizeof(m_locks));
85
86 QString keymap;
87 QStringList args = device.split(QLatin1Char(':'));
88 foreach (const QString &arg, args) {
89 if (arg.startsWith(QLatin1String("keymap=")))
90 keymap = arg.mid(7);
91 else if (arg == QLatin1String("disable-zap"))
92 m_no_zap = true;
93 else if (arg == QLatin1String("enable-compose"))
94 m_do_compose = true;
95 else if (arg.startsWith(QLatin1String("repeat-delay=")))
96 m_ar_delay = arg.mid(13).toInt();
97 else if (arg.startsWith(QLatin1String("repeat-rate=")))
98 m_ar_period = arg.mid(12).toInt();
99 }
100
101 if (keymap.isEmpty() || !loadKeymap(keymap))
102 unloadKeymap();
103 }
104
~QWSKbPrivate()105 ~QWSKbPrivate()
106 {
107 unloadKeymap();
108 }
109
beginAutoRepeat(int uni,int code,Qt::KeyboardModifiers mod)110 void beginAutoRepeat(int uni, int code, Qt::KeyboardModifiers mod)
111 {
112 m_ar_unicode = uni;
113 m_ar_keycode = code;
114 m_ar_modifier = mod;
115 m_ar_timer->start(m_ar_delay);
116 }
117
endAutoRepeat()118 void endAutoRepeat()
119 {
120 m_ar_timer->stop();
121 }
122
toQtModifiers(quint8 mod)123 static Qt::KeyboardModifiers toQtModifiers(quint8 mod)
124 {
125 Qt::KeyboardModifiers qtmod = Qt::NoModifier;
126
127 if (mod & (QWSKeyboard::ModShift | QWSKeyboard::ModShiftL | QWSKeyboard::ModShiftR))
128 qtmod |= Qt::ShiftModifier;
129 if (mod & (QWSKeyboard::ModControl | QWSKeyboard::ModCtrlL | QWSKeyboard::ModCtrlR))
130 qtmod |= Qt::ControlModifier;
131 if (mod & QWSKeyboard::ModAlt)
132 qtmod |= Qt::AltModifier;
133
134 return qtmod;
135 }
136
137 void unloadKeymap();
138 bool loadKeymap(const QString &file);
139
140 private slots:
autoRepeat()141 void autoRepeat()
142 {
143 m_handler->processKeyEvent(m_ar_unicode, m_ar_keycode, m_ar_modifier, false, true);
144 m_handler->processKeyEvent(m_ar_unicode, m_ar_keycode, m_ar_modifier, true, true);
145 m_ar_timer->start(m_ar_period);
146 }
147
148 private:
149 QWSKeyboardHandler *m_handler;
150
151 // auto repeat simulation
152 int m_ar_unicode;
153 int m_ar_keycode;
154 Qt::KeyboardModifiers m_ar_modifier;
155 int m_ar_delay;
156 int m_ar_period;
157 QTimer *m_ar_timer;
158
159 // keymap handling
160 quint8 m_modifiers;
161 quint8 m_locks[3];
162 int m_composing;
163 quint16 m_dead_unicode;
164
165 bool m_no_zap;
166 bool m_do_compose;
167
168 const QWSKeyboard::Mapping *m_keymap;
169 int m_keymap_size;
170 const QWSKeyboard::Composing *m_keycompose;
171 int m_keycompose_size;
172
173 static const QWSKeyboard::Mapping s_keymap_default[];
174 static const QWSKeyboard::Composing s_keycompose_default[];
175
176 friend class QWSKeyboardHandler;
177 };
178
179 // simple builtin US keymap
180 #include "qkbd_defaultmap_qws_p.h"
181
182 // the unloadKeymap() function needs to be AFTER the defaultmap include,
183 // since the sizeof(s_keymap_default) wouldn't work otherwise.
184
unloadKeymap()185 void QWSKbPrivate::unloadKeymap()
186 {
187 if (m_keymap && m_keymap != s_keymap_default)
188 delete [] m_keymap;
189 if (m_keycompose && m_keycompose != s_keycompose_default)
190 delete [] m_keycompose;
191
192 m_keymap = s_keymap_default;
193 m_keymap_size = sizeof(s_keymap_default) / sizeof(s_keymap_default[0]);
194 m_keycompose = s_keycompose_default;
195 m_keycompose_size = sizeof(s_keycompose_default) / sizeof(s_keycompose_default[0]);
196
197 // reset state, so we could switch keymaps at runtime
198 m_modifiers = 0;
199 memset(m_locks, 0, sizeof(m_locks));
200 m_composing = 0;
201 m_dead_unicode = 0xffff;
202 }
203
loadKeymap(const QString & file)204 bool QWSKbPrivate::loadKeymap(const QString &file)
205 {
206 QFile f(file);
207
208 if (!f.open(QIODevice::ReadOnly)) {
209 qWarning("Could not open keymap file '%s'", qPrintable(file));
210 return false;
211 }
212
213 // .qmap files have a very simple structure:
214 // quint32 magic (QWSKeyboard::FileMagic)
215 // quint32 version (1)
216 // quint32 keymap_size (# of struct QWSKeyboard::Mappings)
217 // quint32 keycompose_size (# of struct QWSKeyboard::Composings)
218 // all QWSKeyboard::Mappings via QDataStream::operator(<<|>>)
219 // all QWSKeyboard::Composings via QDataStream::operator(<<|>>)
220
221 quint32 qmap_magic, qmap_version, qmap_keymap_size, qmap_keycompose_size;
222
223 QDataStream ds(&f);
224
225 ds >> qmap_magic >> qmap_version >> qmap_keymap_size >> qmap_keycompose_size;
226
227 if (ds.status() != QDataStream::Ok || qmap_magic != QWSKeyboard::FileMagic || qmap_version != 1 || qmap_keymap_size == 0) {
228 qWarning("'%s' is not a valid .qmap keymap file.", qPrintable(file));
229 return false;
230 }
231
232 QWSKeyboard::Mapping *qmap_keymap = new QWSKeyboard::Mapping[qmap_keymap_size];
233 QWSKeyboard::Composing *qmap_keycompose = qmap_keycompose_size ? new QWSKeyboard::Composing[qmap_keycompose_size] : 0;
234
235 for (quint32 i = 0; i < qmap_keymap_size; ++i)
236 ds >> qmap_keymap[i];
237 for (quint32 i = 0; i < qmap_keycompose_size; ++i)
238 ds >> qmap_keycompose[i];
239
240 if (ds.status() != QDataStream::Ok) {
241 delete [] qmap_keymap;
242 delete [] qmap_keycompose;
243
244 qWarning("Keymap file '%s' can not be loaded.", qPrintable(file));
245 return false;
246 }
247
248 // unload currently active and clear state
249 unloadKeymap();
250
251 m_keymap = qmap_keymap;
252 m_keymap_size = qmap_keymap_size;
253 m_keycompose = qmap_keycompose;
254 m_keycompose_size = qmap_keycompose_size;
255
256 m_do_compose = true;
257
258 return true;
259 }
260
261
262 /*!
263 \class QWSKeyboardHandler
264 \ingroup qws
265
266 \brief The QWSKeyboardHandler class is a base class for keyboard
267 drivers in Qt for Embedded Linux.
268
269 Note that this class is only available in \l{Qt for Embedded Linux}.
270
271 \l{Qt for Embedded Linux} provides ready-made drivers for several keyboard
272 protocols, see the \l{Qt for Embedded Linux Character Input}{character
273 input} documentation for details. Custom keyboard drivers can be
274 implemented by subclassing the QWSKeyboardHandler class and
275 creating a keyboard driver plugin (derived from
276 QKbdDriverPlugin). The default implementation of the
277 QKbdDriverFactory class will automatically detect the plugin, and
278 load the driver into the server application at run-time using Qt's
279 \l{How to Create Qt Plugins}{plugin system}.
280
281 The keyboard driver receives keyboard events from the system
282 device and encapsulates each event with an instance of the
283 QWSEvent class which it then passes to the server application (the
284 server is responsible for propagating the event to the appropriate
285 client). To receive keyboard events, a QWSKeyboardHandler object
286 will usually create a QSocketNotifier object for the given
287 device. The QSocketNotifier class provides support for monitoring
288 activity on a file descriptor. When the socket notifier receives
289 data, it will call the keyboard driver's processKeyEvent()
290 function to send the event to the \l{Qt for Embedded Linux} server
291 application for relaying to clients.
292
293
294 QWSKeyboardHandler also provides functions to control
295 auto-repetion of key sequences, beginAutoRepeat() and
296 endAutoRepeat(), and the transformDirKey() function enabling
297 transformation of arrow keys according to the display orientation.
298
299 \sa QKbdDriverPlugin, QKbdDriverFactory, {Qt for Embedded Linux Character Input}
300 */
301
302
303 /*!
304 Constructs a keyboard driver. The \a device argument is passed by the
305 QWS_KEYBOARD environment variable.
306
307 Call the QWSServer::setKeyboardHandler() function to make the
308 newly created keyboard driver, the primary driver. Note that the
309 primary driver is controlled by the system, i.e., the system will
310 delete it upon exit.
311 */
QWSKeyboardHandler(const QString & device)312 QWSKeyboardHandler::QWSKeyboardHandler(const QString &device)
313 {
314 d = new QWSKbPrivate(this, device);
315 }
316
317 /*!
318 \overload
319 */
QWSKeyboardHandler()320 QWSKeyboardHandler::QWSKeyboardHandler()
321 {
322 d = new QWSKbPrivate(this, QString());
323 }
324
325
326
327 /*!
328 Destroys this keyboard driver.
329
330 Do not call this function if this driver is the primary keyboard
331 handler, i.e., if QWSServer::setKeyboardHandler() function has
332 been called passing this driver as argument. The primary keyboard
333 driver is deleted by the system.
334 */
~QWSKeyboardHandler()335 QWSKeyboardHandler::~QWSKeyboardHandler()
336 {
337 delete d;
338 }
339
340
341 /*!
342 Sends a key event to the \l{Qt for Embedded Linux} server application.
343
344 The key event is identified by its \a unicode value and the \a
345 keycode, \a modifiers, \a isPress and \a autoRepeat parameters.
346
347 The \a keycode parameter is the Qt keycode value as defined by the
348 Qt::Key enum. The \a modifiers is an OR combination of
349 Qt::KeyboardModifier values, indicating whether \gui
350 Shift/Alt/Ctrl keys are pressed. The \a isPress parameter is true
351 if the event is a key press event and \a autoRepeat is true if the
352 event is caused by an auto-repeat mechanism and not an actual key
353 press.
354
355 Note that this function does not handle key mapping. Please use
356 processKeycode() if you need that functionality.
357
358 \sa processKeycode(), beginAutoRepeat(), endAutoRepeat(), transformDirKey()
359 */
processKeyEvent(int unicode,int keycode,Qt::KeyboardModifiers modifiers,bool isPress,bool autoRepeat)360 void QWSKeyboardHandler::processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
361 bool isPress, bool autoRepeat)
362 {
363 #if defined(Q_WS_QWS)
364 qwsServer->processKeyEvent(unicode, keycode, modifiers, isPress, autoRepeat);
365 #elif defined(Q_WS_QPA)
366 QEvent::Type type = isPress ? QEvent::KeyPress : QEvent::KeyRelease;
367 QString str;
368 if (unicode != 0xffff)
369 str = QString(unicode);
370 QWindowSystemInterface::handleKeyEvent(0, type, keycode, modifiers, str, autoRepeat);
371 #endif
372 }
373
374 /*!
375 \fn int QWSKeyboardHandler::transformDirKey(int keycode)
376
377 Transforms the arrow key specified by the given \a keycode, to the
378 orientation of the display and returns the transformed keycode.
379
380 The \a keycode is a Qt::Key value. The values identifying arrow
381 keys are:
382
383 \list
384 \o Qt::Key_Left
385 \o Qt::Key_Up
386 \o Qt::Key_Right
387 \o Qt::Key_Down
388 \endlist
389
390 \sa processKeyEvent()
391 */
transformDirKey(int key)392 int QWSKeyboardHandler::transformDirKey(int key)
393 {
394 #ifdef Q_WS_QWS
395 static int dir_keyrot = -1;
396 if (dir_keyrot < 0) {
397 // get the rotation
398 switch (qgetenv("QWS_CURSOR_ROTATION").toInt()) {
399 case 90: dir_keyrot = 1; break;
400 case 180: dir_keyrot = 2; break;
401 case 270: dir_keyrot = 3; break;
402 default: dir_keyrot = 0; break;
403 }
404 }
405 int xf = qt_screen->transformOrientation() + dir_keyrot;
406 return (key-Qt::Key_Left+xf)%4+Qt::Key_Left;
407 #else
408 return 0;
409 #endif
410 }
411
412 /*!
413 \fn void QWSKeyboardHandler::beginAutoRepeat(int unicode, int keycode, Qt::KeyboardModifiers modifier)
414
415 Begins auto-repeating the specified key press; after a short delay
416 the key press is sent periodically until the endAutoRepeat()
417 function is called.
418
419 The key press is specified by its \a unicode, \a keycode and \a
420 modifier state.
421
422 \sa endAutoRepeat(), processKeyEvent()
423 */
beginAutoRepeat(int uni,int code,Qt::KeyboardModifiers mod)424 void QWSKeyboardHandler::beginAutoRepeat(int uni, int code, Qt::KeyboardModifiers mod)
425 {
426 d->beginAutoRepeat(uni, code, mod);
427 }
428
429 /*!
430 Stops auto-repeating a key press.
431
432 \sa beginAutoRepeat(), processKeyEvent()
433 */
endAutoRepeat()434 void QWSKeyboardHandler::endAutoRepeat()
435 {
436 d->endAutoRepeat();
437 }
438
439 /*!
440 \enum QWSKeyboardHandler::KeycodeAction
441
442 This enum describes the various special actions that actual
443 QWSKeyboardHandler implementations have to take care of.
444
445 \value None No further action required.
446
447 \value CapsLockOn Set the state of the Caps lock LED to on.
448 \value CapsLockOff Set the state of the Caps lock LED to off.
449 \value NumLockOn Set the state of the Num lock LED to on.
450 \value NumLockOff Set the state of the Num lock LED to off.
451 \value ScrollLockOn Set the state of the Scroll lock LED to on.
452 \value ScrollLockOff Set the state of the Scroll lock LED to off.
453
454 \value PreviousConsole Switch to the previous virtual console (by
455 default Ctrl+Alt+Left on Linux).
456 \value NextConsole Switch to the next virtual console (by default
457 Ctrl+Alt+Right on Linux).
458 \value SwitchConsoleFirst Switch to the first virtual console (0).
459 \value SwitchConsoleLast Switch to the last virtual console (255).
460 \value SwitchConsoleMask If the KeyAction value is between SwitchConsoleFirst
461 and SwitchConsoleLast, you can use this mask to get
462 the specific virtual console number to switch to.
463
464 \value Reboot Reboot the machine - this is ignored in both the TTY and
465 LinuxInput handlers though (by default Ctrl+Alt+Del on Linux).
466
467 \sa processKeycode()
468 */
469
470 /*!
471 \fn QWSKeyboardHandler::KeycodeAction QWSKeyboardHandler::processKeycode(quint16 keycode, bool isPress, bool autoRepeat)
472
473 \since 4.6
474
475 Maps \a keycode according to a keymap and sends that key event to the
476 \l{Qt for Embedded Linux} server application.
477
478 Please see the \l{Qt for Embedded Linux Character Input} and the \l
479 {kmap2qmap} documentations for a description on how to create and use
480 keymap files.
481
482 The key event is identified by its \a keycode value and the \a isPress
483 and \a autoRepeat parameters.
484
485 The \a keycode parameter is \bold NOT the Qt keycode value as defined by
486 the Qt::Key enum. This functions expects a standard Linux 16 bit kernel
487 keycode as it is used in the Linux Input Event sub-system. This
488 \a keycode is transformed to a Qt::Key code by using either a
489 compiled-in US keyboard layout or by dynamically loading a keymap at
490 startup which can be specified via the QWS_KEYBOARD environment
491 variable.
492
493 The \a isPress parameter is true if the event is a key press event and
494 \a autoRepeat is true if the event is caused by an auto-repeat mechanism
495 and not an actual key press.
496
497 The return value indicates if the actual QWSKeyboardHandler
498 implementation needs to take care of a special action, like console
499 switching or LED handling.
500
501 If standard Linux console keymaps are used, \a keycode must be one of the
502 standardized values defined in \c /usr/include/linux/input.h
503
504 \sa processKeyEvent(), KeycodeAction
505 */
506
processKeycode(quint16 keycode,bool pressed,bool autorepeat)507 QWSKeyboardHandler::KeycodeAction QWSKeyboardHandler::processKeycode(quint16 keycode, bool pressed, bool autorepeat)
508 {
509 KeycodeAction result = None;
510 bool first_press = pressed && !autorepeat;
511
512 const QWSKeyboard::Mapping *map_plain = 0;
513 const QWSKeyboard::Mapping *map_withmod = 0;
514
515 // get a specific and plain mapping for the keycode and the current modifiers
516 for (int i = 0; i < d->m_keymap_size && !(map_plain && map_withmod); ++i) {
517 const QWSKeyboard::Mapping *m = d->m_keymap + i;
518 if (m->keycode == keycode) {
519 if (m->modifiers == 0)
520 map_plain = m;
521
522 quint8 testmods = d->m_modifiers;
523 if (d->m_locks[0] /*CapsLock*/ && (m->flags & QWSKeyboard::IsLetter))
524 testmods ^= QWSKeyboard::ModShift;
525 if (m->modifiers == testmods)
526 map_withmod = m;
527 }
528 }
529
530 #ifdef QT_DEBUG_KEYMAP
531 qWarning("Processing key event: keycode=%3d, modifiers=%02x pressed=%d, autorepeat=%d | plain=%d, withmod=%d, size=%d", \
532 keycode, d->m_modifiers, pressed ? 1 : 0, autorepeat ? 1 : 0, \
533 map_plain ? map_plain - d->m_keymap : -1, \
534 map_withmod ? map_withmod - d->m_keymap : -1, \
535 d->m_keymap_size);
536 #endif
537
538 const QWSKeyboard::Mapping *it = map_withmod ? map_withmod : map_plain;
539
540 if (!it) {
541 #ifdef QT_DEBUG_KEYMAP
542 // we couldn't even find a plain mapping
543 qWarning("Could not find a suitable mapping for keycode: %3d, modifiers: %02x", keycode, d->m_modifiers);
544 #endif
545 return result;
546 }
547
548 bool skip = false;
549 quint16 unicode = it->unicode;
550 quint32 qtcode = it->qtcode;
551
552 if ((it->flags & QWSKeyboard::IsModifier) && it->special) {
553 // this is a modifier, i.e. Shift, Alt, ...
554 if (pressed)
555 d->m_modifiers |= quint8(it->special);
556 else
557 d->m_modifiers &= ~quint8(it->special);
558 } else if (qtcode >= Qt::Key_CapsLock && qtcode <= Qt::Key_ScrollLock) {
559 // (Caps|Num|Scroll)Lock
560 if (first_press) {
561 quint8 &lock = d->m_locks[qtcode - Qt::Key_CapsLock];
562 lock ^= 1;
563
564 switch (qtcode) {
565 case Qt::Key_CapsLock : result = lock ? CapsLockOn : CapsLockOff; break;
566 case Qt::Key_NumLock : result = lock ? NumLockOn : NumLockOff; break;
567 case Qt::Key_ScrollLock: result = lock ? ScrollLockOn : ScrollLockOff; break;
568 default : break;
569 }
570 }
571 } else if ((it->flags & QWSKeyboard::IsSystem) && it->special && first_press) {
572 switch (it->special) {
573 case QWSKeyboard::SystemReboot:
574 result = Reboot;
575 break;
576
577 case QWSKeyboard::SystemZap:
578 if (!d->m_no_zap)
579 qApp->quit();
580 break;
581
582 case QWSKeyboard::SystemConsolePrevious:
583 result = PreviousConsole;
584 break;
585
586 case QWSKeyboard::SystemConsoleNext:
587 result = NextConsole;
588 break;
589
590 default:
591 if (it->special >= QWSKeyboard::SystemConsoleFirst &&
592 it->special <= QWSKeyboard::SystemConsoleLast) {
593 result = KeycodeAction(SwitchConsoleFirst + ((it->special & QWSKeyboard::SystemConsoleMask) & SwitchConsoleMask));
594 }
595 break;
596 }
597
598 skip = true; // no need to tell QWS about it
599 } else if ((qtcode == Qt::Key_Multi_key) && d->m_do_compose) {
600 // the Compose key was pressed
601 if (first_press)
602 d->m_composing = 2;
603 skip = true;
604 } else if ((it->flags & QWSKeyboard::IsDead) && d->m_do_compose) {
605 // a Dead key was pressed
606 if (first_press && d->m_composing == 1 && d->m_dead_unicode == unicode) { // twice
607 d->m_composing = 0;
608 qtcode = Qt::Key_unknown; // otherwise it would be Qt::Key_Dead...
609 } else if (first_press && unicode != 0xffff) {
610 d->m_dead_unicode = unicode;
611 d->m_composing = 1;
612 skip = true;
613 } else {
614 skip = true;
615 }
616 }
617
618 if (!skip) {
619 // a normal key was pressed
620 const int modmask = Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier | Qt::MetaModifier | Qt::KeypadModifier;
621
622 // we couldn't find a specific mapping for the current modifiers,
623 // or that mapping didn't have special modifiers:
624 // so just report the plain mapping with additional modifiers.
625 if ((it == map_plain && it != map_withmod) ||
626 (map_withmod && !(map_withmod->qtcode & modmask))) {
627 qtcode |= QWSKbPrivate::toQtModifiers(d->m_modifiers);
628 }
629
630 if (d->m_composing == 2 && first_press && !(it->flags & QWSKeyboard::IsModifier)) {
631 // the last key press was the Compose key
632 if (unicode != 0xffff) {
633 int idx = 0;
634 // check if this code is in the compose table at all
635 for ( ; idx < d->m_keycompose_size; ++idx) {
636 if (d->m_keycompose[idx].first == unicode)
637 break;
638 }
639 if (idx < d->m_keycompose_size) {
640 // found it -> simulate a Dead key press
641 d->m_dead_unicode = unicode;
642 unicode = 0xffff;
643 d->m_composing = 1;
644 skip = true;
645 } else {
646 d->m_composing = 0;
647 }
648 } else {
649 d->m_composing = 0;
650 }
651 } else if (d->m_composing == 1 && first_press && !(it->flags & QWSKeyboard::IsModifier)) {
652 // the last key press was a Dead key
653 bool valid = false;
654 if (unicode != 0xffff) {
655 int idx = 0;
656 // check if this code is in the compose table at all
657 for ( ; idx < d->m_keycompose_size; ++idx) {
658 if (d->m_keycompose[idx].first == d->m_dead_unicode && d->m_keycompose[idx].second == unicode)
659 break;
660 }
661 if (idx < d->m_keycompose_size) {
662 quint16 composed = d->m_keycompose[idx].result;
663 if (composed != 0xffff) {
664 unicode = composed;
665 qtcode = Qt::Key_unknown;
666 valid = true;
667 }
668 }
669 }
670 if (!valid) {
671 unicode = d->m_dead_unicode;
672 qtcode = Qt::Key_unknown;
673 }
674 d->m_composing = 0;
675 }
676
677 if (!skip) {
678 #ifdef QT_DEBUG_KEYMAP
679 qWarning("Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode & ~modmask, (qtcode & modmask));
680 #endif
681
682 // send the result to the QWS server
683 processKeyEvent(unicode, qtcode & ~modmask, Qt::KeyboardModifiers(qtcode & modmask), pressed, autorepeat);
684 }
685 }
686 return result;
687 }
688
689 QT_END_NAMESPACE
690
691 #include "qkbd_qws.moc"
692
693 #endif // QT_NO_QWS_KEYBOARD
694