0
|
1 |
/****************************************************************************
|
|
2 |
**
|
|
3 |
** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
|
|
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
|