質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

6103閲覧

InputField内で文字列が変換中か確定済みかわかりづらい

fuka18

総合スコア12

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2019/02/19 12:26

InputFieldを実装したゲームを実行し、日本語を入力しようと
入力文字を変換すると下記の画像のようになります。
画像では見えにくいですが、入力文字が変換中なのか確定済みなのかが判別できません。
変換中の場合は文字に波線または下線を加えることは可能でしょうか。

イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

確かに確定済みと変換中の区別がつかないのは気になりますね。調べてみたものの、インスペクタから設定をいじって手軽にできるような方法はないかもしれません。何とかならないかと思い実験してみましたが、ちょっとトリッキー感のあるものになってしまいました。

下記スクリプトを作成し、InputFieldにアタッチして実行してみたところ、

C#

1using System.Collections; 2using System.Reflection; 3using UnityEngine; 4using UnityEngine.UI; 5 6[RequireComponent(typeof(InputField))] 7public class InputFieldCompositionStringColorizer : MonoBehaviour 8{ 9 // 変換中文字列を何色で表示するか? 10 [SerializeField] private Color compositionStringColor = Color.blue; 11 12 private IEnumerator Start() 13 { 14 // 文字列の整形時に位置の手がかりとなる各種フィールドは、アクセシビリティレベルが 15 // protectedなのでむりやり探し出さないといけない 16 var caretPositionField = typeof(InputField).GetField( 17 "m_CaretPosition", 18 BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic); 19 var drawStartField = typeof(InputField).GetField( 20 "m_DrawStart", 21 BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic); 22 var drawEndField = typeof(InputField).GetField( 23 "m_DrawEnd", 24 BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.NonPublic); 25 26 // 非公開のメンバーはUnityのバージョンアップで予告なしに使えなくなるかもしれないので... 27 if ((caretPositionField == null) || (drawStartField == null) || (drawEndField == null)) 28 { 29 // フィールドの取得に失敗したら、このスクリプトコンポーネントは削除する 30 Debug.LogError("Couldn't find non-public members."); 31 Destroy(this); 32 yield break; 33 } 34 35 // InputFieldに参照されているTextはInputFieldのコントロール下にあるので 36 // リッチテキスト機能が使えないため、Textを複製してそれを表示用に使う 37 var field = this.GetComponent<InputField>(); 38 var text = field.textComponent; 39 var richText = Instantiate(text, text.transform.parent); 40 richText.name = "RichText"; 41 richText.supportRichText = true; 42 43 // 入力用Textは文字色を透明にする 44 text.color = Color.clear; 45 46 // 入力用Textの文字色を変えるとキャレットの色まで変わってしまうので、InputFieldは 47 // カスタムキャレット色を使うようにして、元のテキストの色をセットする 48 field.customCaretColor = true; 49 field.caretColor = richText.color; 50 51 // 前のフレームの入力用Textの内容を覚えておくための変数 52 var previousTextString = text.text; 53 54 // Textの兄弟関係調整(後述)が終わったかどうかを示すフラグ 55 var hierarchyAdjusted = false; 56 57 // 「変換中」から「非変換中」への変わり目を検出するためのフラグ 58 var compositionStringEmptied = false; 59 60 // 「変換中」から「非変換中」へ変わった後、さらにもう1回だけ表示用Textの文字列設定を走らせるためのフラグ 61 var needsReassignTextString = false; 62 63 // 準備が整ったら、あとは毎フレーム文字列を監視して色付け処理を行う 64 while (true) 65 { 66 // 表示用Textが入力用Textよりも手前に来るようにヒエラルキー上の兄弟関係を調整する 67 if (!hierarchyAdjusted) 68 { 69 var textSiblingIndex = text.transform.GetSiblingIndex(); 70 var richTextSiblingIndex = richText.transform.GetSiblingIndex(); 71 if ((textSiblingIndex + 1) != richTextSiblingIndex) 72 { 73 richText.transform.SetSiblingIndex(textSiblingIndex + 1); 74 hierarchyAdjusted = true; 75 } 76 } 77 78 // 変換中の文字列を取得 79 var compositionString = Input.compositionString; 80 var compositionStringLength = compositionString.Length; 81 82 // 入力用Textの表示内容を取得 83 var textString = text.text; 84 85 // 変換中であれば(変換中文字列が空でなければ)... 86 if ((compositionStringLength > 0) || needsReassignTextString) 87 { 88 // まず現在のInputFieldの文字列(まだ変換中文字列が挿入されていない)を取得 89 var fieldText = field.text; 90 var fieldTextLength = fieldText.Length; 91 92 // 変換中文字列を挿入するべき位置を調べる 93 // ※field.caretPositionというプロパティもありますが、それとはちょっと位置が違うようです 94 var insertAt = (int)caretPositionField.GetValue(field); 95 96 // 挿入後文字列から表示用に切り出す範囲を調べる 97 var clipFrom = (int)drawStartField.GetValue(field); 98 var clipTo = Mathf.Min( 99 (int)drawEndField.GetValue(field), 100 fieldTextLength + compositionStringLength); 101 var clipLength = clipTo - clipFrom; 102 103 // 元の文字列に変換中文字列を挿入する 104 var concatenatedString = fieldText.Insert(insertAt, compositionString); 105 106 // 挿入後文字列の中のタグを付けるべき範囲を求める 107 var tagFrom = Mathf.Max(insertAt, clipFrom); 108 var tagTo = Mathf.Min(insertAt + compositionStringLength, clipTo); 109 var tagLength = Mathf.Max(tagTo - tagFrom, 0); 110 111 // 目的の範囲の前後にタグを挿入する 112 var openTagLength = 0; 113 var closeTagLength = 0; 114 if (tagLength > 0) 115 { 116 var openTag = $"<color=#{ColorUtility.ToHtmlStringRGBA(this.compositionStringColor)}>"; 117 const string closeTag = "</color>"; 118 concatenatedString = concatenatedString.Insert(tagTo, closeTag); 119 concatenatedString = concatenatedString.Insert(tagFrom, openTag); 120 openTagLength = openTag.Length; 121 closeTagLength = closeTag.Length; 122 } 123 124 // タグ付きの挿入後文字列から表示範囲を切り出し、表示用Textにセットする 125 var newTextString = concatenatedString.Substring(clipFrom, openTagLength + clipLength + closeTagLength); 126 richText.text = newTextString; 127 128 // 未確定文字を削除することによって「非変換中」に戻った場合に、最後の未確定文字の残骸が残ってしまうようなので 129 // その対策として「非変換中」に戻った後にもう一回だけ表示用Text更新を行わせることにした 130 // 何も特別なスクリプトを付けていないInputFieldでもこの現象が起こるようだが、InputField自体の不具合だろうか...? 131 if (needsReassignTextString) 132 { 133 text.text = newTextString; 134 needsReassignTextString = false; 135 } 136 else 137 { 138 compositionStringEmptied = true; 139 } 140 } 141 else if (compositionStringEmptied) 142 { 143 compositionStringEmptied = false; 144 needsReassignTextString = true; 145 } 146 // 変換中でなくとも、入力用Textの内容に変化(スクロールした、削除した、直接入力したなど)があったら... 147 else if (textString != previousTextString) 148 { 149 // 表示用Textの内容を更新する 150 richText.text = textString; 151 previousTextString = textString; 152 } 153 154 yield return null; 155 } 156 } 157}

下図のように変換中の部分が青色で表示されるようになりました(Unity 2018.3.6f1、Windows 10 Home バージョン1803上でプレイモードで動かし、Microsoft IME 10.0.17134.1で入力)。

動作の様子

protectedフィールドを勝手に覗いていますが、UnityのアップデートでInputFieldの実装が変われば急に動かなくなる可能性があります。また、動きの確認もプレイモードでちょこっとやっただけですので、どの環境でも大丈夫かというと保証しかねます。

また、ご所望の下線ではなく色付けになってしまいすみません。リッチテキストの機能で下線ぐらい付けられるだろう、と思っていたらダメでして(リッチテキスト - Unity マニュアルに使えるタグの一覧がありますが、下線は載っていませんでした)、もしやるとしたら文字の幅やらを勘案して座標を求め、自前で線を引くことになりそうだったため妥協しました...
そして変換中の文字は一律青色です。変換済み文節と未変換文節を塗り分けるのはもっと難しそうです(そもそも可能なのかも未調査です)。

投稿2019/02/22 11:14

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fuka18

2019/02/28 10:39

返信が遅くなり大変申し訳ございません。 .NET 4.x上で確認できました! ただ、現状では.NET 3.5を使用しているので、下記のエラーが発生します。 バージョンアップすると別機能が動かなくなってしまうので、バージョンアップ対応も検討しようと思います。 InputFieldCompositionStringColorizer.cs(116,36): error CS1644: Feature `interpolated strings' cannot be used because it is not part of the C# 4.0 language specification
Bongo

2019/02/28 11:49

文字列補間が使えませんでしたか、すみません。 .NET 3.5非対応なのは多分そこのcolorタグを作っている部分だけかと思いますので、そこを... var openTag = string.Format("<color=#{0}>", ColorUtility.ToHtmlStringRGBA(this.compositionStringColor)); の形にすれば、アップグレードしなくても動かせるかもしれません。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問