Changeset 136 for trunk/src/gui/kernel


Ignore:
Timestamp:
Aug 28, 2009, 7:46:09 PM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

gui: Implemented QKeyMapper (#33).

Location:
trunk/src/gui/kernel
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/gui/kernel/qapplication_pm.cpp

    r134 r136  
    508508#if defined(QT_DEBUGMSGFLOW)
    509509        {
    510             QString str = qStrQMSG(qmsg);
     510            Q str = qStrQMSG(qmsg);
    511511            if (!str.isEmpty())
    512                 qDebug() << "*** [W]" << str.toUtf8().constData();
     512                qDebug() << "*** [W]" << str;
    513513        }
    514514#endif
     
    602602        } else {
    603603            switch(msg) {
     604
     605
     606
     607
     608
     609
     610
     611
     612
     613
     614
     615
     616
     617
     618
     619
     620
     621
     622
     623
     624
     625
     626
     627
     628
     629
    604630
    605631            case WM_PAINT: { // paint event
     
    811837#if defined(QT_DEBUGMSGFLOW)
    812838        {
    813             QString str = qStrQMSG(qmsg);
     839            Q str = qStrQMSG(qmsg);
    814840            if (!str.isEmpty())
    815                 qDebug() << "*** [F]" << str.toUtf8().constData();
     841                qDebug() << "*** [F]" << str;
    816842        }
    817843#endif
     
    10331059 *****************************************************************************/
    10341060
    1035 // State holder for LWIN/RWIN and ALTGr keys
    1036 // (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
    1037 static int qt_extraKeyState = 0;
    1038 
    10391061static int mouseButtonState()
    10401062{
     
    11221144            bst |= Qt::ControlModifier;
    11231145    }
    1124     if ((qt_extraKeyState & Qt::AltModifier))
     1146    if ()
    11251147        bst |= Qt::AltModifier;
    1126     if (qt_extraKeyState & Qt::MetaModifier)
     1148    if (qt_extraKeyState & Qt::MetaModifier)
    11271149        bst |= Qt::MetaModifier;
    11281150
     
    15471569        state |= Qt::ShiftModifier;
    15481570    if (WinGetKeyState(HWND_DESKTOP, VK_ALT) & 0x8000 ||
    1549         (qt_extraKeyState & Qt::AltModifier))
     1571        (qt_extraKeyState & Qt::AltModifier))
    15501572        state |= Qt::AltModifier;
    15511573    if (WinGetKeyState(HWND_DESKTOP, VK_CTRL) & 0x8000)
    15521574        state |= Qt::ControlModifier;
    1553     if (qt_extraKeyState & Qt::MetaModifier)
     1575    if (qt_extraKeyState & Qt::MetaModifier)
    15541576        state |= Qt::MetaModifier;
    15551577
     
    19091931    switch (qmsg.msg) {
    19101932
     1933
     1934
     1935
     1936
     1937
     1938
     1939
     1940
     1941
     1942
     1943
     1944
     1945
     1946
     1947
     1948
     1949
     1950
     1951
     1952
     1953
     1954
     1955
     1956
     1957
     1958
     1959
     1960
     1961
     1962
    19111963    myCaseBegin(WM_PAINT)
    19121964        break;
  • trunk/src/gui/kernel/qkeymapper_p.h

    r2 r136  
    164164    KeyboardLayoutItem *keyLayout[256];
    165165
     166
     167
     168
     169
     170
     171
    166172#elif defined(Q_WS_X11)
    167173
  • trunk/src/gui/kernel/qkeymapper_pm.cpp

    r95 r136  
    4343
    4444#include "qkeymapper_p.h"
     45
     46
     47
     48
    4549
    4650QT_BEGIN_NAMESPACE
    4751
    48 // Uncommend, to show debugging information for the keymapper
    4952//#define DEBUG_KEYMAPPER
    5053
    51 // Keyboard map private ----------------------------------------------------------------[ start ]---
     54// Key recorder ----------------------------------------------------[ start ] --
     55struct KeyRecord {
     56    KeyRecord(int _scan, int _code, int _state, const QString &_text)
     57        : scan(_scan), code(_code), state(_state), text(_text) {}
     58    KeyRecord() {}
     59
     60    int scan;
     61    int code;
     62    int state;
     63    QString text;
     64};
     65
     66static const int QT_MAX_KEY_RECORDINGS = 64; // User has LOTS of fingers...
     67
     68struct KeyRecorder
     69{
     70    KeyRecorder() : nrecs(0) {}
     71
     72    inline KeyRecord *findKey(int code, bool remove);
     73    inline void storeKey(int scan, int code, int state, const QString& text);
     74    inline void clearKeys();
     75
     76    int nrecs;
     77    KeyRecord deleted_record; // A copy of last entry removed from records[]
     78    KeyRecord records[QT_MAX_KEY_RECORDINGS];
     79};
     80static KeyRecorder key_recorder;
     81
     82KeyRecord *KeyRecorder::findKey(int scan, bool remove)
     83{
     84    KeyRecord *result = 0;
     85    for (int i = 0; i < nrecs; ++i) {
     86        if (records[i].scan == scan) {
     87            if (remove) {
     88                deleted_record = records[i];
     89                // Move rest down, and decrease count
     90                while (i + 1 < nrecs) {
     91                    records[i] = records[i + 1];
     92                    ++i;
     93                }
     94                --nrecs;
     95                result = &deleted_record;
     96            } else {
     97                result = &records[i];
     98            }
     99            break;
     100        }
     101    }
     102    return result;
     103}
     104
     105void KeyRecorder::storeKey(int scan, int code, int state, const QString& text)
     106{
     107    Q_ASSERT_X(nrecs != QT_MAX_KEY_RECORDINGS,
     108               "Internal KeyRecorder",
     109               "Keyboard recorder buffer overflow, consider increasing QT_MAX_KEY_RECORDINGS");
     110
     111    if (nrecs == QT_MAX_KEY_RECORDINGS) {
     112        qWarning("Qt: Internal keyboard buffer overflow");
     113        return;
     114    }
     115    records[nrecs++] = KeyRecord(scan, code, state, text);
     116}
     117
     118void KeyRecorder::clearKeys()
     119{
     120    nrecs = 0;
     121}
     122// Key recorder ------------------------------------------------------[ end ] --
     123
     124// Key translation -------------------------------------------------[ start ] --
     125// Meaning of values:
     126//             0 = Character output key, needs keyboard driver mapping
     127//   Key_unknown = Unknown Virtual Key, no translation possible, ignore
     128static const uint KeyTbl[] = { // Keyboard mapping table
     129                        // Dec |  Hex | PM Virtual key
     130    Qt::Key_unknown,    //   0   0x00
     131    Qt::Key_unknown,    //   1   0x01   VK_BUTTON1          | Mouse button 1
     132    Qt::Key_unknown,    //   2   0x02   VK_BUTTON2          | Mouse button 2
     133    Qt::Key_unknown,    //   3   0x03   VK_BUTTON3          | Mouse button 3
     134    Qt::Key_Cancel,     //   4   0x04   VK_BREAK            | Control-Break processing
     135    Qt::Key_Backspace,  //   5   0x05   VK_BACKSPACE        | BackSpace key
     136    Qt::Key_Tab,        //   6   0x06   VK_TAB              | Tab key
     137    Qt::Key_Backtab,    //   7   0x07   VK_BACKTAB          | Shift+Tab key
     138    Qt::Key_Return,     //   8   0x08   VK_RETURN           | Enter key
     139    Qt::Key_Shift,      //   9   0x09   VK_SHIFT            | Shift key
     140    Qt::Key_Control,    //  10   0x0A   VK_CTRL             | Ctrl key
     141    Qt::Key_Alt,        //  11   0x0B   VK_ALT              | Alt key
     142    Qt::Key_Alt,        //  12   0x0C   VK_ALTGRAF          | AltGr key
     143    Qt::Key_Pause,      //  13   0x0D   VK_PAUSE            | Pause key
     144    Qt::Key_CapsLock,   //  14   0x0E   VK_CAPSLOCK         | Caps-Lock
     145    Qt::Key_Escape,     //  15   0x0F   VK_ESC              | Esc key
     146    Qt::Key_Space,      //  16   0x10   VK_SPACE            | Spacebar
     147    Qt::Key_PageUp,     //  17   0x11   VK_PAGEUP           | Page Up key
     148    Qt::Key_PageDown,   //  18   0x12   VK_PAGEDOWN         | Page Down key
     149    Qt::Key_End,        //  19   0x13   VK_END              | End key
     150    Qt::Key_Home,       //  20   0x14   VK_HOME             | Home key
     151    Qt::Key_Left,       //  21   0x15   VK_LEFT             | Left arrow key
     152    Qt::Key_Up,         //  22   0x16   VK_UP               | Up arrow key
     153    Qt::Key_Right,      //  23   0x17   VK_RIGHT            | Right arrow key
     154    Qt::Key_Down,       //  24   0x18   VK_DOWN             | Down arrow key
     155    Qt::Key_Print,      //  25   0x19   VK_PRINTSCRN        | Print Screen key
     156    Qt::Key_Insert,     //  26   0x1A   VK_INSERT           | Ins key
     157    Qt::Key_Delete,     //  27   0x1B   VK_DELETE           | Del key
     158    Qt::Key_NumLock,    //  28   0x1C   VK_SCROLL           | Scroll Lock key
     159    Qt::Key_ScrollLock, //  29   0x1D   VK_NUMLOCK          | Num Lock key
     160    Qt::Key_Enter,      //  30   0x1E   VK_ENTER            | Enter (Numpad) key
     161    Qt::Key_SysReq,     //  31   0x1F   VK_SYSRQ            | SysReq key
     162    Qt::Key_F1,         //  32   0x20   VK_F1               | F1 key
     163    Qt::Key_F2,         //  33   0x21   VK_F2               | F2 key
     164    Qt::Key_F3,         //  34   0x22   VK_F3               | F3 key
     165    Qt::Key_F4,         //  35   0x23   VK_F4               | F4 key
     166    Qt::Key_F5,         //  36   0x24   VK_F5               | F5 key
     167    Qt::Key_F6,         //  37   0x25   VK_F6               | F6 key
     168    Qt::Key_F7,         //  38   0x26   VK_F7               | F7 key
     169    Qt::Key_F8,         //  39   0x27   VK_F8               | F8 key
     170    Qt::Key_F9,         //  40   0x28   VK_F9               | F9 key
     171    Qt::Key_F10,        //  41   0x29   VK_F10              | F10 key
     172    Qt::Key_F11,        //  42   0x2A   VK_F11              | F11 key
     173    Qt::Key_F12,        //  43   0x2B   VK_F12              | F12 key
     174    Qt::Key_F13,        //  44   0x2C   VK_F13              | F13 key
     175    Qt::Key_F14,        //  45   0x2D   VK_F14              | F14 key
     176    Qt::Key_F15,        //  46   0x2E   VK_F15              | F15 key
     177    Qt::Key_F16,        //  47   0x2F   VK_F16              | F16 key
     178    Qt::Key_F17,        //  48   0x30   VK_F17              | F17 key
     179    Qt::Key_F18,        //  49   0x31   VK_F18              | F18 key
     180    Qt::Key_F19,        //  50   0x32   VK_F19              | F19 key
     181    Qt::Key_F20,        //  51   0x33   VK_F20              | F20 key
     182    Qt::Key_F21,        //  52   0x34   VK_F21              | F21 key
     183    Qt::Key_F22,        //  53   0x35   VK_F22              | F22 key
     184    Qt::Key_F23,        //  54   0x36   VK_F23              | F23 key
     185    Qt::Key_F24,        //  55   0x37   VK_F24              | F24 key
     186    Qt::Key_unknown,    //  56   0x38   VK_ENDDRAG          | ???
     187    Qt::Key_Clear,      //  57   0x39   VK_CLEAR            | Clear key
     188    Qt::Key_unknown,    //  58   0x3A   VK_EREOF            | ???
     189    Qt::Key_unknown,    //  59   0x3B   VK_PA1              | ???
     190    Qt::Key_unknown,    //  60   0x3C   VK_ATTN             | ???
     191    Qt::Key_unknown,    //  61   0x3D   VK_CRSEL            | ???
     192    Qt::Key_unknown,    //  62   0x3E   VK_EXSEL            | ???
     193    Qt::Key_unknown,    //  63   0x3F   VK_COPY             | ???
     194    Qt::Key_unknown,    //  64   0x40   VK_BLK1             | ???
     195    Qt::Key_unknown,    //  65   0x41   VK_BLK2             | ???
     196};
     197
     198// Key translation ---------------------------------------------------[ end ]---
     199
     200// QETWidget class is only for accessing the sendSpontaneousEvent function in QApplication
     201class QETWidget : public QWidget {
     202public:
     203    static bool sendSpontaneousEvent(QObject *r, QEvent *e)
     204    { return QApplication::sendSpontaneousEvent(r, e); }
     205};
     206
     207// Keyboard map private --------------------------------------------[ start ]---
    52208
    53209QKeyMapperPrivate::QKeyMapperPrivate()
    54210{
    55     // @todo implement
     211    // State holder for LWIN/RWIN and ALTGr keys
     212    // (ALTGr is also necessary since OS/2 doesn't report ALTGr as KC_ALT)
     213    extraKeyState = 0;
     214
     215   // @todo implement
    56216}
    57217
     
    74234}
    75235
    76 // QKeyMapper (PM) implementation -------------------------------------------------[ start ]---
     236static inline int asciiToKeycode(char a, int state)
     237{
     238    if (a >= 'a' && a <= 'z')
     239        a = toupper(a);
     240    if ((state & Qt::ControlModifier) != 0) {
     241        if (a >= 0 && a <= 31)              // [email protected]+A..CTRL+Z..Ctrl+_
     242            a += '@';                       // to @..A..Z.._
     243    }
     244    return a & 0xff;
     245}
     246
     247bool QKeyMapperPrivate::translateKeyEvent(QWidget *widget, const QMSG &qmsg, bool grab)
     248{
     249    Q_Q(QKeyMapper);
     250
     251    bool k0 = false;
     252    bool k1 = false;
     253
     254    CHRMSG chm = *CHARMSG(&qmsg.msg);
     255
     256    // we combine the flags from the message with the raw chr value and pass
     257    // them as QKeyEvent::nativeModifiers(). Together with chr.vkey passed as
     258    // nativeVirtualKey() and chr.scancode as nativeScanCode(), the Qt
     259    // application gets the full key message details (except the repeat count).
     260    quint32 nativeMods = chm.fs | chm.chr << 16;
     261
     262    // Get the modifier states (may be altered later, depending on key code)
     263    int state = 0;
     264    if (chm.fs & KC_SHIFT)
     265        state |= Qt::ShiftModifier;
     266    if (chm.fs & KC_CTRL)
     267        state |= Qt::ControlModifier;
     268    if (chm.fs & KC_ALT)
     269        state |= Qt::AltModifier;
     270
     271    // Translate VK_* (native) -> Key_* (Qt) keys
     272    int code = 0;
     273    if ((chm.fs & KC_VIRTUALKEY)) {
     274        if (chm.vkey == 0) {
     275            // The only known situation when KC_VIRTUALKEY is present but
     276            // vkey is zero is when Alt+Shift is pressed to switch the
     277            // keyboard layout state from latin to national and back.
     278            // It seems that this way the system informs applications about
     279            // layout changes: chm.chr is 0xF1 when the user switches
     280            // to the national layout (i.e. presses Alt + Left Shift)
     281            // and 0xF0 when he switches back (presses Alt + Right Shift).
     282            // We assume this and restore fs, vkey, scancode and chr accordingly.
     283            if (chm.chr == 0xF0 || chm.chr == 0xF1) {
     284                chm.fs |= KC_ALT | KC_SHIFT;
     285                chm.vkey = VK_SHIFT;
     286                chm.scancode = chm.chr == 0xF1 ? 0x2A : 0x36;
     287                chm.chr = 0;
     288                state |= Qt::AltModifier | Qt::ShiftModifier;
     289                // code will be assigned by the normal procedure below
     290            }
     291        } else if (chm.vkey == VK_ALTGRAF) {
     292            if (!(chm.fs & KC_KEYUP))
     293                extraKeyState |= Qt::AltModifier;
     294            else
     295                extraKeyState &= ~Qt::AltModifier;
     296        }
     297        if (chm.vkey < sizeof(KeyTbl))
     298            code = KeyTbl[chm.vkey];
     299    }
     300
     301    // detect some special keys that don't have a virtual key but have a pseudo
     302    // char code in the high byte of chm.chr (probably this is less
     303    // device-dependent than scancode)
     304    switch (chm.chr) {
     305        case 0xEC00: // LWIN
     306        case 0xED00: // RWIN
     307            code = Qt::Key_Meta;
     308            if (!(chm.fs & KC_KEYUP))
     309                extraKeyState |= Qt::MetaModifier;
     310            else
     311                extraKeyState &= ~Qt::MetaModifier;
     312            break;
     313        case 0xEE00: // WINAPP (menu with arrow)
     314            code = Qt::Key_Menu;
     315            break;
     316        case 0x5600: // additional '\' (0x56 is actually its scancode)
     317            chm.chr = state & Qt::ShiftModifier ? '|' : '\\';
     318            break;
     319    }
     320
     321    // update state after updating extraKeyState
     322    if (extraKeyState & Qt::AltModifier)
     323        state |= Qt::AltModifier;
     324    if (extraKeyState & Qt::MetaModifier)
     325        state |= Qt::MetaModifier;
     326
     327    // Invert state logic:
     328    // If the key actually pressed is a modifier key, then we remove its modifier key from the
     329    // state, since a modifier-key can't have itself as a modifier
     330    //
     331    // ### QKeyEvent::modifiers() already does this inversion which in result
     332    // cancels the inversion we do below and therefore makes the above statement
     333    // incorrect! It looks like the inversion block should be removed from this
     334    // function but it is left here for compatibility with other platforms which
     335    // also have this bug.
     336    //
     337    if (code == Qt::Key_Control)
     338        state = state ^ Qt::ControlModifier;
     339    else if (code == Qt::Key_Shift)
     340        state = state ^ Qt::ShiftModifier;
     341    else if (code == Qt::Key_Alt)
     342        state = state ^ Qt::AltModifier;
     343    else if (code == Qt::Key_Meta)
     344        state = state ^ Qt::MetaModifier;
     345
     346    // KEYDOWN -----------------------------------------------------------------
     347    if (!(chm.fs & KC_KEYUP)) {
     348        // Get the last record of this key press, so we can validate the current state
     349        // The record is not removed from the list
     350        KeyRecord *rec = key_recorder.findKey(chm.scancode, false);
     351
     352        // If rec's state doesn't match the current state, something has changed behind our back
     353        // (Consumed by modal widget is one possibility) So, remove the record from the list
     354        // This will stop the auto-repeat of the key, should a modifier change, for example
     355        if (rec && rec->state != state) {
     356            key_recorder.findKey(chm.scancode, true);
     357            rec = 0;
     358        }
     359
     360        // If we have a record, it means that the key is already pressed, the state is the same
     361        // so, we have an auto-repeating key
     362        if (rec) {
     363            Q_ASSERT(!code || code == rec->code);
     364            if (rec->code < Qt::Key_Shift || rec->code > Qt::Key_ScrollLock) {
     365                k0 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, rec->code,
     366                                     Qt::KeyboardModifier(state), rec->text, true, 0,
     367                                     chm.scancode, chm.vkey, nativeMods);
     368                k1 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, rec->code,
     369                                     Qt::KeyboardModifier(state), rec->text, true, 0,
     370                                     chm.scancode, chm.vkey, nativeMods);
     371            }
     372        }
     373        // No record of the key being previous pressed, so we now send a QEvent::KeyPress event,
     374        // and store the key data into our records.
     375        else {
     376            QString text;
     377            if (chm.chr) {
     378                // Note: We ignore the KC_CHAR flag when generating text for the
     379                // key in order to get correct (non-null) text even for Alt+Letter
     380                // combinations (that don't have KC_CHAR set) because processing
     381                // Alt+Letter shortcuts for non-ASCII letters in widgets (e.g.
     382                // QPushButton) depends on that.
     383                if ((chm.fs & (KC_VIRTUALKEY | KC_CHAR)) == KC_CHAR && (chm.chr & 0xFF00)) {
     384                    // We assime we get a DBCS char if the above condition is met.
     385                    // DBCS chars seem to have KC_CHAR set but not KC_VIRTUALKEY; we
     386                    // use this to prevent keys like ESC (chm=0x011B) with the
     387                    // non-zero high byte to be mistakenly recognized as DBCS.
     388                    text = QString::fromLocal8Bit((char *)&chm.chr, 2);
     389                } else if (chm.chr & 0xFF) {
     390                    text = QString::fromLocal8Bit((char*)&chm.chr, 1);
     391                }
     392
     393                Q_ASSERT(code || !text.isEmpty()); // we must provide the key code
     394                if (!code && !text.isEmpty()) {
     395                    if (!text[0].row())
     396                        code = asciiToKeycode(text[0].cell(), state);
     397                    else
     398                        code = text[0].toUpper().unicode();
     399                }
     400            }
     401            key_recorder.storeKey(chm.scancode, code, state, text);
     402            k0 = q->sendKeyEvent(widget, grab, QEvent::KeyPress, code,
     403                                 Qt::KeyboardModifier(state), text, false, 0,
     404                                 chm.scancode, chm.vkey, nativeMods);
     405        }
     406    }
     407    // KEYUP -------------------------------------------------------------------
     408    else {
     409        // Try to locate the key in our records, and remove it if it exists.
     410        // The key may not be in our records if, for example, the down event was handled by
     411        // PM natively, or our window gets focus while a key is already press, but now gets
     412        // the key release event.
     413        KeyRecord* rec = key_recorder.findKey(chm.scancode, true);
     414        if (!rec) {
     415            // Someone ate the key down event
     416        } else {
     417            k0 = q->sendKeyEvent(widget, grab, QEvent::KeyRelease, rec->code,
     418                                 Qt::KeyboardModifier(state), rec->text, false, 0,
     419                                 chm.scancode, chm.vkey, nativeMods);
     420        }
     421    }
     422
     423    // Return true, if a QKeyEvent was sent to a widget
     424    return k0 || k1;
     425}
     426
     427// QKeyMapper (PM) implementation ----------------------------------[ start ]---
    77428
    78429bool QKeyMapper::sendKeyEvent(QWidget *widget, bool grab,
     
    82433                              bool *)
    83434{
    84     // @todo implement
    85     return false;
     435    Q_UNUSED(count);
     436
     437#if defined QT3_SUPPORT && !defined(QT_NO_SHORTCUT)
     438    if (type == QEvent::KeyPress
     439        && !grab
     440        && QApplicationPrivate::instance()->use_compat()) {
     441        // send accel events if the keyboard is not grabbed
     442        QKeyEventEx a(type, code, modifiers,
     443                      text, autorepeat, qMax(1, int(text.length())),
     444                      nativeScanCode, nativeVirtualKey, nativeModifiers);
     445        if (QApplicationPrivate::instance()->qt_tryAccelEvent(widget, &a))
     446            return true;
     447    }
     448#endif
     449    if (!widget->isEnabled())
     450        return false;
     451
     452    QKeyEventEx e(type, code, modifiers,
     453                  text, autorepeat, qMax(1, int(text.length())),
     454                  nativeScanCode, nativeVirtualKey, nativeModifiers);
     455    QETWidget::sendSpontaneousEvent(widget, &e);
     456
     457    return e.isAccepted();
    86458}
    87459
Note: See TracChangeset for help on using the changeset viewer.