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