gpt4 book ai didi

c++ - Windows 10 1709 中日语输入法的奇怪行为

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:42:33 30 4
gpt4 key购买 nike

我在 Windows 10 Creators 更新中遇到了一个问题,当我尝试使用 IME 向我的应用程序输入内容时,第一个字符被忽略;即,如果我使用 IME 通过输入 K & A 来输入日语平假名字符“か”,我最终只会得到“あ”,而 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 类动态创建一个编辑框,然后使用我作为参数的当前 wParam 和 lParam SendMessage 一个 WM_KEYDOWN WindowProc 函数。运行该程序,我创建一个文档,然后按“k”键。将在文档中创建一个编辑框。如果未使用 IME,字符 'k' 也将被输入到这个新创建的编辑框中。接下来,我按“a”,然后在编辑框中将字符“a”附加到“k”。到现在为止还挺好。

接下来,我再次创建一个新文档。这一次,我将 Windows IME 激活为日语并输入“k”。同样,将创建一个编辑框,它将显示带有波浪下划线的“k”。我输入'a',它正确显示了日语字符'か'。再次,预期和正确。

我将此exe文件复制到Windows 10 1709机器并运行它。同样,我重复上述相同的步骤来输入字符 'k'。在 IME 未激活的情况下,将创建该框并在其中输入“k”。接下来我按“a”,编辑框将正确读取“ka”。接下来,我创建一个新文档。这一次,我将 Windows IME 激活为日语并输入“k”。同样,将创建一个编辑框,但它将是空的。我输入'a',它现在显示日文字符'あ'。这种行为发生在所有角色身上。当 IME 处于事件状态时,用于创建编辑框的第一个 keydown 将不会显示。但是一旦创建了编辑框,一切正常。

我将整个代码复制到 MDI_Sample2。但是有一点点变化。这一次,在 View 中,我覆盖了 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 一起使用。

更新:

关于这个问题的一些额外细节。
例如,我尝试输入日语单词“さくら”。使用英文字母,这将被拼写为“sakura”。现在,我运行该应用程序,为日语平假名输入选择 Microsoft IME 并输入“sakura”。在 Creators 更新之前的 Windows 10 之前,这将按如下方式工作。 's' 击键将生成编辑框。在此之后,它还将调用 IME 组合窗口,该窗口现在将显示带有波浪下划线的“s”。下面的按键“a”会将 IME 窗口中的“s”更新为日文字符“さ”。下一个击键“k”将更新 IME 窗口以显示“さk”,k 带有波浪形下划线等等。这是预期的和正确的行为。

在 Windows 10 1709 中,它的工作原理是:“s”的第一次按键将生成编辑框。但是没有显示 IME 组合窗口。即使在调试运行期间也不会显示错误或警告消息。下一个击键 'a' 现在将调用 IME 合成窗口,其中日语等效于 'a',即字符 'あ'。意思是,最后,我得到了“あくら”,在英文字母中是“akura”。第一个“s”丢失。

当我使用“WindowsProc”处理编辑框创建时会发生这种情况。在这种情况下,它会正常工作,直到您将操作系统更新到 Windows 10 1709。另一方面,如果我在“PreTranslateMessage”中创建编辑框,即使在 Windows 10 1709 中它也能正常工作。 ' 在 Windows 10 1709 中处理,如何解决?

最佳答案

终于我想通了。
似乎 IME 行为在 Windows 10 1709 及更高版本中发生了变化。
我将用一个例子来解释不同的行为:

案例 1:Windows 10 1709 之前
-> 打开记事本。将 IME 设置为日语平假名,然后按“k”键。您将看到“带有波浪下划线的 k”。您需要一个或多个字符才能将这个“k”组合成一个适当的平假名。在您提供更多输入或按 Esc 取消输入之前,“k”将保留为未经确认的 IME 输入。保持原样,没有任何额外的输入,只需点击其他地方(如您的桌面),这样记事本就会失去焦点。您会注意到任务栏/语言栏中的 IME 指示器已更改。而且您可能还会看到 Windows 自己的 IME 组合窗口(Windows 7 中的黑色小窗口)弹出,其中包含您的“k”。现在回到记事本上,您会发现未经确认的“k”仍在等待您提供进一步的输入或取消它。简而言之,当焦点发生变化时,未确认的 IME 字符串仍然保持未确认状态。

案例 2:Windows 10 1709 以后:
-> 重复以上步骤。在这里你可以注意到不同之处。一旦焦点发生变化,IME 合成就会停止。因此,作为未确认的 IME 字符串的 'k' 将被丢弃。

在问题中给出的示例中,WindProc 和 PreTranslateMessage 发生的情况是,使用 WindProc,在 IME keyPress 上, View 处于焦点下并接收 KeyPress 消息。它处理它并将它传递给它的 child ,根据我们的代码,在那里创建一个新的编辑控件。现在,随着编辑控件的创建,它变得聚焦。并且根据新行为,当焦点从 View 更改为控件时,IME 组合将停止。由于这发生在第一次 IME 按键时,我们得到了一个仍处于未确认状态的字符。作为未经确认的 IME 字符,该字符被丢弃。

使用 PreTranslateMessage,我们接收按键消息并继续创建编辑控件。在创建时,编辑控件获得焦点而我们的 View 失去焦点。这将生成 KillFocus 消息,但由于我们仍处于前一个 KeyPress 消息处理的中间,因此没有处理 KillFocus 消息。它正在等待前面的消息处理完成。现在,当我们在创建控件后返回时,我们将按键传递给新创建的编辑框。因此,编辑框最终接收按键以及以下未经确认的 IME 字符。因此,根据我们的示例“k”按键,编辑框而不是 View 接收未经确认的“k”。下一个按键自然会被编辑框接收,因为它现在处于焦点下,因此第二个输入被添加到未确认的“k”中,并且像往常一样执行合成。

此行为不仅限于需要多次按键的字符。甚至像“a”这样的单个按键字符也有同样的作用,因为在我们按下 Enter 键或选择组合候选之一等之前,即使这些字符仍然未经确认。

关于c++ - Windows 10 1709 中日语输入法的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48093581/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com