As I couldn’t find much useful documentation/ examples when I was looking
for a way to add Asian language support to our input code I thought I
should
post what works for us now so other people might have it easier than I did
The below snippet should work fine with Japanese, Chinese and Korean
Windows
(even Win98) though YMMV.
BTW, as a little hint - make sure you have your Korean keyboard plugged in
before installing Korean Windows if you don’t speak the language as
otherwise you won’t be able to use the IME key… had to learn that the
hard
way
Some globals.
INT SupportsIME,
CurrentIMESize;
After creating the window.
HIMC hImc = ImmGetContext( Window->hWnd );
if( !hImc )
{
debugf(TEXT(“Creating IME context.”));
hImc = ImmCreateContext();
if( hImc )
ImmAssociateContext( Window->hWnd, hImc );
else
debugf(TEXT(“OS doesn’t support IME.”));
}
else
ImmReleaseContext( Window->hWnd, hImc );
SupportsIME = hImc != NULL;
Once per frame (could possibly be done by handling some message but I
didn’t> have time to look into this closer and hey, it works ;)).
// IME stuff.
if( SupportsIME )
{
HIMC hImc = ImmGetContext( Window->hWnd );
if( !hImc )
{
debugf(TEXT(“Creating IME context.”));
hImc = ImmCreateContext();
if( hImc )
ImmAssociateContext( Window->hWnd, hImc );
else
SupportsIME = 0;
CurrentIMESize = 0;
}
else
ImmReleaseContext( Window->hWnd, hImc );
}
Below is some code that handles the IME windows message.
case WM_IME_COMPOSITION:
{
// Final composition string.
if( lParam & GCS_RESULTSTR )
{
HIMC hImc = ImmGetContext(Window->hWnd);
if( !hImc )
appErrorf( TEXT(“No IME context”) );
// Get the size of the result string.
INT Size = ImmGetCompositionString( hImc, GCS_RESULTSTR, NULL, 0 );
TCHAR* String = new TCHAR[Size+1];
appMemzero( String, sizeof(TCHAR) * (Size+1) );
// Get the result strings that is generated by IME.
Size = ImmGetCompositionString( hImc, GCS_RESULTSTR, String, Size );
Size /= sizeof( TCHAR );
// Send backspaces.
for( INT i=0; i<CurrentIMESize; i++ )
{
CauseInputEvent( IK_Backspace, IST_Press );
CauseInputEvent( IK_Backspace, IST_Release );
}
// Send key to input system.
for( INT i=0; i<Size; i++ )
{
INT Key = String[i];
if( Key )
Client->Engine->Key( this, IK_Unicode, String[i] );
}
delete [] String;
ImmReleaseContext(Window->hWnd, hImc);
CurrentIMESize = 0;
}
// Composition in progress.
else if( lParam & GCS_COMPSTR )
{
HIMC hImc = ImmGetContext(Window->hWnd);
if( !hImc )
appErrorf( TEXT(“No IME context”) );
// Get the size of the result string.
INT Size = ImmGetCompositionString( hImc, GCS_COMPSTR, NULL, 0 );
TCHAR* String = new TCHAR[Size+1];
appMemzero( String, sizeof(TCHAR) * (Size+1) );
// Get the result strings that is generated by IME.
Size = ImmGetCompositionString( hImc, GCS_COMPSTR, String, Size );
Size /= sizeof( TCHAR );
// Send backspaces.
for( INT i=0; i<CurrentIMESize; i++ )
{
CauseInputEvent( IK_Backspace, IST_Press );
CauseInputEvent( IK_Backspace, IST_Release );
}
// Send key to input system
for( INT i=0; i<Size; i++ )
{
INT Key = String[i];
if( Key )
Client->Engine->Key( this, IK_Unicode, String[i] );
}
delete [] String;
ImmReleaseContext(Window->hWnd, hImc);
CurrentIMESize = Size;
}
else
return DefWindowProcX( Window->hWnd, iMessage, wParam, lParam );
return 0;
}
You only want IME stuff for chatting and not for controlling the player so
here’s some code that toggles it on the fly.
InParamter: bool Enable
if( SupportsIME )
{
if( !Enable )
{
ImmAssociateContext( Window->hWnd, NULL );
CurrentIMESize = 0;
}
else
{
HIMC hImc = ImmGetContext( Window->hWnd );
if( !hImc )
{
debugf(TEXT(“Creating IME context.”));
hImc = ImmCreateContext();
if( hImc )
ImmAssociateContext( Window->hWnd, hImc );
else
SupportsIME = 0;
CurrentIMESize = 0;
}
else
{
ImmAssociateContext( Window->hWnd, hImc );
ImmReleaseContext( Window->hWnd, hImc );
}
}
}
Hope this of help to someone out there
– Daniel, Epic Games Inc.