ОК, похоже, что не так много экспертов по IME в StackOverflow ... или никто не заинтересован.
Во всяком случае, я понял это.
По сути, я должен перехватить следующие сообщения Windows:
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
Я перехватываю WM_KEYUP
и WM_CHAR
, потому что, если я нажимаю где-нибудь в середине компоновки корейского символа, я не получаю составного сообщения, но тем не менее мне нужно добавить этот символ в мое текстовое поле. Это странное поведение, интересно, если это ошибка.
Как только это произойдет, между корейским, китайским и японским языками будет другое поведение.
Корейский язык действительно прост (хотя я не уверен насчет конвертации ханджи, потому что я все равно не знаю, как его использовать).
По сути, для всех языков, когда я получаю WM_IME_COMPOSITION
, я должен вызывать ImmGetCompositionString
в Imm32.dll, как я описал в ответе на этот вопрос . Затем я отображаю это как композицию в процессе, но не добавляю ее в свой сохраненный текст.
Когда строка составлена, сообщение от Windows отличается для каждого IME. Каждый раз я могу получить его из сообщения WM_IME_COMPOSITION
.
В корейском LParam
будет просто GCS_RESULTSTR
, а WParam
будет введенным символом, который я могу просто привести к char
В японском языке "LParam" будет GCS_RESULTREADSTR | GCS_RESULTREADCLAUSE | GCS_RESULTSTR0 | GCS_RESULTCLAUSE
. Я должен использовать результат ImmGetCompositionString
, который я сохранил из предыдущего сообщения WM_IME_COMPOSITION, потому что в это время это будет пустая строка.
На китайском LParam
будет GCS_RESULTREADCLAUSE | GCS_RESULTSTR0 | GCS_RESULTCLAUSE
. Это то же самое, что и японский, за исключением случаев, когда ранее сохраненное ImmGetCompositionString
пусто, и в этом случае мне нужно привести WParam
к символу.
Во всех трех случаях я должен убедиться, что мой отображаемый комп в процессе очищается.
Если я получаю WM_IME_STARTCOMPOSITION
, я устанавливаю флаг композитинга (и отображаю строку композитинга в процессе)
Если я получаю WM_IME_ENDCOMPOSITION
, я сбрасываю этот флаг (и очищаю текущую строку компоновки).
Иногда я не получаю WM_IME_ENDCOMPOSITION
, поэтому я очищаю свой флаг при получении WM_CHAR
.
В целом, это был очень интересный опыт обучения, который еще продолжается - но IME теперь можно использовать под моим контролем, наконец-то! Я остался на работе до 1 часа ночи, чтобы сделать это.