我在Windows 10 Creators更新中遇到问题,当我尝试使用IME向我的应用程序输入内容时,第一个字符被忽略;即,如果我使用IME输入日本平假名字符'か'通过键入K& A,我最终只得到了'あ'随着K丢失。这只发生在第一个字符上。但完全相同的应用程序在Windows 7~8中正常工作。
详情如下:
该应用程序是Container / Server类型的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类动态创建一个编辑框,然后使用当前的wParam和lParam作为参数,使用当前的wParam和lParam发送一个WM_KEYDOWN。 WindowProc功能。运行该程序,我创建了一个文档,然后按下键' k'。将在文档中创建一个编辑框。如果没有使用IME,那么角色' k'也将进入这个新创建的编辑框。接下来,我按下' a'和#39; a'附加到' k'在编辑框中。到目前为止一切都很好。
接下来,我再次创建一个新文档。这次,我将windows IME激活为日语并输入' k'。同样,将创建一个编辑框,它将显示' k'带有波浪状的下划线。我输入了一个'它正确显示日语字符'か'。再次,预期和正确。
我将此exe文件复制到Windows 10 1709计算机并运行它。我再次重复上述相同的步骤来输入字符' k'。如果没有IME处于活动状态,则会创建该框,并且“'进入它。接下来我按下' a'编辑框将正确读取' ka'。接下来,我创建一个新文档。这次,我将windows IME激活为日语并输入' k'。同样,将创建一个编辑框,但它将为空。我输入了一个'它现在显示日语字符'あ'。所有字符都会发生此行为。当IME处于活动状态时,将不会显示用于创建编辑框的第一个keydown。但是一旦创建了编辑框,一切正常。
我将整个代码复制到MDI_Sample2。但是有一点变化。这一次,在视图中,我重写了PreTranslateMessage并执行了之前在WindowProc中完成的完全相同的过程。并删除WindowProc覆盖。即使日语IME处于活动状态,此MDI_Sample2在Windows 7和Windows 10 1709上也能很好地工作。
两个项目的* 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。
更新
有关该问题的一些其他详细信息。 例如,我尝试输入日语单词&#39;さくら&#39;。使用英文字母,这将拼写为&#39; sakura&#39;。现在,我运行应用程序,为日语平假名输入选择Microsoft IME并输入&#39; sakura&#39;。在创建者更新之前,在Windows 10之前,这将按如下方式工作。 &#39;&#39;击键将生成编辑框。在此之后,它还将调用IME组合窗口,该窗口现在将显示&#39; s&#39;带有波浪状的下划线。以下击键&#39; a&#39;将更新“&#39;在IME窗口中的日语字符&#39;さ&#39;。下一次击键&#39; k&#39;将更新IME窗口以显示&#39;さk&#39; k具有波浪下划线等等。这是预期和正确的行为。
在Windows 10 1709中,它的工作原理是:第一次击键&#39;将生成编辑框。但是没有出现IME组合窗口。即使在调试运行期间也不会显示错误或警告消息。下一次击键&#39; a&#39;现在将使用日语等效的&#39; a&#39;来调用IME组合窗口。这就是角色&#39;あ&#39;。意思是,最后,我得到了あくら&#39;在英文字母中是&#39; akura&#39;。第一个&#39;失去了。
当我使用&#39; WindowsProc&#39;处理编辑框创建时会发生这种情况。在这种情况下,它将正常工作,直到您将操作系统更新到Windows 10 1709.另一方面,如果我在&#39; PreTranslateMessage&#39;中创建编辑框。它甚至可以在Windows 10 1709中正常工作。方式发生了什么变化&#39; WindowsProc&#39;在Windows 10 1709中处理以及如何解决它?
答案 0 :(得分:2)
最后我想出了一些事情。 似乎Windows 10 1709及更高版本中的IME行为已发生变化。 我将用一个例子解释不同的行为:
案例1:Windows 10 1709之前 - &GT;打开记事本。将IME设置为日语平假名,然后按“k”键。你会看到一个'带有波浪下划线的'。你需要一个或多个字符来组成这个'k'到一个合适的平假名。在您提供更多输入或按Esc取消输入之前,'k'将保留为未确认的IME输入。保持原样,没有任何额外的输入,只需点击其他地方(如桌面),记事本失去焦点。您会注意到任务栏/语言栏中的IME指示符已更改。你可能还会看到Windows自己的IME组合窗口(Windows 7中的黑色小窗口)弹出你的'k'。现在重点回到记事本,你会发现未经证实的'k'仍然在等待你提供进一步的输入或取消它。简而言之,当焦点发生变化时,未经证实的IME字符串仍然处于未确认状态。
案例2:Windows 10 1709以后: - &GT;重复上述步骤。在这里你可以注意到差异。一旦焦点改变,IME组合就会停止。因此,'k'是一个UNCONFIRMED IME字符串被丢弃。
在问题中给出的示例中,WindProc和PreTranslateMessage发生的情况是,使用WindProc,On IME keyPress,视图处于焦点并收到KeyPress消息。它处理它并将其传递给它的子节点,根据我们的代码,创建一个新的编辑控件。现在,随着编辑控件的创建,它将得到集中。并且根据新行为,当焦点从View更改为控件时,IME组合将停止。当这发生在第一个IME按键时,我们有一个角色仍处于未确认状态。作为未经证实的IME角色,此角色将被丢弃。
使用PreTranslateMessage,我们会收到按键消息并继续创建编辑控件。在创建时,编辑控件获得焦点,我们的视图失去焦点。这会生成KillFocus消息,但由于我们仍处于上一次KeyPress消息处理的中间,因此不会处理KillFocus消息。它正在等待前一个消息处理的完成。现在,当我们在创建控件后返回时,我们将按键传递给新创建的编辑框。因此,最终接收按键的编辑框以及以下未经证实的IME字符。因此,根据我们的示例'k'按键,编辑框而不是视图,接收未经证实的'k'。编辑框自然接收下一个按键,因为它现在处于焦点状态,因此第二个输入被添加到未经证实的'k',并且照常执行合成。
此行为不仅限于需要多个按键的字符。即使像'a'这样的单个按键字符也会以相同的方式起作用,因为即使这些字符仍然未经证实,直到我们按下Enter键,或者选择其中一个候选组合等等。