/* $Id: $ */ /** @file * * dumpchar - dump scancodes, virtual keys, and character conversions. * * Copyright (c) 2006 knut st. osmundsen * * GPL * */ /******************************************************************************* * Header Files * *******************************************************************************/ #define INCL_PM #define INCL_ERRORS #define INCL_DOS #include #include #include #include /** The WinTranlateChar2 operation. */ typedef enum WINTCOP { TC_CHARTOSCANCODE = 0, TC_SCANCODETOCHAR, TC_VIRTUALKEYTOSCANCODE, TC_SCANCODETOVIRTUALKEY, TC_SCANTOOEMSCAN, TC_OEMSCANTOSCAN, TC_SIZE_HACK = 0x7fff } WINTCOP; /** @name WinTranslateChar2 shift state. * This state goes with scancode input/output. * @{ */ #define TCF_LSHIFT 0x1 #define TCF_RSHIFT 0x2 #define TCF_SHIFT (TCF_LSHIFT | TCF_RSHIFT) #define TCF_LCONTROL 0x4 #define TCF_RCONTROL 0x8 #define TCF_CONTROL (TCF_LCONTROL | TCF_RCONTROL) #define TCF_ALT 0x10 #define TCF_ALTGR 0x20 #define TCF_CAPSLOCK 0x40 #define TCF_NUMLOCK 0x80 #define TCF_MAX_BITS 8 /**< bits 0-7 are real shift states */ #define TCF_OEMSCANCODE 0x100 #define TCF_EXTENDEDKEY 0x200 /** @} */ /** * Char to/from keyboard code translator. * * @returns A combination of some of the KC_* values. * @param usCodePage The code page. Anything goes, apparently ignored. * @param pusCharInOut Where to get the char/code to be translated and to * put the output upon return. * @param pulDeadKeyInfo Previous, dead key. * @param enmOperation The kind of translation. * @param pfShiftState Where to read/store the shift state. Used when * translating from/to scancodes. */ USHORT APIENTRY WinTranslateChar2(USHORT usCodePage, PUSHORT pusCharInOut, PULONG pulDeadKeyInfo, WINTCOP enmOperation, PUSHORT pfShiftState); /** * Get the name of a virtual key. * @returns the key name (readonly). * @param ulVirtualKey The virtual key. */ const char *GetVirtualKeyName(ULONG ulVirtualKey) { switch (ulVirtualKey) { #define CASE(vk) case vk: return #vk CASE(VK_BUTTON1); CASE(VK_BUTTON2); CASE(VK_BUTTON3); CASE(VK_BREAK); CASE(VK_BACKSPACE); CASE(VK_TAB); CASE(VK_BACKTAB); CASE(VK_NEWLINE); CASE(VK_SHIFT); CASE(VK_CTRL); CASE(VK_ALT); CASE(VK_ALTGRAF); CASE(VK_PAUSE); CASE(VK_CAPSLOCK); CASE(VK_ESC); CASE(VK_SPACE); CASE(VK_PAGEUP); CASE(VK_PAGEDOWN); CASE(VK_END); CASE(VK_HOME); CASE(VK_LEFT); CASE(VK_UP); CASE(VK_RIGHT); CASE(VK_DOWN); CASE(VK_PRINTSCRN); CASE(VK_INSERT); CASE(VK_DELETE); CASE(VK_SCRLLOCK); CASE(VK_NUMLOCK); CASE(VK_ENTER); CASE(VK_SYSRQ); CASE(VK_F1); CASE(VK_F2); CASE(VK_F3); CASE(VK_F4); CASE(VK_F5); CASE(VK_F6); CASE(VK_F7); CASE(VK_F8); CASE(VK_F9); CASE(VK_F10); CASE(VK_F11); CASE(VK_F12); CASE(VK_F13); CASE(VK_F14); CASE(VK_F15); CASE(VK_F16); CASE(VK_F17); CASE(VK_F18); CASE(VK_F19); CASE(VK_F20); CASE(VK_F21); CASE(VK_F22); CASE(VK_F23); CASE(VK_F24); CASE(VK_ENDDRAG); CASE(VK_CLEAR); CASE(VK_EREOF); CASE(VK_PA1); CASE(VK_ATTN); CASE(VK_CRSEL); CASE(VK_EXSEL); CASE(VK_COPY); CASE(VK_BLK1); CASE(VK_BLK2); #undef CASE default: return ""; } } char GetChar(unsigned ch) { if (ch < 128 && isprint(ch)) { return ch; } return '.'; } int main() { /* * PM prolog. */ PPIB pPib; DosGetInfoBlocks(NULL, &pPib); pPib->pib_ultype = 3; HAB hab = WinInitialize(0); HMQ hmq = WinCreateMsgQueue(hab, 0); (void)hmq; /* * char to scancode to virtual key. */ printf("char -> scancode -> virtual key\n"); for (unsigned iChar = 0; iChar < 256; iChar++) { /* to scancode */ USHORT usScanCode = iChar; ULONG ulScanCodeDeadKeyInfo = 0; USHORT fScanCodeShiftState = 0; USHORT fScanCodeRc = WinTranslateChar2(0, &usScanCode, &ulScanCodeDeadKeyInfo, TC_CHARTOSCANCODE, &fScanCodeShiftState); if (usScanCode) { /* to virtual key */ USHORT usVirtualKey = usScanCode; ULONG ulVirtualKeyDeadKeyInfo = ulScanCodeDeadKeyInfo; USHORT fVirtualKeyShiftState = fScanCodeShiftState; USHORT fVirtualKeyRc = WinTranslateChar2(0, &usVirtualKey, &ulVirtualKeyDeadKeyInfo, TC_SCANCODETOVIRTUALKEY, &fVirtualKeyShiftState); printf("%d/%#x/[%c]: %04x %lx %04x %04x | %04x %lx %04x %04x (%s)\n", iChar, iChar, GetChar(iChar), usScanCode, ulScanCodeDeadKeyInfo, fScanCodeShiftState, fScanCodeRc, usVirtualKey, ulVirtualKeyDeadKeyInfo, fVirtualKeyShiftState, fVirtualKeyRc, GetVirtualKeyName(usVirtualKey)); } } /* * virtual key to scancode and char. */ printf("\n" "\n" "\n" "virtual key -> scancode -> char\n"); for (unsigned iVirtualKey = 0; iVirtualKey < 512; iVirtualKey++) { /* to scancode */ USHORT usScanCode = iVirtualKey; ULONG ulScanCodeDeadKeyInfo = 0; USHORT fScanCodeShiftState = 0; USHORT fScanCodeRc = WinTranslateChar2(0, &usScanCode, &ulScanCodeDeadKeyInfo, TC_VIRTUALKEYTOSCANCODE, &fScanCodeShiftState); if (usScanCode) { /* to char */ USHORT usChar = usScanCode; ULONG ulCharDeadKeyInfo = 0; USHORT fCharShiftState = fScanCodeShiftState; USHORT fCharRc = WinTranslateChar2(0, &usChar, &ulCharDeadKeyInfo, TC_SCANCODETOCHAR, &fCharShiftState); if (usChar) { printf("%3d/%#04x: %04x %lx %04x %04x | %04x[%c] %lx %04x %04x [%s]\n", iVirtualKey, iVirtualKey, usScanCode, ulScanCodeDeadKeyInfo, fScanCodeShiftState, fScanCodeRc, usChar, GetChar(usChar), ulCharDeadKeyInfo, fCharShiftState, fCharRc, GetVirtualKeyName(iVirtualKey)); } else { printf("%3d/%#04x: %04x %lx %04x %04x [%s]\n", iVirtualKey, iVirtualKey, usScanCode, ulScanCodeDeadKeyInfo, fScanCodeShiftState, fScanCodeRc, GetVirtualKeyName(iVirtualKey)); } } } printf("\n" "\n" "\n" "scan code -> oem scan code -> scan code\n"); for (unsigned iScanCode = 0; iScanCode < 256; iScanCode++) { USHORT usOemScanCode = iScanCode; ULONG ulOemScanCodeDeadKeyInfo = 0; USHORT fOemScanCodeShiftState = 0; USHORT fOemScanCodeRc = WinTranslateChar2(0, &usOemScanCode, &ulOemScanCodeDeadKeyInfo, TC_SCANTOOEMSCAN, &fOemScanCodeShiftState); if (usOemScanCode) { printf("%3d/%#04x: %04x %lx %04x %04x", iScanCode, iScanCode, usOemScanCode, ulOemScanCodeDeadKeyInfo, fOemScanCodeShiftState, fOemScanCodeRc); /* the other way */ fOemScanCodeRc = WinTranslateChar2(0, &usOemScanCode, &ulOemScanCodeDeadKeyInfo, TC_SCANTOOEMSCAN, &fOemScanCodeShiftState); printf(" -> %04x %lx %04x %04x%s\n", usOemScanCode, ulOemScanCodeDeadKeyInfo, fOemScanCodeShiftState, fOemScanCodeRc, usOemScanCode != iScanCode ? " *" :""); } } printf("\n" "\n" "\n" "oem scan code -> scan code\n"); for (unsigned iOemScanCode = 0; iOemScanCode < 128; iOemScanCode++) { USHORT usScanCode = iOemScanCode; ULONG ulScanCodeDeadKeyInfo = 0; USHORT fScanCodeShiftState = 0; USHORT fScanCodeRc = WinTranslateChar2(0, &usScanCode, &ulScanCodeDeadKeyInfo, TC_OEMSCANTOSCAN, &fScanCodeShiftState); if (usScanCode) { printf("%3d/%#04x: %04x %lx %04x %04x\n", iOemScanCode, iOemScanCode, usScanCode, ulScanCodeDeadKeyInfo, fScanCodeShiftState, fScanCodeRc); } } printf("\n" "\n" "\n" "scan code -> extended oem scan code -> scan code\n"); for (unsigned iScanCode = 0; iScanCode < 256; iScanCode++) { USHORT usOemScanCode = iScanCode; ULONG ulOemScanCodeDeadKeyInfo = 0; USHORT fOemScanCodeShiftState = TCF_EXTENDEDKEY; USHORT fOemScanCodeRc = WinTranslateChar2(0, &usOemScanCode, &ulOemScanCodeDeadKeyInfo, TC_SCANTOOEMSCAN, &fOemScanCodeShiftState); if (usOemScanCode) { printf("%3d/%#04x: %04x %lx %04x %04x", iScanCode, iScanCode, usOemScanCode, ulOemScanCodeDeadKeyInfo, fOemScanCodeShiftState, fOemScanCodeRc); /* the other way */ fOemScanCodeRc = WinTranslateChar2(0, &usOemScanCode, &ulOemScanCodeDeadKeyInfo, TC_SCANTOOEMSCAN, &fOemScanCodeShiftState); printf(" -> %04x %lx %04x %04x%s\n", usOemScanCode, ulOemScanCodeDeadKeyInfo, fOemScanCodeShiftState, fOemScanCodeRc, usOemScanCode != iScanCode ? " *" :""); } } printf("\n" "\n" "\n" "extended oem scan code -> scan code\n"); for (unsigned iOemScanCode = 0; iOemScanCode < 128; iOemScanCode++) { USHORT usScanCode = iOemScanCode; ULONG ulScanCodeDeadKeyInfo = 0; USHORT fScanCodeShiftState = TCF_EXTENDEDKEY; USHORT fScanCodeRc = WinTranslateChar2(0, &usScanCode, &ulScanCodeDeadKeyInfo, TC_OEMSCANTOSCAN, &fScanCodeShiftState); if (usScanCode) { printf("%3d/%#04x: %04x %lx %04x %04x\n", iOemScanCode, iOemScanCode, usScanCode, ulScanCodeDeadKeyInfo, fScanCodeShiftState, fScanCodeRc); } } /* * scancode to char and virtual key. */ printf("\n" "\n" "\n" "scancode -> char + virtual key \n"); for (unsigned iScanCode = 0; iScanCode < 256; iScanCode++) { struct { USHORT usVirtualKey; USHORT usChar; USHORT fCharRc; } aCombinations[1 << TCF_MAX_BITS]; for (unsigned fShiftState = 0; fShiftState < (1 << TCF_MAX_BITS); fShiftState++) { /* to char */ USHORT usChar = iScanCode; ULONG ulCharDeadKeyInfo = 0; USHORT fCharShiftState = fShiftState; USHORT fCharRc = WinTranslateChar2(0, &usChar, &ulCharDeadKeyInfo, TC_SCANCODETOCHAR, &fCharShiftState); aCombinations[fShiftState].usChar = usChar; aCombinations[fShiftState].fCharRc = fCharRc; /* to virtual key */ USHORT usVirtualKey = iScanCode; ULONG ulVirtualKeyDeadKeyInfo = 0; USHORT fVirtualKeyShiftState = fShiftState; USHORT fVirtualKeyRc = WinTranslateChar2(0, &usVirtualKey, &ulVirtualKeyDeadKeyInfo, TC_SCANCODETOVIRTUALKEY, &fVirtualKeyShiftState); aCombinations[fShiftState].usVirtualKey = usVirtualKey; /* display the result */ printf(" %3d/%#04x+%02x[%c%c%c%c%c%c%c%c]: ", iScanCode, iScanCode, fShiftState, fShiftState & TCF_LSHIFT ? 'L' : '-', fShiftState & TCF_RSHIFT ? 'R' : '-', fShiftState & TCF_LCONTROL ? 'l' : '-', fShiftState & TCF_RCONTROL ? 'r' : '-', fShiftState & TCF_ALT ? 'A' : '-', fShiftState & TCF_ALTGR ? 'G' : '-', fShiftState & TCF_CAPSLOCK ? 'C' : '-', fShiftState & TCF_NUMLOCK ? 'N' : '-'); if (usChar && usVirtualKey) { printf("%04x[%c] %lx %04x %04x | %04x %lx %04x %04x (%s)\n", usChar, GetChar(usChar), ulCharDeadKeyInfo, fCharShiftState, fCharRc, usVirtualKey, ulVirtualKeyDeadKeyInfo, fVirtualKeyShiftState, fVirtualKeyRc, GetVirtualKeyName(usVirtualKey)); } else if (usChar) { printf("%04x[%c] %lx %04x %04x\n", usChar, GetChar(usChar), ulCharDeadKeyInfo, fCharShiftState, fCharRc); } else if (usVirtualKey) { printf(" | %04x %lx %04x %04x (%s)\n", usVirtualKey, ulVirtualKeyDeadKeyInfo, fVirtualKeyShiftState, fVirtualKeyRc, GetVirtualKeyName(usVirtualKey)); } else { printf("\n"); } } #if 0 /* 2. Eliminate duplicates. */ for (unsigned j = 0; j < sizeof(aCombinations) / sizeof(aCombinations[0]); j++) { unsigned iBest = j; for (unsigned k = j + 1; k < sizeof(aCombinations) / sizeof(aCombinations[0]); k++) { if ( aCombinations[iBest].usChar == aCombinations[k].usChar && aCombinations[iBest].usVirtualKey == aCombinations[k].usVirtualKey) { // check if one of these is a subset of the other. if ((iBest & k) == k) { aCombinations[iBest].usChar = aCombinations[iBest].usVirtualKey = 0; iBest = k; } else if ( (iBest & k) == iBest /*|| iBest == k - when we can ignore L/R keys */) { aCombinations[k].usChar = aCombinations[k].usVirtualKey = 0; } } } } // 3. Print the remainders. for (unsigned fShiftState = 0; fShiftState < sizeof(aCombinations) / sizeof(aCombinations[0]); fShiftState++) { if (aCombinations[fShiftState].usChar || aCombinations[fShiftState].usVirtualKey) { const USHORT usChar = aCombinations[fShiftState].usChar; const USHORT fCharRc = aCombinations[fShiftState].fCharRc; const USHORT usVirtualKey = aCombinations[fShiftState].usVirtualKey; printf("*%3d/%#04x+%02x[%c%c%c%c%c%c%c%c]: ", iScanCode, iScanCode, fShiftState, fShiftState & TCF_LSHIFT ? 'L' : '-', fShiftState & TCF_RSHIFT ? 'R' : '-', fShiftState & TCF_LCONTROL ? 'l' : '-', fShiftState & TCF_RCONTROL ? 'r' : '-', fShiftState & TCF_ALT ? 'A' : '-', fShiftState & TCF_ALTGR ? 'G' : '-', fShiftState & TCF_CAPSLOCK ? 'C' : '-', fShiftState & TCF_NUMLOCK ? 'N' : '-'); if (usChar && usVirtualKey) { printf("%04x[%c] %04x | %04x (%s)\n", usChar, GetChar(usChar), fCharRc, usVirtualKey, GetVirtualKeyName(usVirtualKey)); } else if (usChar) { printf("%04x[%c] %04x \n", usChar, GetChar(usChar), fCharRc); } else if (usVirtualKey) { printf(" | %04x (%s)\n", usVirtualKey, GetVirtualKeyName(usVirtualKey)); } else { printf("\n"); } } } #endif } return 0; }