Ignore:
Timestamp:
Aug 20, 2006, 8:11:44 AM (19 years ago)
Author:
bird
Message:

Expanded m_client to 64-bit. Finally managed to hack together a getKeyMap and fakeKey for PM.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/synergy/lib/platform/CPMKeyState.cpp

    r2765 r2768  
    2828
    2929// map virtual keys to synergy key enumeration
    30 const KeyID                             CPMKeyState::s_virtualKey[0x42] =
    31 {
    32         /* 0x000 */ kKeyNone,           // reserved
    33         /* 0x001 */ kKeyNone,           // VK_BUTTON1
    34         /* 0x002 */ kKeyNone,           // VK_BUTTON2
    35         /* 0x003 */ kKeyNone,           // VK_BUTTON3
    36         /* 0x004 */ kKeyBreak,          // VK_BREAK
    37         /* 0x005 */ kKeyBackSpace,      // VK_BACKSPACE
    38         /* 0x006 */ kKeyTab,            // VK_TAB
    39         /* 0x007 */ kKeyLeftTab,        // VK_BACKTAB -- ???
    40         /* 0x008 */ kKeyReturn,         // VK_NEWLINE
    41         /* 0x009 */ kKeyShift_L,        // VK_SHIFT
    42         /* 0x00a */ kKeyControl_L,      // VK_CTRL
    43         /* 0x00b */ kKeyAlt_L,          // VK_ALT
    44         /* 0x00c */ kKeyAltGr,          // VK_ALTGRAF
    45         /* 0x00d */ kKeyPause,          // VK_PAUSE
    46         /* 0x00e */ kKeyCapsLock,       // VK_CAPSLOCK
    47         /* 0x00f */ kKeyEscape,         // VK_ESC
    48         /* 0x010 */ kKeyNone,           // VK_SPACE
    49         /* 0x011 */ kKeyPageUp,         // VK_PAGEUP
    50         /* 0x012 */ kKeyPageDown,       // VK_PAGEDOWN
    51         /* 0x013 */ kKeyEnd,            // VK_END
    52         /* 0x014 */ kKeyHome,           // VK_HOME
    53         /* 0x015 */ kKeyLeft,           // VK_LEFT
    54         /* 0x016 */ kKeyUp,                     // VK_UP
    55         /* 0x017 */ kKeyRight,          // VK_RIGHT
    56         /* 0x018 */ kKeyDown,           // VK_DOWN
    57         /* 0x019 */ kKeyNone,           // VK_PRINTSCRN
    58         /* 0x01a */ kKeyInsert,         // VK_INSERT
    59         /* 0x01b */ kKeyDelete,         // VK_DELETE
    60         /* 0x01c */ kKeyScrollLock,     // VK_SCRLLOCK
    61         /* 0x01d */ kKeyNumLock,        // VK_NUMLOCK
    62         /* 0x01e */ kKeyKP_Enter,       // VK_ENTER
    63         /* 0x01f */ kKeySysReq,         // VK_SYSRQ
    64         /* 0x020 */ kKeyF1,                     // VK_F1
    65         /* 0x021 */ kKeyF2,                     // VK_F2
    66         /* 0x022 */ kKeyF3,                     // VK_F3
    67         /* 0x023 */ kKeyF4,                     // VK_F4
    68         /* 0x024 */ kKeyF5,                     // VK_F5
    69         /* 0x025 */ kKeyF6,                     // VK_F6
    70         /* 0x026 */ kKeyF7,                     // VK_F7
    71         /* 0x027 */ kKeyF8,                     // VK_F8
    72         /* 0x028 */ kKeyF9,                     // VK_F9
    73         /* 0x029 */ kKeyF10,            // VK_F10
    74         /* 0x02a */ kKeyF11,            // VK_F11
    75         /* 0x02b */ kKeyF12,            // VK_F12
    76         /* 0x02c */ kKeyF13,            // VK_F13
    77         /* 0x02d */ kKeyF14,            // VK_F14
    78         /* 0x02e */ kKeyF15,            // VK_F15
    79         /* 0x02f */ kKeyF16,            // VK_F16
    80         /* 0x030 */ kKeyF17,            // VK_F17
    81         /* 0x031 */ kKeyF18,            // VK_F18
    82         /* 0x032 */ kKeyF19,            // VK_F19
    83         /* 0x033 */ kKeyF20,            // VK_F20
    84         /* 0x034 */ kKeyF21,            // VK_F21
    85         /* 0x035 */ kKeyF22,            // VK_F22
    86         /* 0x036 */ kKeyF23,            // VK_F23
    87         /* 0x037 */ kKeyF24,            // VK_F24
    88         /* 0x038 */ kKeyNone,           // VK_ENDDRAG
    89         /* 0x039 */ kKeyClear,          // VK_CLEAR
    90         /* 0x03a */ kKeyNone,           // VK_EREOF
    91         /* 0x03b */ kKeyNone,           // VK_PA1
    92         /* 0x03c */ kKeyNone,           // VK_ATTN
    93         /* 0x03d */ kKeyNone,           // VK_CRSEL
    94         /* 0x03e */ kKeyNone,           // VK_EXSEL
    95         /* 0x03f */ kKeyNone,           // VK_COPY
    96         /* 0x040 */ kKeyNone,           // VK_BLK1
    97         /* 0x041 */ kKeyNone            // VK_BLK2
     30const CPMKeyState::VirtualKey   CPMKeyState::s_virtualKey[0x42] =
     31{
     32{ /* 0x000 */ kKeyNone,         0,    0,    0 },    // reserved
     33{ /* 0x001 */ kKeyNone,         0,    0,    0 },    // VK_BUTTON1
     34{ /* 0x002 */ kKeyNone,         0,    0,    0 },    // VK_BUTTON2
     35{ /* 0x003 */ kKeyNone,         0,    0,    0 },    // VK_BUTTON3
     36{ /* 0x004 */ kKeyBreak,        0,    0,    0 },    // VK_BREAK
     37{ /* 0x005 */ kKeyBackSpace,    8,    0,    0 },    // VK_BACKSPACE
     38{ /* 0x006 */ kKeyTab,          9,    0,    0 },    // VK_TAB
     39{ /* 0x007 */ kKeyLeftTab,      9,    0,    1 },    // VK_BACKTAB
     40{ /* 0x008 */ kKeyReturn,    0x0d,    0,    0 },    // VK_NEWLINE
     41{ /* 0x009 */ kKeyShift_L,      0,    0,    0 },    // VK_SHIFT
     42{ /* 0x00a */ kKeyControl_L,    0,    0,    0 },    // VK_CTRL
     43{ /* 0x00b */ kKeyAlt_L,        0,    0,    0 },    // VK_ALT
     44{ /* 0x00c */ kKeyAltGr,        0,    0,    0 },    // VK_ALTGRAF
     45{ /* 0x00d */ kKeyPause,        0,    0,    0 },    // VK_PAUSE
     46{ /* 0x00e */ kKeyCapsLock,     0,    0,    0 },    // VK_CAPSLOCK
     47{ /* 0x00f */ kKeyEscape,    0x1b,    0,    0 },    // VK_ESC
     48{ /* 0x010 */ ' ',           0x20,    0,    0 },    // VK_SPACE
     49{ /* 0x011 */ kKeyPageUp,    0xe0,    1,   -1 },    // VK_PAGEUP
     50{ /* 0x012 */ kKeyPageDown,  0xe0,    1,   -1 },    // VK_PAGEDOWN
     51{ /* 0x013 */ kKeyEnd,       0xe0,    1,   -1 },    // VK_END
     52{ /* 0x014 */ kKeyHome,      0xe0,    1,   -1 },    // VK_HOME
     53{ /* 0x015 */ kKeyLeft,      0xe0,    1,   -1 },    // VK_LEFT
     54{ /* 0x016 */ kKeyUp,        0xe0,    1,   -1 },    // VK_UP
     55{ /* 0x017 */ kKeyRight,     0xe0,    1,   -1 },    // VK_RIGHT
     56{ /* 0x018 */ kKeyDown,      0xe0,    1,   -1 },    // VK_DOWN
     57{ /* 0x019 */ kKeyNone,      0xe0,    0,    0 },    // VK_PRINTSCRN
     58{ /* 0x01a */ kKeyInsert,    0xe0,    1,    1 },    // VK_INSERT
     59{ /* 0x01b */ kKeyDelete,    0xe0,    1,    1 },    // VK_DELETE
     60{ /* 0x01c */ kKeyScrollLock,   0,    0,    0 },    // VK_SCRLLOCK
     61{ /* 0x01d */ kKeyNumLock,      0,    0,    0 },    // VK_NUMLOCK
     62{ /* 0x01e */ kKeyKP_Enter,  0x0d,    1,    1 },    // VK_ENTER
     63{ /* 0x01f */ kKeySysReq,       0,    0,    0 },    // VK_SYSRQ
     64{ /* 0x020 */ kKeyF1,           0,    0,    1 },    // VK_F1
     65{ /* 0x021 */ kKeyF2,           0,    0,    1 },    // VK_F2
     66{ /* 0x022 */ kKeyF3,           0,    0,    1 },    // VK_F3
     67{ /* 0x023 */ kKeyF4,           0,    0,    1 },    // VK_F4
     68{ /* 0x024 */ kKeyF5,           0,    0,    1 },    // VK_F5
     69{ /* 0x025 */ kKeyF6,           0,    0,    1 },    // VK_F6
     70{ /* 0x026 */ kKeyF7,           0,    0,    1 },    // VK_F7
     71{ /* 0x027 */ kKeyF8,           0,    0,    1 },    // VK_F8
     72{ /* 0x028 */ kKeyF9,           0,    0,    1 },    // VK_F9
     73{ /* 0x029 */ kKeyF10,          0,    0,    1 },    // VK_F10
     74{ /* 0x02a */ kKeyF11,          0,    0,    1 },    // VK_F11
     75{ /* 0x02b */ kKeyF12,          0,    0,    1 },    // VK_F12
     76{ /* 0x02c */ kKeyF13,          0,    0,    1 },    // VK_F13
     77{ /* 0x02d */ kKeyF14,          0,    0,    1 },    // VK_F14
     78{ /* 0x02e */ kKeyF15,          0,    0,    1 },    // VK_F15
     79{ /* 0x02f */ kKeyF16,          0,    0,    1 },    // VK_F16
     80{ /* 0x030 */ kKeyF17,          0,    0,    1 },    // VK_F17
     81{ /* 0x031 */ kKeyF18,          0,    0,    1 },    // VK_F18
     82{ /* 0x032 */ kKeyF19,          0,    0,    1 },    // VK_F19
     83{ /* 0x033 */ kKeyF20,          0,    0,    1 },    // VK_F20
     84{ /* 0x034 */ kKeyF21,          0,    0,    1 },    // VK_F21
     85{ /* 0x035 */ kKeyF22,          0,    0,    1 },    // VK_F22
     86{ /* 0x036 */ kKeyF23,          0,    0,    1 },    // VK_F23
     87{ /* 0x037 */ kKeyF24,          0,    0,    1 },    // VK_F24
     88{ /* 0x038 */ kKeyNone,         0,    0,    0 },    // VK_ENDDRAG
     89{ /* 0x039 */ kKeyNone,         0,    0,    0 },    // VK_CLEAR
     90{ /* 0x03a */ kKeyNone,         0,    0,    0 },    // VK_EREOF
     91{ /* 0x03b */ kKeyNone,         0,    0,    0 },    // VK_PA1
     92{ /* 0x03c */ kKeyNone,         0,    0,    0 },    // VK_ATTN
     93{ /* 0x03d */ kKeyNone,         0,    0,    0 },    // VK_CRSEL
     94{ /* 0x03e */ kKeyNone,         0,    0,    0 },    // VK_EXSEL
     95{ /* 0x03f */ kKeyNone,         0,    0,    0 },    // VK_COPY
     96{ /* 0x040 */ kKeyNone,         0,    0,    0 },    // VK_BLK1
     97{ /* 0x041 */ kKeyNone,         0,    0,    0 },    // VK_BLK2
    9898};
    9999
     
    354354}
    355355
     356static USHORT
     357convertKeyModiferMaskToTCF(const KeyModifierMask mask)
     358{
     359    USHORT fShiftState = 0;
     360    if (mask & KeyModifierShift)    fShiftState |= TCF_SHIFT;
     361    if (mask & KeyModifierControl)  fShiftState |= TCF_CONTROL;
     362    if (mask & KeyModifierAlt)      fShiftState |= TCF_ALT;
     363    if (mask & KeyModifierAltGr)    fShiftState |= TCF_ALTGR;
     364    if (mask & KeyModifierCapsLock) fShiftState |= TCF_CAPSLOCK;
     365    if (mask & KeyModifierNumLock)  fShiftState |= TCF_NUMLOCK;
     366    return fShiftState;
     367}
     368
     369static KeyModifierMask
     370convertTCFToKeyModiferMask(const USHORT fShiftState)
     371{
     372    KeyModifierMask mask = 0;
     373    if (fShiftState & TCF_SHIFT)    mask |= KeyModifierShift;
     374    if (fShiftState & TCF_CONTROL)  mask |= KeyModifierControl;
     375    if (fShiftState & TCF_ALT)      mask |= KeyModifierAlt;
     376    if (fShiftState & TCF_ALTGR)    mask |= KeyModifierAltGr;
     377    if (fShiftState & TCF_CAPSLOCK) mask |= KeyModifierCapsLock;
     378    if (fShiftState & TCF_NUMLOCK)  mask |= KeyModifierNumLock;
     379    return mask;
     380}
     381
     382static bool
     383isASCIIControlChar(const USHORT usChar)
     384{
     385    switch (usChar) {
     386        /* Skip the ones with virtual keys. */
     387        case 0x08 + 0x40: case 0x08 + 0x60: // backspace
     388        case 0x09 + 0x40: case 0x09 + 0x60: // horizontal tab
     389        case 0x1b + 0x40: case 0x1b + 0x60: // escape
     390        case 0x0d + 0x40: case 0x0d + 0x60: // return
     391            return false;
     392        default:
     393            return (usChar >= 'A' && usChar <= '_')
     394                || (usChar >= 'a' && usChar <= 'z');
     395    }
     396}
     397
     398void
     399CPMKeyState::convertScancodes(ClientData *pData)
     400{
     401        /*
     402         * This is a bit tricky / hackish, but what we have to do here is to
     403         * deal with extended keys and the keypad stuff. The scancode
     404         * translation tables doesn't seem to be 100% correct for these
     405         * keys, and these keys are the ones we need them the most. sigh.
     406     */
     407
     408        //
     409        // navigation and insert/delete buttons left of the numpad:
     410        //              home, up, pgup, left, right, end, down, pgdn, insert, delete
     411        //
     412        // The pm and translated scancodes are mixed up in these cases.
     413        // The keys are all extended and secondary.
     414        //
     415        if (    pData->s.xlatScan >= 0x60 /* VK_HOME */
     416                &&      pData->s.xlatScan <= 0x69 /* VK_DELETE */
     417                &&  pData->s.virtualKey != 0) {
     418                pData->s.scan = pData->s.xlatScan;
     419                pData->s.xlatScan = m_pmScanToOemScanExt[pData->s.xlatScan];
     420                pData->s.fExtendedKey = true;
     421                pData->s.fNeedNumUnlockKey = true;
     422                pData->s.fSecondary = true;
     423                return;
     424        }
     425
     426        //
     427        // There are some virtual keys we know are extended, mark them so (like the Fxx keys).
     428        //
     429        if (    pData->s.virtualKey < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])
     430                &&      !pData->s.fExtendedKey) {
     431                if (    s_virtualKey[pData->s.virtualKey].extended == 1
     432                        ||  (   s_virtualKey[pData->s.virtualKey].extended == -1
     433                                 && (   pData->s.xlatChar == 0
     434                                         || pData->s.xlatChar == s_virtualKey[pData->s.virtualKey].ch))) {
     435                        pData->s.fExtendedKey = true;
     436                }
     437        }
     438
     439        //
     440        // Do the translating.
     441        //
     442        if (pData->s.xlatScan == pData->s.scan) {
     443                pData->s.scan = m_pmScanToOemScan[pData->s.xlatScan];
     444                //if (pData->s.fExtendedKey) {
     445                //      pData->s.scan = m_pmScanToOemScanExt[pData->s.xlatScan];
     446                //} else {
     447                //      pData->s.scan = m_pmScanToOemScan[pData->s.xlatScan];
     448                //}
     449        }
     450}
     451
     452
    356453void
    357454CPMKeyState::getKeyMap(CKeyMap& keyMap)
     
    375472
    376473        CKeyMap::KeyItem item;
    377 //      SInt32 numGroups = (SInt32)m_groups.size();
    378 //      for (SInt32 g = 0; g < numGroups; ++g) {
    379474        for (SInt32 g = 0; g < 1; ++g) {
    380475                item.m_group = g;
    381 //              ActivateKeyboardLayout(m_groups[g], 0);
    382 
    383                 // clear tables
     476
     477                //
     478                // Fill the scan code conversion tables.
     479                //
     480                for (unsigned i = 0; i < sizeof(m_pmScanToOemScan) / sizeof(m_pmScanToOemScan[0]); i++) {
     481                        USHORT us = i;
     482                        USHORT fShiftState = 0;
     483                        WinTranslateChar2(0, &us, NULL, TC_SCANTOOEMSCAN, &fShiftState);
     484                        m_pmScanToOemScan[i] = us;
     485                }
     486                for (unsigned i = 0; i < sizeof(m_pmScanToOemScanExt) / sizeof(m_pmScanToOemScanExt[0]); i++) {
     487                        USHORT us = i;
     488                        USHORT fShiftState = TCF_EXTENDEDKEY;
     489                        WinTranslateChar2(0, &us, NULL, TC_SCANTOOEMSCAN, &fShiftState);
     490                        m_pmScanToOemScanExt[i] = us;
     491                }
     492                for (unsigned i = 0; i < sizeof(m_oemScanToPmScan) / sizeof(m_oemScanToPmScan[0]); i++) {
     493                        USHORT us = i;
     494                        USHORT fShiftState = 0;
     495                        WinTranslateChar2(0, &us, NULL, TC_OEMSCANTOSCAN, &fShiftState);
     496                        m_oemScanToPmScan[i] = us;
     497                }
     498                for (unsigned i = 0; i < sizeof(m_oemScanToPmScanExt) / sizeof(m_oemScanToPmScanExt[0]); i++) {
     499                        USHORT us = i;
     500                        USHORT fShiftState = TCF_EXTENDEDKEY;
     501                        WinTranslateChar2(0, &us, NULL, TC_OEMSCANTOSCAN, &fShiftState);
     502                        m_oemScanToPmScanExt[i] = us;
     503                }
     504
     505
     506                //
     507                // map buttons (scancodes) to virtual keys
     508                //
    384509                memset(m_buttonToVK, 0, sizeof(m_buttonToVK));
    385 
    386                 // map buttons (scancodes) to virtual keys
    387510                for (KeyButton i = 1; i < 256; ++i) {
    388511            USHORT usVirtualKey = i;
     
    394517                        }
    395518                }
     519
     520/// @todo the stuff down to the button loop isn't really done yet.
    396521
    397522                // now map virtual keys to buttons.  multiple virtual keys may map
     
    406531                        case VK_BUTTON2:
    407532                        case VK_BUTTON3:
    408                         case VK_SHIFT:
    409                         case VK_CTRL:
    410533                        case VK_MENU:
    411534                                continue;
     
    423546                        }
    424547                }
    425 
    426 /// @todo?
    427 //              // add alt+printscreen
    428 //              if (m_buttonToVK[0x54u] == 0) {
    429 //                      m_buttonToVK[0x54u] = VK_SNAPSHOT;
    430 //              }
    431548
    432549                // set virtual key to button table
     
    441558//              }
    442559
    443                 // add the keys to the map.
    444                 BYTE keys[256];
    445                 memset(keys, 0, sizeof(keys));
    446                 for (KeyButton i = 0; i < 512; ++i) {
     560                //
     561                // Add the keys to the map.
     562                //
     563                //for (KeyButton i = 0; i < 256; ++i) {
     564                for (KeyButton i = 0; i < 256; ++i) {
     565                        //
     566            // Does this translate to a virtual key or character?
     567                        //
    447568            USHORT usChar = i;
    448             USHORT fCharShiftState = 0;
    449             USHORT fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOVIRTUALKEY, &fCharShiftState);
     569            USHORT fShiftState = 0;
     570            USHORT fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
     571            USHORT usVirtualKey = i;
     572            USHORT fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     573                        if (!usChar && !usVirtualKey) {
     574                                // try with control down.
     575                                usChar = i;
     576                                fShiftState = TCF_CONTROL;
     577                                fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
     578                                usVirtualKey = i;
     579                                fShiftState = TCF_CONTROL;
     580                                fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     581                        }
     582                        if (!usChar && !usVirtualKey) {
     583                                // try with altgr down.
     584                                usChar = i;
     585                                fShiftState = TCF_ALTGR;
     586                                fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
     587                                usVirtualKey = i;
     588                                fShiftState = TCF_ALTGR;
     589                                fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     590                        }
     591                        if (!usChar && !usVirtualKey) {
     592                                // try with numlock toggled.
     593                                usChar = i;
     594                                fShiftState = TCF_NUMLOCK;
     595                                fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
     596                                usVirtualKey = i;
     597                                fShiftState = TCF_NUMLOCK;
     598                                fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     599                        }
    450600                        if (    usChar
    451                 ||  m_buttonToVK[i]) {
    452                                 // initialize item
    453                                 item.m_id        = getKeyID(m_buttonToVK[i], i);
     601                ||  usVirtualKey) {
     602                                // initialize the item
     603                                item.m_id        = getKeyID(m_buttonToVK[i], i, false, usChar);
    454604                                item.m_button    = i;
    455605                                item.m_required  = 0;
    456606                                item.m_sensitive = 0;
    457                                 item.m_client    = (m_buttonToVK[i] & 0xff) //  0-7 : virtual key.
    458                                  | (i << 8)                 //  8-15: scancode
    459                                  | (usChar & 0x3fff)        // 16-29: PM char
    460                                  | (0 << 30)                //    30: KC_DEADKEY ??
    461                                  | (0 << 31);               //    31: KC_COMPOSITE ??
     607                                item.m_dead      = false;
     608                                item.m_lock      = false;
    462609
    463610                                // get flags for modifier keys
    464611                                CKeyMap::initModifierKey(item);
    465 
    466                                 if (item.m_id == 0) {
    467 #if 0
    468                                         // translate virtual key to a character with and without
    469                                         // shift, caps lock, and AltGr.
    470                                         struct Modifier {
    471                                                 ULONG                   m_vk1;
    472                                                 ULONG                   m_vk2;
    473                                                 BYTE                    m_state;
    474                                                 KeyModifierMask m_mask;
    475                                         };
    476                                         static const Modifier modifiers[] = {
    477                                                 { VK_SHIFT,   VK_SHIFT,   0x80u, KeyModifierShift    },
    478                                                 { VK_CAPITAL, VK_CAPITAL, 0x01u, KeyModifierCapsLock },
    479                                                 { VK_CONTROL, VK_MENU,    0x80u, KeyModifierControl | KeyModifierAlt }
    480                                         };
    481                                         static const size_t s_numModifiers = sizeof(modifiers) / sizeof(modifiers[0]);
    482                                         static const size_t s_numCombinations = 1 << s_numModifiers;
    483                                         KeyID id[s_numCombinations];
    484 
    485                                         bool anyFound = false;
    486                                         KeyButton button = static_cast<KeyButton>(i & 0xffu);
    487                                         for (size_t j = 0; j < s_numCombinations; ++j) {
    488                                                 for (size_t k = 0; k < s_numModifiers; ++k) {
    489                                                         if ((j & (1 << k)) != 0) {
    490                                                                 keys[modifiers[k].m_vk1] = modifiers[k].m_state;
    491                                                                 keys[modifiers[k].m_vk2] = modifiers[k].m_state;
    492                                                         }
    493                                                         else {
    494                                                                 keys[modifiers[k].m_vk1] = 0;
    495                                                                 keys[modifiers[k].m_vk2] = 0;
    496                                                         }
    497                                                 }
    498                                                 id[j] = getIDForKey(item, button, m_buttonToVK[i], keys, m_groups[g]);
    499                                                 if (id[j] != 0) {
    500                                                         anyFound = true;
    501                                                 }
    502                                         }
    503 
    504                                         if (anyFound) {
    505                                                 // determine what modifiers we're sensitive to.
    506                                                 // we're sensitive if the KeyID changes when the
    507                                                 // modifier does.
    508                                                 item.m_sensitive = 0;
    509                                                 for (size_t k = 0; k < s_numModifiers; ++k) {
    510                                                         for (size_t j = 0; j < s_numCombinations; ++j) {
    511                                                                 if (id[j] != id[j ^ (1u << k)]) {
    512                                                                         item.m_sensitive |= modifiers[k].m_mask;
    513                                                                         break;
    514                                                                 }
    515                                                         }
    516                                                 }
    517 
    518                                                 // save each key.  the map will automatically discard
    519                                                 // duplicates, like an unshift and shifted version of
    520                                                 // a key that's insensitive to shift.
    521                                                 for (size_t j = 0; j < s_numCombinations; ++j) {
    522                                                         item.m_id       = id[j];
    523                                                         item.m_required = 0;
    524                                                         for (size_t k = 0; k < s_numModifiers; ++k) {
    525                                                                 if ((j & (1 << k)) != 0) {
    526                                                                         item.m_required |= modifiers[k].m_mask;
    527                                                                 }
    528                                                         }
    529                                                         addKeyEntry(keyMap, item);
    530                                                 }
    531                                         }
    532 #endif
    533                                 } else {
    534                                         // found in table - adjust modifiers and add it.
    535                                         switch (m_buttonToVK[i]) {
    536                                         case VK_BACKTAB:
    537                                                 item.m_required  |= KeyModifierShift;
    538                                                 item.m_sensitive |= KeyModifierShift;
    539                                                 break;
    540                                         }
    541                                         addKeyEntry(keyMap, item);
    542                                 }
    543                         }
    544                 } // for buttons 0 thru 511
     612                if (item.m_generates != 0) {
     613                    // it's a modifier key.
     614                    item.m_lock = usVirtualKey == VK_NUMLOCK
     615                               || usVirtualKey == VK_SCRLLOCK
     616                               || usVirtualKey == VK_CAPSLOCK;
     617                                        ClientData data;
     618                                        data.u = 0;
     619                                        data.s.scan       = i;
     620                                        data.s.xlatScan   = i;
     621                                        data.s.fShiftKey  = true;
     622                                        data.s.xlatChar   = usChar;
     623                                        data.s.virtualKey = usVirtualKey;
     624                                        convertScancodes(&data);
     625                                        item.m_client = data.u;
     626                    addKeyEntry(keyMap, item);
     627                } else {
     628                    //
     629                    // Check which keys it might be sensitive to.
     630                    // We assume (possibly incorrectly) that combinations doesn't matter... :)
     631                    //
     632                    static const struct {
     633                        KeyModifierMask mask;
     634                        unsigned        fShiftState;
     635                    } modifiers[] = {
     636                        { KeyModifierShift, TCF_SHIFT},
     637                        { KeyModifierControl, TCF_CONTROL },
     638                        { KeyModifierAlt, TCF_ALT },
     639                        { KeyModifierAltGr, TCF_ALTGR },
     640                        { KeyModifierCapsLock, TCF_CAPSLOCK },
     641                        { KeyModifierNumLock, TCF_NUMLOCK }
     642                    };
     643                                        usChar = i;
     644                                        fShiftState = 0;
     645                                        fCharKCFlags = WinTranslateChar2(0, &usChar, NULL, TC_SCANCODETOCHAR, &fShiftState);
     646                                        usVirtualKey = i;
     647                                        fShiftState = 0;
     648                                        fVirtualKeyKCFlags = WinTranslateChar2(0, &usVirtualKey, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     649                    for (unsigned j = 0; j < sizeof(modifiers) / sizeof(modifiers[0]); j++) {
     650                        USHORT usCh = i;
     651                        fShiftState = modifiers[j].fShiftState;
     652                        if (    WinTranslateChar2(0, &usCh, NULL, TC_SCANCODETOCHAR, &fShiftState) != 0
     653                            &&  usCh != 0
     654                            &&  usCh != usChar) {
     655                            item.m_sensitive |= modifiers[j].mask;
     656                            continue;
     657                        }
     658                        usCh = i;
     659                        fShiftState = modifiers[j].fShiftState;
     660                        WinTranslateChar2(0, &usCh, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     661                        if (    usCh != 0
     662                            &&  usCh != usVirtualKey) {
     663                            item.m_sensitive |= modifiers[j].mask;
     664                            continue;
     665                        }
     666                    }
     667                    if (isASCIIControlChar(usChar)) {
     668                        item.m_sensitive |= KeyModifierControl;
     669                    }
     670
     671                    //
     672                    // Check for numpad keys. We need to adjust stuff then.
     673                    // It think this test should be sufficient.
     674                    //
     675                    bool numpad = (item.m_sensitive & KeyModifierNumLock) != 0;
     676
     677                    //
     678                    // Unoptimized brute force algorithm for determining the
     679                    // possible combinations and adding them to the key map.
     680                    //
     681                    struct
     682                    {
     683                        UCHAR   uchChar;
     684                        UCHAR   uchVirtualKey;
     685                    } combinations[1 << TCF_MAX_BITS];
     686
     687                    for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
     688                        const KeyModifierMask mask = convertTCFToKeyModiferMask(j);
     689                        if ((mask & item.m_sensitive) != mask /*|| j>3*/) {
     690                            combinations[j].uchChar = combinations[j].uchVirtualKey = 0;
     691                            continue;
     692                        }
     693                        // get any character value
     694                        USHORT us = i;
     695                        fShiftState = j;
     696                        if (WinTranslateChar2(0, &us, NULL, TC_SCANCODETOCHAR, &fShiftState) == 0) {
     697                            us = 0;
     698                        }
     699                        combinations[j].uchChar = us;
     700
     701                        // get any virtual key value
     702                        us = i;
     703                        fShiftState = j;
     704                        WinTranslateChar2(0, &us, NULL, TC_SCANCODETOVIRTUALKEY, &fShiftState);
     705                        combinations[j].uchVirtualKey = us;
     706
     707                        // deal with missing character translations
     708                        if (    combinations[j].uchChar == 0
     709                            &&  us != 0
     710                            &&  us < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])) {
     711                            combinations[j].uchChar = s_virtualKey[us].ch;
     712                        }
     713                    }
     714
     715                    // 2. Eliminate duplicates.
     716                    for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
     717                        unsigned best = j;
     718                        KeyModifierMask bestMask = convertTCFToKeyModiferMask(j);
     719                        for (unsigned k = j + 1; k < sizeof(combinations) / sizeof(combinations[0]); k++) {
     720                            if (    combinations[best].uchChar == combinations[k].uchChar
     721                                &&  combinations[best].uchVirtualKey == combinations[k].uchVirtualKey) {
     722                                const KeyModifierMask mask = convertTCFToKeyModiferMask(k);
     723                                // drop L/R mixes.
     724                                if (mask == bestMask) {
     725                                    combinations[k].uchChar = combinations[k].uchVirtualKey = 0;
     726                                }
     727                            }
     728                        }
     729                    }
     730
     731                    // 3. Add the remainders.
     732                    for (unsigned j = 0; j < sizeof(combinations) / sizeof(combinations[0]); j++) {
     733                        if (combinations[j].uchChar || combinations[j].uchVirtualKey) {
     734                            USHORT usChar = combinations[j].uchChar;
     735                            USHORT usVirtualKey = combinations[j].uchVirtualKey;
     736
     737                            // update the changing item members
     738                            item.m_required  = convertTCFToKeyModiferMask(j);
     739                            if (usVirtualKey) {
     740                                switch (usVirtualKey) {
     741                                case VK_BACKTAB:
     742                                    item.m_required  |= KeyModifierShift;
     743                                    item.m_sensitive |= KeyModifierShift;
     744                                                                        usChar                    = 0; // this one is translated incorrectly
     745                                    break;
     746                                }
     747                                item.m_id    = getKeyID(usVirtualKey, i, numpad, usChar);
     748                            } else {
     749                                item.m_id    = usChar; /// @todo translate to unicode!
     750                            }
     751                                                        ClientData data;
     752                                                        data.u = 0;
     753                                                        data.s.scan       = i;
     754                                                        data.s.xlatScan   = i;
     755                                                        data.s.xlatChar   = usChar;
     756                                                        data.s.virtualKey = usVirtualKey;
     757                                                        convertScancodes(&data);
     758                                                        item.m_client = data.u;
     759                            addKeyEntry(keyMap, item);
     760                        }
     761                    }
     762
     763                    // 4. ASCII Control Character variants. (ARG! this doesn't work, fakeMsg hacks it.)
     764                    if (isASCIIControlChar(usChar)) {
     765                        /* add key */
     766                        item.m_id        = usChar - (usChar >= 'a' ? 0x60 : 0x40);
     767                        item.m_required  = KeyModifierControl;
     768                                                ClientData data;
     769                                                data.u = 0;
     770                                                data.s.scan      = i;
     771                                                data.s.xlatScan  = i;
     772                                                data.s.xlatChar  = item.m_id;
     773                                                convertScancodes(&data);
     774                                                item.m_client    = data.u;
     775                        addKeyEntry(keyMap, item);
     776                        item.m_id        = usChar;
     777                        addKeyEntry(keyMap, item);
     778                    }
     779                }
     780                        }
     781                } // for buttons 0 thru 254
     782
     783                //
     784                // Various other keys for which we don't expect the above loops to catch.
     785                //
     786                item.m_id        = kKeyMenu;
     787                item.m_button    = 0xee;
     788                item.m_required  = 0;
     789                item.m_sensitive = 0;
     790                item.m_dead      = false;
     791                item.m_lock      = false;
     792                ClientData data;
     793                data.u = 0;
     794                data.s.scan      = 0x7c;
     795                data.s.xlatScan  = 0xee;
     796                data.s.fSecondary = true;
     797                data.s.fExtendedKey = true;
     798                data.s.fNeedNumUnlockKey = true;
     799                item.m_client    = data.u;
     800                CKeyMap::initModifierKey(item);
     801                addKeyEntry(keyMap, item);
     802
     803                item.m_id                = kKeySuper_L;
     804                item.m_button    = 0xec;
     805                data.s.xlatScan  = 0xec;
     806                data.s.scan      = 0x7e;
     807                item.m_client    = data.u;
     808                CKeyMap::initModifierKey(item);
     809                addKeyEntry(keyMap, item);
     810
     811                item.m_id                = kKeySuper_R;
     812                item.m_button    = 0xed;
     813                data.s.xlatScan  = 0xed;
     814                data.s.scan      = 0x7f;
     815                item.m_client    = data.u;
     816                CKeyMap::initModifierKey(item);
     817                addKeyEntry(keyMap, item);
     818
    545819        }
    546820
     
    557831        switch (keystroke.m_type) {
    558832        case Keystroke::kButton: {
    559                 LOG((CLOG_DEBUG1 "  %03x (%08x) %s%s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client,
     833                LOG((CLOG_DEBUG1 "  %03x (%08llx) %s%s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client,
    560834             keystroke.m_data.m_button.m_press ? "down" : "up", keystroke.m_data.m_button.m_repeat ? " repeate" : ""));
    561835                KeyButton button = keystroke.m_data.m_button.m_button;
     
    569843
    570844                // unpack the m_client packet.
    571                 USHORT virtualKey = 0;//keystroke.m_data.m_button.m_client & 0xff;
    572         UCHAR  scanCode = (keystroke.m_data.m_button.m_client >> 8) & 0xff;
    573         USHORT pmChar = 0;//(keystroke.m_data.m_button.m_client >> 16) & 0xff;
    574         bool   fKC_DEADKEY = (keystroke.m_data.m_button.m_client >> 30) & 1;
    575         bool   fKC_COMPOSITE = (keystroke.m_data.m_button.m_client >> 31) & 1;
    576 
     845                ClientData data;
     846                data.u = keystroke.m_data.m_button.m_client;
     847
     848        //
    577849        // synthesize message
     850        // There are two options at this point, WM_CHAR or WM_VIOCHAR. It seems
     851        // like WM_VIOCHAR is the better choice since that's the form in which
     852        // keyboard events normally arrive in the system queue.
     853        //
     854        // WM_VIOCHAR:
     855        //      mp1.s1: KC_ flags.
     856        //      mp1.c3: repeat
     857        //      mp1.c4: scancode
     858        //      mp2.c1: translated char
     859        //      mp2.c2: translated scancode
     860        //      mp2.s2: KDD_ flags.
     861        //
     862
     863        // the standard bits.
    578864        HAB hab = CPMUtil::getHAB();/// @todo fix this
    579865        QMSG qmsg;
    580866        qmsg.hwnd = NULLHANDLE;
    581         qmsg.msg = WM_CHAR;
     867        qmsg.msg = WM_VIOCHAR;
    582868        qmsg.ptl.x = 0;
    583869        qmsg.ptl.y = 0;
     
    585871        qmsg.reserved = 0;
    586872
    587         // mp2
    588         if (!keystroke.m_data.m_button.m_press) {
    589             pmChar |= 0x0e00; /// @todo figure out what's going on here...
     873        //
     874        // calc the key code flags.
     875        // PM deals with: KC_TOGGLE, KC_VIRTUALKEY, KC_CHAR, (WM_CHAR: also KC_CTRL, KC_ALT, KC_SHIFT).
     876        //
     877        USHORT fKC = 0;
     878        if (data.s.scan)
     879            fKC |= KC_SCANCODE;
     880        if (!keystroke.m_data.m_button.m_press)
     881            fKC |= KC_KEYUP;
     882        /// @todo check that PM does KC_INVALIDCOMP
     883        if (data.s.fDeadKey)
     884            fKC |= KC_DEADKEY;
     885        if (data.s.fComposite)
     886            fKC |= KC_COMPOSITE;
     887        if (!keystroke.m_data.m_button.m_press && m_lastButton == data.s.scan)
     888            fKC |= KC_LONEKEY;
     889
     890        // we need these for calcing fKDD, so just put them in even if PM can do it for us.
     891        KeyModifierMask modifierMask = this->getActiveModifiers();
     892        if (modifierMask & KeyModifierShift)
     893            fKC |= KC_SHIFT;
     894        if (modifierMask & KeyModifierControl)
     895            fKC |= KC_CTRL;
     896        if (modifierMask & KeyModifierAlt)
     897            fKC |= KC_ALT;
     898
     899        //
     900        // Calc the keyboard device driver flags.
     901        //
     902        USHORT fKDD;
     903        // the action
     904        if (data.s.fShiftKey)
     905            fKDD = KDD_SHIFTKEY;
     906/** @todo Determin the KDD_ACTIONMASK value.
     907KDD_PREFIXKEY
     908KDD_PAUSEKEY
     909KDD_PSEUDOPAUSE
     910KDD_WAKEUPKEY
     911KDD_BREAKKEY
     912KDD_PSEUDOBREAK
     913KDD_PRTECHOKEY
     914KDD_PSEUDOPRECH */
     915        else
     916            fKDD = KDD_PUTINKIB;
     917#if 0
     918        if (fKC & KC_LONEKEY)       fKDD |= KDD_KC_LONEKEY;
     919        if (fKC & KC_PREVDOWN)      fKDD |= KDD_KC_PREVDOWN;
     920        if (fKC & KC_KEYUP)         fKDD |= KDD_KC_KEYUP | KDD_BREAK;
     921        if (fKC & KC_ALT)           fKDD |= KDD_KC_ALT;
     922        if (fKC & KC_CTRL)          fKDD |= KDD_KC_CTRL;
     923        if (fKC & KC_SHIFT)         fKDD |= KDD_KC_SHIFT;
     924#else
     925        if (fKC & KC_KEYUP)         fKDD |= KDD_BREAK;
     926#endif
     927        if (data.s.fSecondary)      fKDD |= KDD_SECONDARY;
     928        if (data.s.fExtendedKey)    fKDD |= KDD_EXTENDEDKEY;
     929
     930        //
     931        // Adjust char for ASCII control keys. (Ctrl+C and stuff)
     932        //
     933        if (    (fKC & KC_CTRL)
     934            &&  isASCIIControlChar(data.s.xlatChar)) {
     935            data.s.xlatChar -= (data.s.xlatChar >= 'a' ? 0x60 : 0x40);
    590936        }
    591         qmsg.mp2 = MPFROM2SHORT(pmChar, virtualKey);
    592 
    593         // mp1
    594         USHORT fFlags = 0;
    595         if (!keystroke.m_data.m_button.m_press) {
    596             fFlags |= KC_KEYUP;
    597             /// @todo KC_LONEKEY and KC_TOGGLE, or will PM take care of that?
     937
     938                //
     939                // For some keys (navigation and edit keys left to the numpad),
     940                // any numlock or shift needs to be 'canceled'.
     941                // (At least this happens with my logitech diNovo keyboards.)
     942                //
     943        if (    data.s.fNeedNumUnlockKey
     944                        &&      (       (modifierMask & (KeyModifierShift | KeyModifierNumLock)) == KeyModifierNumLock
     945                                 ||     (modifierMask & (KeyModifierShift | KeyModifierNumLock)) == KeyModifierShift)) {
     946                        // need to insert a key nullifying the numlock/shift.
     947                        QMSG qmsg0 = qmsg;
     948                        qmsg0.mp1 = MPFROMSH2CH(fKC & KC_KEYUP, 1, 0);
     949                        qmsg0.mp2 = MPFROM2SHORT(MAKESHORT(0, 0x2a), (fKDD & KDD_BREAK) | KDD_UNDEFINED | KDD_SECONDARY | KDD_EXTENDEDKEY);
     950
     951                        // this message comes first on keydown and last on keyup.
     952                        if (fKC & KC_KEYUP) {
     953                                QMSG tmp = qmsg;
     954                                qmsg = qmsg0;
     955                                qmsg0 = tmp;
     956                        }
     957
     958                        LOG((CLOG_INFO "WM_VIOCHAR: fKC=%04x rep=%02x scan=%02x xlch=%02x(%c) xlscan=%02x fKDD=%04x ",
     959                                 SHORT1FROMMP(qmsg0.mp1), CHAR3FROMMP(qmsg0.mp1), CHAR4FROMMP(qmsg0.mp1), CHAR1FROMMP(qmsg0.mp2),
     960                                 isprint(CHAR1FROMMP(qmsg0.mp2)) ? CHAR1FROMMP(qmsg0.mp2) : '.', CHAR2FROMMP(qmsg0.mp2), SHORT2FROMMP(qmsg0.mp2)));
     961                        const char *pszError = m_fakeMsg(hab, &qmsg0);
     962                        if (pszError) {
     963                                LOG((CLOG_ERR " fakeMsg failed to inject msg=%#lx mp1=%#lx mp2=%#lx: %s", qmsg0.msg, qmsg0.mp1, qmsg0.mp2, pszError));
     964                        }
    598965        }
    599         /// @todo check that PM does KC_CTRL, KC_ALT and KC_SHIFT.
    600         /// @todo check that PM does KC_INVALIDCOMP
    601         if (fKC_DEADKEY)    fFlags |= KC_DEADKEY;
    602         if (fKC_COMPOSITE)  fFlags |= KC_COMPOSITE;
    603 //        if (virtualKey)     fFlags |= KC_VIRTUALKEY;
    604 //        if (keystroke.m_data.m_button.m_press && pmChar)
    605 //                            fFlags |= KC_CHAR;
    606         if (scanCode)       fFlags |= KC_SCANCODE;
    607         if (!keystroke.m_data.m_button.m_press && m_lastButton == scanCode)
    608                             fFlags |= KC_LONEKEY;
    609         // PM does: KC_TOGGLE, KC_CTRL, KC_ALT, KC_SHIFT. more?
    610         qmsg.mp1 = MPFROMSH2CH(fFlags, 1, scanCode); /** @todo translate the scan code back to its untranslated form. */
    611 
    612         // finaly inject it.
     966
     967                //
     968                // Inject the (last) message.
     969                //
     970        qmsg.mp1 = MPFROMSH2CH(fKC, 1, data.s.scan);
     971        qmsg.mp2 = MPFROM2SHORT(MAKESHORT(data.s.xlatChar, data.s.xlatScan), fKDD);
     972        LOG((CLOG_INFO "WM_VIOCHAR: fKC=%04x rep=%02x scan=%02x xlch=%02x(%c) xlscan=%02x fKDD=%04x ",
     973             SHORT1FROMMP(qmsg.mp1), CHAR3FROMMP(qmsg.mp1), CHAR4FROMMP(qmsg.mp1), CHAR1FROMMP(qmsg.mp2),
     974             isprint(CHAR1FROMMP(qmsg.mp2)) ? CHAR1FROMMP(qmsg.mp2) : '.', CHAR2FROMMP(qmsg.mp2), SHORT2FROMMP(qmsg.mp2)));
    613975        const char *pszError = m_fakeMsg(hab, &qmsg);
    614976        if (pszError) {
     
    618980        // remember the previous key for KC_LONEKEY.
    619981        if (keystroke.m_data.m_button.m_press && !keystroke.m_data.m_button.m_repeat)
    620             m_lastButton = scanCode;
     982            m_lastButton = data.s.scan;
    621983                break;
    622984        }
     
    6541016
    6551017KeyID
    656 CPMKeyState::getKeyID(ULONG virtualKey, KeyButton button)
     1018CPMKeyState::getKeyID(ULONG virtualKey, KeyButton button, bool numpad, USHORT usChar)
    6571019{
    6581020    LOG((CLOG_DEBUG "getKeyID:"));
    659 //      if ((button & 0x100u) != 0) {
    660 //              virtualKey += 0x100u;
    661 //      }
    662 //      return s_virtualKey[virtualKey];
    663         return  virtualKey < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])
    664         ?  s_virtualKey[virtualKey]
    665         : kKeyNone;
     1021    if (virtualKey < sizeof(s_virtualKey) / sizeof(s_virtualKey[0])) {
     1022
     1023                //
     1024                // Numpad kludge.
     1025                //
     1026        if (numpad && s_virtualKey[virtualKey].numpad) {
     1027            switch (usChar) {
     1028                case '=':   return kKeyKP_Equal;
     1029                case '*':   return kKeyKP_Multiply;
     1030                case '+':   return kKeyKP_Add;
     1031                //case ',':
     1032                //case '.':   return kKeyKP_Separator ? kKeyKP_Decimal;
     1033                case '-':   return kKeyKP_Subtract;
     1034                case '/':   return kKeyKP_Divide;
     1035                case '0':   return kKeyKP_0;
     1036                case '1':   return kKeyKP_1;
     1037                case '2':   return kKeyKP_2;
     1038                case '3':   return kKeyKP_3;
     1039                case '4':   return kKeyKP_4;
     1040                case '5':   return kKeyKP_5;
     1041                case '6':   return kKeyKP_6;
     1042                case '7':   return kKeyKP_7;
     1043                case '8':   return kKeyKP_8;
     1044                case '9':   return kKeyKP_9;
     1045                case ' ':   return kKeyKP_Space;
     1046            }
     1047            switch (s_virtualKey[virtualKey].key) {
     1048               case kKeyHome:       return kKeyKP_Home;
     1049               case kKeyLeft:       return kKeyKP_Left;
     1050               case kKeyUp:         return kKeyKP_Up;
     1051               case kKeyRight:      return kKeyKP_Right;
     1052               case kKeyDown:       return kKeyKP_Down;
     1053               case kKeyPageUp:     return kKeyKP_PageUp;
     1054               case kKeyPageDown:   return kKeyKP_PageDown;
     1055               case kKeyEnd:        return kKeyKP_End;
     1056               case kKeyBegin:      return kKeyKP_Begin;
     1057               case kKeyInsert:     return kKeyKP_Insert;
     1058               case kKeyDelete:     return kKeyKP_Delete;
     1059            }
     1060        } else {
     1061                        //
     1062                        // Left/right shift and control kludge.
     1063                        //
     1064            switch (virtualKey) {
     1065                case VK_CTRL:
     1066                    if (m_virtualKeyToButton[VK_CTRL] != button) {
     1067                        return kKeyControl_R;
     1068                    }
     1069                    break;
     1070                case VK_SHIFT:
     1071                    if (m_virtualKeyToButton[VK_SHIFT] != button) {
     1072                        return kKeyShift_R;
     1073                    }
     1074                    break;
     1075            }
     1076        }
     1077        return s_virtualKey[virtualKey].key;
     1078    }
     1079    return kKeyNone;
    6661080}
    6671081
     
    7001114}
    7011115
     1116static const char *
     1117getKeyName(KeyID key)
     1118{
     1119    const KeyNameMapEntry *entry = &kKeyNameMap[0];
     1120    while (entry->m_id != kKeyNone) {
     1121        if (entry->m_id == key) {
     1122            return entry->m_name;
     1123        }
     1124        entry++;
     1125    }
     1126    /* ASCII? */
     1127    static char s_buf[2][2];
     1128    static char s_idxBuf;
     1129    if (key >= ' ' && key <= 'z') {
     1130        char *buf = &s_buf[s_idxBuf = (s_idxBuf + 1) % 2][0];
     1131        *buf = key;
     1132        return buf;
     1133    }
     1134    return "";
     1135}
     1136
    7021137void
    7031138CPMKeyState::addKeyEntry(CKeyMap& keyMap, CKeyMap::KeyItem& item)
    7041139{
    705     LOG((CLOG_DEBUG "addKeyEntry:"));
    706         keyMap.addKeyEntry(item);
     1140        ClientData data; data.u = item.m_client; assert(sizeof(data.u) == sizeof(data));
     1141    LOG((CLOG_DEBUG
     1142         "addKeyEntry: scan=%02x+%02x req=%c%c%c%c%c%c[%c%c%c%c%c%c]{%x} id=%04x(%c) xlatChar=%02x(%c) scan=%02x xlatScan=%02x [%s]%s%s%s%s%s%s",
     1143         item.m_button, convertKeyModiferMaskToTCF(item.m_required),
     1144         item.m_required & KeyModifierShift ? 'S' : '-',
     1145         item.m_required & KeyModifierControl ? 'C' : '-',
     1146         item.m_required & KeyModifierAlt ? 'A' : '-',
     1147         item.m_required & KeyModifierAltGr ? 'R' : '-',
     1148         item.m_required & KeyModifierCapsLock ? 'U' : '-',
     1149         item.m_required & KeyModifierNumLock ? 'N' : '-',
     1150         item.m_sensitive & KeyModifierShift ? 'S' : '-',
     1151         item.m_sensitive & KeyModifierControl ? 'C' : '-',
     1152         item.m_sensitive & KeyModifierAlt ? 'A' : '-',
     1153         item.m_sensitive & KeyModifierAltGr ? 'R' : '-',
     1154         item.m_sensitive & KeyModifierCapsLock ? 'U' : '-',
     1155         item.m_sensitive & KeyModifierNumLock ? 'N' : '-',
     1156         item.m_generates,
     1157         item.m_id,             item.m_id < 128 && isprint(item.m_id)       ? item.m_id       : '.',
     1158                 data.s.xlatChar, data.s.xlatChar < 128 && isprint(data.s.xlatChar) ? data.s.xlatChar : '.',
     1159                 data.s.scan, data.s.xlatScan,
     1160         getKeyName(item.m_id),
     1161         data.s.fExtendedKey ? " extendedkey" : "",
     1162         data.s.fShiftKey    ? " shiftkey" : "",
     1163         data.s.fDeadKey     ? " deadkey" : "",
     1164         data.s.fComposite   ? " composite" : "",
     1165         item.m_lock         ? " lock" : "",
     1166         item.m_dead         ? " dead" : ""
     1167         ));
     1168        if (data.s.scan2 || data.s.xlatScan2) {
     1169                LOG((CLOG_DEBUG
     1170                         "addKeyEntry: xlatChar2=%02x(%c) scan2=%02x xlatScan2=%02x",
     1171                         data.s.xlatChar2, data.s.xlatChar2 < 128 && isprint(data.s.xlatChar2) ? data.s.xlatChar2 : '.',
     1172                         data.s.scan2, data.s.xlatScan2));
     1173        }
     1174
     1175        if (!keyMap.addKeyEntry(item)) {
     1176                LOG((CLOG_DEBUG "!not accepted!"));
     1177    }
    7071178        if (item.m_group == 0) {
    7081179                m_keyToVKMap[item.m_id] = item.m_client;
Note: See TracChangeset for help on using the changeset viewer.