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