summaryrefslogtreecommitdiffstats
path: root/src/gui/embedded/qkbdqnx_qws.cpp
blob: fbc683ec27f8262503239735cae4a2e45f2db10f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the QtGui module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qkbdqnx_qws.h"
#include "QtCore/qsocketnotifier.h"
#include "QtCore/qdebug.h"

#include <sys/dcmd_input.h>
#include <photon/keycodes.h>

#include "qplatformdefs.h"
#include <errno.h>


QT_BEGIN_NAMESPACE

/*!
    \class QWSQnxKeyboardHandler
    \preliminary
    \ingroup qws
    \since 4.6
    \internal

    \brief The QWSQnxKeyboardHandler class implements a keyboard driver
    for the QNX \c{devi-hid} input manager.

    To be able to compile this mouse handler, \l{Qt for Embedded Linux}
    must be configured with the \c -qt-kbd-qnx option, see the
    \l{Qt for Embedded Linux Character Input} documentation for details.

    In order to use this keyboard handler, the \c{devi-hid} input manager
    must be set up and run with the resource manager interface (option \c{-r}).
    Also, Photon must not be running.

    Example invocation from command line: \c{/usr/photon/bin/devi-hid -Pr kbd mouse}
    Note that after running \c{devi-hid}, you will not be able to use the local
    shell anymore. It is suggested to run the command in a shell scrip, that launches
    a Qt application after invocation of \c{devi-hid}.

    To make \l{Qt for Embedded Linux} explicitly choose the qnx keyboard
    handler, set the QWS_KEYBOARD environment variable to \c{qnx}. By default,
    the first keyboard device (\c{/dev/devi/keyboard0}) is used. To override, pass a device
    name as the first and only parameter, for example
    \c{QWS_KEYBOARD=qnx:/dev/devi/keyboard1; export QWS_KEYBOARD}.

    \sa {Qt for Embedded Linux Character Input}, {Qt for Embedded Linux}
*/

/*!
    Constructs a keyboard handler for the specified \a device, defaulting to
    \c{/dev/devi/keyboard0}.

    Note that you should never instanciate this class, instead let QKbdDriverFactory
    handle the keyboard handlers.

    \sa QKbdDriverFactory
 */
QWSQnxKeyboardHandler::QWSQnxKeyboardHandler(const QString &device)
{
    // open the keyboard device
    keyboardFD = QT_OPEN(device.isEmpty() ? "/dev/devi/keyboard0" : device.toLatin1().constData(),
                         QT_OPEN_RDONLY);
    if (keyboardFD == -1) {
        qErrnoWarning(errno, "QWSQnxKeyboardHandler: Unable to open device");
        return;
    }

    // create a socket notifier so we'll wake up whenever keyboard input is detected.
    QSocketNotifier *notifier = new QSocketNotifier(keyboardFD, QSocketNotifier::Read, this);
    connect(notifier, SIGNAL(activated(int)), SLOT(socketActivated()));

    qDebug() << "QWSQnxKeyboardHandler: connected.";

}

/*!
    Destroys this keyboard handler and closes the connection to the keyboard device.
 */
QWSQnxKeyboardHandler::~QWSQnxKeyboardHandler()
{
    QT_CLOSE(keyboardFD);
}

/*! \internal
    Translates the QNX keyboard events to Qt keyboard events
 */
