Странное поведение с японским IME в Windows 10 1709

Я сталкиваюсь с проблемой обновления Windows 10 Creators, когда при попытке ввести что-либо в мое приложение с помощью IME первый символ игнорируется; т.е. если я использую IME для ввода японского символа хирагана ‘か’, набрав K & А, в итоге я получаю только «あ», когда К теряется. Это происходит только с первым персонажем. Но точно такое же приложение работает правильно в Windows 7 ~ 8.

Детали как ниже:

Приложение представляет собой приложение MFC MDI типа «Контейнер / Сервер». Его работа действительно проста & простой. Если документ открыт, то при срабатывании WM_KEYDOWN динамически создайте поле CEdit и введите нажатую клавишу в поле редактирования. Если поле для редактирования уже существует, нет необходимости создавать его снова. Просто добавьте ввод к содержимому поля редактирования.

Я создал 2 примера проектов MFC MDI (например, MDI_sample1 & MDI_Sample2). Сохранение по умолчанию cpp & h файлы, как есть, только что добавили новый класс (например, CwEdit), который подклассирует класс CEdit к обоим MDI_Sample1 & Проекты MDI_Sample2. Теперь в MDI_Sample1 я открываю * View.cpp и добавляю переопределение WindowProc. В этой функции я проверяю сообщение WM_KEYDOWN и на WM_KEYDOWN, исключая VK_BACK, VK_ENTER, VK_TAB, динамически создаю поле редактирования с использованием класса CwEdit, а затем SendMessage WM_KEYDOWN с текущим wParam и lParam, которые я получил в качестве аргументов аргумента Функция WindowProc. Запустив программу, я создаю документ и затем нажимаю клавишу «k». Поле редактирования будет создано в документе. Если IME не используется, символ ‘k’ также будет введен в это вновь созданное поле редактирования. Затем я нажимаю «а», и символ «а» добавляется к «к» в окне редактирования. Все идет нормально.

Затем я снова создаю новый документ. На этот раз я активирую Windows IME на японский язык и ввожу ‘k’. Снова, поле редактирования будет создано, и это покажет ‘k’ с волнистыми подчеркиваниями. Я ввел «а», и он правильно отображает японский символ «か». Опять ожидаемо и правильно.

Я копирую этот exe-файл на компьютер с Windows 10 1709 и запускаю его. Я повторяю те же шаги, что и выше, чтобы ввести символ «к». Если IME не активен, поле создается, и в него вводится ‘k’. Затем я нажимаю «а», и окно редактирования будет правильно читать «ка». Далее я создаю новый документ. На этот раз я активирую Windows IME на японский язык и ввожу ‘k’. Снова, поле редактирования будет создано, но оно будет пустым. Я ввел «а», и теперь он отображает японский символ «あ». Такое поведение происходит со всеми персонажами. Первая клавиша, которая использовалась для создания поля редактирования, не будет отображаться, когда IME активен. Но как только поле редактирования создано, все работает нормально.

Я копирую весь код в MDI_Sample2. Но есть одно небольшое изменение. На этот раз, в представлении, я переопределяю PreTranslateMessage и делаю точно такой же процесс, который ранее выполнялся в WindowProc. И удалите переопределение WindowProc. Этот MDI_Sample2 отлично работает как в Windows 7, так и в Windows 10 1709, даже когда японский IME активен.

Код для * View.cpp для обоих проектов приведен ниже:

MDI_Sample1View.cpp


BOOL MDI_Sample1View::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
if(message == WM_CHAR)
{
int wp = static_cast<int>(wParam);
// All printable ascii characters
if (wp >= 0x32 && wp <= 0x255)
{
EnableEdit();
M_pEdit->SendMessage(message, wParam, lParam);
return TRUE;
}
}
else if(message == WM_KEYDOWN)
{
if (wParam == VK_ESCAPE)
{
if(M_pEdit &&
GetFocus() == M_pEdit)
{
DisableEdit();
return TRUE;
}
}
EnableEdit();
}
return CView::WindowProc(message, wParam, lParam);
}

MDI_Sample2View.cpp


BOOL MDI_Sample2View::PreTranslateMessage(MSG* pMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(pMsg->message == WM_CHAR)
{
int wp = static_cast<int>(pMsg->wParam);
// All printable ascii characters
if (wp >= 0x32 && wp <= 0x255)
{
EnableEdit();
M_pEdit->SendMessage(pMsg->message, pMsg->wParam, pMsg->lParam);
return TRUE;
}
}
else if(pMsg->message == WM_KEYDOWN)
{
if (pMsg->wParam == VK_ESCAPE)
{
if(M_pEdit &&
GetFocus() == M_pEdit)
{
DisableEdit();
return TRUE;
}
}
EnableEdit();
}
return CView::PreTranslateMessage(pMsg);
}

Все остальные файлы такие же, как были созданы Visual Studio при создании нового проекта.
Класс CwEdit.cpp имеет 2 функции, а именно Create для создания поля редактирования, и OnKeyDown, который приведен ниже:

void CwSpEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if(nChar == VK_ESCAPE)
{
SetWindowText(_T(""));
return;
}
CEdit::OnKeyDown(nChar, nRepCnt, nFlags);
}

Остальные оба проекта идентичны. Итак, что здесь происходит? Почему WindowProc игнорирует первый символ, а PreTranslateMessage работает нормально?

