diff options
Diffstat (limited to 'src/gui/embedded/qkbdtty_qws.cpp')
-rw-r--r-- | src/gui/embedded/qkbdtty_qws.cpp | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/src/gui/embedded/qkbdtty_qws.cpp b/src/gui/embedded/qkbdtty_qws.cpp new file mode 100644 index 0000000..b588e55 --- /dev/null +++ b/src/gui/embedded/qkbdtty_qws.cpp @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (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 either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qkbdtty_qws.h" + +#if !defined(QT_NO_QWS_KEYBOARD) && !defined(QT_NO_QWS_KBD_TTY) + +#include "qscreen_qws.h" + +#include "qwindowsystem_qws.h" +#include "qapplication.h" +#include "qsocketnotifier.h" +#include "qnamespace.h" +#include "qtimer.h" +#include <private/qwssignalhandler_p.h> +#include <private/qwindowsurface_qws_p.h> + +#include <unistd.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <termios.h> + +#include <qeventloop.h> + +#ifdef Q_OS_LINUX +#include <sys/kd.h> +#include <sys/vt.h> +#endif + +QT_BEGIN_NAMESPACE + +#define VTACQSIG SIGUSR1 +#define VTRELSIG SIGUSR2 + +static int vtQws = 0; +static int kbdFD = -1; + +//=========================================================================== + +// +// Tty keyboard +// + +class QWSTtyKbPrivate : public QObject +{ + Q_OBJECT +public: + QWSTtyKbPrivate(QWSPC101KeyboardHandler *, const QString &device); + ~QWSTtyKbPrivate(); + +private slots: + void readKeyboardData(); + void handleTtySwitch(int); + +private: + QWSPC101KeyboardHandler *handler; + struct termios origTermData; +}; + +QWSTtyKeyboardHandler::QWSTtyKeyboardHandler(const QString &device) + : QWSPC101KeyboardHandler(device) +{ + d = new QWSTtyKbPrivate(this, device); +} + +QWSTtyKeyboardHandler::~QWSTtyKeyboardHandler() +{ + delete d; +} + +void QWSTtyKeyboardHandler::processKeyEvent(int unicode, int keycode, + Qt::KeyboardModifiers modifiers, bool isPress, + bool autoRepeat) +{ +#if defined(Q_OS_LINUX) + // Virtual console switching + int term = 0; + bool ctrl = modifiers & Qt::ControlModifier; + bool alt = modifiers & Qt::AltModifier; + if (ctrl && alt && keycode >= Qt::Key_F1 && keycode <= Qt::Key_F10) + term = keycode - Qt::Key_F1 + 1; + else if (ctrl && alt && keycode == Qt::Key_Left) + term = qMax(vtQws - 1, 1); + else if (ctrl && alt && keycode == Qt::Key_Right) + term = qMin(vtQws + 1, 10); + if (term && isPress) { + ioctl(kbdFD, VT_ACTIVATE, term); + return; + } +#endif + + QWSPC101KeyboardHandler::processKeyEvent(unicode, keycode, modifiers, + isPress, autoRepeat); +} + + +QWSTtyKbPrivate::QWSTtyKbPrivate(QWSPC101KeyboardHandler *h, const QString &device) : handler(h) +{ + kbdFD = ::open(device.isEmpty()?"/dev/tty0":device.toLatin1().constData(), O_RDWR|O_NDELAY, 0); +#ifndef QT_NO_QWS_SIGNALHANDLER + QWSSignalHandler::instance()->addObject(this); +#endif + + if (kbdFD >= 0) { + QSocketNotifier *notifier; + notifier = new QSocketNotifier(kbdFD, QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)),this, + SLOT(readKeyboardData())); + + // save for restore. + tcgetattr(kbdFD, &origTermData); + + struct termios termdata; + tcgetattr(kbdFD, &termdata); + +#if defined(Q_OS_LINUX) +# ifdef QT_QWS_USE_KEYCODES + ioctl(kbdFD, KDSKBMODE, K_MEDIUMRAW); +# else + ioctl(kbdFD, KDSKBMODE, K_RAW); +# endif +#endif + + termdata.c_iflag = (IGNPAR | IGNBRK) & (~PARMRK) & (~ISTRIP); + termdata.c_oflag = 0; + termdata.c_cflag = CREAD | CS8; + termdata.c_lflag = 0; + termdata.c_cc[VTIME]=0; + termdata.c_cc[VMIN]=1; + cfsetispeed(&termdata, 9600); + cfsetospeed(&termdata, 9600); + tcsetattr(kbdFD, TCSANOW, &termdata); + +#if defined(Q_OS_LINUX) + + connect(QApplication::instance(), SIGNAL(unixSignal(int)), this, SLOT(handleTtySwitch(int))); + QApplication::instance()->watchUnixSignal(VTACQSIG, true); + QApplication::instance()->watchUnixSignal(VTRELSIG, true); + + struct vt_mode vtMode; + ioctl(kbdFD, VT_GETMODE, &vtMode); + + // let us control VT switching + vtMode.mode = VT_PROCESS; + vtMode.relsig = VTRELSIG; + vtMode.acqsig = VTACQSIG; + ioctl(kbdFD, VT_SETMODE, &vtMode); + + struct vt_stat vtStat; + ioctl(kbdFD, VT_GETSTATE, &vtStat); + vtQws = vtStat.v_active; +#endif + } else { + qCritical("Cannot open keyboard: %s", strerror(errno)); + } + +} + +QWSTtyKbPrivate::~QWSTtyKbPrivate() +{ + if (kbdFD >= 0) { +#if defined(Q_OS_LINUX) + ioctl(kbdFD, KDSKBMODE, K_XLATE); +#endif + tcsetattr(kbdFD, TCSANOW, &origTermData); + ::close(kbdFD); + kbdFD = -1; + } +} + +void QWSTtyKbPrivate::handleTtySwitch(int sig) +{ +#if defined(Q_OS_LINUX) + if (sig == VTACQSIG) { + if (ioctl(kbdFD, VT_RELDISP, VT_ACKACQ) == 0) { + qwsServer->enablePainting(true); + qt_screen->restore(); + qwsServer->resumeMouse(); + qwsServer->refresh(); + } + } else if (sig == VTRELSIG) { + qwsServer->enablePainting(false); + + // Check for reserved surfaces which might still do painting + bool allWindowsHidden = true; + const QList<QWSWindow*> windows = QWSServer::instance()->clientWindows(); + for (int i = 0; i < windows.size(); ++i) { + const QWSWindow *w = windows.at(i); + QWSWindowSurface *s = w->windowSurface(); + if (s && s->isRegionReserved() && !w->allocatedRegion().isEmpty()) { + allWindowsHidden = false; + break; + } + } + + if (!allWindowsHidden) { + ioctl(kbdFD, VT_RELDISP, 0); // abort console switch + qwsServer->enablePainting(true); + } else if (ioctl(kbdFD, VT_RELDISP, 1) == 0) { + qt_screen->save(); + qwsServer->suspendMouse(); + } else { + qwsServer->enablePainting(true); + } + } +#endif +} + +void QWSTtyKbPrivate::readKeyboardData() +{ + unsigned char buf[81]; + int n = read(kbdFD, buf, 80); + for (int loop = 0; loop < n; loop++) + handler->doKey(buf[loop]); +} + +QT_END_NAMESPACE + +#include "qkbdtty_qws.moc" + +#endif // QT_NO_QWS_KEYBOARD || QT_NO_QWS_KBD_TTY |