DirectInput to CEGUI utf32
Written for CEGUI 0.4
Works with versions 0.4.x (obsolete)
Written for CEGUI 0.5
Works with versions 0.5.x (obsolete)
Written for CEGUI 0.6
Works with versions 0.6.x (obsolete)
Written for CEGUI 0.7
Works with versions 0.7.x (obsolete)
This function converts DirectInput's scan codes into a utf32 character value compatible with the injectChar() function. It converts both simple characters as well as characters composed of a dead key as well as a single character, simplifying multi-lingual support. The value of zero is returned if a character could not be converted.
Some characters are composed by two keystrokes; a dead key followed by a simple key. An example with the French (Canada) keyboard is the letter è, which is composed of the dead key (diacritic) ALT-[ followed by the letter e. In order to correctly generate the letter è the dead key must be converted from a standalone diacritic to a combining diacritic. The unicode character set specifies the combining diacritics in the range of 0x300 to 0x36F. This current implementation only supports 5 diacritic, making the following code compatible with both English and French languages. The list of combining diacritics can be obtained from http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
By default CEGUI only loads a portion of the character set specified in a font. The following code loads the entire Latin character set:
CEGUI::Font* guiFont = CEGUI::FontManager::getSingleton().createFont("Arial", "c:/windows/fonts/arial.ttf", 16, CEGUI::Default); guiFont->defineFontGlyphs(0x0020, 0x0323); // Latin character set mGUISystem->setDefaultFont(guiFont);
The Character Map (charmap.exe) tool is very useful when trying to figure out the range of characters needed.
CEGUI::utf32 keycodeToUTF32( unsigned int scanCode) { CEGUI::utf32 utf = 0; BYTE keyboardState[256]; unsigned char ucBuffer[3]; static WCHAR deadKey = '\0'; // Retrieve the keyboard layout in order to perform the necessary convertions HKL hklKeyboardLayout = GetKeyboardLayout(0); // 0 means current thread // This seemingly cannot fail // If this value is cached then the application must respond to WM_INPUTLANGCHANGE // Retrieve the keyboard state // Handles CAPS-lock and SHIFT states if (GetKeyboardState(keyboardState) == FALSE) return utf; /* 0. Convert virtual-key code into a scan code 1. Convert scan code into a virtual-key code Does not distinguish between left- and right-hand keys. 2. Convert virtual-key code into an unshifted character value in the low order word of the return value. Dead keys (diacritics) are indicated by setting the top bit of the return value. 3. Windows NT/2000/XP: Convert scan code into a virtual-key Distinguishes between left- and right-hand keys.*/ UINT virtualKey = MapVirtualKeyEx(scanCode, 3, hklKeyboardLayout); if (virtualKey == 0) // No translation possible return utf; /* Parameter 5: 0. No menu is active 1. A menu is active Return values: Negative. Returned a dead key 0. No translation available 1. A translation exists 2. Dead-key could not be combined with character */ int ascii = ToAsciiEx(virtualKey, scanCode, keyboardState, (LPWORD) ucBuffer, 0, hklKeyboardLayout); if(deadKey != '\0' && ascii == 1) { // A dead key is stored and we have just converted a character key // Combine the two into a single character WCHAR wcBuffer[3]; WCHAR out[3]; wcBuffer[0] = ucBuffer[0]; wcBuffer[1] = deadKey; wcBuffer[2] = '\0'; if( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) ) utf = out[0]; else { // FoldStringW failed DWORD dw = GetLastError(); switch(dw) { case ERROR_INSUFFICIENT_BUFFER: case ERROR_INVALID_FLAGS: case ERROR_INVALID_PARAMETER: break; } } deadKey = '\0'; } else if (ascii == 1) { // We have a single character utf = ucBuffer[0]; deadKey = '\0'; } else { // Convert a non-combining diacritical mark into a combining diacritical mark switch(ucBuffer[0]) { case 0x5E: // Circumflex accent: â deadKey = 0x302; break; case 0x60: // Grave accent: à deadKey = 0x300; break; case 0xA8: // Diaeresis: ü deadKey = 0x308; break; case 0xB4: // Acute accent: é deadKey = 0x301; break; case 0xB8: // Cedilla: ç deadKey = 0x327; break; default: deadKey = ucBuffer[0]; } } return utf; }