Как мне решить эту проблему? Мне нужно, чтобы он работал с WindowProc, как это было раньше.

Обновить:

Некоторые дополнительные подробности по этому вопросу.
В качестве примера я пытаюсь ввести японское слово «さ く ら». Используя английские алфавиты, это будет записано как «сакура». Теперь я запускаю приложение, выбираю Microsoft IME для японского ввода хирагана и набираю ‘sakura’. До Windows 10 до обновления Создателей это будет работать следующим образом. Клавиша ‘s’ сгенерирует окно редактирования. После этого он также вызовет окно композиции IME, которое теперь будет отображать ‘s’ с волнистыми подчеркиваниями. следующее нажатие клавиши «а» обновит «s» в окне IME до японского символа «さ». Следующее нажатие клавиши «k» обновит окно IME, чтобы показать «さ k» с k, имеющим волнистые подчеркивания и так далее. Это ожидаемое и правильное поведение.

В Windows 10 1709 это работает так: первое нажатие клавиши ‘s’ создаст окно редактирования. Но не появляется окно композиции IME. Никакие сообщения об ошибках или предупреждения не отображаются даже во время отладочных прогонов. Следующее нажатие клавиши «a» теперь вызывает окно композиции IME с японским эквивалентом «a», то есть символом «あ». То есть, наконец, я получаю «あ く ​​ら», что в английском алфавите — «акура». Первое ‘s’ потеряно.

Это происходит, когда я занимаюсь созданием поля редактирования с помощью «WindowsProc». В этом случае он будет работать правильно до тех пор, пока вы не обновите свою ОС до Windows 10 1709. С другой стороны, если я создам поле редактирования в «PreTranslateMessage», он будет работать правильно даже в Windows 10 1709. Что изменилось в способе «WindowsProc» в Windows 10 1709 и как обойти это?

4

Решение

Наконец-то я разобрался.
Кажется, что поведение IME изменилось в Windows 10 1709 и выше.
Я объясню различные варианты поведения на примере:

Случай 1: до Windows 10 1709
-> Открыть блокнот. Установите IME на японский хирагана и нажмите клавишу «k». Вы увидите ‘k с волнистым подчеркиванием’. Вам нужен один или несколько символов, чтобы составить это ‘k’ для правильного хирагана. Пока вы не введете дополнительные данные или не нажмете клавишу Esc, чтобы отменить ввод, «k» останется как неподтвержденный ввод IME. Оставьте все как есть без каких-либо дополнительных входов, просто щелкните где-нибудь еще (например, на рабочем столе), чтобы блокнот потерял фокус. Вы заметите, что индикатор IME на панели задач / языковой панели изменился. И вы МОЖЕТЕ также увидеть, что собственное окно композиции IME Windows (маленькое черное в windows 7) всплывает с вашим ‘k’ в нем. Теперь вернитесь к блокноту, и вы обнаружите, что неподтвержденное «k» все еще остается в ожидании, чтобы вы либо предоставили дополнительный ввод, либо отменили его. Короче говоря, при изменении фокуса неподтвержденные строки IME по-прежнему сохраняются, поскольку находятся в неподтвержденном состоянии.

Случай 2: Windows 10 1709 года:
-> Повторите вышеуказанные шаги. Здесь вы можете заметить разницу. Как только фокус меняется, композиция IME останавливается. Таким образом, ‘k’, являющаяся неподтвержденной строкой IME, отбрасывается.

В примере, приведенном в вопросе, то, что происходило с WindProc и PreTranslateMessage, было то, что с WindProc, на IME keyPress, представление находится в фокусе и получает сообщение KeyPress. Он обрабатывает его и передает его своим дочерним элементам, где, согласно нашему коду, создается новый элемент управления для редактирования. Теперь, когда элемент управления редактирования создан, он становится сфокусированным. И в соответствии с новым поведением, когда фокус меняется с представления на элемент управления, композиция IME останавливается. Как это происходит при первом нажатии клавиши IME, у нас есть персонаж, который все еще находится в неподтвержденном состоянии. Будучи неподтвержденным персонажем IME, этот персонаж отбрасывается.

С PreTranslateMessage мы получаем сообщение о нажатии клавиши и приступаем к созданию элемента управления для редактирования. При создании элемент управления редактирования получает фокус, а наш просмотр теряет фокус. Это генерирует сообщение KillFocus, но, поскольку мы все еще находимся в середине предыдущей обработки сообщения KeyPress, сообщение KillFocus не обрабатывается. Он ожидает завершения предыдущей обработки сообщения. Теперь, когда мы вернемся назад после создания элемента управления, мы передадим нажатие клавиши во вновь созданное поле редактирования. Таким образом, это поле ввода, которое, наконец, получает нажатие клавиши, а также следующий неподтвержденный символ IME. Таким образом, согласно нашему примеру нажатие клавиши «k», поле ввода и НЕ представление, получает неподтвержденное «k». Следующее нажатие клавиши, естественно, принимается блоком редактирования, так как теперь оно находится в фокусе, и поэтому этот второй ввод добавляется к неподтвержденному «k», и композиция выполняется как обычно.

Это поведение не ограничивается только символами, нуждающимися в нескольких нажатиях клавиш. Даже одиночные символы нажатия клавиш, такие как «а», также действуют одинаково, потому что даже эти символы остаются неподтвержденными до тех пор, пока мы не нажмем клавишу «Ввод» или не выберем одного из кандидатов на композицию и так далее.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]