显示弹出窗口时如何防止IME输入切换?

时间:2019-04-23 21:57:31

标签: c# winforms winapi ime

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

我需要显示一个带有搜索文本框的弹出窗口。每当我显示此弹出窗口时,我的IME输入都会从中文/日语切换到英语模式。根据{{​​3}}之类的文章,输入上下文应该是针对每个用户还是针对每个线程,为什么我的输入会在同一应用程序中更改? (我正在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);
        }

当我的活动窗口改变时,输入似乎会切换。但是我的搜索框需要抓住键盘,因此我相信我没有其他选择,只能更改活动窗口。

我还尝试创建自己的this,覆盖CanEnableIme并设置ImeMode,但这些方法都无法完美运行,如果有帮助,我可以解释细节。

注意:我的搜索框是自定义的文本编辑器,而不是表单文本框控件;我通过处理诸如input context之类的系统消息来使其处理IME输入,但是我没有修改输入上下文,而只是从中读取内容。

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

1 个答案:

答案 0 :(得分:0)

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

但是要在显示带有搜索框的弹出窗口后保持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修复,但是总比没有好:(