Qt 4.8
qkbd_qws.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #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 
68 
69 class QWSKbPrivate : public QObject
70 {
71  Q_OBJECT
72 public:
74  : m_handler(h), m_modifiers(0), m_composing(0), m_dead_unicode(0xffff),
75  m_no_zap(false), m_do_compose(false),
77  {
78  m_ar_timer = new QTimer(this);
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 
106  {
107  unloadKeymap();
108  }
109 
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;
116  }
117 
119  {
120  m_ar_timer->stop();
121  }
122 
123  static Qt::KeyboardModifiers toQtModifiers(quint8 mod)
124  {
125  Qt::KeyboardModifiers qtmod = Qt::NoModifier;
126 
128  qtmod |= Qt::ShiftModifier;
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:
141  void autoRepeat()
142  {
146  }
147 
148 private:
150 
151  // auto repeat simulation
154  Qt::KeyboardModifiers m_ar_modifier;
158 
159  // keymap handling
164 
165  bool m_no_zap;
167 
172 
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 
186 {
188  delete [] m_keymap;
190  delete [] m_keycompose;
191 
193  m_keymap_size = sizeof(s_keymap_default) / sizeof(s_keymap_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 
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 
316 {
317  d = new QWSKbPrivate(this, device);
318 }
319 
324 {
325  d = new QWSKbPrivate(this, QString());
326 }
327 
328 
329 
339 {
340  delete d;
341 }
342 
343 
363 void QWSKeyboardHandler::processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers,
364  bool isPress, bool autoRepeat)
365 {
366 #if defined(Q_WS_QWS)
367  qwsServer->processKeyEvent(unicode, keycode, modifiers, isPress, autoRepeat);
368 #elif defined(Q_WS_QPA)
370  QString str;
371  if (unicode != 0xffff)
372  str = QString(unicode);
373  QWindowSystemInterface::handleKeyEvent(0, type, keycode, modifiers, str, autoRepeat);
374 #endif
375 }
376 
399 {
400 #ifdef Q_WS_QWS
401  static int dir_keyrot = -1;
402  if (dir_keyrot < 0) {
403  // get the rotation
404  switch (qgetenv("QWS_CURSOR_ROTATION").toInt()) {
405  case 90: dir_keyrot = 1; break;
406  case 180: dir_keyrot = 2; break;
407  case 270: dir_keyrot = 3; break;
408  default: dir_keyrot = 0; break;
409  }
410  }
411  int xf = qt_screen->transformOrientation() + dir_keyrot;
412  return (key-Qt::Key_Left+xf)%4+Qt::Key_Left;
413 #else
414  return 0;
415 #endif
416 }
417 
433 void QWSKeyboardHandler::beginAutoRepeat(int uni, int code, Qt::KeyboardModifiers mod)
434 {
435  d->beginAutoRepeat(uni, code, mod);
436 }
437 
444 {
445  d->endAutoRepeat();
446 }
447 
522 {
523  KeycodeAction result = None;
524  bool first_press = pressed && !autorepeat;
525 
526  const QWSKeyboard::Mapping *map_plain = 0;
527  const QWSKeyboard::Mapping *map_withmod = 0;
528 
529  // get a specific and plain mapping for the keycode and the current modifiers
530  for (int i = 0; i < d->m_keymap_size && !(map_plain && map_withmod); ++i) {
531  const QWSKeyboard::Mapping *m = d->m_keymap + i;
532  if (m->keycode == keycode) {
533  if (m->modifiers == 0)
534  map_plain = m;
535 
536  quint8 testmods = d->m_modifiers;
537  if (d->m_locks[0] /*CapsLock*/ && (m->flags & QWSKeyboard::IsLetter))
538  testmods ^= QWSKeyboard::ModShift;
539  if (m->modifiers == testmods)
540  map_withmod = m;
541  }
542  }
543 
544 #ifdef QT_DEBUG_KEYMAP
545  qWarning("Processing key event: keycode=%3d, modifiers=%02x pressed=%d, autorepeat=%d | plain=%d, withmod=%d, size=%d", \
546  keycode, d->m_modifiers, pressed ? 1 : 0, autorepeat ? 1 : 0, \
547  map_plain ? map_plain - d->m_keymap : -1, \
548  map_withmod ? map_withmod - d->m_keymap : -1, \
549  d->m_keymap_size);
550 #endif
551 
552  const QWSKeyboard::Mapping *it = map_withmod ? map_withmod : map_plain;
553 
554  if (!it) {
555 #ifdef QT_DEBUG_KEYMAP
556  // we couldn't even find a plain mapping
557  qWarning("Could not find a suitable mapping for keycode: %3d, modifiers: %02x", keycode, d->m_modifiers);
558 #endif
559  return result;
560  }
561 
562  bool skip = false;
563  quint16 unicode = it->unicode;
564  quint32 qtcode = it->qtcode;
565 
566  if ((it->flags & QWSKeyboard::IsModifier) && it->special) {
567  // this is a modifier, i.e. Shift, Alt, ...
568  if (pressed)
569  d->m_modifiers |= quint8(it->special);
570  else
571  d->m_modifiers &= ~quint8(it->special);
572  } else if (qtcode >= Qt::Key_CapsLock && qtcode <= Qt::Key_ScrollLock) {
573  // (Caps|Num|Scroll)Lock
574  if (first_press) {
575  quint8 &lock = d->m_locks[qtcode - Qt::Key_CapsLock];
576  lock ^= 1;
577 
578  switch (qtcode) {
579  case Qt::Key_CapsLock : result = lock ? CapsLockOn : CapsLockOff; break;
580  case Qt::Key_NumLock : result = lock ? NumLockOn : NumLockOff; break;
581  case Qt::Key_ScrollLock: result = lock ? ScrollLockOn : ScrollLockOff; break;
582  default : break;
583  }
584  }
585  } else if ((it->flags & QWSKeyboard::IsSystem) && it->special && first_press) {
586  switch (it->special) {
588  result = Reboot;
589  break;
590 
592  if (!d->m_no_zap)
593  qApp->quit();
594  break;
595 
597  result = PreviousConsole;
598  break;
599 
601  result = NextConsole;
602  break;
603 
604  default:
608  }
609  break;
610  }
611 
612  skip = true; // no need to tell QWS about it
613  } else if ((qtcode == Qt::Key_Multi_key) && d->m_do_compose) {
614  // the Compose key was pressed
615  if (first_press)
616  d->m_composing = 2;
617  skip = true;
618  } else if ((it->flags & QWSKeyboard::IsDead) && d->m_do_compose) {
619  // a Dead key was pressed
620  if (first_press && d->m_composing == 1 && d->m_dead_unicode == unicode) { // twice
621  d->m_composing = 0;
622  qtcode = Qt::Key_unknown; // otherwise it would be Qt::Key_Dead...
623  } else if (first_press && unicode != 0xffff) {
624  d->m_dead_unicode = unicode;
625  d->m_composing = 1;
626  skip = true;
627  } else {
628  skip = true;
629  }
630  }
631 
632  if (!skip) {
633  // a normal key was pressed
635 
636  // we couldn't find a specific mapping for the current modifiers,
637  // or that mapping didn't have special modifiers:
638  // so just report the plain mapping with additional modifiers.
639  if ((it == map_plain && it != map_withmod) ||
640  (map_withmod && !(map_withmod->qtcode & modmask))) {
641  qtcode |= QWSKbPrivate::toQtModifiers(d->m_modifiers);
642  }
643 
644  if (d->m_composing == 2 && first_press && !(it->flags & QWSKeyboard::IsModifier)) {
645  // the last key press was the Compose key
646  if (unicode != 0xffff) {
647  int idx = 0;
648  // check if this code is in the compose table at all
649  for ( ; idx < d->m_keycompose_size; ++idx) {
650  if (d->m_keycompose[idx].first == unicode)
651  break;
652  }
653  if (idx < d->m_keycompose_size) {
654  // found it -> simulate a Dead key press
655  d->m_dead_unicode = unicode;
656  unicode = 0xffff;
657  d->m_composing = 1;
658  skip = true;
659  } else {
660  d->m_composing = 0;
661  }
662  } else {
663  d->m_composing = 0;
664  }
665  } else if (d->m_composing == 1 && first_press && !(it->flags & QWSKeyboard::IsModifier)) {
666  // the last key press was a Dead key
667  bool valid = false;
668  if (unicode != 0xffff) {
669  int idx = 0;
670  // check if this code is in the compose table at all
671  for ( ; idx < d->m_keycompose_size; ++idx) {
672  if (d->m_keycompose[idx].first == d->m_dead_unicode && d->m_keycompose[idx].second == unicode)
673  break;
674  }
675  if (idx < d->m_keycompose_size) {
676  quint16 composed = d->m_keycompose[idx].result;
677  if (composed != 0xffff) {
678  unicode = composed;
679  qtcode = Qt::Key_unknown;
680  valid = true;
681  }
682  }
683  }
684  if (!valid) {
685  unicode = d->m_dead_unicode;
686  qtcode = Qt::Key_unknown;
687  }
688  d->m_composing = 0;
689  }
690 
691  if (!skip) {
692 #ifdef QT_DEBUG_KEYMAP
693  qWarning("Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode & ~modmask, (qtcode & modmask));
694 #endif
695 
696  // send the result to the QWS server
697  processKeyEvent(unicode, qtcode & ~modmask, Qt::KeyboardModifiers(qtcode & modmask), pressed, autorepeat);
698  }
699  }
700  return result;
701 }
702 
704 
705 #include "qkbd_qws.moc"
706 
707 #endif // QT_NO_QWS_KEYBOARD
Q_GUI_EXPORT QScreen * qt_screen
Definition: qscreen_qws.cpp:69
double d
Definition: qnumeric_p.h:62
Status status() const
Returns the status of the data stream.
void setSingleShot(bool singleShot)
Definition: qtimer.h:108
void endAutoRepeat()
Stops auto-repeating a key press.
Definition: qkbd_qws.cpp:443
The QWSKeyboardHandler class is a base class for keyboard drivers in Qt for Embedded Linux...
Definition: qkbd_qws.h:57
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
int type
Definition: qmetatype.cpp:239
QWSKbPrivate(QWSKeyboardHandler *h, const QString &device)
Definition: qkbd_qws.cpp:73
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
int keycode
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
#define it(className, varName)
bool open(OpenMode flags)
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition: qfile.cpp:1064
#define SLOT(a)
Definition: qobjectdefs.h:226
static void handleKeyEvent(QWidget *w, QEvent::Type t, int k, Qt::KeyboardModifiers mods, const QString &text=QString(), bool autorep=false, ushort count=1)
int transformDirKey(int key)
Transforms the arrow key specified by the given keycode, to the orientation of the display and return...
Definition: qkbd_qws.cpp:398
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition: qstring.cpp:3734
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
unsigned char quint8
Definition: qglobal.h:934
The QString class provides a Unicode character string.
Definition: qstring.h:83
quint8 m_locks[3]
Definition: qkbd_qws.cpp:161
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
static void processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat)
Processes the given key event.
bool m_do_compose
Definition: qkbd_qws.cpp:166
quint16 m_dead_unicode
Definition: qkbd_qws.cpp:163
#define SIGNAL(a)
Definition: qobjectdefs.h:227
QTimer * m_ar_timer
Definition: qkbd_qws.cpp:157
void beginAutoRepeat(int uni, int code, Qt::KeyboardModifiers mod)
Definition: qkbd_qws.cpp:110
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
void autoRepeat()
Definition: qkbd_qws.cpp:141
static bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
Creates a connection of the given type from the signal in the sender object to the method in the rece...
Definition: qobject.cpp:2580
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
#define qApp
The QStringList class provides a list of strings.
Definition: qstringlist.h:66
static int toInt(const QByteArray &str)
Definition: generator.cpp:167
QWSKeyboardHandler()
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qkbd_qws.cpp:323
void unloadKeymap()
Definition: qkbd_qws.cpp:185
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
bool loadKeymap(const QString &file)
Definition: qkbd_qws.cpp:204
The QLatin1String class provides a thin wrapper around an US-ASCII/Latin-1 encoded string literal...
Definition: qstring.h:654
const QWSKeyboard::Mapping * m_keymap
Definition: qkbd_qws.cpp:168
int m_keycompose_size
Definition: qkbd_qws.cpp:171
static Qt::KeyboardModifiers toQtModifiers(quint8 mod)
Definition: qkbd_qws.cpp:123
QWSKeyboardHandler * m_handler
Definition: qkbd_qws.cpp:149
KeycodeAction
This enum describes the various special actions that actual QWSKeyboardHandler implementations have t...
Definition: qkbd_qws.h:67
#define Q_OBJECT
Definition: qobjectdefs.h:157
#define None
QString mid(int position, int n=-1) const Q_REQUIRED_RESULT
Returns a string that contains n characters of this string, starting at the specified position index...
Definition: qstring.cpp:3706
Qt::KeyboardModifiers m_ar_modifier
Definition: qkbd_qws.cpp:154
The QFile class provides an interface for reading from and writing to files.
Definition: qfile.h:65
const QWSKeyboard::Composing * m_keycompose
Definition: qkbd_qws.cpp:170
Type
This enum type defines the valid event types in Qt.
Definition: qcoreevent.h:62
int m_keymap_size
Definition: qkbd_qws.cpp:169
void beginAutoRepeat(int uni, int code, Qt::KeyboardModifiers mod)
Begins auto-repeating the specified key press; after a short delay the key press is sent periodically...
Definition: qkbd_qws.cpp:433
int key
unsigned int quint32
Definition: qglobal.h:938
void endAutoRepeat()
Definition: qkbd_qws.cpp:118
static QReadWriteLock lock
Definition: proxyconf.cpp:399
virtual int transformOrientation() const
Returns the current rotation as an integer value.
int m_ar_keycode
Definition: qkbd_qws.cpp:153
QStringList split(const QString &sep, SplitBehavior behavior=KeepEmptyParts, Qt::CaseSensitivity cs=Qt::CaseSensitive) const Q_REQUIRED_RESULT
Splits the string into substrings wherever sep occurs, and returns the list of those strings...
Definition: qstring.cpp:6526
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:71
int m_ar_unicode
Definition: qkbd_qws.cpp:152
virtual void processKeyEvent(int unicode, int keycode, Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat)
Sends a key event to the Qt for Embedded Linux server application.
Definition: qkbd_qws.cpp:363
The QTimer class provides repetitive and single-shot timers.
Definition: qtimer.h:56
#define slots
Definition: qobjectdefs.h:68
quint8 m_modifiers
Definition: qkbd_qws.cpp:160
void stop()
Stops the timer.
Definition: qtimer.cpp:284
static const QWSKeyboard::Composing s_keycompose_default[]
Definition: qkbd_qws.cpp:174
void start(int msec)
Starts or restarts the timer with a timeout interval of msec milliseconds.
Definition: qtimer.cpp:249
#define qPrintable(string)
Definition: qglobal.h:1750
const quint32 FileMagic
Definition: qkbd_qws_p.h:61
KeycodeAction processKeycode(quint16 keycode, bool pressed, bool autorepeat)
Maps keycode according to a keymap and sends that key event to the Qt for Embedded Linux server appli...
Definition: qkbd_qws.cpp:521
The QLatin1Char class provides an 8-bit ASCII/Latin-1 character.
Definition: qchar.h:55
static const QWSKeyboard::Mapping s_keymap_default[]
Definition: qkbd_qws.cpp:173
QWSServer Q_GUI_EXPORT * qwsServer
virtual ~QWSKeyboardHandler()
Destroys this keyboard driver.
Definition: qkbd_qws.cpp:338