none
TopmostのWindow上でTextBoxのIMEを上書きモードにした場合の挙動 RRS feed

  • 質問

  • Windows7、Vista環境下で、以下の手順を踏むと、IMEの入力欄がウインドウの裏に隠れてしまう現象が発生します。
    (VisualStudio2010,NET Framework4,WPFアプリケーション)
    ■再現コード
    MainWindow.xamlを用意し、ウインドウ内にテキストボックス(textBox1)を配置します。
        MainWindow.xaml
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
                this.Topmost = true;
            }
            private void textBox1_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Return)
                {
                    MessageBox.Show("Enter!");
                    this.textBox1.Text = "";
                    this.textBox1.Focus();
                }
            }
        }
    ■再現手順
    1.テキストボックスにフォーカスを移し、IMEをONします。
    2.[Insert]キーを押し、IMEを上書きモードにします。
    ※この時点で、IMEレベル?で上書き用の入力欄が表示されます。
    3.Enterキーを押します。(KeyDownイベントが発生し、テキストボックス内がクリアされます)
    この後、再度テキストボックスにて入力すると、IMEレベル?での上書き用の入力欄が表示されません。
    (MainWindowの裏に隠れており、入力自体はできています。Enterキーで確定させると、やっとテキストボックスに反映されます。)
    ※「MainWindowの裏に隠れていること」は、このMainWindow.xamlをさらに親Windowから呼び出すように修正後、
    現象を発生させた後、MainWindowをクローズすることで確認しました。コードは省略します。)
    ■これまでに検証したこと
    ・Windows7、Vistaの環境で発生します。
    WindowsXP環境では発生しません。
    WindowxXPでは、手順2の操作でIMEレベル?での上書き用の入力欄自体が発生しません。
    ・System.Windows.Forms.TextBoxを使用した場合は発生しません。
    ・非WPFプロジェクト、WPFプロジェクト+WindowsFormsHost+System.Windows.Forms.TextBoxで試しました。
    これらについても、手順2の操作でIMEレベル?での上書き用の入力欄自体が発生しませんでした。
    ・Topmost=true;を止めた場合は[IMEレベル?での上書き用の入力欄]が表示されます。
    ・KeyDownイベント内の[MessageBox.Show]を止めた場合も表示されます。
    検証結果から、WPF、またはIMEのバグ?といった挙動に見えます。
    Topmostを止める、System.Windows.Forms.TextBoxを利用する、といった方法で回避することはできそうなのですが、処理の都合上、Topmost指定ははずせません。
    また、System.Windows.Formsを使用せず、WPFコードのみで回避できることがベストと考えています。
    質問
    WPFコードのみで回避できる方法はあるでしょうか?
    ・手順2の[Insert]キーを抑止し、IMEレベル?での上書き用の入力欄を発生させないようなことができれば良いのですが・・・。
    (KeyDownイベント内で[Insert]キーを無効にするコードではIMEの上書きモードを無効にできませんでした。)
    よろしくお願いします。

    • 編集済み Hiroyuki 2011年11月11日 2:14
    2011年11月11日 2:00

すべての返信

  • IME に関わる話であれば、ご使用の IME についても言及いただきたいところです。

    Win7 において追試してみたところ、手元の ATOK2009 では再現せず、標準の MS-IME では再現しました。このことから TSF(Text Services Framework)絡みの問題と推測できます。それ以上を探るのは私の手に余りますが。

    入力は、複数のイベント/ウィンドウメッセージによって制御される複雑な機構です。その中で MessageBox を呼び出してしまうと、メッセージループが回ってしまうため、ウィンドウメッセージを正しい順番で処理できない可能性があります。

    Dispatcher.BeginInvoke を使って、実際の処理を遅延させてやるのはいかがでしょうか。

    2011年11月11日 2:26
  • IMEはWindows7標準の[Microsoft IME]を使用していました。

    Dispatcher.BeginInvokeを利用するアイデアを試してみたいと思います。(追って報告します。)

    2011年11月11日 3:05
  • Hongliang様のアイデアを取り入れてみましたが、結果は変わりませんでした。
    取り急ぎ報告します。
    ■検証コード
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
     
                this.Topmost = true;
            }
     
            private void textBox1_KeyDown(object sender, KeyEventArgs e)
            {
                if (e.Key == Key.Return)
                {
                    var dispatcher = Application.Current.Dispatcher;
                    dispatcher.BeginInvoke(
                        DispatcherPriority.Normal,
                        new DispatcherOperationCallback(
                            delegate
                            {
                                MessageBox.Show("Enter!");
                                this.textBox1.Text = "";
                                this.textBox1.Focus();
                                return null;
                            }), null);
     
                    //MessageBox.Show("Enter!");
                    //this.textBox1.Text = "";
                    //this.textBox1.Focus();
                }
            }
        }
    2011年11月11日 3:16