/**************************************************************************** ** $Id: qt/src/kernel/qkeyboard_qws.cpp 2.3.7 edited 2003-05-30 $ ** ** Implementation of Qt/Embedded keyboard drivers ** ** Created : 991025 ** ** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. ** ** This file is part of the kernel module of the Qt GUI Toolkit. ** ** This file may be distributed and/or modified under the terms of the ** GNU General Public License version 2 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. ** ** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition ** licenses for Qt/Embedded may use this file in accordance with the ** Qt Embedded Commercial License Agreement provided with the Software. ** ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ** ** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for ** information about Qt Commercial License Agreements. ** See http://www.trolltech.com/gpl/ for GPL licensing information. ** ** Contact info@trolltech.com if any conditions of this licensing are ** not clear to you. ** **********************************************************************/ #include "qwindowsystem_qws.h" #include "qwsutils_qws.h" #include "qgfx_qws.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef QT_NO_QWS_KEYBOARD #include #include #include #include #include #define VTSWITCHSIG SIGUSR2 static bool vtActive = true; static int vtQws = 0; static int kbdFD = -1; static QIntDict *overrideMap = 0; /*! Changes the mapping of the keyboard; adding the scancode to Unicode mappings from \a map. The server takes over ownership of \a map and will delete it. Use QCollection::setAutoDelete() to control whether the contents of \a map should be deleted. Passing a null pointer for \a map will revert to the default keymap. */ void QWSServer::setOverrideKeys( QIntDict *map ) { delete overrideMap; overrideMap = map; } /*! \class QWSKeyboardHandler qkeyboard_qws.h \brief Keyboard driver/handler for Qt/Embedded The keyboard driver/handler handles events from system devices and generates key events. A QWSKeyboardHandler will usually open some system device in its constructor, create a QSocketNotifier on that opened device and when it receives data, it will call processKeyEvent() to send the event to Qt/Embedded for relaying to clients. */ /*! Subclasses call this to send a key event. The server may additionally filter it before sending it on to applications.
  • \a unicode is the Unicode value for the key, or 0xffff if none is appropriate.
  • \a keycode is the Qt keycode for the key (see Qt::Key). for the list of codes).
  • \a modifiers is the set of modifier keys (see Qt::Modifier).
  • \a isPress says whether this is a press or a release.
  • \a autoRepeat says whether this event was generated by an auto-repeat mechanism, or an actual key press.
