none
変換確定後の読み仮名取得について(IMEの制御) RRS feed

  • 質問

  • c#でWPFアプリケーションを作成しています。

    「Microsoft Visual Studio International Feature Pack」にある
    よみがなを取得できるYomiganaWPFTextBoxというコントロールを使用して、
    入力されたテキストの読み仮名を取得する処理を実装しております。

    以下の特定の条件を満たす場合に正しく読み仮名を取得できず困っております。


    入力テキストに「あ」「い」「う」「え」「お」「や」「ゆ」「よ」「つ」のいずれか一文字を入力して、
    変換候補一覧の[小]の文字を越えて決定すると、読み仮名が小文字(「ァ」「ィ」等)になる。


    入力テキストに「mai(まい)」と入力して、
    変換候補一覧の「my」の文字を超えて決定すると、読み仮名が『my』(半角英数)になる。
    (daikiでも同様の現象が発生する)


    入力テキストに「ゐ」「ヱ」と入力して、
    決定すると、読み仮名が(「ィ」「ェ」等)になる。

    使用しているOSはWindows10(x64)です。

    YomiganaWPFTextBoxコントロール以外のコントロールでも同様の現象を確認しているため
    IMEの動作に起因している可能性が高いと考えております。

    変換候補一覧の[小]の文字や英単語を表示しないようにする方法等を検討してみましたが
    うまくいきませんでした。

    同様の現象に対する回避方法をご存知の方がいらっしゃいましたら、
    ご教授願えませんでしょうか。
    2017年6月1日 3:47

