none
[WPF]ウィンドウにおける日本語入力開始をテキストボックスに引き継ぎたい RRS feed

  • 質問

  • いつも参考にさせていただいております。

    WPFのアプリケーションにおいて、ウィンドウにキーボードフォーカスが適用されているときに日本語入力が開始されたら内包するテキストボックスにフォーカスを移してそのまま入力を継続させたいと考えています。

    そこで以下の方法を試しましたが、上手くいきません。

    1. PreviewKeyDown イベントでテキストボックスの Focus を呼出
    -> 最初の文字の入力がスキップされてしまう。

    2. TextCompositionManager.AddPreviewTextInputStartHandler イベントでテキストボックスの Focus を呼出
    -> IMEがONの場合は同イベントがコールされない。

    上記の状況から、.NET Frameworkに用意された標準の機能では厳しそうと考えています。(IME関連のウィンドウメッセージやText Services Framework関連のAPIの調査が必要?)

    このようなニーズを実現するための方法に関して、よろしければ何かヒントをいただければと思います。どうぞよろしくお願いします。

    XAML

    <Window x:Class="WpfApplication1.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525"
            Focusable="True"
            FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
        <TextBox Width="100" Height="20" Name="txt" />
    </Window>

    ソース

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApplication1
    {
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                InputMethod.SetIsInputMethodEnabled(this, true);
                InputMethod.SetPreferredImeState(this, InputMethodState.On);
    
                // 1.
                PreviewKeyDown += (sender, e) =>
                    {
                        if (e.OriginalSource == txt)
                            return;
    
                        e.Handled = true;
                        txt.Focus();
                    };
    
                // 2.
                //TextCompositionManager.AddPreviewTextInputStartHandler(
                //    this, new TextCompositionEventHandler((sender, e) =>
                //    {
                //        if (e.OriginalSource == txt)
                //            return;
    
                //        txt.Focus();
                //    }));
            }
        }
    }

    環境

    • Windows 7 以上
    • .NET Framework 4.5(できれば.NET 4互換が望ましい)

    備考

    「始めからテキストボックスにフォーカスを適用すればよい」というのは"無し"とさせてください。

    実際のシナリオは、テキストボックスはカスタムUIコントロールから動的に表示するものとなっています。

    したがって、始めからフォーカスをテキストボックスに置いておくことはできません。

    • 編集済み Yuichi-Public 2013年9月23日 12:41 「備考」を追記
    • 移動 星 睦美 2013年9月24日 0:37 Windows クライアント開発 から
    2013年9月23日 3:03

回答

  • 以下の方法でフォーカスを移動させた後に入力を継続できました。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            InputMethod.SetIsInputMethodEnabled(this, true);
            InputMethod.SetPreferredImeState(this, InputMethodState.On);
    
            InputManager.Current.PreProcessInput += new PreProcessInputEventHandler(Current_PreProcessInput);
        }
    
        void Current_PreProcessInput(object sender, PreProcessInputEventArgs e)
        {
            InputEventArgs ie = e.StagingItem.Input;
            KeyEventArgs ke = ie as KeyEventArgs;
            if (ke != null)
            {
                if (System.Windows.Input.Keyboard.FocusedElement != this.txt)
                {
                    //System.Diagnostics.Debug.WriteLine("*** Focus Change ***");
                    this.txt.Focus();
                }
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2013年9月26日 10:42

すべての返信

  • フォーラム オペレーターの星 睦美です。
    Yuichi-Public さん、投稿ありがとうございます。

    Windows Presentation Foundation ( WPF ) に関する質問内容ですので、私のほうで質問を移動させていただきました。

    フォーラムで役立つ情報がありましたら、投稿者から[回答としてマーク] をお願いします。


    フォーラム オペレーター 星 睦美 - MSDN Community Support

    2013年9月24日 0:37
  • 以下の方法でフォーカスを移動させた後に入力を継続できました。

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
    
            InputMethod.SetIsInputMethodEnabled(this, true);
            InputMethod.SetPreferredImeState(this, InputMethodState.On);
    
            InputManager.Current.PreProcessInput += new PreProcessInputEventHandler(Current_PreProcessInput);
        }
    
        void Current_PreProcessInput(object sender, PreProcessInputEventArgs e)
        {
            InputEventArgs ie = e.StagingItem.Input;
            KeyEventArgs ke = ie as KeyEventArgs;
            if (ke != null)
            {
                if (System.Windows.Input.Keyboard.FocusedElement != this.txt)
                {
                    //System.Diagnostics.Debug.WriteLine("*** Focus Change ***");
                    this.txt.Focus();
                }
            }
        }
    }


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2013年9月26日 10:42
  • 私の方でもご提示いただいたソースコードで期待の動作が実現できることを確認しました。

    恥ずかしながらPreProcessInputというイベントを把握できていませんでした...。

    大変貴重な情報をいただき感謝いたします。ありがとうございました。

    2013年9月26日 15:06