*/ void QWSKeyboardHandler::processKeyEvent(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat) { qwsServer->processKeyEvent( unicode, keycode, modifiers, isPress, autoRepeat ); } bool qwsSetKeyboardAutoRepeat( int /* delay */ , int /* period */ ) { return FALSE; } bool qwsGetKeyboardAutoRepeat( int /* delay */ , int /* period */ ) { return FALSE; } void qwsRestoreKeyboardLeds() { } /* * Virtual framebuffer keyboard driver */ class QWSVFbKeyboardHandler : public QWSKeyboardHandler { Q_OBJECT public: QWSVFbKeyboardHandler(); virtual ~QWSVFbKeyboardHandler(); bool isOpen() { return fd > 0; } private slots: void readKeyboardData(); private: QString terminalName; int fd; int kbdIdx; int kbdBufferLen; unsigned char *kbdBuffer; QSocketNotifier *notifier; }; #ifndef QT_NO_QWS_VFB #include "qvfbhdr.h" extern int qws_display_id; #endif QWSVFbKeyboardHandler::QWSVFbKeyboardHandler() { kbdFD = -1; #ifndef QT_NO_QWS_VFB kbdIdx = 0; kbdBufferLen = sizeof( QVFbKeyData ) * 5; kbdBuffer = new unsigned char [kbdBufferLen]; terminalName = QString(QT_VFB_KEYBOARD_PIPE).arg(qws_display_id); if ((kbdFD = open( terminalName.local8Bit(), O_RDWR | O_NDELAY)) < 0) { qDebug( "Cannot open %s (%s)", terminalName.latin1(), strerror(errno)); } else { // Clear pending input char buf[2]; while (read(kbdFD, buf, 1) > 0) { } notifier = new QSocketNotifier( kbdFD, QSocketNotifier::Read, this ); connect(notifier, SIGNAL(activated(int)),this, SLOT(readKeyboardData())); } #endif } QWSVFbKeyboardHandler::~QWSVFbKeyboardHandler() { #ifndef QT_NO_QWS_VFB if ( kbdFD >= 0 ) close( kbdFD ); delete [] kbdBuffer; #endif } void QWSVFbKeyboardHandler::readKeyboardData() { #ifndef QT_NO_QWS_VFB int n; do { n = read(kbdFD, kbdBuffer+kbdIdx, kbdBufferLen - kbdIdx ); if ( n > 0 ) kbdIdx += n; } while ( n > 0 ); int idx = 0; while ( kbdIdx - idx >= (int)sizeof( QVFbKeyData ) ) { QVFbKeyData *kd = (QVFbKeyData *)(kbdBuffer + idx); if ( kd->unicode == 0 && kd->modifiers == 0 && kd->press ) { // magic exit key qWarning( "Instructed to quit by Virtual Keyboard" ); qApp->quit(); } processKeyEvent( kd->unicode&0xffff, kd->unicode>>16, kd->modifiers, kd->press, kd->repeat ); idx += sizeof( QVFbKeyData ); } int surplus = kbdIdx - idx; for ( int i = 0; i < surplus; i++ ) kbdBuffer[i] = kbdBuffer[idx+i]; kbdIdx = surplus; #endif } struct termios origTermData; static void init_kbd(void) { struct termios termdata; tcgetattr( kbdFD, &origTermData ); tcgetattr( kbdFD, &termdata ); ioctl(kbdFD, KDSKBMODE, K_XLATE); 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); } static void done_kbd(void) { if (kbdFD >= 0) { tcsetattr(kbdFD, TCSANOW, &origTermData); } } static void vtSwitchHandler(int /*sig*/) { if (vtActive) { qwsServer->enablePainting(false); qt_screen->save(); if (ioctl(kbdFD, VT_RELDISP, VT_ACKACQ) == 0) { vtActive = false; qwsServer->closeMouse(); done_kbd(); } else { qwsServer->enablePainting(true); } usleep(200000); } else { if (ioctl(kbdFD, VT_RELDISP, VT_ACKACQ) == 0) { init_kbd(); qwsServer->enablePainting(true); vtActive = true; qt_screen->restore(); qwsServer->openMouse(); qwsServer->refresh(); } } signal(VTSWITCHSIG, vtSwitchHandler); } class QWSRamsesKbPrivate; class QWSRamsesKeyboardHandler : public QWSKeyboardHandler { public: QWSRamsesKeyboardHandler( const QString& ); virtual ~QWSRamsesKeyboardHandler(); virtual void processKeyEvent(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat); private: QWSRamsesKbPrivate *d; }; class QWSRamsesKbPrivate : public QObject { Q_OBJECT public: QWSRamsesKbPrivate( QWSRamsesKeyboardHandler *, const QString &device ); ~QWSRamsesKbPrivate(); private slots: void readKeyboardData(); private: void handleKey(unsigned char code, int n); QWSRamsesKeyboardHandler *handler; char rbuf[255]; int rptr; }; QWSRamsesKbPrivate::QWSRamsesKbPrivate( QWSRamsesKeyboardHandler *h, const QString &device ) : handler(h), rptr(0) { #ifdef QT_QWS_DEVFS kbdFD = ::open(device.isEmpty()?"/dev/vc/2":device.latin1(), O_RDWR|O_NDELAY, 0); #else kbdFD = ::open(device.isEmpty()?"/dev/tty2":device.latin1(), O_RDWR|O_NDELAY, 0); #endif if ( kbdFD >= 0 ) { QSocketNotifier *notifier; notifier = new QSocketNotifier( kbdFD, QSocketNotifier::Read, this ); connect( notifier, SIGNAL(activated(int)),this, SLOT(readKeyboardData()) ); } else { qDebug( "Cannot open keyboard" ); } init_kbd(); struct vt_mode vtMode; ioctl(kbdFD, VT_GETMODE, &vtMode); // let us control VT switching vtMode.mode = VT_PROCESS; vtMode.relsig = VTSWITCHSIG; vtMode.acqsig = VTSWITCHSIG; ioctl(kbdFD, VT_SETMODE, &vtMode); struct vt_stat vtStat; ioctl(kbdFD, VT_GETSTATE, &vtStat); vtQws = vtStat.v_active; signal(VTSWITCHSIG, vtSwitchHandler); } QWSRamsesKbPrivate::~QWSRamsesKbPrivate() { signal(VTSWITCHSIG, 0); done_kbd(); struct vt_mode vtMode; ioctl(kbdFD, VT_GETMODE, &vtMode); /* Mickey says: "Better give up control of VT switching. * Hey, I really hate that OS-will-reacquire-resources on process-death * kind of thinking! */ vtMode.mode = VT_AUTO; vtMode.relsig = 0; vtMode.acqsig = 0; ioctl(kbdFD, VT_SETMODE, &vtMode); ::close(kbdFD); kbdFD = -1; } static inline int map_to_modif(int current_map) { int modifiers = 0; if (current_map & KG_ALT) modifiers |= Qt::ALT; else if (current_map & KG_CTRL) modifiers |= Qt::CTRL; else if (current_map & KG_SHIFT) modifiers |= Qt::SHIFT; return modifiers; } struct { const char *code; unsigned short qtcode; } qtesc_lookup[] = { { "\e[A", Qt::Key_Up }, { "\e[B", Qt::Key_Down }, { "\e[C", Qt::Key_Right }, { "\e[D", Qt::Key_Left }, { "\e[1~", Qt::Key_Home }, { "\e[4~", Qt::Key_End }, { "\e[5~", Qt::Key_PageUp }, { "\e[6~", Qt::Key_PageDown }, { "\e[[A", Qt::Key_F1 }, { "\e[[B", Qt::Key_F2 }, { "\e[[C", Qt::Key_F3 }, { "\e[[D", Qt::Key_F4 }, { "\e[[E", Qt::Key_F5 }, { "\e[17~", Qt::Key_F6 }, { "\e[18~", Qt::Key_F7 }, { "\e[19~", Qt::Key_F8 }, { "\e[20~", Qt::Key_F9 }, { "\e[21~", Qt::Key_F10 }, { "\e[23~", Qt::Key_F11 }, { "\e[24~", Qt::Key_F12 }, // { "\ex", Qt::FieldExit }, // { "\er", Qt::FieldReset }, }; struct { unsigned char code; unsigned short qtcode; } qtkey_lookup[] = { { 0x08, Qt::Key_Backspace }, { 0x09, Qt::Key_Tab }, { 0x0d, Qt::Key_Enter }, { 0x1b, Qt::Key_Escape }, }; void QWSRamsesKbPrivate::handleKey(unsigned char code, int n) { int qtKeyCode = Qt::Key_unknown; unsigned int i; //qDebug("\nhandleKey %02x %d %c", code, n, code >= ' ' ? code : ' '); // Single keys if ((n==1) && (rptr==0)) { qtKeyCode = code; for (i=0; i < sizeof(qtkey_lookup)/sizeof(qtkey_lookup[0]); i++) { if (qtkey_lookup[i].code == code) { qtKeyCode = qtkey_lookup[i].qtcode; code = 0; break; } } } else // Alt- sequence if ((n==1) && (rptr==1) && (rbuf[0] == '\e')) { //qDebug("alt-key %d", code); handler->processKeyEvent(0, Qt::Key_Alt, 0, 1, 0); handler->processKeyEvent(0, code-32, Qt::ALT, 1, 0); handler->processKeyEvent(0, code-32, Qt::ALT, 0, 0); handler->processKeyEvent(0, Qt::Key_Alt, 0, 0, 0); rptr = 0; return; } else // End of a function key sequence if ((n==1) && (rptr!=0)) { rbuf[rptr++] = code; rbuf[rptr] = 0; for (i=0; i < sizeof(qtesc_lookup)/sizeof(qtesc_lookup[0]); i++) { if (strncmp(rbuf, qtesc_lookup[i].code, sizeof(rbuf)) == 0) { qtKeyCode = qtesc_lookup[i].qtcode; code = 0; break; } } if (code != 0) { //qWarning("no entry in key sequence table for %s", &rbuf[1]); int oldrptr = rptr; rptr = 0; for (i=0; i <= oldrptr; i++) { handleKey(rbuf[i], 1); } return; } rptr = 0; } else // Middle of a function key sequence { if (rptr < sizeof(rbuf)) rbuf[rptr++] = code; return; } //qDebug(" code 0x%2x %d -> qtKeyCode 0x%04x", code, code, qtKeyCode); handler->processKeyEvent(code, qtKeyCode, 0, 1, 0); handler->processKeyEvent(code, qtKeyCode, 0, 0, 0); } void QWSRamsesKbPrivate::readKeyboardData() { unsigned char buf[81]; int n = read(kbdFD, buf, 80 ); for ( int loop = 0; loop < n; loop++ ) { handleKey(buf[loop], n-loop); } } QWSRamsesKeyboardHandler::QWSRamsesKeyboardHandler( const QString &device ) { d = new QWSRamsesKbPrivate( this, device ); } QWSRamsesKeyboardHandler::~QWSRamsesKeyboardHandler() { delete d; } void QWSRamsesKeyboardHandler::processKeyEvent(int unicode, int keycode, int modifiers, bool isPress, bool autoRepeat) { // Virtual console switching int term = 0; bool ctrl = modifiers & Qt::ControlButton; bool alt = modifiers & Qt::AltButton; 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; } QWSKeyboardHandler::processKeyEvent( unicode, keycode, modifiers, isPress, autoRepeat ); } /* * keyboard driver instantiation */ QWSKeyboardHandler *QWSServer::newKeyboardHandler( const QString &spec ) { QWSKeyboardHandler *handler = 0; QString device; QString type; int colon=spec.find(':'); if ( colon>=0 ) { type = spec.left(colon); device = spec.mid(colon+1); } else { type = spec; } if ( type == "QVFbKeyboard" ) { handler = new QWSVFbKeyboardHandler(); } else if ( type == "TTY" ) { handler = new QWSRamsesKeyboardHandler(device); } else { qWarning( "Keyboard type %s:%s unsupported", spec.latin1(), device.latin1() ); } return handler; } #include "qkeyboard_qws.moc" #endif // QT_NO_QWS_KEYBOARD