1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QEVDEVKEYBOARDHANDLER_P_H
41 #define QEVDEVKEYBOARDHANDLER_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <qobject.h>
55 #include <QTimer>
56 #include <QDataStream>
57 
58 #include <memory>
59 
60 QT_BEGIN_NAMESPACE
61 
62 class QSocketNotifier;
63 
64 namespace QEvdevKeyboardMap {
65     const quint32 FileMagic = 0x514d4150; // 'QMAP'
66 
67     struct Mapping {
68         quint16 keycode;
69         quint16 unicode;
70         quint32 qtcode;
71         quint8 modifiers;
72         quint8 flags;
73         quint16 special;
74 
75     };
76 
77     enum Flags {
78         IsDead     = 0x01,
79         IsLetter   = 0x02,
80         IsModifier = 0x04,
81         IsSystem   = 0x08
82     };
83 
84     enum System {
85         SystemConsoleFirst    = 0x0100,
86         SystemConsoleMask     = 0x007f,
87         SystemConsoleLast     = 0x017f,
88         SystemConsolePrevious = 0x0180,
89         SystemConsoleNext     = 0x0181,
90         SystemReboot          = 0x0200,
91         SystemZap             = 0x0300
92     };
93 
94     struct Composing {
95         quint16 first;
96         quint16 second;
97         quint16 result;
98     };
99 
100     enum Modifiers {
101         ModPlain   = 0x00,
102         ModShift   = 0x01,
103         ModAltGr   = 0x02,
104         ModControl = 0x04,
105         ModAlt     = 0x08,
106         ModShiftL  = 0x10,
107         ModShiftR  = 0x20,
108         ModCtrlL   = 0x40,
109         ModCtrlR   = 0x80
110         // ModCapsShift = 0x100, // not supported!
111     };
112 }
113 
114 inline QDataStream &operator>>(QDataStream &ds, QEvdevKeyboardMap::Mapping &m)
115 {
116     return ds >> m.keycode >> m.unicode >> m.qtcode >> m.modifiers >> m.flags >> m.special;
117 }
118 
119 inline QDataStream &operator<<(QDataStream &ds, const QEvdevKeyboardMap::Mapping &m)
120 {
121     return ds << m.keycode << m.unicode << m.qtcode << m.modifiers << m.flags << m.special;
122 }
123 
124 inline QDataStream &operator>>(QDataStream &ds, QEvdevKeyboardMap::Composing &c)
125 {
126     return ds >> c.first >> c.second >> c.result;
127 }
128 
129 inline QDataStream &operator<<(QDataStream &ds, const QEvdevKeyboardMap::Composing &c)
130 {
131     return ds << c.first << c.second << c.result;
132 }
133 
134 class QFdContainer
135 {
136     int m_fd;
137     Q_DISABLE_COPY_MOVE(QFdContainer);
138 public:
m_fd(fd)139     explicit QFdContainer(int fd = -1) noexcept : m_fd(fd) {}
~QFdContainer()140     ~QFdContainer() { reset(); }
141 
get()142     int get() const noexcept { return m_fd; }
143 
release()144     int release() noexcept { int result = m_fd; m_fd = -1; return result; }
145     void reset() noexcept;
146 };
147 
148 class QEvdevKeyboardHandler : public QObject
149 {
150 public:
151     QEvdevKeyboardHandler(const QString &device, QFdContainer &fd, bool disableZap, bool enableCompose, const QString &keymapFile);
152     ~QEvdevKeyboardHandler();
153 
154     enum KeycodeAction {
155         None               = 0,
156 
157         CapsLockOff        = 0x01000000,
158         CapsLockOn         = 0x01000001,
159         NumLockOff         = 0x02000000,
160         NumLockOn          = 0x02000001,
161         ScrollLockOff      = 0x03000000,
162         ScrollLockOn       = 0x03000001,
163 
164         Reboot             = 0x04000000,
165 
166         PreviousConsole    = 0x05000000,
167         NextConsole        = 0x05000001,
168         SwitchConsoleFirst = 0x06000000,
169         SwitchConsoleLast  = 0x0600007f,
170         SwitchConsoleMask  = 0x0000007f
171     };
172 
173     static std::unique_ptr<QEvdevKeyboardHandler> create(const QString &device,
174                                          const QString &specification,
175                                          const QString &defaultKeymapFile = QString());
176 
toQtModifiers(quint8 mod)177     static Qt::KeyboardModifiers toQtModifiers(quint8 mod)
178     {
179         Qt::KeyboardModifiers qtmod = Qt::NoModifier;
180 
181         if (mod & (QEvdevKeyboardMap::ModShift | QEvdevKeyboardMap::ModShiftL | QEvdevKeyboardMap::ModShiftR))
182             qtmod |= Qt::ShiftModifier;
183         if (mod & (QEvdevKeyboardMap::ModControl | QEvdevKeyboardMap::ModCtrlL | QEvdevKeyboardMap::ModCtrlR))
184             qtmod |= Qt::ControlModifier;
185         if (mod & QEvdevKeyboardMap::ModAlt)
186             qtmod |= Qt::AltModifier;
187 
188         return qtmod;
189     }
190 
191     bool loadKeymap(const QString &file);
192     void unloadKeymap();
193 
194     void readKeycode();
195     KeycodeAction processKeycode(quint16 keycode, bool pressed, bool autorepeat);
196 
197     void switchLang();
198 
199 private:
200     void processKeyEvent(int nativecode, int unicode, int qtcode,
201                          Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat);
202     void switchLed(int, bool);
203 
204     QString m_device;
205     QFdContainer m_fd;
206     QSocketNotifier *m_notify;
207 
208     // keymap handling
209     quint8 m_modifiers;
210     quint8 m_locks[3];
211     int m_composing;
212     quint16 m_dead_unicode;
213     quint8 m_langLock;
214 
215     bool m_no_zap;
216     bool m_do_compose;
217 
218     const QEvdevKeyboardMap::Mapping *m_keymap;
219     int m_keymap_size;
220     const QEvdevKeyboardMap::Composing *m_keycompose;
221     int m_keycompose_size;
222 
223     static const QEvdevKeyboardMap::Mapping s_keymap_default[];
224     static const QEvdevKeyboardMap::Composing s_keycompose_default[];
225 };
226 
227 
228 QT_END_NAMESPACE
229 
230 #endif // QEVDEVKEYBOARDHANDLER_P_H
231