Chinese Input in xNa (2)
For personal use only, do not reprint, do not use for any commercial purposes.
In full screen mode GDI And DirectX Conflicts may occur, and we need to render it ourselves. IME Window. Many people think that rendering IME The window is a complicated task, but take a closer look. Customui Or Wow In IME Window is actually a simple Text Or Label Control!
As long as you getIMEThe character information in, the next step is very simple. To this end,We need to handle the following4Messages:
The first one isWm_ime_startcompositionThis message is triggered when a new character combination is started when the first character is pressed.BufferPut the work here.
Next, Wm_ime_composition Is a very important message. SDK The document says" The Imm sends a wm_ime_composition message to the application when the user enters a keystroke to change the composition string. " Lparam Parameter description IME What changes have taken place, so here we only need to care about Gcs_compstr Or Gcs_compreadstr For Chinese characters, the two symbols indicate the same content, indicating that the input characters have changed. Available Immgetcompositionstring Obtain IME The input character.
when IME when the window changes, send to Program wm_ime_notify message, wparam parameter description. Generally, you only need to care about imn_changecandidate , which indicates IME the candidate characters in the window have changed. immgetcandidatelist obtain candidate characters.
Finally, when the input is completeWm_ime_endcompositionMessage.ImmgetcompositionstringObtain the final Generated Chinese characters.
The basic steps are that simple. The following are some implementation details, mainlyP/invokePossible problems. The first is the declaration of two functions.
[Dllimport ( " Imm32.dll " , Charset = Charset. Unicode, setlasterror = True )]
Public Static Extern Int Immgetcompositionstring (intptr himc, Int Compositionstringflag, stringbuilder buffer, Int Bufferlength );
[Dllimport ( " Imm32.dll " , Charset = Charset. Unicode, entrypoint = " Immgetcandidatelist " )]
Public Static Extern Uint Immgetcandidatelist (intptr himc, Uint Deindex, intptr candidatelist, Uint Dwbuflen );
Note: You must explicitly specifyCharsetAttribute. Otherwise, the data is always imported.ANSIVersionAPI.
First look Immgetcompositionstring Function. Its first parameter is Input Context Handle. The second parameter indicates that we want to obtain IME Which string is in. Generally Wm_ime_composition You should use Gcs_compstr And Gcs_compreadstr , In Wm_ime_endcomposition Use Gcs_resultstr . The function places the resulting string in the third parameter. The last value is the string length. If the value is 0 Returns the length of the string. Therefore, you may first query the length of the string and then obtain the string.
ImmgetcandidatelistAndImmgetcompositionstringThe usage is very similar. Here, the technical difference lies in the returnedCandidatelistParameters. First, you need to make the following declaration for this structure:
Candidatelist
[Structlayoutattribute (layoutkind. Sequential)]
Public Struct Candidatelist
{
Public Uint Dwsize;
Public Uint Dwstyle;
Public Uint Dwcount;
Public Uint Dwselection;
Public Uint Dwpagestart;
Public Uint Dwpagesize;
/// DWORD [1]
[Externalasattribute (unmanagedtype. byvalarray, sizeconst = 1 , Arraysubtype = Unmanagedtype. U4)]
Public Uint [] Dwoffset;
}
CandidatelistSavedIMEBut take a closer lookCandidatelistDoes not seem to have any string-related member. The instructions in this document will only confuse you. This is a very special structure.4When the string is a candidate string,CandidatelistLayout in memory:
Swsize | dwstyle | ....... | Dwpagesize | dwoffset | offset1 | offset2 | offset3 | string0 | string1 | string2 | string3
We can see that all string information is actually appended Dwoffset Later, Dwoffset Record the first string relative Candidatelist Offset value, if any N Strings. N-1 Items 32 Bit value, indicating N Strings Candidatelist . In these 32 Is the actual value of each string. That is to say Dwoffset Recorded String0 Offset Value, Offset3 Recorded String3 . Note that when Swsize Is 1 , Candidatelist Another layout. For more information, see SDK Documentation. Obviously, each string can be obtained only by directly accessing the physical address. How C # Access the physical address? The following is an analysis Candidatelist OfCode:
If (M. msg = Windowmessage. imenoworkflow)
{
If (M. wparam. toint32 () = Imn_changecandidate)
{
Candidatelist candidate;
Intptr;
Uint Size = Imm. immgetcandidatelist (imecontext, 0 , Intptr. Zero, 0 );
If (Size > 0 )
{
PTR = Marshal. allochglobal (( Int ) Size );
Size = Imm. immgetcandidatelist (imecontext, 0 , PTR, size );
Candidate = (Candidatelist) Marshal. ptrtostructure (PTR, Typeof (Candidatelist ));
If (Candidate. dwcount > 1 )
{
For ( Int I = 0 ; I < Candidate. dwcount; I ++ )
{
Int Stringoffset = Marshal. readint32 (PTR, 24 + 4 * I );
Intptr ADDR = (Intptr) (PTR. toint32 () + Stringoffset );
String Str = Marshal. ptrtostringuni (ADDR );
Console. writeline (STR );
}
}
Else ......
Marshal. freehglobal (PTR );
}
}
}
Now you can successfully call IME and get the characters in ime. Next, we will discuss how to use ime in the xNa game framework.
Update 12.28.09:
In Vista and Windows 7, Ms replaces Imm with text service framework. Although most Imm APIs are still available, there may be compatibility issues due to internal reasons of TSF. A better way is to directly use TSF.