Changeset 2768
- Timestamp:
- Aug 20, 2006, 8:11:44 AM (19 years ago)
- Location:
- trunk/synergy/lib
- Files:
-
- 14 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/synergy/lib/common/BasicTypes.h
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2002 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 45 45 #endif 46 46 47 #if !defined(TYPE_OF_SIZE_8) 48 # ifdef _MSC_VER 49 # define TYPE_OF_SIZE_8 _int64 50 # else 51 # define TYPE_OF_SIZE_8 long long 52 # endif 53 #endif 54 47 55 // 48 56 // verify existence of required types … … 57 65 #if !defined(TYPE_OF_SIZE_4) 58 66 # error No 4 byte integer type 67 #endif 68 #if !defined(TYPE_OF_SIZE_8) 69 # error No 8 byte integer type 59 70 #endif 60 71 … … 71 82 typedef signed TYPE_OF_SIZE_2 SInt16; 72 83 typedef signed TYPE_OF_SIZE_4 SInt32; 84 typedef signed TYPE_OF_SIZE_8 SInt64; 73 85 74 86 typedef unsigned TYPE_OF_SIZE_1 UInt8; 75 87 typedef unsigned TYPE_OF_SIZE_2 UInt16; 76 88 typedef unsigned TYPE_OF_SIZE_4 UInt32; 89 typedef unsigned TYPE_OF_SIZE_8 UInt64; 77 90 78 91 // … … 83 96 #undef TYPE_OF_SIZE_2 84 97 #undef TYPE_OF_SIZE_4 98 #undef TYPE_OF_SIZE_8 85 99 86 100 #endif -
trunk/synergy/lib/platform/CMSWindowsKeyState.cpp
r2753 r2768 1189 1189 switch (keystroke.m_type) { 1190 1190 case Keystroke::kButton: { 1191 LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));1191 LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, (UInt32)keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); 1192 1192 KeyButton button = keystroke.m_data.m_button.m_button; 1193 1193 … … 1200 1200 1201 1201 // get the virtual key for the button 1202 UINT vk = keystroke.m_data.m_button.m_client;1202 UINT vk = (UINT)keystroke.m_data.m_button.m_client; 1203 1203 1204 1204 // special handling of VK_SNAPSHOT -
trunk/synergy/lib/platform/COSXKeyState.cpp
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2004 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 145 145 } 146 146 147 KeyButton 147 KeyButton 148 148 COSXKeyState::mapKeyFromEvent(CKeyIDs& ids, 149 149 KeyModifierMask* maskOut, EventRef event) const … … 366 366 switch (keystroke.m_type) { 367 367 case Keystroke::kButton: 368 LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));368 LOG((CLOG_DEBUG1 " %03x (%08x) %s", keystroke.m_data.m_button.m_button, (UInt32)keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); 369 369 370 370 // let system figure out character for us … … 552 552 } 553 553 macVirtualKey = mapKeyButtonToVirtualKey(button); 554 554 555 555 // calculate modifier mask 556 556 macModifierMask = 0; … … 570 570 macModifierMask |= alphaLock; 571 571 } 572 572 573 573 return true; 574 574 } 575 575 576 576 void 577 577 COSXKeyState::handleModifierKeys(void* target, -
trunk/synergy/lib/platform/CPMKeyState.cpp
r2765 r2768 28 28 29 29 // map virtual keys to synergy key enumeration 30 const KeyIDCPMKeyState::s_virtualKey[0x42] =31 { 32 /* 0x000 */ kKeyNone,// reserved33 /* 0x001 */ kKeyNone,// VK_BUTTON134 /* 0x002 */ kKeyNone,// VK_BUTTON235 /* 0x003 */ kKeyNone,// VK_BUTTON336 /* 0x004 */ kKeyBreak,// VK_BREAK37 /* 0x005 */ kKeyBackSpace,// VK_BACKSPACE38 /* 0x006 */ kKeyTab,// VK_TAB39 /* 0x007 */ kKeyLeftTab, // VK_BACKTAB -- ??? 40 /* 0x008 */ kKeyReturn,// VK_NEWLINE41 /* 0x009 */ kKeyShift_L,// VK_SHIFT42 /* 0x00a */ kKeyControl_L,// VK_CTRL43 /* 0x00b */ kKeyAlt_L,// VK_ALT44 /* 0x00c */ kKeyAltGr,// VK_ALTGRAF45 /* 0x00d */ kKeyPause,// VK_PAUSE46 /* 0x00e */ kKeyCapsLock,// VK_CAPSLOCK47 /* 0x00f */ kKeyEscape,// VK_ESC48 /* 0x010 */ kKeyNone,// VK_SPACE49 /* 0x011 */ kKeyPageUp,// VK_PAGEUP50 /* 0x012 */ kKeyPageDown,// VK_PAGEDOWN51 /* 0x013 */ kKeyEnd,// VK_END52 /* 0x014 */ kKeyHome,// VK_HOME53 /* 0x015 */ kKeyLeft,// VK_LEFT54 /* 0x016 */ kKeyUp,// VK_UP55 /* 0x017 */ kKeyRight,// VK_RIGHT56 /* 0x018 */ kKeyDown,// VK_DOWN57 /* 0x019 */ kKeyNone,// VK_PRINTSCRN58 /* 0x01a */ kKeyInsert,// VK_INSERT59 /* 0x01b */ kKeyDelete,// VK_DELETE60 /* 0x01c */ kKeyScrollLock,// VK_SCRLLOCK61 /* 0x01d */ kKeyNumLock,// VK_NUMLOCK62 /* 0x01e */ kKeyKP_Enter,// VK_ENTER63 /* 0x01f */ kKeySysReq,// VK_SYSRQ64 /* 0x020 */ kKeyF1,// VK_F165 /* 0x021 */ kKeyF2,// VK_F266 /* 0x022 */ kKeyF3,// VK_F367 /* 0x023 */ kKeyF4,// VK_F468 /* 0x024 */ kKeyF5,// VK_F569 /* 0x025 */ kKeyF6,// VK_F670 /* 0x026 */ kKeyF7,// VK_F771 /* 0x027 */ kKeyF8,// VK_F872 /* 0x028 */ kKeyF9,// VK_F973 /* 0x029 */ kKeyF10,// VK_F1074 /* 0x02a */ kKeyF11,// VK_F1175 /* 0x02b */ kKeyF12,// VK_F1276 /* 0x02c */ kKeyF13,// VK_F1377 /* 0x02d */ kKeyF14,// VK_F1478 /* 0x02e */ kKeyF15,// VK_F1579 /* 0x02f */ kKeyF16,// VK_F1680 /* 0x030 */ kKeyF17,// VK_F1781 /* 0x031 */ kKeyF18,// VK_F1882 /* 0x032 */ kKeyF19,// VK_F1983 /* 0x033 */ kKeyF20,// VK_F2084 /* 0x034 */ kKeyF21,// VK_F2185 /* 0x035 */ kKeyF22,// VK_F2286 /* 0x036 */ kKeyF23,// VK_F2387 /* 0x037 */ kKeyF24,// VK_F2488 /* 0x038 */ kKeyNone,// VK_ENDDRAG89 /* 0x039 */ kKeyClear,// VK_CLEAR90 /* 0x03a */ kKeyNone,// VK_EREOF91 /* 0x03b */ kKeyNone,// VK_PA192 /* 0x03c */ kKeyNone,// VK_ATTN93 /* 0x03d */ kKeyNone,// VK_CRSEL94 /* 0x03e */ kKeyNone,// VK_EXSEL95 /* 0x03f */ kKeyNone,// VK_COPY96 /* 0x040 */ kKeyNone,// VK_BLK197 /* 0x041 */ kKeyNone// VK_BLK230 const 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 98 98 }; 99 99 … … 354 354 } 355 355 356 static USHORT 357 convertKeyModiferMaskToTCF(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 369 static KeyModifierMask 370 convertTCFToKeyModiferMask(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 382 static bool 383 isASCIIControlChar(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 398 void 399 CPMKeyState::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 356 453 void 357 454 CPMKeyState::getKeyMap(CKeyMap& keyMap) … … 375 472 376 473 CKeyMap::KeyItem item; 377 // SInt32 numGroups = (SInt32)m_groups.size();378 // for (SInt32 g = 0; g < numGroups; ++g) {379 474 for (SInt32 g = 0; g < 1; ++g) { 380 475 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 // 384 509 memset(m_buttonToVK, 0, sizeof(m_buttonToVK)); 385 386 // map buttons (scancodes) to virtual keys387 510 for (KeyButton i = 1; i < 256; ++i) { 388 511 USHORT usVirtualKey = i; … … 394 517 } 395 518 } 519 520 /// @todo the stuff down to the button loop isn't really done yet. 396 521 397 522 // now map virtual keys to buttons. multiple virtual keys may map … … 406 531 case VK_BUTTON2: 407 532 case VK_BUTTON3: 408 case VK_SHIFT:409 case VK_CTRL:410 533 case VK_MENU: 411 534 continue; … … 423 546 } 424 547 } 425 426 /// @todo?427 // // add alt+printscreen428 // if (m_buttonToVK[0x54u] == 0) {429 // m_buttonToVK[0x54u] = VK_SNAPSHOT;430 // }431 548 432 549 // set virtual key to button table … … 441 558 // } 442 559 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 // 447 568 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 } 450 600 if ( usChar 451 || m_buttonToVK[i]) {452 // initialize item453 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); 454 604 item.m_button = i; 455 605 item.m_required = 0; 456 606 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; 462 609 463 610 // get flags for modifier keys 464 611 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 545 819 } 546 820 … … 557 831 switch (keystroke.m_type) { 558 832 case Keystroke::kButton: { 559 LOG((CLOG_DEBUG1 " %03x (%08 x) %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, 560 834 keystroke.m_data.m_button.m_press ? "down" : "up", keystroke.m_data.m_button.m_repeat ? " repeate" : "")); 561 835 KeyButton button = keystroke.m_data.m_button.m_button; … … 569 843 570 844 // 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 // 577 849 // 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. 578 864 HAB hab = CPMUtil::getHAB();/// @todo fix this 579 865 QMSG qmsg; 580 866 qmsg.hwnd = NULLHANDLE; 581 qmsg.msg = WM_ CHAR;867 qmsg.msg = WM_VIOCHAR; 582 868 qmsg.ptl.x = 0; 583 869 qmsg.ptl.y = 0; … … 585 871 qmsg.reserved = 0; 586 872 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. 907 KDD_PREFIXKEY 908 KDD_PAUSEKEY 909 KDD_PSEUDOPAUSE 910 KDD_WAKEUPKEY 911 KDD_BREAKKEY 912 KDD_PSEUDOBREAK 913 KDD_PRTECHOKEY 914 KDD_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); 590 936 } 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 } 598 965 } 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))); 613 975 const char *pszError = m_fakeMsg(hab, &qmsg); 614 976 if (pszError) { … … 618 980 // remember the previous key for KC_LONEKEY. 619 981 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; 621 983 break; 622 984 } … … 654 1016 655 1017 KeyID 656 CPMKeyState::getKeyID(ULONG virtualKey, KeyButton button )1018 CPMKeyState::getKeyID(ULONG virtualKey, KeyButton button, bool numpad, USHORT usChar) 657 1019 { 658 1020 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; 666 1080 } 667 1081 … … 700 1114 } 701 1115 1116 static const char * 1117 getKeyName(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 702 1137 void 703 1138 CPMKeyState::addKeyEntry(CKeyMap& keyMap, CKeyMap::KeyItem& item) 704 1139 { 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 } 707 1178 if (item.m_group == 0) { 708 1179 m_keyToVKMap[item.m_id] = item.m_client; -
trunk/synergy/lib/platform/CPMKeyState.h
r2765 r2768 113 113 no such key. 114 114 */ 115 static KeyID getKeyID(ULONG virtualKey, KeyButton button);115 KeyID getKeyID(ULONG virtualKey, KeyButton button, bool fNumPadKey, USHORT usChar); 116 116 117 117 //@} … … 142 142 143 143 private: 144 typedef union { 145 /** the 64-bit data view. */ 146 UInt64 u; 147 /** the struct view. */ 148 struct 149 { 150 /** The pm scan code. */ 151 unsigned xlatScan : 8; 152 /** The char. */ 153 unsigned xlatChar: 8; 154 /** The raw scan code. */ 155 unsigned scan : 7; 156 /** KDD_EXTENDEDKEY. */ 157 unsigned fExtendedKey : 1; 158 /** The pm scan code of the 2nd message. */ 159 unsigned xlatScan2 : 8; 160 /** The char of the 2nd message. */ 161 unsigned xlatChar2: 8; 162 /** The raw scan code of the 2nd message. */ 163 unsigned scan2 : 7; 164 /** KDD_SECONDARY. */ 165 unsigned fSecondary : 1; 166 /** The virtual key. */ 167 unsigned virtualKey : 7; 168 /** KC_DEADKEY. */ 169 unsigned fDeadKey : 1; 170 /** KC_COMPOSITE. */ 171 unsigned fComposite : 1; 172 /** shift key. */ 173 unsigned fShiftKey : 1; 174 /** Indicates that the key requires the xlscan=2a KDD_SECONADARY+KDD_UNDEFINED+KDD_UNDEFINED 175 * key if numlock is effective. */ 176 unsigned fNeedNumUnlockKey : 1; 177 /** Bits we haven't used yet. */ 178 unsigned fReserved : 4; 179 } s; 180 } ClientData; 181 182 void convertScancodes(ClientData *pData); 144 183 KeyID getIDForKey(CKeyMap::KeyItem& item, 145 184 KeyButton button, ULONG virtualKey, … … 160 199 KeyToVKMap m_keyToVKMap; 161 200 201 // scan code conversions. 202 UInt8 m_pmScanToOemScan[256]; 203 UInt8 m_pmScanToOemScanExt[256]; 204 UInt8 m_oemScanToPmScan[128]; 205 UInt8 m_oemScanToPmScanExt[128]; 206 162 207 // function which can inject fake WM_CHAR messages. 163 208 FakeMsgFunc m_fakeMsg; … … 180 225 KeyModifierMask m_originalSavedModifiers; 181 226 182 static const KeyID s_virtualKey[0x42]; 227 typedef struct { 228 KeyID key; 229 unsigned char ch; 230 bool numpad; 231 char extended; 232 } VirtualKey; 233 static const VirtualKey s_virtualKey[0x42]; 183 234 }; 184 235 -
trunk/synergy/lib/platform/CPMSynergyHook.cpp
r2764 r2768 22 22 #include <InnoTekLIBC/FastInfoBlocks.h> 23 23 #else 24 unsigned long fibGetMsCount(void 24 unsigned long fibGetMsCount(void) 25 25 { 26 26 ULONG ul = 0; … … 50 50 } 51 51 52 #endif 52 #endif 53 53 54 54 // … … 542 542 * @param hab The hab of the current thread. 543 543 * @param pqmsg Where to put the message. 544 * @param fSkip Skip message flag. 544 * @param fSkip Skip message flag. 545 545 * If TRUE we should just skip a message (pqmsg is NULL). If no futher 546 546 * messages are queued, we must release the hook. … … 567 567 } else { 568 568 *pqmsg = g_qmsg; 569 } 570 569 if (pqmsg->msg == WM_VIOCHAR) { 570 /* mp1.s1: KC_ flags. 571 * mp1.c3: repeat 572 * mp1.c4: scancode 573 * mp2.c1: translated char 574 * mp2.c2: translated scancode 575 * mp2.s2: KDD_ flags. 576 */ 577 KbdPacket[0].monFlags = 0; // no monitor flag 578 KbdPacket[0].scancode = CHAR4FROMMP(pqmsg->mp1); 579 KbdPacket[0].xlatedchar = CHAR1FROMMP(pqmsg->mp2); 580 KbdPacket[0].xlatedscan = CHAR2FROMMP(pqmsg->mp2); 581 KbdPacket[0].time = pqmsg->time; 582 KbdPacket[0].ddFlags = SHORT2FROMMP(pqmsg->mp2); 583 /** @todo extended stuff, keypad, workarounds. see pmvnc. */ 584 } 585 } 586 587 /* 588 * We're not recording, so no chance of a feedback loop here. 589 * This doesn't seem to work, bah! 590 */ 591 if (pfNoRecord) { 592 *pfNoRecord = FALSE; 593 } 571 594 return TRUE; 572 595 } … … 587 610 assert(g_fSynergyInitialized); 588 611 if (g_fSynergyInitialized) { 589 /* 612 /* 590 613 * Reset the event semaphore and queue the message for MsgInputHook. 591 614 */ … … 609 632 610 633 /* 611 * It took a bit longer than expected. We'll wait for some 2-3 634 * It took a bit longer than expected. We'll wait for some 2-3 612 635 * seconds before we give up. This might be a bit paranoid, but 613 636 * I'd rather drop a message than locking up PM. … … 623 646 if (rc != ERROR_TIMEOUT && rc != ERROR_SEM_TIMEOUT && rc != ERROR_INTERRUPT) { 624 647 break; 625 } 648 } 626 649 if (fibGetMsCount() - ulStart > 2500) { 627 650 break; … … 630 653 } 631 654 632 /* 633 * Since we probably didn't manage to inject the message, we should 634 * release the hook to make sure we're not overwriting g_qmsg while 655 /* 656 * Since we probably didn't manage to inject the message, we should 657 * release the hook to make sure we're not overwriting g_qmsg while 635 658 * some other thread is reading it from MsgInputHook. 636 659 */ … … 639 662 pszRet = g_pszErrorMsg; 640 663 return pszRet ? pszRet : "timed out"; 641 } 664 } 642 665 pszRet = "WinSetHook failed"; 643 666 } else { -
trunk/synergy/lib/platform/CPMSynergyHook.def
r2763 r2768 2 2 DATA SHARED 3 3 4 IMPORTS 5 _KbdPacket = PMWIN.174 ; fix KbdPacket in win.imp and make it data! 6 -
trunk/synergy/lib/platform/CPMSynergyHook.h
r2763 r2768 87 87 CSYNERGYHOOK_API const char * fakeMsg(HAB hab, const QMSG *pQmsg); 88 88 89 90 91 // 92 // Various OS/2 stuff from the DDK. 93 // 94 95 /* 96 * video/rel/.../pmwinp.mac and pmwinx.h in the ddk. 97 */ 98 typedef struct _KBDEVENT { /* kevt */ 99 BYTE monFlags; /* Open, Close and Flush monitor flags */ 100 BYTE scancode; /* Original scan code (actually high byte of 101 monitor flags */ 102 BYTE xlatedchar; /* Output of interrupt level character translation 103 table */ 104 105 BYTE xlatedscan; /* Translated scan code. Different only for 106 the enhanced keyboard */ 107 108 USHORT shiftDBCS; /* DBCS shift state and status */ 109 USHORT shiftstate; /* Current state of shift keys */ 110 ULONG time; /* millisecond counter time stamp */ 111 USHORT ddFlags; /* Keyboard device driver flags */ 112 } KBDEVENT; 113 typedef KBDEVENT *PKBDEVENT; 114 // guess MON_* are for the monFlags field. 115 #define MON_OPEN EQU 0001H 116 #define MON_CLOSE EQU 0002H 117 #define MON_FLUSH EQU 0004H 118 // guess KSS_* is for the shiftstate field. 119 #define KSS_SYSREQ EQU 8000H 120 #define KSS_CAPSLOCK EQU 4000H 121 #define KSS_NUMLOCK EQU 2000H 122 #define KSS_SCROLLLOCK EQU 1000H 123 #define KSS_RIGHTALT EQU 0800H 124 #define KSS_RIGHTCTRL EQU 0400H 125 #define KSS_LEFTALT EQU 0200H 126 #define KSS_LEFTCTRL EQU 0100H 127 #define KSS_INSERTON EQU 0080H 128 #define KSS_CAPSLOCKON EQU 0040H 129 #define KSS_NUMLOCKON EQU 0020H 130 #define KSS_SCROLLLOCKON EQU 0010H 131 #define KSS_EITHERALT EQU 0008H 132 #define KSS_EITHERCTRL EQU 0004H 133 #define KSS_LEFTSHIFT EQU 0002H 134 #define KSS_RIGHTSHIFT EQU 0001H 135 #define KSS_EITHERSHIFT EQU 0003H 136 /* Valid values for ddFlags field */ 137 #define KDD_MONFLAG1 0x8000 // bird: conflicts with KDD_KC_LONEKEY - relevant for VIOCHAR? 138 #define KDD_MONFLAG2 0x4000 // bird: conflicts with KDD_KC_PREVDOWN - relevant for VIOCHAR? 139 #define KDD_RESERVED 0x3C00 140 #define KDD_ACCENTED 0x0200 141 #define KDD_MULTIMAKE 0x0100 142 #define KDD_SECONDARY 0x0080 143 #define KDD_BREAK 0x0040 144 #define KDD_EXTENDEDKEY 0x0020 145 #define KDD_ACTIONFIELD 0x001F 146 #define KDD_KC_LONEKEY 0x8000 147 #define KDD_KC_PREVDOWN 0x4000 148 #define KDD_KC_KEYUP 0x2000 149 #define KDD_KC_ALT 0x1000 150 #define KDD_KC_CTRL 0x0800 151 #define KDD_KC_SHIFT 0x0400 152 #define KDD_KC_FLAGS 0x0FC00 153 /* Valid values for KDD_ACTIONFIELD portion of ddFlags field */ 154 #define KDD_PUTINKIB 0x0000 155 #define KDD_ACK 0x0001 156 #define KDD_PREFIXKEY 0x0002 157 #define KDD_OVERRUN 0x0003 158 #define KDD_RESEND 0x0004 159 #define KDD_REBOOTKEY 0x0005 160 #define KDD_DUMPKEY 0x0006 161 #define KDD_SHIFTKEY 0x0007 162 #define KDD_PAUSEKEY 0x0008 163 #define KDD_PSEUDOPAUSE 0x0009 164 #define KDD_WAKEUPKEY 0x000A 165 #define KDD_BADACCENT 0x000B 166 #define KDD_HOTKEY 0x000C 167 #define KDD_ACCENTKEY 0x0010 168 #define KDD_BREAKKEY 0x0011 169 #define KDD_PSEUDOBREAK 0x0012 170 #define KDD_PRTSCKEY 0x0013 171 #define KDD_PRTECHOKEY 0x0014 172 #define KDD_PSEUDOPRECH 0x0015 173 #define KDD_STATUSCHG 0x0016 174 #define KDD_WRITTENKEY 0x0017 175 #define KDD_UNDEFINED 0x001F 176 177 /// PMWIN.174 178 // This needs to be used when pushing stuff to VIO programs. (pmvnc does anyway) 179 extern "C" KBDEVENT KbdPacket[2]; 180 89 181 #endif -
trunk/synergy/lib/platform/CPMUtil.h
r2765 r2768 42 42 43 43 }; 44 45 44 46 45 /** The WinTranlateChar2 operation. */ -
trunk/synergy/lib/platform/CXWindowsKeyState.cpp
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2003 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 206 206 switch (keystroke.m_type) { 207 207 case Keystroke::kButton: 208 LOG((CLOG_DEBUG1 " %03x (%08 x) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up"));208 LOG((CLOG_DEBUG1 " %03x (%08llx) %s", keystroke.m_data.m_button.m_button, keystroke.m_data.m_button.m_client, keystroke.m_data.m_button.m_press ? "down" : "up")); 209 209 if (keystroke.m_data.m_button.m_repeat) { 210 210 int c = keystroke.m_data.m_button.m_button; … … 301 301 tmpKeysyms[maxKeysyms * i + j] = NoSymbol; 302 302 } 303 } 303 } 304 304 } 305 305 XFree(allKeysyms); -
trunk/synergy/lib/synergy/CKeyMap.cpp
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2005 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 60 60 } 61 61 62 void 62 bool 63 63 CKeyMap::addKeyEntry(const KeyItem& item) 64 64 { 65 65 // ignore kKeyNone 66 66 if (item.m_id == kKeyNone) { 67 return ;67 return false; 68 68 } 69 69 … … 93 93 for (size_t i = 0, n = entries.size(); i < n; ++i) { 94 94 if (entries[i].size() == 1 && newItem == entries[i][0]) { 95 return ;95 return false; 96 96 } 97 97 } … … 99 99 // add item list 100 100 entries.push_back(items); 101 LOG((CLOG_DEBUG1 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); 101 LOG((CLOG_DEBUG1 "add key: %04x %d %03x %04x (%04x %04x %04x)%s", newItem.m_id, newItem.m_group, newItem.m_button, (UInt32)newItem.m_client, newItem.m_required, newItem.m_sensitive, newItem.m_generates, newItem.m_dead ? " dead" : "")); 102 return true; 102 103 } 103 104 … … 722 723 assert(group >= 0 && group < getNumGroups()); 723 724 724 // find a key that generates the given modifier in the given group 725 // find a key that generates the given modifier in the given group 725 726 // but doesn't use the given button, presumably because we're trying 726 727 // to generate a KeyID that's only bound the the given button. … … 960 961 { 961 962 KeyButton button = keyItem.m_button; 962 UInt 32data = keyItem.m_client;963 UInt64 data = keyItem.m_client; 963 964 switch (type) { 964 965 case kKeystrokePress: … … 978 979 } 979 980 break; 980 981 981 982 case kKeystrokeRelease: 982 983 keystrokes.push_back(Keystroke(button, false, false, data)); … … 1000 1001 } 1001 1002 break; 1002 1003 1003 1004 case kKeystrokeRepeat: 1004 1005 keystrokes.push_back(Keystroke(button, false, true, data)); … … 1006 1007 // no modifier changes on key repeat 1007 1008 break; 1008 1009 1009 1010 case kKeystrokeClick: 1010 1011 keystrokes.push_back(Keystroke(button, true, false, data)); … … 1012 1013 // no modifier changes on key click 1013 1014 break; 1014 1015 1015 1016 case kKeystrokeModify: 1016 1017 case kKeystrokeUnmodify: … … 1313 1314 1314 1315 CKeyMap::Keystroke::Keystroke(KeyButton button, 1315 bool press, bool repeat, UInt 32data) :1316 bool press, bool repeat, UInt64 data) : 1316 1317 m_type(kButton) 1317 1318 { -
trunk/synergy/lib/synergy/CKeyMap.h
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2005 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 51 51 bool m_dead; //!< \c true if this is a dead KeyID 52 52 bool m_lock; //!< \c true if this locks a modifier 53 UInt 32m_client; //!< Client data53 UInt64 m_client; //!< Client data 54 54 55 55 public: … … 77 77 }; 78 78 79 Keystroke(KeyButton, bool press, bool repeat, UInt 32clientData);79 Keystroke(KeyButton, bool press, bool repeat, UInt64 clientData); 80 80 Keystroke(SInt32 group, bool absolute, bool restore); 81 81 … … 86 86 bool m_press; //!< \c true iff press 87 87 bool m_repeat; //!< \c true iff for an autorepeat 88 UInt 32m_client; //!< Client data88 UInt64 m_client; //!< Client data 89 89 }; 90 90 struct CGroup { … … 127 127 Adds \p item to the entries for the item's id and group. The 128 128 \c m_dead member is set automatically. 129 */ 130 void addKeyEntry(const KeyItem& item); 129 Returns true if accepted, false if for some reasons rejected. 130 */ 131 bool addKeyEntry(const KeyItem& item); 131 132 132 133 //! Add an alias key entry … … 315 316 and \c false if the string cannot be parsed. The modifiers plus any 316 317 remaining leading and trailing whitespace is stripped from the input 317 string. 318 string. 318 319 */ 319 320 static bool parseModifiers(CString&, KeyModifierMask&); … … 331 332 kKeystrokeUnmodify //!< Synthesize releasing a modifier 332 333 }; 333 334 334 335 // A list of ways to synthesize a KeyID 335 336 typedef std::vector<KeyItemList> KeyEntryList; -
trunk/synergy/lib/synergy/CKeyState.cpp
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2004 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 503 503 context->m_activeModifiers.insert(std::make_pair( 504 504 keyItem.m_generates, keyItem)); 505 } 505 } 506 506 } 507 507 … … 614 614 ++m_keys[localID]; 615 615 ++m_syntheticKeys[localID]; 616 m_keyClientData[localID] = keyItem->m_client;617 616 m_serverKeys[serverID] = localID; 618 617 } -
trunk/synergy/lib/synergy/CKeyState.h
r2749 r2768 2 2 * synergy -- mouse and keyboard sharing utility 3 3 * Copyright (C) 2004 Chris Schoeneman 4 * 4 * 5 5 * This package is free software; you can redistribute it and/or 6 6 * modify it under the terms of the GNU General Public License 7 7 * found in the file COPYING that should have accompanied this file. 8 * 8 * 9 9 * This package is distributed in the hope that it will be useful, 10 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of … … 148 148 CAddActiveModifierContext& operator=(const CAddActiveModifierContext&); 149 149 }; 150 150 151 151 class ButtonToKeyLess { 152 152 public: … … 207 207 208 208 // client data for each pressed key 209 UInt 32m_keyClientData[kNumButtons];209 UInt64 m_keyClientData[kNumButtons]; 210 210 211 211 // server keyboard state. an entry is 0 if not the key isn't pressed
Note:
See TracChangeset
for help on using the changeset viewer.