Diffstat (limited to 'noncore/comm/keypebble/krfbdecoder.cpp') (more/less context) (ignore whitespace changes)
-rw-r--r-- | noncore/comm/keypebble/krfbdecoder.cpp | 839 |
1 files changed, 839 insertions, 0 deletions
diff --git a/noncore/comm/keypebble/krfbdecoder.cpp b/noncore/comm/keypebble/krfbdecoder.cpp new file mode 100644 index 0000000..174dd7b --- a/dev/null +++ b/noncore/comm/keypebble/krfbdecoder.cpp @@ -0,0 +1,839 @@ +#include "krfbconnection.h" +#include "krfboptions.h" +#include "krfbserverinfo.h" +#include "krfbdecoder.h" +#include "krfbbuffer.h" + +#include <qpe/qpeapplication.h> + +#include <qpixmap.h> +#include <qsocket.h> +#include <qevent.h> +#include <qstring.h> +#include <qclipboard.h> + +#include <assert.h> + +// +// Endian stuff +// +#ifndef KDE_USE_FINAL +const int endianTest = 1; +#endif + +#define Swap16IfLE(s) \ + (*(char *)&endianTest ? ((((s) & 0xff) << 8) | (((s) >> 8) & 0xff)) : (s)) + +#define Swap32IfLE(l) \ + (*(char *)&endianTest ? ((((l) & 0xff000000) >> 24) | \ + (((l) & 0x00ff0000) >> 8) | \ + (((l) & 0x0000ff00) << 8) | \ + (((l) & 0x000000ff) << 24)) : (l)) + +// +// The lengths of the messages we need to wait for +// +const int ServerInitLength = 24; +const int UpdateHeaderLength = 4; +const int RectHeaderLength = 12; +const int RectChunkSize = 4; +const int CopyRectPosLength = 4; +const int ServerCutLenLength = 7; + +// +// Client -> Server Message Identifiers +// +static CARD8 SetPixelFormatId = 0; +//static CARD8 FixColourMapEntriesId = 1; // Not used +static CARD8 SetEncodingsId = 2; +static CARD8 UpdateRequestId = 3; +static CARD8 KeyEventId = 4; +static CARD8 PointerEventId = 5; +static CARD8 ClientCutTextId = 6; + +// +// Server -> Client Message Identifiers +// +static CARD8 UpdateId = 0; +static CARD8 BellId = 2; +static CARD8 ServerCutId = 3; + +// +// Encoding identifiers +// +static CARD32 RawEncoding = Swap32IfLE( 0 ); +static CARD32 CopyRectEncoding = Swap32IfLE(1 ); +static CARD32 RreEncoding = Swap32IfLE( 2 ); +static CARD32 CorreEncoding = Swap32IfLE( 4 ); +static CARD32 HexTileEncoding = Swap32IfLE( 5 ); + +static struct { + int keysym; + int keycode; +} keyMap[] = { + { 0xff08, Qt::Key_Backspace }, + { 0xff09, Qt::Key_Tab }, + { 0xff0d, Qt::Key_Return }, + { 0xff1b, Qt::Key_Escape }, + { 0xff63, Qt::Key_Insert }, + { 0xffff, Qt::Key_Delete }, + { 0xff50, Qt::Key_Home }, + { 0xff57, Qt::Key_End }, + { 0xff55, Qt::Key_Prior }, + { 0xff56, Qt::Key_Next }, + { 0xff51, Qt::Key_Left }, + { 0xff52, Qt::Key_Up }, + { 0xff53, Qt::Key_Right }, + { 0xff54, Qt::Key_Down }, + { 0xffbe, Qt::Key_F1 }, + { 0xffbf, Qt::Key_F2 }, + { 0xffc0, Qt::Key_F3 }, + { 0xffc1, Qt::Key_F4 }, + { 0xffc2, Qt::Key_F5 }, + { 0xffc3, Qt::Key_F6 }, + { 0xffc4, Qt::Key_F7 }, + { 0xffc5, Qt::Key_F8 }, + { 0xffc6, Qt::Key_F9 }, + { 0xffc7, Qt::Key_F10 }, + { 0xffc8, Qt::Key_F11 }, + { 0xffc9, Qt::Key_F12 }, + { 0xffe1, Qt::Key_Shift }, + { 0xffe2, Qt::Key_Shift }, + { 0xffe3, Qt::Key_Control }, + { 0xffe4, Qt::Key_Control }, + { 0xffe7, Qt::Key_Meta }, + { 0xffe8, Qt::Key_Meta }, + { 0xffe9, Qt::Key_Alt }, + { 0xffea, Qt::Key_Alt }, + { 0, 0 } +}; + + +KRFBDecoder::KRFBDecoder( KRFBConnection *con ) + : QObject( con, "RFB Decoder" ) +{ + assert( con ); + assert( con->state() == KRFBConnection::Connected ); + + this->con = con; + this->buf = 0; + this->info = 0; + this->format = 0; + this->buttonMask = 0; + currentState = Idle; +} + +KRFBDecoder::~KRFBDecoder() +{ + if ( info ) + delete info; + if ( format ) + delete format; +} + +void KRFBDecoder::start() +{ + sendClientInit(); +} + +void KRFBDecoder::sendClientInit() +{ + con->write( &( con->options()->shared ), 1 ); + + // Wait for server init + qWarning( "Waiting for server init" ); + + static QString statusMsg = tr( "Waiting for server initialisation..." ); + emit status( statusMsg ); + + currentState = AwaitingServerInit; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotServerInit() ) ); + con->waitForData( ServerInitLength ); +} + +void KRFBDecoder::gotServerInit() +{ + qWarning( "Got server init" ); + disconnect( con, SIGNAL( gotEnoughData() ), this, SLOT( gotServerInit() ) ); + + if ( info ) + delete info; + info = new KRFBServerInfo; + CHECK_PTR( info ); + + con->read( &(info->width), 2 ); + info->width = Swap16IfLE( info->width ); + con->read( &info->height, 2 ); + info->height = Swap16IfLE( info->height ); + + con->read( &(info->bpp), 1 ); + con->read( &(info->depth), 1 ); + con->read( &(info->bigEndian), 1 ); + con->read( &(info->trueColor), 1 ); + + con->read( &(info->redMax), 2 ); + info->redMax = Swap16IfLE( info->redMax ); + con->read( &(info->greenMax), 2 ); + info->greenMax = Swap16IfLE( info->greenMax ); + con->read( &(info->blueMax), 2 ); + info->blueMax = Swap16IfLE( info->blueMax ); + + con->read( &(info->redShift), 1 ); + con->read( &(info->greenShift), 1 ); + con->read( &(info->blueShift), 1 ); + + con->read( info->padding, 3 ); + + con->read( &(info->nameLength), 4 ); + info->nameLength = Swap32IfLE( info->nameLength ); + + qWarning( "Width = %d, Height = %d", info->width, info->height ); + qWarning( "Bpp = %d, Depth = %d, Big = %d, True = %d", + info->bpp, info->depth, info->bigEndian, info->trueColor ); + qWarning( "RedMax = %d, GreenMax = %d, BlueMax = %d", + info->redMax, info->greenMax, info->blueMax ); + qWarning( "RedShift = %d, GreenShift = %d, BlueShift = %d", + info->redShift, info->greenShift,info-> blueShift ); + + buf->resize( info->width, info->height ); + + // Wait for desktop name + qWarning( "Waiting for desktop name" ); + + static QString statusMsg = tr( "Waiting for desktop name..." ); + emit status( statusMsg ); + + currentState = AwaitingDesktopName; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotDesktopName() ) ); + con->waitForData( info->nameLength ); +} + +void KRFBDecoder::gotDesktopName() +{ + assert( info ); + assert( currentState == AwaitingDesktopName ); + + qWarning( "Got desktop name" ); + + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotDesktopName() ) ); + + char *buf = new char[ info->nameLength + 1 ]; + CHECK_PTR( buf ); + + con->read( buf, info->nameLength ); + buf[ info->nameLength ] = '\0'; + info->name = buf; + + qWarning( "Desktop: %s", info->name.latin1() ); + + delete buf; + + // Get the format we'll really use and tell the server + decidePixelFormat(); + sendPixelFormat(); + sendAllowedEncodings(); + currentState = Idle; + + QString msg; + msg = tr( "Connected to %1" ); + msg = msg.arg( info->name ); + emit status( msg ); + + sendUpdateRequest( false ); +} + +void KRFBDecoder::decidePixelFormat() +{ + assert( info ); + + if ( format ) + delete format; + format = new KRFBPixelFormat; + CHECK_PTR( format ); + + // What depth do we want? + // + // We'll use the minimum of the remote and local depths, UNLESS an + // eight bit session has been specifically requested by the user. + int screenDepth = QPixmap::defaultDepth(); + int bestDepth = ( screenDepth > info->depth ) ? info->depth : screenDepth; + int chosenDepth; + + if ( con->options()->colors256 ) + chosenDepth = 8; + else + chosenDepth = bestDepth; + + qWarning( "Screen depth=%d, server depth=%d, best depth=%d, " \ + "eight bit %d, chosenDepth=%d", + screenDepth, + info->depth, + bestDepth, + con->options()->colors256, chosenDepth ); + + format->depth = chosenDepth; + + // If we're using the servers native depth + if ( chosenDepth == info->depth ) { + // Use the servers native format + format->bpp = info->bpp; + // format->bigEndian = info->bigEndian; + format->bigEndian = true; + format->trueColor = info->trueColor; + format->redMax = info->redMax; + format->greenMax = info->greenMax; + format->blueMax = info->blueMax; + format->redShift = info->redShift; + format->greenShift = info->greenShift; + format->blueShift = info->blueShift; + } + else { + if ( chosenDepth == 8 ) { + format->bpp = 8; + format->bigEndian = true; + format->trueColor = true; + format->redMax = 7; + format->greenMax = 7; + format->blueMax = 3; + format->redShift = 0; + format->greenShift = 3; + format->blueShift = 6; + } + } + + format->redMax = Swap16IfLE( format->redMax ); + format->greenMax = Swap16IfLE( format->greenMax ); + format->blueMax = Swap16IfLE( format->blueMax ); +} + +void KRFBDecoder::sendPixelFormat() +{ + static char padding[3]; + con->write( &SetPixelFormatId, 1 ); + con->write( padding, 3 ); + + con->write( &(format->bpp), 1 ); + con->write( &(format->depth), 1 ); + con->write( &(format->bigEndian), 1 ); + con->write( &(format->trueColor), 1 ); + + con->write( &(format->redMax), 2 ); + con->write( &(format->greenMax), 2 ); + con->write( &(format->blueMax), 2 ); + + con->write( &(format->redShift), 1 ); + con->write( &(format->greenShift), 1 ); + con->write( &(format->blueShift), 1 ); + con->write( format->padding, 3 ); // Padding +} + +void KRFBDecoder::sendAllowedEncodings() +{ + static CARD8 padding[1]; + con->write( &SetEncodingsId, 1 ); + con->write( padding, 1 ); + + static CARD16 noEncodings = con->options()->encodings(); + noEncodings = Swap16IfLE( noEncodings ); + con->write( &noEncodings, 2 ); + + if ( con->options()->corre ) + con->write( &CorreEncoding, 4 ); + if ( con->options()->hexTile ) + con->write( &HexTileEncoding, 4 ); + if ( con->options()->rre ) + con->write( &RreEncoding, 4 ); + if ( con->options()->copyrect ) + con->write( &CopyRectEncoding, 4 ); + // We always support this + con->write( &RawEncoding, 4 ); +} + +void KRFBDecoder::sendUpdateRequest( bool incremental ) +{ + if ( currentState != Idle ) + return; + + con->write( &UpdateRequestId, 1 ); + con->write( &incremental, 1 ); + + static CARD16 x = 0, y = 0; + static CARD16 w = Swap16IfLE( info->width ); + static CARD16 h = Swap16IfLE( info->height ); + + con->write( &x, 2 ); + con->write( &y, 2 ); + con->write( &w, 2 ); + con->write( &h, 2 ); + + // Now wait for the update + currentState = AwaitingUpdate; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotUpdateHeader() ) ); + con->waitForData( UpdateHeaderLength ); +} + +void KRFBDecoder::gotUpdateHeader() +{ + assert( currentState == AwaitingUpdate ); + + // qWarning( "Got update header" ); + + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotUpdateHeader() ) ); + + CARD8 msgType; + con->read( &msgType, 1 ); + + if ( msgType != UpdateId ) { + // We might have a bell or server cut + if ( msgType == ServerCutId ) { + oldState = currentState; + gotServerCut(); + } + else if ( msgType == BellId ) { + oldState = currentState; + gotBell(); + } + else { + int msg = msgType; + QString protocolError = tr( "Protocol Error: Message Id %1 was " + "found when expecting an update " + "message." ).arg( msg ); + currentState = Error; + emit error( protocolError ); + } + return; + } + + CARD8 padding; + con->read( &padding, 1 ); + + con->read( &noRects, 2 ); + noRects = Swap16IfLE( noRects ); + + // qWarning( "Expecting %d rects", noRects ); + + // Now wait for the data + currentState = AwaitingRectHeader; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotRectHeader() ) ); + con->waitForData( RectHeaderLength ); +} + +void KRFBDecoder::gotRectHeader() +{ + assert( currentState == AwaitingRectHeader ); + + // qWarning( "Got rect header" ); + + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotRectHeader() ) ); + + con->read( &x, 2 ); + x = Swap16IfLE( x ); + con->read( &y, 2 ); + y = Swap16IfLE( y ); + + con->read( &w, 2 ); + w = Swap16IfLE( w ); + con->read( &h, 2 ); + h = Swap16IfLE( h ); + + con->read( &encoding, 4 ); + + // CARD32 encodingLocal = Swap32IfLE( encoding ); + // qWarning( "Rect: x=%d, y= %d, w=%d, h=%d, encoding=%ld", + // x, y, w, h, encodingLocal ); + + // + // Each encoding needs to be handled differently. Some require + // waiting for more data, but others like a copyrect do not. + // Our constants have already been byte swapped, so we use + // the remote value as is. + // + if ( encoding == RawEncoding ) { + // qWarning( "Raw encoding" ); + handleRawRect(); + } + else if ( encoding == CopyRectEncoding ) { +// qWarning( "CopyRect encoding" ); + handleCopyRect(); + } + else if ( encoding == RreEncoding ) { + qWarning( "RRE encoding" ); + handleRRERect(); + } + else if ( encoding == CorreEncoding ) { + qWarning( "CoRRE encoding" ); + handleCoRRERect(); + } + else if ( encoding == HexTileEncoding ) { + qWarning( "HexTile encoding" ); + handleHexTileRect(); + } + else { + int msg = Swap32IfLE( encoding ); + QString protocolError = tr( "Protocol Error: An unknown encoding was " + "used by the server %1" ).arg( msg ); + currentState = Error; + qWarning( "Unknown encoding, %d", msg ); + emit error( protocolError ); + return; + } +} + +// +// Raw Encoding +// + +void KRFBDecoder::handleRawRect() +{ + // We need something a bit cleverer here to handle large + // rectanges nicely. The chunking should be based on the + // overall size (but has to be in complete lines). + + // qWarning( "Handling a raw rect chunk" ); + + // CARD32 lineCount = w * format->bpp / 8; + + if ( h > RectChunkSize ) { + // if ( con->sock->size() / lineCount ) { + // getRawRectChunk( con->sock->size() / lineCount ); + // } + // else { + getRawRectChunk( RectChunkSize ); + // } + } + else { + getRawRectChunk( h ); + } +} + +void KRFBDecoder::getRawRectChunk( int lines ) +{ + this->lines = lines; + CARD32 count = lines * w * format->bpp / 8; + + // Wait for server init + // qWarning( "Waiting for raw rect chunk, %ld", count ); + + currentState = AwaitingRawRectChunk; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotRawRectChunk() ) ); + con->waitForData( count ); +} + +void KRFBDecoder::gotRawRectChunk() +{ + assert( currentState == AwaitingRawRectChunk ); + + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotRawRectChunk() ) ); + + // qWarning( "Got raw rect chunk" ); + + // + // Read the rect data and copy it to the buffer. + // + + // TODO: Replace this! + int count = lines * w * format->bpp / 8; + char *hack = new char[ count ]; + con->read( hack, count ); + buf->drawRawRectChunk( hack, x, y, w, lines ); + delete hack; + // /TODO: + + h = h - lines; + y = y + lines; + + if ( h > 0 ) { + handleRawRect(); + } + else { + noRects--; + + // qWarning( "There are %d rects left", noRects ); + + if ( noRects ) { + currentState = AwaitingRectHeader; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotRectHeader() ) ); + con->waitForData( RectHeaderLength ); + } + else + currentState = Idle; + } +} + +// +// Copy Rectangle Encoding +// + +void KRFBDecoder::handleCopyRect() +{ + currentState = AwaitingCopyRectPos; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotCopyRectPos() ) ); + con->waitForData( CopyRectPosLength ); +} + +void KRFBDecoder::gotCopyRectPos() +{ + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotCopyRectPos() ) ); + + CARD16 srcX; + CARD16 srcY; + + con->read( &srcX, 2 ); + con->read( &srcY, 2 ); + + srcX = Swap16IfLE( srcX ); + srcY = Swap16IfLE( srcY ); + + buf->copyRect( srcX, srcY, x, y, w, h ); + + noRects--; + + // qWarning( "There are %d rects left", noRects ); + + if ( noRects ) { + currentState = AwaitingRectHeader; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotRectHeader() ) ); + con->waitForData( RectHeaderLength ); + } + else + currentState = Idle; +} + +void KRFBDecoder::handleRRERect() +{ + qWarning( "RRE not implemented" ); +} + +void KRFBDecoder::handleCoRRERect() +{ + qWarning( "CoRRE not implemented" ); +} + +void KRFBDecoder::handleHexTileRect() +{ + qWarning( "HexTile not implemented" ); +} + +void KRFBDecoder::sendMouseEvent( QMouseEvent *e ) +{ + // Deal with the buttons + if ( e->type() != QEvent::MouseMove ) { + buttonMask = 0; + if ( e->type() == QEvent::MouseButtonPress ) { + if ( e->button() & LeftButton ) + buttonMask |= 0x01; + if ( e->button() & MidButton ) + buttonMask |= 0x04; + if ( e->button() & RightButton ) + buttonMask |= 0x02; + } + else if ( e->type() == QEvent::MouseButtonRelease ) { + if ( e->button() & LeftButton ) + buttonMask &= 0x06; + if ( e->button() & MidButton ) + buttonMask |= 0x03; + if ( e->button() & RightButton ) + buttonMask |= 0x05; + } + } + + CARD16 x = Swap16IfLE( e->x() ); + CARD16 y = Swap16IfLE( e->y() ); + + con->write( &PointerEventId, 1 ); + con->write( &buttonMask, 1 ); + con->write( &x, 2 ); + con->write( &y, 2 ); +} + + +void KRFBDecoder::sendCutEvent( const QString &unicode ) +{ + // + // Warning: There is a bug in the RFB protocol because there is no way to find + // out the codepage in use on the remote machine. This could be fixed by requiring + // the remote server to use utf8 etc. but for now we have to assume they're the + // same. I've reported this problem to the ORL guys, but they apparantly have no + // immediate plans to fix the issue. :-( (rich) + // + + CARD8 padding[3]; + QCString text = unicode.local8Bit(); + CARD32 length = text.length(); + length = Swap32IfLE( length ); + + con->write( &ClientCutTextId, 1 ); + con->write( &padding, 3 ); + con->write( &length, 4 ); + con->write( text.data(), length ); +} + +void KRFBDecoder::gotServerCut() +{ + qWarning( "Got server cut" ); + + currentState = AwaitingServerCutLength; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotServerCutLength() ) ); + con->waitForData( ServerCutLenLength ); +} + +void KRFBDecoder::gotServerCutLength() +{ + assert( currentState = AwaitingServerCutLength ); + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotServerCutLength() ) ); + + CARD8 padding[3]; + con->read( padding, 3 ); + + con->read( &serverCutTextLen, 4 ); + serverCutTextLen = Swap32IfLE( serverCutTextLen ); + + currentState = AwaitingServerCutText; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotServerCutText() ) ); + con->waitForData( serverCutTextLen ); +} + +void KRFBDecoder::gotServerCutText() +{ + assert( currentState = AwaitingServerCutText ); + + disconnect( con, SIGNAL( gotEnoughData() ), + this, SLOT( gotServerCutText() ) ); + + // + // Warning: There is a bug in the RFB protocol because there is no way to find + // out the codepage in use on the remote machine. This could be fixed by requiring + // the remote server to use utf8 etc. but for now we have to assume they're the + // same. I've reported this problem to the ORL guys, but they apparantly have no + // immediate plans to fix the issue. :-( (rich) + // + + char *cutbuf = new char[ serverCutTextLen + 1 ]; + CHECK_PTR( cutbuf ); + + con->read( cutbuf, serverCutTextLen ); + cutbuf[ serverCutTextLen ] = '\0'; + + qWarning( "Server cut: %s", cutbuf ); + + QString cutText( cutbuf ); // DANGER!! + qApp->clipboard()->setText( cutText ); + + delete cutbuf; + + // Now wait for the update (again) + if ( oldState == AwaitingUpdate ) { + currentState = AwaitingUpdate; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotUpdateHeader() ) ); + con->waitForData( UpdateHeaderLength ); + } + else if ( oldState == Idle ) { + currentState = Idle; + } + else { + qWarning( "Async handled in weird state" ); + currentState = oldState; + }; +} + +void KRFBDecoder::gotBell() +{ + qWarning( "Got server bell" ); + buf->soundBell(); + + // Now wait for the update (again) + if ( oldState == AwaitingUpdate ) { + currentState = AwaitingUpdate; + connect( con, SIGNAL( gotEnoughData() ), SLOT( gotUpdateHeader() ) ); + con->waitForData( UpdateHeaderLength ); + } + else if ( oldState == Idle ) { + currentState = Idle; + } + else { + qWarning( "Async handled in weird state" ); + currentState = oldState; + }; +} + +void KRFBDecoder::sendKeyPressEvent( QKeyEvent *event ) +{ + int key; + key = toKeySym( event ); + if ( key ) { + key = Swap32IfLE( key ); + + CARD8 mask = true; + + CARD16 padding = 0; + con->write( &KeyEventId, 1 ); + con->write( &mask, 1 ); + con->write( &padding, 2 ); + con->write( &key, 4 ); + } +} + +void KRFBDecoder::sendKeyReleaseEvent( QKeyEvent *event ) +{ + int key; + key = toKeySym( event ); + if ( key ) { + key = Swap32IfLE( key ); + + CARD8 mask = false; + + CARD16 padding = 0; + con->write( &KeyEventId, 1 ); + con->write( &mask, 1 ); + con->write( &padding, 2 ); + con->write( &key, 4 ); + } +} + +int KRFBDecoder::toKeySym( QKeyEvent *k ) +{ + int ke = 0; + + ke = k->ascii(); + // Markus: Crappy hack. I dont know why lower case letters are + // not defined in qkeydefs.h. The key() for e.g. 'l' == 'L'. + // This sucks. :-( + + if ( (ke == 'a') || (ke == 'b') || (ke == 'c') || (ke == 'd') + || (ke == 'e') || (ke == 'f') || (ke == 'g') || (ke == 'h') + || (ke == 'i') || (ke == 'j') || (ke == 'k') || (ke == 'l') + || (ke == 'm') || (ke == 'n') || (ke == 'o') || (ke == 'p') + || (ke == 'q') || (ke == 'r') || (ke == 's') || (ke == 't') + || (ke == 'u') || (ke == 'v') ||( ke == 'w') || (ke == 'x') + || (ke == 'y') || (ke == 'z') ) { + ke = k->key(); + ke = ke + 0x20; + return ke; + } + + // qkeydefs = xkeydefs! :-) + if ( ( k->key() >= 0x0a0 ) && k->key() <= 0x0ff ) + return k->key(); + + if ( ( k->key() >= 0x20 ) && ( k->key() <= 0x7e ) ) + return k->key(); + + // qkeydefs != xkeydefs! :-( + // This is gonna suck :-( + + int i = 0; + while ( keyMap[i].keycode ) { + if ( k->key() == keyMap[i].keycode ) + return keyMap[i].keysym; + i++; + } + + return 0; +} + |