OK, it looks like there aren't many IME experts on StackOverflow... or no one is interested.
Anyway, I figured it out.
Basically, I have to trap the following Windows messages:
WM_INPUTLANGCHANGE = 0x51
WM_KEYUP = 0x101
WM_CHAR = 0x102
WM_CONVERTREQUESTEX = 0x108
WM_IME_STARTCOMPOSITION = 0x10D
WM_IME_ENDCOMPOSITION = 0x10E
WM_IME_COMPOSITION = 0x10F
WM_IME_SETCONTEXT = 0x281
WM_IME_NOTIFY = 0x282
WM_IME_CONTROL = 0x283
WM_IME_COMPOSITIONFULL = 0x284
WM_IME_SELECT = 0x285
WM_IME_CHAR = 0x286
WM_IME_REQUEST = 0x0288
WM_IME_KEYDOWN = 0x290
WM_IME_KEYUP = 0x291
I'm trapping WM_KEYUP
and WM_CHAR
, because if I click somewhere in the middle of compositing a Korean character, I do not get a composition message, but I need to add that character to my text box nonetheless. This is a weird behaviour, I wonder if it's a bug.
Once that happens, there are different behaviours between Korean, Chinese and Japanese.
Korean is a really easy one (I'm not sure about Hanja convert though, because I don't know how to use that anyway).
Basically, for all languages, whenever I get a WM_IME_COMPOSITION
, I have to call ImmGetCompositionString
in Imm32.dll as I have described in answer to this question. I then display this as a composition in progress, but don't add it to my stored text.
When a string has been composited the message from Windows is different for each IME. Each time, I can get it from the WM_IME_COMPOSITION
message.
In Korean, LParam
will simply be GCS_RESULTSTR
, and WParam
will be the entered character, which I can just cast to char
In Japanese 'LParam' will be GCS_RESULTREADSTR | GCS_RESULTREADCLAUSE | GCS_RESULTSTR0 | GCS_RESULTCLAUSE
. I have to use the result of ImmGetCompositionString
that I stored from the previous WM_IME_COMPOSITION message, because at this time it will be an empty string.
In Chinese, LParam
will be GCS_RESULTREADCLAUSE | GCS_RESULTSTR0 | GCS_RESULTCLAUSE
. It's the same as Japanese, except when the previously stored ImmGetCompositionString
is empty, in which case I need to cast WParam
to a char.
In all three cases, I have to make sure that my displayed comp in progress is cleared.
If I receive WM_IME_STARTCOMPOSITION
, I set a compositing flag (and display the compositing string in progress)
If I receive WM_IME_ENDCOMPOSITION
I clear that flag (and clear the compositing string in progress).
Sometimes I don't receive WM_IME_ENDCOMPOSITION
, so I clear my flag on receiving WM_CHAR
.
All in all, it was a very interesting learning experience, and one that is still in progress - but IME is now usable on my control, at last! I stayed at work till 1am to get it done.