すべての返信

  • YomiganaWPFTextBoxが対象としている「読み仮名」は漢字から仮名への変換です。「入力文字」とは異なる概念です。
    2017年6月1日 4:04
  • 入力テキストに、文字列を入れ変換候補から漢字を選択して変換したときに
    読み仮名を取得しようとしていますが、上記の条件を満たすときのみ正しく読み仮名を取得できません。

    以下は、コードの一部です。

    ~Xaml~

    <yomi:YomiganaWPFTextBox
          Name="Kanji"
          YomiganaChanged="Kanji_YomiganaChanged" />

    ~コードビハインド~

    private void Kanji_YomiganaChanged(object sender, RoutedEventArgs e)
    {
    Kana.Text = Kanji.TextCaptured;
    }

    参考)http://www.makcraft.com/blog/meditation/2014/06/07/get-the-yomigana-in-wpf-1/

    読み仮名を取得できる方法で以下のものを試しましたが
    期待通りの結果にはなりませんでした。

    ①Windows.Globalization.JapanesePhoneticAnalyzer を使う方法

    コード例)var result = Windows.Globalization.JapanesePhoneticAnalyzer.GetWords(value);

    参考)http://www.makcraft.com/blog/meditation/2016/05/16/get-the-yomigana-in-wpf-3/

    期待通りでない理由:『masayosi(マサヨシ)』と入力して『大義』に変換して決定すると読み仮名が『タイギ』となってしまう。
    2017年6月1日 4:57
  • 「漢字を含まない入力中の文字列」という条件で読み仮名が抽出されるなら、変換候補一覧から選択中の文字列も入力されていた可能性がある文字列なので区別ができないんじゃないかなぁ。
    ひらがな入力中にアルファベット混在の入力はできるのでアルファベットも読み仮名の候補になりえますし。

    入力した通りの文字列がほしいなら、入力中の文字列を監視しておいて、そこから目的にかなう文字列を探せばいいと思う

    using System.Collections.Generic;
    using System.Linq;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    //参照
    //JpnKanaConvHelper.dll
    //YomiganaWPFTextBox.dll
    
    namespace WpfApplication1
    {
    
        public partial class MainWindow : Window
        {
            private TextBlock furigana;
            private Microsoft.International.Windows.Controls.YomiganaWPFTextBox Kanji;
    
            public MainWindow()
            {
                InitializeComponent();
    
                furigana = new TextBlock() { Margin = new Thickness(5) }; ;
    
                Kanji = new Microsoft.International.Windows.Controls.YomiganaWPFTextBox() { Margin = new Thickness(5) }; ;
                Kanji.YomiganaChanged += Kanji_YomiganaChanged;
    
                ComboBox combo = new ComboBox() { Margin = new Thickness(5) };
                combo.ItemsSource = System.Enum.GetValues(typeof(Microsoft.International.Windows.Controls.PreferredConversion));
                combo.SelectionChanged += (s, e) => Kanji.TextCapturedPreferredConversion = (Microsoft.International.Windows.Controls.PreferredConversion)combo.SelectedItem;
                combo.SelectedItem = Microsoft.International.Windows.Controls.PreferredConversion.ToHiragana;
    
                StackPanel stack = new StackPanel();
                stack.Children.Add(combo);
                stack.Children.Add(Kanji);
                stack.Children.Add(furigana);
                this.Content = stack;
              
                System.Windows.Input.TextCompositionManager.AddTextInputStartHandler(this.Kanji, Composition_TextInputStart);
                System.Windows.Input.TextCompositionManager.AddTextInputUpdateHandler(this.Kanji, Composition_TextInputUpdate);
            }
    
            List<string> inputList = new List<string>();
    
            void Composition_TextInputStart(object sender, TextCompositionEventArgs e)
            {
                inputList.Clear();
            }
    
            void Composition_TextInputUpdate(object sender, TextCompositionEventArgs e)
            {
                //入力中の文字列を保存しておく
                string text = e.TextComposition.CompositionText;
                if (inputList.Count > 0)
                {
                    string last = inputList.Last();
                    if (last.StartsWith(text))
                    {
                        //入力中文字列の末尾が削除された
                        inputList.RemoveAt(inputList.Count - 1);
                    }
                }
                inputList.Add(text);
            }
    
            private void Kanji_YomiganaChanged(object sender, RoutedEventArgs e)
            {
                var yomiTextBox = sender as Microsoft.International.Windows.Controls.YomiganaWPFTextBox;
    
                CharCounter[] cs = inputList.Select(text => CharCounter.CountChar(text, yomiTextBox.TextCapturedPreferredConversion)).Where(_ => _.Count > 0).ToArray();
                int max = cs.Max(_ => _.Count);//指定した文字種の数が最も多い文字列を探す
                CharCounter foundLast = cs.Last(_ => _.Count == max);//指定した文字種が多いもののうち一番最後が候補とみなす
                CharCounter foundFrist = cs.First(_ => _.LargeText == foundLast.LargeText); //大文字小文字を揃えて一致する最初のものが入力したものとみなす
    
                furigana.Text = this.Kanji.TextCaptured;
                yomiTextBox.Text = yomiTextBox.Text + "[" + foundFrist.Text + "]";
                yomiTextBox.SelectionStart = yomiTextBox.Text.Length;
            }
        }
    
        class CharCounter
        {
            public static System.Text.RegularExpressions.Regex regHiragana = new System.Text.RegularExpressions.Regex(@"[\u3041-\u3096\u3099-\u309F]");
            public static System.Text.RegularExpressions.Regex regKatakana = new System.Text.RegularExpressions.Regex(@"[\u30A1-\u30FF]");
            public static System.Text.RegularExpressions.Regex regHankana = new System.Text.RegularExpressions.Regex(@"[\uFF61-\uFF9F]");
    
            public const string HalfSmall = "ァィゥェォャュョッ";
            public const string HalfLarge = "アイウエオヤユヨツ";
            public const string WideSmall = "ぁぃぅぇぉゃゅょっゕゖ";
            public const string WideLarge = "あいうえおやゆよつかけ";
    
            public CharCounter(string original, string text, Microsoft.International.Windows.Controls.PreferredConversion conversion, int count)
            {
                this.Origial = original;
                this.Text = text;
                this.LargeText = new string(text.Select(c => ToLarge(c)).ToArray());
    
                this.PreferredConversion = conversion;
                this.Count = count;
                
            }
    
            public string Origial { get; private set; }
            public string Text { get; private set; }
            public string LargeText { get; private set; }
            public Microsoft.International.Windows.Controls.PreferredConversion PreferredConversion { get; private set; }
            public int Count { get; private set; }
    
            /// <summary>//目的の文字種の文字数を数える</summary>
            /// <param name="text">入力文字列</param>
            /// <param name="conversion">文字種</param>
            /// <returns></returns>
            public static CharCounter CountChar(string text, Microsoft.International.Windows.Controls.PreferredConversion conversion)
            {
                //text = Microsoft.International.Converters.KanaConverter.RomajiToHiragana(text);
                string org = text;
                int count;
                switch (conversion)
                {
                    case Microsoft.International.Windows.Controls.PreferredConversion.ToHiragana:
                        text = Microsoft.International.Converters.KanaConverter.HalfwidthKatakanaToHiragana(text);
                        text = Microsoft.International.Converters.KanaConverter.KatakanaToHiragana(text);
                        count = text.Count(c => regHiragana.IsMatch(char.ToString(c)));
                        break;
    
                    case Microsoft.International.Windows.Controls.PreferredConversion.ToKatakana:
                        text = Microsoft.International.Converters.KanaConverter.HiraganaToKatakana(text);
                        text = Microsoft.International.Converters.KanaConverter.HalfwidthKatakanaToKatakana(text);
                        count = text.Count(c => regKatakana.IsMatch(char.ToString(c)));
                        break;
    
                    case Microsoft.International.Windows.Controls.PreferredConversion.ToHalfwidthKatakana:
                        text = Microsoft.International.Converters.KanaConverter.HiraganaToHalfwidthKatakana(text);
                        text = Microsoft.International.Converters.KanaConverter.KatakanaToHalfwidthKatakana(text);
                        count = text.Count(c => regHankana.IsMatch(char.ToString(c)));
                        break;
    
                    default:
    
                        count = text.Length;
    
                        break;
                }
    
                return new CharCounter(org, text, conversion, count);
            }
    
            public static char ToLarge(char c)
            {
                int index;
                index = HalfSmall.IndexOf(c);
                
                if (index >= 0)
                {
                    return HalfLarge[index];
                }
                index = WideSmall.IndexOf(c);
                if (index >= 0)
                {
                    return WideLarge[index];
                }
                return c;
            }
        }
    }

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

    2017年6月1日 11:38
  • このコードって、入力中や変換中でのBackSpaceやDeleteキー操作に対応しているのでしょうか?

    # 対応する入力文字の特定が困難だからこそ、入力文字のことは忘れて読み仮名(=漢字かな変換)を行っているのかと…。

    2017年6月1日 21:38
  • キーの入力を監視する方法であれば、変換候補の影響を受けないとは思います。
    しかし、入力中(変換前の状態)で矢印キーで移動して文字列を編集した場合等も対応させるとなる
    別途処理を追加する必要があるのではないかと思います。

    現在は、読み仮名を取得する方法で実現できればと考えております。


    最初の説明では、分かりにくい点があったため追記します。


    上記の画像のように、決定した変換候補に依存しているのではなく、
    [小]や英単語の変換候補以降は、どれを決定しても正しく読み仮名を取得できないという現象です。

    この現象を回避したいと考えています。
    2017年6月2日 0:57
  • 上記の件、拝見させていただきました。
    私も上記同様な問題に困っています。

    C#のWindowsForm版では、正しい結果がとれるのですが、
    WPFでは、IMEの変換候補から意図した読み仮名がとれないという
    IMEの動作不良になるのでしょうか。


    2017年6月6日 7:42