ホーム >> 左脳Script >> Adobe Flash >> TextField と IME 入力 について

TextField と IME 入力 について


「もチャット」チャット入力機能の使い勝手を向上させるために、入力関連についてあれこれ検索&実験&検証した事をまとめてみました。



IME と TextField の入力フォーカス

英数字1文字の入力をトリガーにチャット入力を開始できるようにしたいが、IME がネックでなかなか上手くいかない。
input_ime.png

TextField にフォーカスが無い状態で IME 入力があると、このように IME 入力パレットが出てしまう。

TextField にフォーカスが無い状態」かつ「IME 日本語入力状態」の時に、このパレットを出さずに正しく TextField から入力する方法はないものか。

→検索&検証&実験の結果、それっぽいものが出来た。


チャット入力シミュレーション




水色の入力領域以外の場所をクリックしても、イキナリ文字列の入力を始められる。 どこにフォーカスがあっても、入力を始めると指定TextFieldへフォーカスが移り、正しくIMEの入力ができる。




ただし、完璧ではない(後述)


ソース

たいした大きさではないので、全容公開。


package  
{
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.FocusEvent;
    import flash.events.KeyboardEvent;
    import flash.events.TextEvent;
    import flash.events.TimerEvent;
    import flash.text.TextFieldType;
    import flash.ui.Keyboard;
    import flash.text.TextField;
    import flash.utils.Timer;

    import flash.system.Capabilities;
    import flash.system.IME;
    import flash.system.IMEConversionMode;

    /**
     * ...
     * @author 
     */
    public class inputBase extends Sprite
    {
        private var logField:TextField; //  入力ログ
        private var inputField:TextField;   //  入力領域

        private var statusField:TextField;  //  フォーカス情報
        private var keycodeField:TextField; //  キーコード情報

        public function inputBase() 
        {
            //  入力ログ
            logField = new TextField();
            logField.width = 256;
            logField.height = 160;
            logField.x = 32;
            logField.y = 64;
            logField.background = true;
            logField.backgroundColor = 0xeeee99;
            logField.selectable = false;
            logField.multiline = true;
            addChild(logField);
            //  入力領域
            inputField = new TextField();
            inputField.type = TextFieldType.INPUT;
            inputField.width = 256;
            inputField.height = 32;
            inputField.x = 32;
            inputField.y = logField.y + logField.height + 32;
            inputField.background = true;
            inputField.backgroundColor = 0x99eeee;
            addChild(inputField);
            //  フォーカス情報
            statusField = new TextField();
            statusField.width = 256;
            statusField.height = 32;
            statusField.background = true;
            statusField.backgroundColor = 0xee99ee;
            statusField.x = 32;
            statusField.y = 0;
            statusField.selectable = false;
            addChild(statusField);
            addEventListener(Event.ENTER_FRAME, onEnter, false, 0, true);
            //  キーコード情報
            keycodeField = new TextField();
            keycodeField.width = 256;
            keycodeField.height = 32;
            keycodeField.background = true;
            keycodeField.backgroundColor = 0x99ee99;
            keycodeField.x = 32;
            keycodeField.y = 32;
            keycodeField.selectable = false;
            addChild(keycodeField);
            //
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            //
            startKey = new Array();
            var i:int;
            for (i = 0x30; i <= 0x39; i++)  startKey[i] = true; //  数字
            for (i = 0x41; i <= 0x5a; i++)  startKey[i] = true; //  アルファベット
            for (i = 186; i <= 192; i++)    startKey[i] = true; //  記号
            for (i = 219; i <= 222; i++)    startKey[i] = true; //  記号
            //
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownStage);
            inputField.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDownInput);
            inputField.addEventListener(FocusEvent.FOCUS_OUT, onFocusOut);
            //  FOCUS_INは特に必要ない。IME.setCompositionStringが「IME.enabled = true;」を兼ねる。
    //      inputField.addEventListener(FocusEvent.FOCUS_IN, onFocusIn);
        }

        //  判定用
        private var startKey:Array;

        /**
         * 入力開始判定
         * @param   e
         */
        private function onKeyDownStage(e:KeyboardEvent):void 
        {
            if (startKey[e.keyCode])
            {
                var t:Timer = new Timer(0, 1);
                t.addEventListener(TimerEvent.TIMER,function (te:TimerEvent):void 
                {
                    t.stop();
                    t.removeEventListener(TimerEvent.TIMER, arguments.callee);
                    /*  キーダウンイベントを抜けた後でTextFieldにフォーカスをあわせないと、
                     *  TextFieldが入力文字を拾ってしまう。    */
                    stage.focus = inputField;
                    //  TextFieldにフォーカスが無いとIME.conversionModeから正しい値が拾えない。
                    if (Capabilities.hasIME
                    &&  IME.conversionMode != IMEConversionMode.ALPHANUMERIC_HALF
                    &&  IME.conversionMode != IMEConversionMode.UNKNOWN )
                    {   //  IMEインライン入力モード
                        IME.setCompositionString(String.fromCharCode(e.charCode));
                    }
                    else
                    {   //  IME変換入力モードではない
                        inputField.appendText(String.fromCharCode(e.charCode));
                        var last:int = inputField.caretIndex + 1;
                        inputField.setSelection(last, last);
                    }
                });
                t.start();
            }
            //
            keycodeField.text = "STAGE:" + e.keyCode.toString();
        }

        /**
         * 入力フィールドキー入力判定
         * @param   e
         */
        private function onKeyDownInput(e:KeyboardEvent):void 
        {
            switch (e.keyCode) 
            {
                case    Keyboard.ENTER: //  文字列入力完了検知
                    logField.appendText("\n" + inputField.text);
                    logField.scrollV = logField.maxScrollV;
                    inputField.text = "";
                    break;
                case    Keyboard.ESCAPE:
                    stage.focus = stage;    //  フォーカスを別のコンポーネントへ移動可能
                    break;
            }
            e.stopPropagation();
            //
            keycodeField.text = "INPUT:" + e.keyCode.toString();
        }

        //  TextField以外のDisplayObjectがフォーカスを得る場合、IME.enabledの操作が必要。
        private function onFocusOut(e:FocusEvent):void 
        {   //  これが無いと、IME 入力パレットが出てしまう。
            IME.enabled = false;
        }

        /**
         * フォーカス表示
         * @param   e
         */
        private function onEnter(e:Event):void 
        {
            if (stage.focus === logField) 
            {
                statusField.text = "入力ログ領域";
            }
            else if (stage.focus === inputField) 
            {
                statusField.text = "入力領域";
            }
            else if (stage.focus === statusField) 
            {
                statusField.text = "ステータス領域";
            }
            else if (stage.focus === keycodeField) 
            {
                statusField.text = "キーコード領域";
            }
            else
            {
                statusField.text = "どこか";
            }
        }
    }
}