void QWSQnxKeyboardHandler::socketActivated()
{
    _keyboard_packet packet;

    // read one keyboard event
    int bytesRead = QT_READ(keyboardFD, &packet, sizeof(_keyboard_packet));
    if (bytesRead == -1) {
        qErrnoWarning(errno, "QWSQnxKeyboardHandler::socketActivated(): Unable to read data.");
        return;
    }

    // the bytes read must be the size of a keyboard packet
    Q_ASSERT(bytesRead == sizeof(_keyboard_packet));

#if 0
    qDebug() << "keyboard got scancode"
             << hex << packet.data.modifiers
             << packet.data.flags
             << packet.data.key_cap
             << packet.data.key_sym
             << packet.data.key_scan;
#endif

    // QNX is nice enough to translate the raw keyboard data into a QNX data structure
    // Now we just have to translate it into a format Qt understands.

    // figure out whether it's a press
    bool isPress = packet.data.key_cap & KEY_DOWN;
    // figure out wheter the key is still pressed and the key event is repeated
    bool isRepeat = packet.data.key_cap & KEY_REPEAT;

    Qt::Key key = Qt::Key_unknown;
    int unicode = 0xffff;

    // TODO - this switch is not complete!
    switch (packet.data.key_scan) {
    case KEYCODE_SPACE: key = Qt::Key_Space; unicode = 0x20; break;
    case KEYCODE_F1: key = Qt::Key_F1; break;
    case KEYCODE_F2: key = Qt::Key_F2; break;
    case KEYCODE_F3: key = Qt::Key_F3; break;
    case KEYCODE_F4: key = Qt::Key_F4; break;
    case KEYCODE_F5: key = Qt::Key_F5; break;
    case KEYCODE_F6: key = Qt::Key_F6; break;
    case KEYCODE_F7: key = Qt::Key_F7; break;
    case KEYCODE_F8: key = Qt::Key_F8; break;
    case KEYCODE_F9: key = Qt::Key_F9; break;
    case KEYCODE_F10: key = Qt::Key_F10; break;
    case KEYCODE_F11: key = Qt::Key_F11; break;
    case KEYCODE_F12: key = Qt::Key_F12; break;
    case KEYCODE_BACKSPACE: key = Qt::Key_Backspace; break;
    case KEYCODE_TAB: key = Qt::Key_Tab; break;
    case KEYCODE_RETURN: key = Qt::Key_Return; break;
    case KEYCODE_KP_ENTER: key = Qt::Key_Enter; break;
    case KEYCODE_UP:
    case KEYCODE_KP_UP:
        key = Qt::Key_Up; break;
    case KEYCODE_DOWN:
    case KEYCODE_KP_DOWN:
        key = Qt::Key_Down; break;
    case KEYCODE_LEFT:
    case KEYCODE_KP_LEFT:
        key = Qt::Key_Left; break;
    case KEYCODE_RIGHT:
    case KEYCODE_KP_RIGHT:
        key = Qt::Key_Right; break;
    case KEYCODE_HOME:
    case KEYCODE_KP_HOME:
        key = Qt::Key_Home; break;
    case KEYCODE_END:
    case KEYCODE_KP_END:
        key = Qt::Key_End; break;
    case KEYCODE_PG_UP:
    case KEYCODE_KP_PG_UP:
        key = Qt::Key_PageUp; break;
    case KEYCODE_PG_DOWN:
    case KEYCODE_KP_PG_DOWN:
        key = Qt::Key_PageDown; break;
    case KEYCODE_INSERT:
    case KEYCODE_KP_INSERT:
        key = Qt::Key_Insert; break;
    case KEYCODE_DELETE:
    case KEYCODE_KP_DELETE:
        key = Qt::Key_Delete; break;
    case KEYCODE_ESCAPE:
        key = Qt::Key_Escape; break;
    default: // none of the above, try the key_scan directly
        unicode = packet.data.key_scan;
        break;
    }

    // figure out the modifiers that are currently pressed
    Qt::KeyboardModifiers modifiers = Qt::NoModifier;
    if (packet.data.flags & KEYMOD_SHIFT)
        modifiers |= Qt::ShiftModifier;
    if (packet.data.flags & KEYMOD_CTRL)
        modifiers |= Qt::ControlModifier;
    if (packet.data.flags & KEYMOD_ALT)
        modifiers |= Qt::AltModifier;

    // if the unicode value is not ascii, we ignore it.
    // TODO - do a complete mapping between all QNX scan codes and Qt codes
    if (unicode != 0xffff && !isascii(unicode))
        return; // unprintable character

    // call processKeyEvent. This is where all the magic happens to insert a
    // key event into Qt's event loop.
    // Note that for repeated key events, isPress must be true
    // (on QNX, isPress is not set when the key event is repeated).
    processKeyEvent(unicode, key, modifiers, isPress || isRepeat, isRepeat);
}

QT_END_NAMESPACE