首页 > 解决方案 > 显示弹出窗口时如何防止 IME 输入切换?

问题描述

在我的应用程序中,我们使用Form作为容器,然后我们制作定制的NativeWindow

我需要显示一个带有搜索文本框的弹出窗口。每当我显示此弹出窗口时,我的 IME 输入将从中文/日文切换到英文模式。基于这样的文章输入上下文应该是每个用户或每个线程,为什么我的输入会在我的同一个应用程序中改变?(我在 Windows 10 上进行测试)

我试图通过这样做来保持主应用程序处于活动状态,这会阻止输入切换,但是当我显示它时,我的搜索框将不再获得键盘输入,所以我不能使用这种方法:

       protected override void WndProc(ref System.Windows.Forms.Message m) {
            switch(m.Msg) {
                case (int)WM.ACTIVATE:
                    if(m.WParam.ToInt64() == 1) {
                        UserMethods.SetActiveWindow(PopupOwner.Handle);
                    }
                    break;
            }
            base.WndProc(ref m);
        }

当我的活动窗口发生变化时,输入似乎会切换。但是我的搜索框需要抓取键盘,所以我相信我别无选择,只能更改活动窗口。

我还尝试创建自己的输入上下文,覆盖 CanEnableIme 并设置 ImeMode,这些都不是完美的,如果有帮助,我可以解释细节。

注意:我的搜索框是自定义的文本编辑器,不是表单文本框控件;我通过处理这样的系统消息让它处理 IME 输入但我没有修改输入上下文,只是从中读取。

更改活动窗口时如何保持 IME 输入模式保持不变?

标签: c#winformswinapiime

解决方案


我仍然不知道为什么我的输入会在我的应用程序中切换。

但是为了在显示带有搜索框的弹出窗口后保持 IME 模式保持不变,我在弹出窗口被激活之前捕获 IME 状态,在它被激活之后,我修改 IME 状态。像这样的东西:

var imeOpened = false;
//get ime status
var hImc = ImmGetContext(popup.handle);
if(hImc != IntPtr.Zero) {
  imeOpened = ImmGetOpenStatus(hImc);
}

Showpopup();

//open ime if it was opened
if(hImc != IntPtr.Zero) {
  if(imeOpened) ImmSetOpenStatus(hImc, true);
  ImmReleaseContext(popup.handle, hImc);
}

在我的应用程序中,我有一个一次性捕集器,这使它更清洁:

using(TrapOpenedIme(popup.handle)) Showpopup()

注意:ImmSetConversionStatusImmGetConversionStatus没有为我工作。

这是一个hacky修复,但总比没有好:(


推荐阅读