ポイントは、2点。チャット入力開始判定をしている onKeyDownStage にある。
  • 入力のあった文字が文章入力の開始であると判定した際、直ちに入力の TextField にフォーカスを設定していない事。判定のあったイベント処理内でフォーカスを設定すると、TextField が最初の一文字を拾ってしまう。

    もし、IME のモードが日本語入力状態だった場合、ここでフォーカスを移すと、冒頭で述べた入力パレットがでるか、フラッシュの左上に入力文字列が表示されてしまう事になる。

    入力判定をした後、そのイベント処理をぬけた直後に、入力 TextField へフォーカスを移動し、最初の一文字を、モードによって場合わけ処理をする。

  • 「イベントを抜けた直後に処理をする」を実現するために、遅延ゼロの Timer イベントを利用。
    一定時間後である必要はないが、一旦処理を抜けた後に実行したい処理が在る場合に使う。 これは、意外に応用範囲が広い。



バグと言うか不具合

バグというか不具合がある。

ime_pallet.png
ごく稀に(初回入力時が多いので追求が不可能ではないと見ている)、IME の入力パレットがでる。

マウスによる操作で、適切にフォーカスを設定してやると入力は出来るようになるので、致命的なレベルではない。また、動作モードが不安定で(今のところ)このようになるモードが特定できない。




限界

もうチョっと便利にしようとしたが、IME 関連の仕様の壁は厚かった。

TextField にフォーカスが無いと「半角/全角キーによる IME モード切替」が不可能であることが判明。どんなに検索しても、IME 周りは不安定でバグが多いとしか情報が出ない。「半角/全角キーによる IME モード切替」をメソッドなりプロパティなりで変更が出来ない。

Flex SDK 4 で、IME 関連のインターフェースが追加されたようだが、解決したい問題との関連性を見出せなかった。


もぅ、Adobe の今後に期待するしかない。





トラックバック(0)

トラックバックURL: http://n-yagi.0r2.net/sanoupulurun/mt-tb.cgi/264

コメント(1)

コメントする

ホーム >> 左脳Script >> Adobe Flash >> TextField と IME 入力 について

アーカイブ

このブログ記事について

このページは、n-yagiが2010年8月14日 15:38に書いたブログ記事です。

ひとつ前のブログ記事は「もチャット作成日誌:2010年7月1日」です。

次のブログ記事は「もチャット作成日誌:2010年7月2日」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

Creative Commons License
このブログはクリエイティブ・コモンズでライセンスされています。