Difference between revisions of "DirectInput to CEGUI utf32"

From CEGUI Wiki - Crazy Eddie's GUI System (Open Source)
Jump to: navigation, search
 
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.
+
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 keycodeToUTF32( unsigned int scanCode)
+
Some characters are composed by two keystrokes; a dead key followed by a simple key.  An example 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
{
+
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
+
CEGUI::utf32 keycodeToUTF32( unsigned int scanCode)
HKL hklKeyboardLayout = GetKeyboardLayout(0); // 0 means current thread  
+
{
// This seemingly cannot fail  
+
CEGUI::utf32 utf = 0;
// If this value is cached then the application must respond to WM_INPUTLANGCHANGE  
+
 
+
BYTE keyboardState[256];
// Retrieve the keyboard state
+
unsigned char ucBuffer[3];
// Handles CAPS-lock and SHIFT states
+
static WCHAR deadKey = '\0';
if (GetKeyboardState(keyboardState) == FALSE)
+
return utf;
+
// Retrieve the keyboard layout in order to perform the necessary convertions
 
+
HKL hklKeyboardLayout = GetKeyboardLayout(0); // 0 means current thread  
/* 0. Convert virtual-key code into a scan code
+
// This seemingly cannot fail  
      1. Convert scan code into a virtual-key code
+
// If this value is cached then the application must respond to WM_INPUTLANGCHANGE  
      Does not distinguish between left- and right-hand keys.
+
      2. Convert virtual-key code into an unshifted character value
+
// Retrieve the keyboard state
      in the low order word of the return value. Dead keys (diacritics)
+
// Handles CAPS-lock and SHIFT states
  are indicated by setting the top bit of the return value.
+
if (GetKeyboardState(keyboardState) == FALSE)
      3. Windows NT/2000/XP: Convert scan code into a virtual-key
+
return utf;
      Distinguishes between left- and right-hand keys.*/
+
UINT virtualKey = MapVirtualKeyEx(scanCode, 3, hklKeyboardLayout);
+
/* 0. Convert virtual-key code into a scan code
if (virtualKey == 0) // No translation possible
+
        1. Convert scan code into a virtual-key code
return utf;
+
      Does not distinguish between left- and right-hand keys.
 
+
        2. Convert virtual-key code into an unshifted character value
    /* Parameter 5:
+
      in the low order word of the return value. Dead keys (diacritics)
0. No menu is active
+
  are indicated by setting the top bit of the return value.
1. A menu is active
+
        3. Windows NT/2000/XP: Convert scan code into a virtual-key
      Return values:
+
      Distinguishes between left- and right-hand keys.*/
Negative. Returned a dead key
+
UINT virtualKey = MapVirtualKeyEx(scanCode, 3, hklKeyboardLayout);
0. No translation available
+
if (virtualKey == 0) // No translation possible
1. A translation exists  
+
return utf;
2. Dead-key could not be combined with character */
+
int ascii = ToAsciiEx(virtualKey, scanCode, keyboardState, (LPWORD) ucBuffer, 0, hklKeyboardLayout);
+
    /* Parameter 5:
if(deadKey != '\0' && ascii == 1)
+
0. No menu is active
{
+
1. A menu is active
// A dead key is stored and we have just converted a character key
+
        Return values:
// Combine the two into a single character
+
Negative. Returned a dead key
WCHAR wcBuffer[3];
+
0. No translation available
WCHAR out[3];
+
1. A translation exists  
wcBuffer[0] = ucBuffer[0];
+
2. Dead-key could not be combined with character */
wcBuffer[1] = deadKey;
+
int ascii = ToAsciiEx(virtualKey, scanCode, keyboardState, (LPWORD) ucBuffer, 0, hklKeyboardLayout);
wcBuffer[2] = '\0';
+
if(deadKey != '\0' && ascii == 1)
if( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
+
{
utf = out[0];
+
// A dead key is stored and we have just converted a character key
else
+
// Combine the two into a single character
{
+
WCHAR wcBuffer[3];
// FoldStringW failed
+
WCHAR out[3];
DWORD dw = GetLastError();
+
wcBuffer[0] = ucBuffer[0];
switch(dw)
+
wcBuffer[1] = deadKey;
{
+
wcBuffer[2] = '\0';
case ERROR_INSUFFICIENT_BUFFER:
+
if( FoldStringW(MAP_PRECOMPOSED, (LPWSTR) wcBuffer, 3, (LPWSTR) out, 3) )
case ERROR_INVALID_FLAGS:
+
utf = out[0];
case ERROR_INVALID_PARAMETER:
+
else
break;
+
{
}
+
// FoldStringW failed
}
+
DWORD dw = GetLastError();
deadKey = '\0';
+
switch(dw)
}
+
{
else if (ascii == 1)
+
case ERROR_INSUFFICIENT_BUFFER:
{
+
case ERROR_INVALID_FLAGS:
// We have a single character
+
case ERROR_INVALID_PARAMETER:
utf = ucBuffer[0];
+
break;
deadKey = '\0';
+
}
}
+
}
else
+
deadKey = '\0';
{
+
}
// Convert a non-combining diacritical mark into a combining diacritical mark
+
else if (ascii == 1)
// Combining versions range from 0x300 to 0x36F; only 5 (for French) have been mapped below
+
{
// http://www.fileformat.info/info/unicode/block/combining_diacritical_marks/images.htm
+
// We have a single character
switch(ucBuffer[0])
+
utf = ucBuffer[0];
{
+
deadKey = '\0';
case 0x5E: // Circumflex accent: â
+
}
deadKey = 0x302;
+
else
break;
+
{
case 0x60: // Grave accent: à
+
// Convert a non-combining diacritical mark into a combining diacritical mark
deadKey = 0x300;
+
switch(ucBuffer[0])
break;
+
{
case 0xA8: // Diaeresis: ü
+
case 0x5E: // Circumflex accent: â
deadKey = 0x308;
+
deadKey = 0x302;
break;
+
break;
case 0xB4: // Acute accent: é
+
case 0x60: // Grave accent: à
deadKey = 0x301;
+
deadKey = 0x300;
break;
+
break;
case 0xB8: // Cedilla: ç
+
case 0xA8: // Diaeresis: ü
deadKey = 0x327;
+
deadKey = 0x308;
break;
+
break;
default:
+
case 0xB4: // Acute accent: é
deadKey = ucBuffer[0];
+
deadKey = 0x301;
}
+
break;
}
+
case 0xB8: // Cedilla: ç
 
+
deadKey = 0x327;
return utf;
+
break;
}
+
default:
 +
deadKey = ucBuffer[0];
 +
}
 +
}
 +
 +
return utf;
 +
}

Revision as of 13:04, 16 January 2006

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


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