Difference between revisions of "DirectInput to CEGUI utf32"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
 
m (because references rule)
 
(7 intermediate revisions by 3 users not shown)
Line 1: Line 1:
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. The value of zero is returned if a character could not be converted.
+
{{VersionBadge|0.4}} {{VersionBadge|0.5}} {{VersionBadge|0.6}} {{VersionBadge|0.7}}
  
CEGUI::utf32 keycodeToUTF32( unsigned int scanCode)
+
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.
{
+
CEGUI::utf32 utf = 0;
+
  
BYTE keyboardState[256];
+
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
unsigned char ucBuffer[3];
+
static WCHAR deadKey = '\0';
+
  
// Retrieve the keyboard layout in order to perform the necessary convertions
+
By default CEGUI only loads a portion of the character set specified in a font. The following code loads the entire Latin character set:
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
+
<source lang="cpp">
// Handles CAPS-lock and SHIFT states
+
CEGUI::Font* guiFont = CEGUI::FontManager::getSingleton().createFont("Arial", "c:/windows/fonts/arial.ttf", 16, CEGUI::Default);
if (GetKeyboardState(keyboardState) == FALSE)
+
guiFont->defineFontGlyphs(0x0020, 0x0323); // Latin character set
return utf;
+
mGUISystem->setDefaultFont(guiFont);
 +
</source>
  
/* 0. Convert virtual-key code into a scan code
+
The Character Map (charmap.exe) tool is very useful when trying to figure out the range of characters needed.
      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:
+
<source lang="cpp">
0. No menu is active
+
CEGUI::utf32 keycodeToUTF32( unsigned int scanCode)
1. A menu is active
+
{
      Return values:
+
CEGUI::utf32 utf = 0;
Negative. Returned a dead key
+
0. No translation available
+
BYTE keyboardState[256];
1. A translation exists  
+
unsigned char ucBuffer[3];
2. Dead-key could not be combined with character */
+
static WCHAR deadKey = '\0';
int ascii = ToAsciiEx(virtualKey, scanCode, keyboardState, (LPWORD) ucBuffer, 0, hklKeyboardLayout);
+
if(deadKey != '\0' && ascii == 1)
+
// Retrieve the keyboard layout in order to perform the necessary convertions
{
+
HKL hklKeyboardLayout = GetKeyboardLayout(0); // 0 means current thread
// A dead key is stored and we have just converted a character key
+
// This seemingly cannot fail
// Combine the two into a single character
+
// If this value is cached then the application must respond to WM_INPUTLANGCHANGE
WCHAR wcBuffer[3];
+
WCHAR out[3];
+
// Retrieve the keyboard state
wcBuffer[0] = ucBuffer[0];
+
// Handles CAPS-lock and SHIFT states
wcBuffer[1] = deadKey;
+
if (GetKeyboardState(keyboardState) == FALSE)
wcBuffer[2] = '\0';
+
return utf;
if( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
+
utf = out[0];
+
/* 0. Convert virtual-key code into a scan code
else
+
        1. Convert scan code into a virtual-key code
{
+
      Does not distinguish between left- and right-hand keys.
// FoldStringW failed
+
        2. Convert virtual-key code into an unshifted character value
DWORD dw = GetLastError();
+
      in the low order word of the return value. Dead keys (diacritics)
switch(dw)
+
  are indicated by setting the top bit of the return value.
{
+
        3. Windows NT/2000/XP: Convert scan code into a virtual-key
case ERROR_INSUFFICIENT_BUFFER:
+
      Distinguishes between left- and right-hand keys.*/
case ERROR_INVALID_FLAGS:
+
UINT virtualKey = MapVirtualKeyEx(scanCode, 3, hklKeyboardLayout);
case ERROR_INVALID_PARAMETER:
+
if (virtualKey == 0) // No translation possible
break;
+
return utf;
}
+
}
+
    /* Parameter 5:
deadKey = '\0';
+
0. No menu is active
}
+
1. A menu is active
else if (ascii == 1)
+
        Return values:
{
+
Negative. Returned a dead key
// We have a single character
+
0. No translation available
utf = ucBuffer[0];
+
1. A translation exists  
deadKey = '\0';
+
2. Dead-key could not be combined with character */
}
+
int ascii = ToAsciiEx(virtualKey, scanCode, keyboardState, (LPWORD) ucBuffer, 0, hklKeyboardLayout);
else
+
if(deadKey != '\0' && ascii == 1)
{
+
{
// Convert a non-combining diacritical mark into a combining diacritical mark
+
// A dead key is stored and we have just converted a character key
// Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
+
// Combine the two into a single character
// http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
+
WCHAR wcBuffer[3];
switch(ucBuffer[0])
+
WCHAR out[3];
{
+
wcBuffer[0] = ucBuffer[0];
case 0x5E: // Circumflex accent: â
+
wcBuffer[1] = deadKey;
deadKey = 0x302;
+
wcBuffer[2] = '\0';
break;
+
if( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
case 0x60: // Grave accent: à
+
utf = out[0];
deadKey = 0x300;
+
else
break;
+
{
case 0xA8: // Diaeresis: ü
+
// FoldStringW failed
deadKey = 0x308;
+
DWORD dw = GetLastError();
break;
+
switch(dw)
case 0xB4: // Acute accent: é
+
{
deadKey = 0x301;
+
case ERROR_INSUFFICIENT_BUFFER:
break;
+
case ERROR_INVALID_FLAGS:
case 0xB8: // Cedilla: ç
+
case ERROR_INVALID_PARAMETER:
deadKey = 0x327;
+
break;
break;
+
}
default:
+
}
deadKey = ucBuffer[0];
+
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;
 +
}
 +
</source>
  
return utf;
+
[[Category:HowTo]]
}
+

Latest revision as of 01:37, 6 March 2011

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;
 }