Home | History | Annotate | Download | only in openwnn
      1 /*
      2  * Copyright (C) 2008-2012  OMRON SOFTWARE Co., Ltd.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package jp.co.omronsoft.openwnn;
     18 
     19 
     20 import jp.co.omronsoft.openwnn.EN.OpenWnnEngineEN;
     21 import jp.co.omronsoft.openwnn.JAJP.*;
     22 import android.content.SharedPreferences;
     23 import android.content.Context;
     24 import android.content.Intent;
     25 import android.content.res.Configuration;
     26 import android.os.Handler;
     27 import android.os.Message;
     28 import android.preference.PreferenceManager;
     29 import android.text.SpannableStringBuilder;
     30 import android.text.Spanned;
     31 import android.text.style.BackgroundColorSpan;
     32 import android.text.style.CharacterStyle;
     33 import android.text.style.ForegroundColorSpan;
     34 import android.text.style.UnderlineSpan;
     35 import android.util.Log;
     36 import android.view.KeyEvent;
     37 import android.view.inputmethod.EditorInfo;
     38 import android.view.inputmethod.InputConnection;
     39 import android.view.MotionEvent;
     40 import android.view.View;
     41 import android.view.KeyCharacterMap;
     42 import android.text.method.MetaKeyKeyListener;
     43 
     44 import jp.co.omronsoft.openwnn.BaseInputView;
     45 import jp.co.omronsoft.openwnn.OpenWnnControlPanelJAJP;
     46 
     47 import java.util.HashMap;
     48 import java.util.regex.Pattern;
     49 import java.util.regex.Matcher;
     50 
     51 /**
     52  * The OpenWnn Japanese IME class
     53  *
     54  * @author Copyright (C) 2009-2011 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
     55  */
     56 public class OpenWnnJAJP extends OpenWnn {
     57     /**
     58      * Mode of the convert engine (Full-width KATAKANA).
     59      * Use with {@code OpenWnn.CHANGE_MODE} event.
     60      */
     61     public static final int ENGINE_MODE_FULL_KATAKANA = 101;
     62 
     63     /**
     64      * Mode of the convert engine (Half-width KATAKANA).
     65      * Use with {@code OpenWnn.CHANGE_MODE} event.
     66      */
     67     public static final int ENGINE_MODE_HALF_KATAKANA = 102;
     68 
     69     /**
     70      * Mode of the convert engine (EISU-KANA conversion).
     71      * Use with {@code OpenWnn.CHANGE_MODE} event.
     72      */
     73     public static final int ENGINE_MODE_EISU_KANA = 103;
     74 
     75     /**
     76      * Mode of the convert engine (Symbol list).
     77      * Use with {@code OpenWnn.CHANGE_MODE} event.
     78      */
     79     public static final int ENGINE_MODE_SYMBOL_NONE     = 1040;
     80     public static final int ENGINE_MODE_SYMBOL          = 1041;
     81     public static final int ENGINE_MODE_SYMBOL_KAO_MOJI = 1042;
     82 
     83     /**
     84      * Mode of the convert engine (Keyboard type is QWERTY).
     85      * Use with {@code OpenWnn.CHANGE_MODE} event to change ambiguous searching pattern.
     86      */
     87     public static final int ENGINE_MODE_OPT_TYPE_QWERTY = 105;
     88 
     89     /**
     90      * Mode of the convert engine (Keyboard type is 12-keys).
     91      * Use with {@code OpenWnn.CHANGE_MODE} event to change ambiguous searching pattern.
     92      */
     93     public static final int ENGINE_MODE_OPT_TYPE_12KEY = 106;
     94 
     95     /** Never move cursor in to the composing text (adapting to IMF's specification change) */
     96     private static final boolean FIX_CURSOR_TEXT_END = true;
     97 
     98     /** Highlight color style for the converted clause */
     99     private static final CharacterStyle SPAN_CONVERT_BGCOLOR_HL   = new BackgroundColorSpan(0xFF8888FF);
    100     /** Highlight color style for the selected string  */
    101     private static final CharacterStyle SPAN_EXACT_BGCOLOR_HL     = new BackgroundColorSpan(0xFF66CDAA);
    102     /** Highlight color style for EISU-KANA conversion */
    103     private static final CharacterStyle SPAN_EISUKANA_BGCOLOR_HL  = new BackgroundColorSpan(0xFF9FB6CD);
    104     /** Highlight color style for the composing text */
    105     private static final CharacterStyle SPAN_REMAIN_BGCOLOR_HL    = new BackgroundColorSpan(0xFFF0FFFF);
    106     /** Highlight text color */
    107     private static final CharacterStyle SPAN_TEXTCOLOR  = new ForegroundColorSpan(0xFF000000);
    108     /** Underline style for the composing text */
    109     private static final CharacterStyle SPAN_UNDERLINE            = new UnderlineSpan();
    110 
    111     /** IME's status for {@code mStatus} input/no candidates). */
    112     private static final int STATUS_INIT            = 0x0000;
    113     /** IME's status for {@code mStatus}(input characters). */
    114     private static final int STATUS_INPUT           = 0x0001;
    115     /** IME's status for {@code mStatus}(input functional keys). */
    116     private static final int STATUS_INPUT_EDIT      = 0x0003;
    117     /** IME's status for {@code mStatus}(all candidates are displayed). */
    118     private static final int STATUS_CANDIDATE_FULL  = 0x0010;
    119 
    120     /** Alphabet-last pattern */
    121     private static final Pattern ENGLISH_CHARACTER_LAST = Pattern.compile(".*[a-zA-Z]$");
    122 
    123     /**
    124      *  Private area character code got by {@link KeyEvent#getUnicodeChar()}.
    125      *   (SHIFT+ALT+X G1 specific)
    126      */
    127     private static final int PRIVATE_AREA_CODE = 61184;
    128 
    129     /** Maximum length of input string */
    130     private static final int LIMIT_INPUT_NUMBER = 30;
    131 
    132     /** Bit flag for English auto commit mode (ON) */
    133     private static final int AUTO_COMMIT_ENGLISH_ON      = 0x0000;
    134     /** Bit flag for English auto commit mode (OFF) */
    135     private static final int AUTO_COMMIT_ENGLISH_OFF     = 0x0001;
    136     /** Bit flag for English auto commit mode (symbol list) */
    137     private static final int AUTO_COMMIT_ENGLISH_SYMBOL  = 0x0010;
    138 
    139     /** Message for {@code mHandler} (execute prediction) */
    140     private static final int MSG_PREDICTION = 0;
    141 
    142     /** Message for {@code mHandler} (execute tutorial) */
    143     private static final int MSG_START_TUTORIAL = 1;
    144 
    145     /** Message for {@code mHandler} (close) */
    146     private static final int MSG_CLOSE = 2;
    147 
    148     /** Delay time(msec.) to start prediction after key input when the candidates view is not shown. */
    149     private static final int PREDICTION_DELAY_MS_1ST = 200;
    150 
    151     /** Delay time(msec.) to start prediction after key input when the candidates view is shown. */
    152     private static final int PREDICTION_DELAY_MS_SHOWING_CANDIDATE = 200;
    153 
    154     /** H/W 12Keyboard keycode replace table */
    155     private static final HashMap<Integer, Integer> HW12KEYBOARD_KEYCODE_REPLACE_TABLE
    156             = new HashMap<Integer, Integer>() {{
    157           put(KeyEvent.KEYCODE_0, DefaultSoftKeyboard.KEYCODE_JP12_0);
    158           put(KeyEvent.KEYCODE_1, DefaultSoftKeyboard.KEYCODE_JP12_1);
    159           put(KeyEvent.KEYCODE_2, DefaultSoftKeyboard.KEYCODE_JP12_2);
    160           put(KeyEvent.KEYCODE_3, DefaultSoftKeyboard.KEYCODE_JP12_3);
    161           put(KeyEvent.KEYCODE_4, DefaultSoftKeyboard.KEYCODE_JP12_4);
    162           put(KeyEvent.KEYCODE_5, DefaultSoftKeyboard.KEYCODE_JP12_5);
    163           put(KeyEvent.KEYCODE_6, DefaultSoftKeyboard.KEYCODE_JP12_6);
    164           put(KeyEvent.KEYCODE_7, DefaultSoftKeyboard.KEYCODE_JP12_7);
    165           put(KeyEvent.KEYCODE_8, DefaultSoftKeyboard.KEYCODE_JP12_8);
    166           put(KeyEvent.KEYCODE_9, DefaultSoftKeyboard.KEYCODE_JP12_9);
    167           put(KeyEvent.KEYCODE_POUND, DefaultSoftKeyboard.KEYCODE_JP12_SHARP);
    168           put(KeyEvent.KEYCODE_STAR, DefaultSoftKeyboard.KEYCODE_JP12_ASTER);
    169           put(KeyEvent.KEYCODE_CALL, DefaultSoftKeyboard.KEYCODE_JP12_REVERSE);
    170     }};
    171 
    172 
    173     /** Convert engine's state */
    174     private class EngineState {
    175         /** Definition for {@code EngineState.*} (invalid) */
    176         public static final int INVALID = -1;
    177 
    178         /** Definition for {@code EngineState.dictionarySet} (Japanese) */
    179         public static final int DICTIONARYSET_JP = 0;
    180 
    181         /** Definition for {@code EngineState.dictionarySet} (English) */
    182         public static final int DICTIONARYSET_EN = 1;
    183 
    184         /** Definition for {@code EngineState.convertType} (prediction/no conversion) */
    185         public static final int CONVERT_TYPE_NONE = 0;
    186 
    187         /** Definition for {@code EngineState.convertType} (consecutive clause conversion) */
    188         public static final int CONVERT_TYPE_RENBUN = 1;
    189 
    190         /** Definition for {@code EngineState.convertType} (EISU-KANA conversion) */
    191         public static final int CONVERT_TYPE_EISU_KANA = 2;
    192 
    193         /** Definition for {@code EngineState.temporaryMode} (change back to the normal dictionary) */
    194         public static final int TEMPORARY_DICTIONARY_MODE_NONE = 0;
    195 
    196         /** Definition for {@code EngineState.temporaryMode} (change to the symbol dictionary) */
    197         public static final int TEMPORARY_DICTIONARY_MODE_SYMBOL = 1;
    198 
    199         /** Definition for {@code EngineState.temporaryMode} (change to the user dictionary) */
    200         public static final int TEMPORARY_DICTIONARY_MODE_USER = 2;
    201 
    202         /** Definition for {@code EngineState.preferenceDictionary} (no preference dictionary) */
    203         public static final int PREFERENCE_DICTIONARY_NONE = 0;
    204 
    205         /** Definition for {@code EngineState.preferenceDictionary} (person's name) */
    206         public static final int PREFERENCE_DICTIONARY_PERSON_NAME = 1;
    207 
    208         /** Definition for {@code EngineState.preferenceDictionary} (place name) */
    209         public static final int PREFERENCE_DICTIONARY_POSTAL_ADDRESS = 2;
    210 
    211         /** Definition for {@code EngineState.preferenceDictionary} (email/URI) */
    212         public static final int PREFERENCE_DICTIONARY_EMAIL_ADDRESS_URI = 3;
    213 
    214         /** Definition for {@code EngineState.keyboard} (undefined) */
    215         public static final int KEYBOARD_UNDEF = 0;
    216 
    217         /** Definition for {@code EngineState.keyboard} (QWERTY) */
    218         public static final int KEYBOARD_QWERTY = 1;
    219 
    220         /** Definition for {@code EngineState.keyboard} (12-keys) */
    221         public static final int KEYBOARD_12KEY  = 2;
    222 
    223         /** Set of dictionaries */
    224         public int dictionarySet = INVALID;
    225 
    226         /** Type of conversion */
    227         public int convertType = INVALID;
    228 
    229         /** Temporary mode */
    230         public int temporaryMode = INVALID;
    231 
    232         /** Preference dictionary setting */
    233         public int preferenceDictionary = INVALID;
    234 
    235         /** keyboard */
    236         public int keyboard = INVALID;
    237 
    238         /**
    239          * Returns whether current type of conversion is consecutive clause(RENBUNSETSU) conversion.
    240          *
    241          * @return {@code true} if current type of conversion is consecutive clause conversion.
    242          */
    243         public boolean isRenbun() {
    244             return convertType == CONVERT_TYPE_RENBUN;
    245         }
    246 
    247         /**
    248          * Returns whether current type of conversion is EISU-KANA conversion.
    249          *
    250          * @return {@code true} if current type of conversion is EISU-KANA conversion.
    251          */
    252         public boolean isEisuKana() {
    253             return convertType == CONVERT_TYPE_EISU_KANA;
    254         }
    255 
    256         /**
    257          * Returns whether current type of conversion is no conversion.
    258          *
    259          * @return {@code true} if no conversion is executed currently.
    260          */
    261         public boolean isConvertState() {
    262             return convertType != CONVERT_TYPE_NONE;
    263         }
    264 
    265         /**
    266          * Check whether or not the mode is "symbol list".
    267          *
    268          * @return {@code true} if the mode is "symbol list".
    269          */
    270         public boolean isSymbolList() {
    271             return temporaryMode == TEMPORARY_DICTIONARY_MODE_SYMBOL;
    272         }
    273 
    274         /**
    275          * Check whether or not the current language is English.
    276          *
    277          * @return {@code true} if the current language is English.
    278          */
    279         public boolean isEnglish() {
    280             return dictionarySet == DICTIONARYSET_EN;
    281         }
    282     }
    283 
    284     /** IME's status */
    285     protected int mStatus = STATUS_INIT;
    286 
    287     /** Whether exact match searching or not */
    288     protected boolean mExactMatchMode = false;
    289 
    290     /** Spannable string builder for displaying the composing text */
    291     protected SpannableStringBuilder mDisplayText;
    292 
    293     /** Instance of this service */
    294     private static OpenWnnJAJP mSelf = null;
    295 
    296     /** Backup for switching the converter */
    297     private WnnEngine mConverterBack;
    298 
    299     /** Backup for switching the pre-converter */
    300     private LetterConverter mPreConverterBack;
    301 
    302     /** OpenWnn conversion engine for Japanese */
    303     private OpenWnnEngineJAJP mConverterJAJP;
    304 
    305     /** OpenWnn conversion engine for English */
    306     private OpenWnnEngineEN mConverterEN;
    307 
    308     /** Conversion engine for listing symbols */
    309     private SymbolList mConverterSymbolEngineBack;
    310 
    311     /** Symbol lists to display when the symbol key is pressed */
    312     private static final String[] SYMBOL_LISTS = {
    313         SymbolList.SYMBOL_JAPANESE, SymbolList.SYMBOL_JAPANESE_FACE
    314     };
    315 
    316     /** Current symbol list */
    317     private int mCurrentSymbol = -1;
    318 
    319     /** Romaji-to-Kana converter (HIRAGANA) */
    320     private Romkan mPreConverterHiragana;
    321 
    322     /** Romaji-to-Kana converter (full-width KATAKANA) */
    323     private RomkanFullKatakana mPreConverterFullKatakana;
    324 
    325     /** Romaji-to-Kana converter (half-width KATAKANA) */
    326     private RomkanHalfKatakana mPreConverterHalfKatakana;
    327 
    328     /** Conversion Engine's state */
    329     private EngineState mEngineState = new EngineState();
    330 
    331     /** Whether learning function is active of not. */
    332     private boolean mEnableLearning = true;
    333 
    334     /** Whether prediction is active or not. */
    335     private boolean mEnablePrediction = true;
    336 
    337     /** Whether using the converter */
    338     private boolean mEnableConverter = true;
    339 
    340     /** Whether displaying the symbol list */
    341     private boolean mEnableSymbolList = true;
    342 
    343     /** Whether non ASCII code is enabled */
    344     private boolean mEnableSymbolListNonHalf = true;
    345 
    346     /** Enable mistyping spell correction or not */
    347     private boolean mEnableSpellCorrection = true;
    348 
    349     /** Auto commit state (in English mode) */
    350     private int mDisableAutoCommitEnglishMask = AUTO_COMMIT_ENGLISH_ON;
    351 
    352     /** Whether removing a space before a separator or not. (in English mode) */
    353     private boolean mEnableAutoDeleteSpace = false;
    354 
    355     /** Whether auto-spacing is enabled or not. */
    356     private boolean mEnableAutoInsertSpace = true;
    357 
    358     /** Whether dismissing the keyboard when the enter key is pressed */
    359     private boolean mEnableAutoHideKeyboard = true;
    360 
    361     /** Number of committed clauses on consecutive clause conversion */
    362     private int mCommitCount = 0;
    363 
    364     /** Target layer of the {@link ComposingText} */
    365     private int mTargetLayer = 1;
    366 
    367     /** Current orientation of the display */
    368     private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
    369 
    370     /** Current normal dictionary set */
    371     private int mPrevDictionarySet = OpenWnnEngineJAJP.DIC_LANG_INIT;
    372 
    373     /** Regular expression pattern for English separators */
    374     private  Pattern mEnglishAutoCommitDelimiter = null;
    375 
    376     /** Cursor position in the composing text */
    377     private int mComposingStartCursor = 0;
    378 
    379     /** Cursor position before committing text */
    380     private int mCommitStartCursor = 0;
    381 
    382     /** Previous committed text */
    383     private StringBuffer mPrevCommitText = null;
    384 
    385     /** Call count of {@code commitText} */
    386     private int mPrevCommitCount = 0;
    387 
    388     /** Shift lock status of the Hardware keyboard */
    389     private int mHardShift;
    390 
    391     /** SHIFT key state (pressing) */
    392     private boolean mShiftPressing;
    393 
    394     /** ALT lock status of the Hardware keyboard */
    395     private int mHardAlt;
    396 
    397     /** ALT key state (pressing) */
    398     private boolean mAltPressing;
    399 
    400     /** Shift lock toggle definition */
    401     private static final int[] mShiftKeyToggle = {0, MetaKeyKeyListener.META_SHIFT_ON, MetaKeyKeyListener.META_CAP_LOCKED};
    402 
    403     /** ALT lock toggle definition */
    404     private static final int[] mAltKeyToggle = {0, MetaKeyKeyListener.META_ALT_ON, MetaKeyKeyListener.META_ALT_LOCKED};
    405 
    406     /** Auto caps mode */
    407     private boolean mAutoCaps = false;
    408 
    409     /** List of words in the user dictionary */
    410     private WnnWord[] mUserDictionaryWords = null;
    411 
    412     /** Tutorial */
    413     private TutorialJAJP mTutorial;
    414 
    415     /** Whether tutorial mode or not */
    416     private boolean mEnableTutorial;
    417 
    418     /** Whether there is a continued predicted candidate */
    419     private boolean mHasContinuedPrediction = false;
    420 
    421     /** Whether text selection has started */
    422     private boolean mHasStartedTextSelection = true;
    423 
    424     /** Whether the H/W 12keyboard is active or not. */
    425     private boolean mEnableHardware12Keyboard = false;
    426 
    427     /** {@code Handler} for drawing candidates/displaying tutorial */
    428     Handler mHandler = new Handler() {
    429             @Override
    430                 public void handleMessage(Message msg) {
    431                 switch (msg.what) {
    432                 case MSG_PREDICTION:
    433                     updatePrediction();
    434                     break;
    435                 case MSG_START_TUTORIAL:
    436                     if (mTutorial == null) {
    437                         if (isInputViewShown()) {
    438                             DefaultSoftKeyboardJAJP inputManager = ((DefaultSoftKeyboardJAJP) mInputViewManager);
    439                             View v = inputManager.getKeyboardView();
    440                             mTutorial = new TutorialJAJP(OpenWnnJAJP.this, v, inputManager);
    441 
    442                             mTutorial.start();
    443                         } else {
    444                             /* Try again soon if the view is not yet showing */
    445                             sendMessageDelayed(obtainMessage(MSG_START_TUTORIAL), 100);
    446                         }
    447                     }
    448                     break;
    449                 case MSG_CLOSE:
    450                     if (mConverterJAJP != null) mConverterJAJP.close();
    451                     if (mConverterEN != null) mConverterEN.close();
    452                     if (mConverterSymbolEngineBack != null) mConverterSymbolEngineBack.close();
    453                     break;
    454                 }
    455             }
    456         };
    457 
    458     /** The candidate filter */
    459     private CandidateFilter mFilter;
    460 
    461     /**
    462      * Constructor
    463      */
    464     public OpenWnnJAJP() {
    465         super();
    466         mSelf = this;
    467         mComposingText = new ComposingText();
    468         mCandidatesViewManager = new TextCandidatesViewManager(-1);
    469         mInputViewManager  = new DefaultSoftKeyboardJAJP();
    470 
    471         if (OpenWnn.getCurrentIme() != null) {
    472             if (mConverter == null || mConverterJAJP == null) {
    473                 mConverter = mConverterJAJP = new OpenWnnEngineJAJP("/data/data/jp.co.omronsoft.openwnn/writableJAJP.dic");
    474             }
    475             if (mConverterEN == null) {
    476                 mConverterEN = new OpenWnnEngineEN("/data/data/jp.co.omronsoft.openwnn/writableEN.dic");
    477             }
    478         }
    479 
    480         mPreConverter = mPreConverterHiragana = new Romkan();
    481         mPreConverterFullKatakana = new RomkanFullKatakana();
    482         mPreConverterHalfKatakana = new RomkanHalfKatakana();
    483         mFilter = new CandidateFilter();
    484 
    485         mDisplayText = new SpannableStringBuilder();
    486         mAutoHideMode = false;
    487 
    488         mPrevCommitText = new StringBuffer();
    489     }
    490 
    491     /**
    492      * Constructor
    493      *
    494      * @param context       The context
    495      */
    496     public OpenWnnJAJP(Context context) {
    497         this();
    498         attachBaseContext(context);
    499     }
    500 
    501     /** @see jp.co.omronsoft.openwnn.OpenWnn#onCreate */
    502     @Override public void onCreate() {
    503         updateXLargeMode();
    504         super.onCreate();
    505 
    506         if (mConverter == null || mConverterJAJP == null) {
    507             mConverter = mConverterJAJP = new OpenWnnEngineJAJP("/data/data/jp.co.omronsoft.openwnn/writableJAJP.dic");
    508         }
    509         if (mConverterEN == null) {
    510             mConverterEN = new OpenWnnEngineEN("/data/data/jp.co.omronsoft.openwnn/writableEN.dic");
    511         }
    512 
    513         String delimiter = Pattern.quote(getResources().getString(R.string.en_word_separators));
    514         mEnglishAutoCommitDelimiter = Pattern.compile(".*[" + delimiter + "]$");
    515         if (mConverterSymbolEngineBack == null) {
    516             mConverterSymbolEngineBack = new SymbolList(this, SymbolList.LANG_JA);
    517         }
    518     }
    519 
    520     /** @see jp.co.omronsoft.openwnn.OpenWnn#onCreateInputView */
    521     @Override public View onCreateInputView() {
    522         int hiddenState = getResources().getConfiguration().hardKeyboardHidden;
    523         boolean hidden = (hiddenState == Configuration.HARDKEYBOARDHIDDEN_YES);
    524         boolean type12Key
    525                 = (getResources().getConfiguration().keyboard == Configuration.KEYBOARD_12KEY);
    526         ((DefaultSoftKeyboardJAJP) mInputViewManager).setHardKeyboardHidden(hidden);
    527         ((DefaultSoftKeyboard) mInputViewManager).setHardware12Keyboard(type12Key);
    528         mTextCandidatesViewManager.setHardKeyboardHidden(hidden);
    529         mEnableTutorial = hidden;
    530         mEnableHardware12Keyboard = type12Key;
    531         return super.onCreateInputView();
    532     }
    533 
    534     /** @see jp.co.omronsoft.openwnn.OpenWnn#onStartInputView */
    535     @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
    536 
    537         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
    538         if (restarting) {
    539             super.onStartInputView(attribute, restarting);
    540         } else {
    541             EngineState state = new EngineState();
    542             state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
    543             updateEngineState(state);
    544 
    545             mPrevCommitCount = 0;
    546             clearCommitInfo();
    547 
    548             ((DefaultSoftKeyboard) mInputViewManager).resetCurrentKeyboard();
    549 
    550             super.onStartInputView(attribute, restarting);
    551 
    552             if (OpenWnn.isXLarge()) {
    553                 mTextCandidatesViewManager.setPreferences(pref);
    554             }
    555 
    556             mCandidatesViewManager.clearCandidates();
    557             mStatus = STATUS_INIT;
    558             mExactMatchMode = false;
    559 
    560             /* hardware keyboard support */
    561             mHardShift = 0;
    562             mHardAlt   = 0;
    563             updateMetaKeyStateDisplay();
    564         }
    565 
    566         /* initialize the engine's state */
    567         fitInputType(pref, attribute);
    568 
    569         if (OpenWnn.isXLarge()) {
    570             mTextCandidates1LineViewManager.setAutoHide(true);
    571         } else {
    572             ((TextCandidatesViewManager)mCandidatesViewManager).setAutoHide(true);
    573         }
    574 
    575         if (isEnableL2Converter()) {
    576             breakSequence();
    577         }
    578     }
    579 
    580     /** @see jp.co.omronsoft.openwnn.OpenWnn#hideWindow */
    581     @Override public void hideWindow() {
    582         mCandidatesViewManager.setCandidateMsgRemove();
    583 
    584         BaseInputView baseInputView = ((BaseInputView)((DefaultSoftKeyboard) mInputViewManager).getCurrentView());
    585         if (baseInputView != null) {
    586             baseInputView.closeDialog();
    587         }
    588         mComposingText.clear();
    589         mInputViewManager.onUpdateState(this);
    590         clearCommitInfo();
    591         mHandler.removeMessages(MSG_START_TUTORIAL);
    592         mInputViewManager.closing();
    593         if (mTutorial != null) {
    594             mTutorial.close();
    595             mTutorial = null;
    596         }
    597 
    598         if (OpenWnn.isXLarge()) {
    599             mTextCandidates1LineViewManager.closeDialog();
    600         } else {
    601             mTextCandidatesViewManager.closeDialog();
    602         }
    603 
    604         super.hideWindow();
    605     }
    606 
    607     /** @see jp.co.omronsoft.openwnn.OpenWnn#onUpdateSelection */
    608     @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd, int newSelStart, int newSelEnd, int candidatesStart, int candidatesEnd) {
    609 
    610         mComposingStartCursor = (candidatesStart < 0) ? newSelEnd : candidatesStart;
    611 
    612         boolean prevSelection = mHasStartedTextSelection;
    613         if (newSelStart != newSelEnd) {
    614             clearCommitInfo();
    615             mHasStartedTextSelection = true;
    616         } else {
    617             mHasStartedTextSelection = false;
    618         }
    619 
    620         if (mHasContinuedPrediction) {
    621             mHasContinuedPrediction = false;
    622             if (0 < mPrevCommitCount) {
    623                 mPrevCommitCount--;
    624             }
    625             return;
    626         }
    627 
    628         if (mEngineState.isSymbolList()) {
    629             return;
    630         }
    631 
    632         boolean isNotComposing = ((candidatesStart < 0) && (candidatesEnd < 0));
    633         if ((mComposingText.size(ComposingText.LAYER1) != 0)
    634             && !isNotComposing) {
    635             updateViewStatus(mTargetLayer, false, true);
    636         } else {
    637             if (0 < mPrevCommitCount) {
    638                 mPrevCommitCount--;
    639             } else {
    640                 int commitEnd = mCommitStartCursor + mPrevCommitText.length();
    641                 if ((((newSelEnd < oldSelEnd) || (commitEnd < newSelEnd)) && clearCommitInfo())
    642                     || isNotComposing) {
    643                     if (isEnableL2Converter()) {
    644                         breakSequence();
    645                     }
    646 
    647                     if (mInputConnection != null) {
    648                         if (isNotComposing && (mComposingText.size(ComposingText.LAYER1) != 0)) {
    649                             mInputConnection.finishComposingText();
    650                         }
    651                     }
    652                     if ((prevSelection != mHasStartedTextSelection) || !mHasStartedTextSelection) {
    653                         initializeScreen();
    654                     }
    655                 }
    656             }
    657         }
    658     }
    659 
    660     /** @see jp.co.omronsoft.openwnn.OpenWnn#onConfigurationChanged */
    661     @Override public void onConfigurationChanged(Configuration newConfig) {
    662         try {
    663             super.onConfigurationChanged(newConfig);
    664 
    665             if (mInputConnection != null) {
    666                 if (super.isInputViewShown()) {
    667                     updateViewStatus(mTargetLayer, true, true);
    668                 }
    669 
    670                 /* display orientation */
    671                 if (mOrientation != newConfig.orientation) {
    672                     mOrientation = newConfig.orientation;
    673                     commitConvertingText();
    674                     initializeScreen();
    675                 }
    676 
    677                 /* Hardware keyboard */
    678                 int hiddenState = newConfig.hardKeyboardHidden;
    679                 boolean hidden = (hiddenState == Configuration.HARDKEYBOARDHIDDEN_YES);
    680                 boolean type12Key = (newConfig.keyboard == Configuration.KEYBOARD_12KEY);
    681                 ((DefaultSoftKeyboardJAJP) mInputViewManager).setHardKeyboardHidden(hidden);
    682                 ((DefaultSoftKeyboard) mInputViewManager).setHardware12Keyboard(type12Key);
    683                 mTextCandidatesViewManager.setHardKeyboardHidden(hidden);
    684                 mEnableTutorial = hidden;
    685                 mEnableHardware12Keyboard = type12Key;
    686             }
    687         } catch (Exception ex) {
    688             /* do nothing if an error occurs. */
    689         }
    690     }
    691 
    692     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvent */
    693     @Override synchronized public boolean onEvent(OpenWnnEvent ev) {
    694 
    695         EngineState state;
    696 
    697         /* handling events which are valid when InputConnection is not active. */
    698         switch (ev.code) {
    699 
    700         case OpenWnnEvent.KEYUP:
    701             onKeyUpEvent(ev.keyEvent);
    702             return true;
    703 
    704         case OpenWnnEvent.KEYLONGPRESS:
    705             return onKeyLongPressEvent(ev.keyEvent);
    706 
    707         case OpenWnnEvent.INITIALIZE_LEARNING_DICTIONARY:
    708             mConverterEN.initializeDictionary(WnnEngine.DICTIONARY_TYPE_LEARN);
    709             mConverterJAJP.initializeDictionary(WnnEngine.DICTIONARY_TYPE_LEARN);
    710             return true;
    711 
    712         case OpenWnnEvent.INITIALIZE_USER_DICTIONARY:
    713             return mConverterJAJP.initializeDictionary( WnnEngine.DICTIONARY_TYPE_USER );
    714 
    715         case OpenWnnEvent.LIST_WORDS_IN_USER_DICTIONARY:
    716             mUserDictionaryWords = mConverterJAJP.getUserDictionaryWords( );
    717             return true;
    718 
    719         case OpenWnnEvent.GET_WORD:
    720             if (mUserDictionaryWords != null) {
    721                 ev.word = mUserDictionaryWords[0];
    722                 for (int i = 0 ; i < mUserDictionaryWords.length - 1 ; i++) {
    723                     mUserDictionaryWords[i] = mUserDictionaryWords[i + 1];
    724                 }
    725                 mUserDictionaryWords[mUserDictionaryWords.length - 1] = null;
    726                 if (mUserDictionaryWords[0] == null) {
    727                     mUserDictionaryWords = null;
    728                 }
    729                 return true;
    730             }
    731             break;
    732 
    733         case OpenWnnEvent.ADD_WORD:
    734             mConverterJAJP.addWord(ev.word);
    735             return true;
    736 
    737         case OpenWnnEvent.DELETE_WORD:
    738             mConverterJAJP.deleteWord(ev.word);
    739             return true;
    740 
    741         case OpenWnnEvent.CHANGE_MODE:
    742             changeEngineMode(ev.mode);
    743             if (!(ev.mode == ENGINE_MODE_SYMBOL || ev.mode == ENGINE_MODE_EISU_KANA)) {
    744                 initializeScreen();
    745             }
    746             return true;
    747 
    748         case OpenWnnEvent.UPDATE_CANDIDATE:
    749             if (mEngineState.isRenbun()) {
    750                 mComposingText.setCursor(ComposingText.LAYER1,
    751                                          mComposingText.toString(ComposingText.LAYER1).length());
    752                 mExactMatchMode = false;
    753                 updateViewStatusForPrediction(true, true);
    754             } else {
    755                 updateViewStatus(mTargetLayer, true, true);
    756             }
    757             return true;
    758 
    759         case OpenWnnEvent.CHANGE_INPUT_VIEW:
    760             setInputView(onCreateInputView());
    761             return true;
    762 
    763         case OpenWnnEvent.CANDIDATE_VIEW_TOUCH:
    764             boolean ret;
    765             ret = ((TextCandidatesViewManager)mCandidatesViewManager).onTouchSync();
    766             return ret;
    767 
    768         case OpenWnnEvent.TOUCH_OTHER_KEY:
    769             mStatus |= STATUS_INPUT_EDIT;
    770             return true;
    771 
    772         case OpenWnnEvent.CANDIDATE_VIEW_SCROLL_UP:
    773             if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
    774                 ((TextCandidatesViewManager) mCandidatesViewManager).setScrollUp();
    775             }
    776             return true;
    777 
    778         case OpenWnnEvent.CANDIDATE_VIEW_SCROLL_DOWN:
    779             if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
    780                 ((TextCandidatesViewManager) mCandidatesViewManager).setScrollDown();
    781             }
    782             return true;
    783 
    784         case OpenWnnEvent.CANDIDATE_VIEW_SCROLL_FULL_UP:
    785             if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
    786                 ((TextCandidatesViewManager) mCandidatesViewManager).setScrollFullUp();
    787             }
    788             return true;
    789 
    790         case OpenWnnEvent.CANDIDATE_VIEW_SCROLL_FULL_DOWN:
    791             if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
    792                 ((TextCandidatesViewManager) mCandidatesViewManager).setScrollFullDown();
    793             }
    794             return true;
    795 
    796         case OpenWnnEvent.FOCUS_CANDIDATE_START:
    797             return true;
    798 
    799         case OpenWnnEvent.FOCUS_CANDIDATE_END:
    800             mInputViewManager.onUpdateState(this);
    801             return true;
    802 
    803         default:
    804             break;
    805         }
    806 
    807         KeyEvent keyEvent = ev.keyEvent;
    808         int keyCode = 0;
    809         if (keyEvent != null) {
    810             keyCode = keyEvent.getKeyCode();
    811         }
    812 
    813         if (mDirectInputMode) {
    814             if (mInputConnection != null) {
    815                 switch (ev.code) {
    816                 case OpenWnnEvent.INPUT_SOFT_KEY:
    817                     if (keyCode == KeyEvent.KEYCODE_ENTER) {
    818                         sendKeyChar('\n');
    819                     } else {
    820                         mInputConnection.sendKeyEvent(keyEvent);
    821                         mInputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP,
    822                                                                    keyEvent.getKeyCode()));
    823                     }
    824                     break;
    825                 case OpenWnnEvent.INPUT_CHAR:
    826                     sendKeyChar(ev.chars[0]);
    827                     break;
    828                 default:
    829                     break;
    830                 }
    831             }
    832 
    833             /* return if InputConnection is not active */
    834             return false;
    835         }
    836 
    837         if (mEngineState.isSymbolList()) {
    838             if (keyEvent != null && keyEvent.isPrintingKey() && isTenKeyCode(keyCode) && !keyEvent.isNumLockOn()) {
    839                 return false;
    840             }
    841             switch (keyCode) {
    842             case KeyEvent.KEYCODE_DEL:
    843                 return false;
    844 
    845             case KeyEvent.KEYCODE_BACK:
    846                 initializeScreen();
    847                 return true;
    848 
    849             case KeyEvent.KEYCODE_DPAD_CENTER:
    850             case KeyEvent.KEYCODE_ENTER:
    851             case KeyEvent.KEYCODE_NUMPAD_ENTER:
    852                 if (mCandidatesViewManager.isFocusCandidate()) {
    853                     mCandidatesViewManager.selectFocusCandidate();
    854                     return true;
    855                 }
    856                 return false;
    857 
    858             case KeyEvent.KEYCODE_DPAD_LEFT:
    859                 if (mCandidatesViewManager.isFocusCandidate()) {
    860                     processLeftKeyEvent();
    861                     return true;
    862                 }
    863                 return false;
    864 
    865             case KeyEvent.KEYCODE_DPAD_RIGHT:
    866                 if (mCandidatesViewManager.isFocusCandidate()) {
    867                     processRightKeyEvent();
    868                     return true;
    869                 }
    870                 return false;
    871 
    872             case KeyEvent.KEYCODE_DPAD_DOWN:
    873                 processDownKeyEvent();
    874                 return true;
    875 
    876             case KeyEvent.KEYCODE_DPAD_UP:
    877                 if (mCandidatesViewManager.isFocusCandidate()) {
    878                     processUpKeyEvent();
    879                     return true;
    880                 }
    881                 return false;
    882 
    883             case KeyEvent.KEYCODE_SPACE:
    884                 if (keyEvent != null) {
    885                     if (keyEvent.isShiftPressed()) {
    886                         onEvent(new OpenWnnEvent(OpenWnnEvent.CANDIDATE_VIEW_SCROLL_UP));
    887                     } else if (keyEvent.isAltPressed()) {
    888                         if (keyEvent.getRepeatCount() == 0) {
    889                             switchSymbolList();
    890                         }
    891                     } else {
    892                         onEvent(new OpenWnnEvent(OpenWnnEvent.CANDIDATE_VIEW_SCROLL_DOWN));
    893                     }
    894                 }
    895                 return true;
    896 
    897             case KeyEvent.KEYCODE_SYM:
    898                 switchSymbolList();
    899                 return true;
    900 
    901             case KeyEvent.KEYCODE_PAGE_UP:
    902                 onEvent(new OpenWnnEvent(OpenWnnEvent.CANDIDATE_VIEW_SCROLL_UP));
    903                 return true;
    904 
    905             case KeyEvent.KEYCODE_PAGE_DOWN:
    906                 onEvent(new OpenWnnEvent(OpenWnnEvent.CANDIDATE_VIEW_SCROLL_DOWN));
    907                 return true;
    908 
    909             case KeyEvent.KEYCODE_PICTSYMBOLS:
    910                 if (keyEvent != null) {
    911                     if (keyEvent.getRepeatCount() == 0) {
    912                         switchSymbolList();
    913                     }
    914                 }
    915                 return true;
    916 
    917             default:
    918             }
    919 
    920             if ((ev.code == OpenWnnEvent.INPUT_KEY) &&
    921                 (keyCode != KeyEvent.KEYCODE_SEARCH) &&
    922                 (keyCode != KeyEvent.KEYCODE_ALT_LEFT) &&
    923                 (keyCode != KeyEvent.KEYCODE_ALT_RIGHT) &&
    924                 (keyCode != KeyEvent.KEYCODE_SHIFT_LEFT) &&
    925                 (keyCode != KeyEvent.KEYCODE_SHIFT_RIGHT)) {
    926                 state = new EngineState();
    927                 state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
    928                 updateEngineState(state);
    929             }
    930         }
    931 
    932         if (!((ev.code == OpenWnnEvent.COMMIT_COMPOSING_TEXT)
    933               || ((keyEvent != null)
    934                   && ((keyCode == KeyEvent.KEYCODE_SHIFT_LEFT)
    935                       || (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)
    936                       || (keyCode == KeyEvent.KEYCODE_ALT_LEFT)
    937                       || (keyCode == KeyEvent.KEYCODE_ALT_RIGHT)
    938                       || (keyEvent.isAltPressed() && (keyCode == KeyEvent.KEYCODE_SPACE)))))) {
    939 
    940             clearCommitInfo();
    941         }
    942 
    943         /* change back the dictionary if necessary */
    944         if (!((ev.code == OpenWnnEvent.SELECT_CANDIDATE)
    945               || (ev.code == OpenWnnEvent.LIST_CANDIDATES_NORMAL)
    946               || (ev.code == OpenWnnEvent.LIST_CANDIDATES_FULL)
    947               || ((keyEvent != null)
    948                   && ((keyCode == KeyEvent.KEYCODE_SHIFT_LEFT)
    949                       ||(keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT)
    950                       ||(keyCode == KeyEvent.KEYCODE_ALT_LEFT)
    951                       ||(keyCode == KeyEvent.KEYCODE_ALT_RIGHT)
    952                       ||(keyCode == KeyEvent.KEYCODE_BACK && mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL)
    953                       ||(keyEvent.isAltPressed() && (keyCode == KeyEvent.KEYCODE_SPACE)))))) {
    954 
    955             state = new EngineState();
    956             state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
    957             updateEngineState(state);
    958         }
    959 
    960         if ((ev.code == OpenWnnEvent.INPUT_KEY) && processHardware12Keyboard(keyEvent)) {
    961             return true;
    962         }
    963 
    964         if (ev.code == OpenWnnEvent.LIST_CANDIDATES_FULL) {
    965             mStatus |= STATUS_CANDIDATE_FULL;
    966             mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_FULL);
    967             if (!mEngineState.isSymbolList()) {
    968                 mInputViewManager.hideInputView();
    969             }
    970             return true;
    971         } else if (ev.code == OpenWnnEvent.LIST_CANDIDATES_NORMAL) {
    972             mStatus &= ~STATUS_CANDIDATE_FULL;
    973             mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
    974             mInputViewManager.showInputView();
    975             return true;
    976         }
    977 
    978         boolean ret = false;
    979         switch (ev.code) {
    980         case OpenWnnEvent.INPUT_CHAR:
    981             if ((mPreConverter == null) && !isEnableL2Converter()) {
    982                 /* direct input (= full-width alphabet/number input) */
    983                 commitText(false);
    984                 commitText(new String(ev.chars));
    985                 mCandidatesViewManager.clearCandidates();
    986             } else if (!isEnableL2Converter()) {
    987                 processSoftKeyboardCodeWithoutConversion(ev.chars);
    988             } else {
    989                 processSoftKeyboardCode(ev.chars);
    990             }
    991             ret = true;
    992             break;
    993 
    994         case OpenWnnEvent.TOGGLE_CHAR:
    995             processSoftKeyboardToggleChar(ev.toggleTable);
    996             ret = true;
    997             break;
    998 
    999         case OpenWnnEvent.TOGGLE_REVERSE_CHAR:
   1000             if (((mStatus & ~STATUS_CANDIDATE_FULL) == STATUS_INPUT)
   1001                 && !(mEngineState.isConvertState()) && (ev.toggleTable != null)) {
   1002 
   1003                 int cursor = mComposingText.getCursor(ComposingText.LAYER1);
   1004                 if (cursor > 0) {
   1005                     String prevChar = mComposingText.getStrSegment(ComposingText.LAYER1, cursor - 1).string;
   1006                     String c = searchToggleCharacter(prevChar, ev.toggleTable, true);
   1007                     if (c != null) {
   1008                         mComposingText.delete(ComposingText.LAYER1, false);
   1009                         appendStrSegment(new StrSegment(c));
   1010                         updateViewStatusForPrediction(true, true);
   1011                         ret = true;
   1012                         break;
   1013                     }
   1014                 }
   1015             }
   1016             break;
   1017 
   1018         case OpenWnnEvent.REPLACE_CHAR:
   1019             int cursor = mComposingText.getCursor(ComposingText.LAYER1);
   1020             if ((cursor > 0)
   1021                 && !(mEngineState.isConvertState())) {
   1022 
   1023                 String search = mComposingText.getStrSegment(ComposingText.LAYER1, cursor - 1).string;
   1024                 String c = (String)ev.replaceTable.get(search);
   1025                 if (c != null) {
   1026                     mComposingText.delete(1, false);
   1027                     appendStrSegment(new StrSegment(c));
   1028                     updateViewStatusForPrediction(true, true);
   1029                     ret = true;
   1030                     mStatus = STATUS_INPUT_EDIT;
   1031                     break;
   1032                 }
   1033             }
   1034             break;
   1035 
   1036         case OpenWnnEvent.INPUT_KEY:
   1037             /* update shift/alt state */
   1038             switch (keyCode) {
   1039             case KeyEvent.KEYCODE_DPAD_DOWN:
   1040             case KeyEvent.KEYCODE_DPAD_LEFT:
   1041             case KeyEvent.KEYCODE_DPAD_RIGHT:
   1042             case KeyEvent.KEYCODE_DPAD_UP:
   1043                 if (mTutorial != null) {
   1044                     return true;
   1045                 }
   1046                 break;
   1047 
   1048             case KeyEvent.KEYCODE_ALT_LEFT:
   1049             case KeyEvent.KEYCODE_ALT_RIGHT:
   1050                 if (keyEvent.getRepeatCount() == 0) {
   1051                     if (++mHardAlt > 2) { mHardAlt = 0; }
   1052                 }
   1053                 mAltPressing   = true;
   1054                 updateMetaKeyStateDisplay();
   1055                 return false;
   1056 
   1057             case KeyEvent.KEYCODE_SHIFT_LEFT:
   1058             case KeyEvent.KEYCODE_SHIFT_RIGHT:
   1059                 if (keyEvent.getRepeatCount() == 0) {
   1060                     if (++mHardShift > 2) { mHardShift = 0; }
   1061                 }
   1062                 mShiftPressing = true;
   1063                 updateMetaKeyStateDisplay();
   1064                 return false;
   1065             }
   1066 
   1067             /* handle other key event */
   1068             ret = processKeyEvent(keyEvent);
   1069             break;
   1070 
   1071         case OpenWnnEvent.INPUT_SOFT_KEY:
   1072             ret = processKeyEvent(keyEvent);
   1073             if (!ret) {
   1074                 int code = keyEvent.getKeyCode();
   1075                 if (code == KeyEvent.KEYCODE_ENTER) {
   1076                     sendKeyChar('\n');
   1077                 } else {
   1078                     mInputConnection.sendKeyEvent(keyEvent);
   1079                     mInputConnection.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, code));
   1080                 }
   1081                 ret = true;
   1082             }
   1083             break;
   1084 
   1085         case OpenWnnEvent.SELECT_CANDIDATE:
   1086             initCommitInfoForWatchCursor();
   1087             if (isEnglishPrediction()) {
   1088                 mComposingText.clear();
   1089             }
   1090             mStatus = commitText(ev.word);
   1091             if (isEnglishPrediction() && !mEngineState.isSymbolList() && mEnableAutoInsertSpace) {
   1092                 commitSpaceJustOne();
   1093             }
   1094             checkCommitInfo();
   1095 
   1096             if (mEngineState.isSymbolList()) {
   1097                 mEnableAutoDeleteSpace = false;
   1098             }
   1099             break;
   1100 
   1101         case OpenWnnEvent.CONVERT:
   1102             if (mEngineState.isRenbun()) {
   1103                 if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
   1104                     if (!mCandidatesViewManager.isFocusCandidate()) {
   1105                         processDownKeyEvent();
   1106                     }
   1107                     processRightKeyEvent();
   1108                 } else {
   1109                     mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
   1110                 }
   1111                 break;
   1112             }
   1113             startConvert(EngineState.CONVERT_TYPE_RENBUN);
   1114             break;
   1115 
   1116         case OpenWnnEvent.COMMIT_COMPOSING_TEXT:
   1117             commitAllText();
   1118             break;
   1119         }
   1120 
   1121         return ret;
   1122     }
   1123 
   1124     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateFullscreenMode */
   1125     @Override public boolean onEvaluateFullscreenMode() {
   1126         /* never use full-screen mode */
   1127         return false;
   1128     }
   1129 
   1130     /** @see jp.co.omronsoft.openwnn.OpenWnn#onEvaluateInputViewShown */
   1131     @Override public boolean onEvaluateInputViewShown() {
   1132         return true;
   1133     }
   1134 
   1135     /**
   1136      * Get the instance of this service.
   1137      * <br>
   1138      * Before using this method, the constructor of this service must be invoked.
   1139      *
   1140      * @return      The instance of this service
   1141      */
   1142     public static OpenWnnJAJP getInstance() {
   1143         return mSelf;
   1144     }
   1145 
   1146     /**
   1147      * Create a {@link StrSegment} from a character code.
   1148      * <br>
   1149      * @param charCode           A character code
   1150      * @return                  {@link StrSegment} created; {@code null} if an error occurs.
   1151      */
   1152     private StrSegment createStrSegment(int charCode) {
   1153         if (charCode == 0) {
   1154             return null;
   1155         }
   1156         return new StrSegment(Character.toChars(charCode));
   1157     }
   1158 
   1159     /**
   1160      * Key event handler.
   1161      *
   1162      * @param ev        A key event
   1163      * @return  {@code true} if the event is handled in this method.
   1164      */
   1165     private boolean processKeyEvent(KeyEvent ev) {
   1166         int key = ev.getKeyCode();
   1167 
   1168         /* keys which produce a glyph */
   1169         if (ev.isPrintingKey()) {
   1170             if (isTenKeyCode(key) && !ev.isNumLockOn()) {
   1171                 return false;
   1172             }
   1173             if (ev.isCtrlPressed()){
   1174                 if (key == KeyEvent.KEYCODE_A || key == KeyEvent.KEYCODE_F || key == KeyEvent.KEYCODE_C ||
   1175                     key == KeyEvent.KEYCODE_V || key == KeyEvent.KEYCODE_X || key == KeyEvent.KEYCODE_Z) {
   1176                     if (mComposingText.size(ComposingText.LAYER1) < 1) {
   1177                         return false;
   1178                     } else {
   1179                         return true;
   1180                     }
   1181                 }
   1182             }
   1183 
   1184             /* do nothing if the character is not able to display or the character is dead key */
   1185             if ((mHardShift > 0 && mHardAlt > 0) ||
   1186                 (ev.isAltPressed() && ev.isShiftPressed())) {
   1187                 int charCode = ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON | MetaKeyKeyListener.META_ALT_ON);
   1188                 if (charCode == 0 || (charCode & KeyCharacterMap.COMBINING_ACCENT) != 0 || charCode == PRIVATE_AREA_CODE) {
   1189                     if(mHardShift == 1){
   1190                         mShiftPressing = false;
   1191                     }
   1192                     if(mHardAlt == 1){
   1193                         mAltPressing   = false;
   1194                     }
   1195                     if(!ev.isAltPressed()){
   1196                         if (mHardAlt == 1) {
   1197                             mHardAlt = 0;
   1198                         }
   1199                     }
   1200                     if(!ev.isShiftPressed()){
   1201                         if (mHardShift == 1) {
   1202                             mHardShift = 0;
   1203                         }
   1204                     }
   1205                     if(!ev.isShiftPressed() && !ev.isAltPressed()){
   1206                         updateMetaKeyStateDisplay();
   1207                     }
   1208                     return true;
   1209                 }
   1210             }
   1211 
   1212             commitConvertingText();
   1213 
   1214             EditorInfo edit = getCurrentInputEditorInfo();
   1215             StrSegment str;
   1216 
   1217             /* get the key character */
   1218             if (mHardShift== 0 && mHardAlt == 0) {
   1219                 /* no meta key is locked */
   1220                 int shift = (mAutoCaps)? getShiftKeyState(edit) : 0;
   1221                 if (shift != mHardShift && (key >= KeyEvent.KEYCODE_A && key <= KeyEvent.KEYCODE_Z)) {
   1222                     /* handling auto caps for a alphabet character */
   1223                     str = createStrSegment(ev.getUnicodeChar(MetaKeyKeyListener.META_SHIFT_ON));
   1224                 } else {
   1225                     str = createStrSegment(ev.getUnicodeChar());
   1226                 }
   1227             } else {
   1228                 str = createStrSegment(ev.getUnicodeChar(mShiftKeyToggle[mHardShift]
   1229                                                          | mAltKeyToggle[mHardAlt]));
   1230                 if(mHardShift == 1){
   1231                     mShiftPressing = false;
   1232                 }
   1233                 if(mHardAlt == 1){
   1234                     mAltPressing   = false;
   1235                 }
   1236                 /* back to 0 (off) if 1 (on/not locked) */
   1237                 if (!ev.isAltPressed()) {
   1238                     if (mHardAlt == 1) {
   1239                         mHardAlt = 0;
   1240                     }
   1241                 }
   1242                 if (!ev.isShiftPressed()) {
   1243                     if (mHardShift == 1) {
   1244                         mHardShift = 0;
   1245                     }
   1246                 }
   1247                 if (!ev.isShiftPressed() && !ev.isShiftPressed()) {
   1248                     updateMetaKeyStateDisplay();
   1249                 }
   1250             }
   1251 
   1252             if (str == null) {
   1253                 return true;
   1254             }
   1255 
   1256             /* append the character to the composing text if the character is not TAB */
   1257             if (str.string.charAt(0) != '\u0009') {
   1258                 processHardwareKeyboardInputChar(str);
   1259                 return true;
   1260             } else {
   1261                 commitText(true);
   1262                 commitText(str.string);
   1263                 initializeScreen();
   1264                 return true;
   1265             }
   1266 
   1267         } else if (key == KeyEvent.KEYCODE_SPACE) {
   1268             /* H/W space key */
   1269             processHardwareKeyboardSpaceKey(ev);
   1270             return true;
   1271 
   1272         } else if (key == KeyEvent.KEYCODE_SYM) {
   1273             /* display the symbol list */
   1274             initCommitInfoForWatchCursor();
   1275             mStatus = commitText(true);
   1276             checkCommitInfo();
   1277             changeEngineMode(ENGINE_MODE_SYMBOL);
   1278             mHardAlt = 0;
   1279             updateMetaKeyStateDisplay();
   1280             return true;
   1281         }
   1282 
   1283         /* Functional key */
   1284         if (mComposingText.size(ComposingText.LAYER1) > 0) {
   1285             switch (key) {
   1286             case KeyEvent.KEYCODE_DEL:
   1287                 mStatus = STATUS_INPUT_EDIT;
   1288                 if (mEngineState.isConvertState()) {
   1289                     mComposingText.setCursor(ComposingText.LAYER1,
   1290                                              mComposingText.toString(ComposingText.LAYER1).length());
   1291                     mExactMatchMode = false;
   1292                 } else {
   1293                     if ((mComposingText.size(ComposingText.LAYER1) == 1)
   1294                         && mComposingText.getCursor(ComposingText.LAYER1) != 0) {
   1295                         initializeScreen();
   1296                         return true;
   1297                     } else {
   1298                         mComposingText.delete(ComposingText.LAYER1, false);
   1299                     }
   1300                 }
   1301                 updateViewStatusForPrediction(true, true);
   1302                 return true;
   1303 
   1304             case KeyEvent.KEYCODE_BACK:
   1305                 if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) {
   1306                     mStatus &= ~STATUS_CANDIDATE_FULL;
   1307                     mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
   1308                     mInputViewManager.showInputView();
   1309                 } else {
   1310                     if (!mEngineState.isConvertState()) {
   1311                         initializeScreen();
   1312                         if (mConverter != null) {
   1313                             mConverter.init();
   1314                         }
   1315                     } else {
   1316                         mCandidatesViewManager.clearCandidates();
   1317                         mStatus = STATUS_INPUT_EDIT;
   1318                         mExactMatchMode = false;
   1319                         mComposingText.setCursor(ComposingText.LAYER1,
   1320                                                  mComposingText.toString(ComposingText.LAYER1).length());
   1321                         updateViewStatusForPrediction(true, true);
   1322                     }
   1323                 }
   1324                 return true;
   1325 
   1326             case KeyEvent.KEYCODE_DPAD_LEFT:
   1327                 if (!isEnableL2Converter()) {
   1328                     commitText(false);
   1329                     return false;
   1330                 } else {
   1331                     processLeftKeyEvent();
   1332                     return true;
   1333                 }
   1334 
   1335             case KeyEvent.KEYCODE_DPAD_RIGHT:
   1336                 if (!isEnableL2Converter()) {
   1337                     if (mEngineState.keyboard == EngineState.KEYBOARD_12KEY) {
   1338                         commitText(false);
   1339                     }
   1340                 } else {
   1341                     processRightKeyEvent();
   1342                 }
   1343                 return true;
   1344 
   1345             case KeyEvent.KEYCODE_DPAD_DOWN:
   1346                 processDownKeyEvent();
   1347                 return true;
   1348 
   1349             case KeyEvent.KEYCODE_DPAD_UP:
   1350                 if (OpenWnn.isXLarge()) {
   1351                     updateViewStatusForPrediction(true, true);
   1352                 } else {
   1353                     if (mCandidatesViewManager.isFocusCandidate()) {
   1354                         processUpKeyEvent();
   1355                     }
   1356                 }
   1357                 return true;
   1358 
   1359             case KeyEvent.KEYCODE_DPAD_CENTER:
   1360             case KeyEvent.KEYCODE_ENTER:
   1361             case KeyEvent.KEYCODE_NUMPAD_ENTER:
   1362                 if (mCandidatesViewManager.isFocusCandidate()) {
   1363                     mCandidatesViewManager.selectFocusCandidate();
   1364                     return true;
   1365                 }
   1366                 if (!isEnglishPrediction()) {
   1367                     int cursor = mComposingText.getCursor(ComposingText.LAYER1);
   1368                     if (cursor < 1) {
   1369                         return true;
   1370                     }
   1371                 }
   1372                 initCommitInfoForWatchCursor();
   1373                 mStatus = commitText(true);
   1374                 checkCommitInfo();
   1375 
   1376                 if (isEnglishPrediction()) {
   1377                     initializeScreen();
   1378                 }
   1379 
   1380                 if (mEnableAutoHideKeyboard) {
   1381                     mInputViewManager.closing();
   1382                     requestHideSelf(0);
   1383                 }
   1384                 return true;
   1385 
   1386             case KeyEvent.KEYCODE_CALL:
   1387             case KeyEvent.KEYCODE_VOLUME_DOWN:
   1388             case KeyEvent.KEYCODE_VOLUME_UP:
   1389                 return false;
   1390 
   1391             default:
   1392                 return !isThroughKeyCode(key);
   1393             }
   1394         } else {
   1395             /* if there is no composing string. */
   1396             if (mCandidatesViewManager.getCurrentView().isShown()) {
   1397                 /* displaying relational prediction candidates */
   1398                 switch (key) {
   1399                 case KeyEvent.KEYCODE_DPAD_LEFT:
   1400                     if (mCandidatesViewManager.isFocusCandidate()) {
   1401                         mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
   1402                         return true;
   1403                     }
   1404                     if (isEnableL2Converter()) {
   1405                         /* initialize the converter */
   1406                         mConverter.init();
   1407                     }
   1408                     mStatus = STATUS_INPUT_EDIT;
   1409                     updateViewStatusForPrediction(true, true);
   1410                     return false;
   1411 
   1412                 case KeyEvent.KEYCODE_DPAD_RIGHT:
   1413                     if (mCandidatesViewManager.isFocusCandidate()) {
   1414                         mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
   1415                         return true;
   1416                     }
   1417                     if (isEnableL2Converter()) {
   1418                         /* initialize the converter */
   1419                         mConverter.init();
   1420                     }
   1421                     mStatus = STATUS_INPUT_EDIT;
   1422                     updateViewStatusForPrediction(true, true);
   1423                     return false;
   1424 
   1425                 case KeyEvent.KEYCODE_DPAD_DOWN:
   1426                     processDownKeyEvent();
   1427                     return true;
   1428 
   1429                 case KeyEvent.KEYCODE_DPAD_UP:
   1430                     if (mCandidatesViewManager.isFocusCandidate()) {
   1431                         processUpKeyEvent();
   1432                         return true;
   1433                     }
   1434                     break;
   1435 
   1436                 case KeyEvent.KEYCODE_DPAD_CENTER:
   1437                 case KeyEvent.KEYCODE_ENTER:
   1438                 case KeyEvent.KEYCODE_NUMPAD_ENTER:
   1439                     if (mCandidatesViewManager.isFocusCandidate()) {
   1440                         mCandidatesViewManager.selectFocusCandidate();
   1441                         return true;
   1442                     }
   1443                     break;
   1444 
   1445                 default:
   1446                     return processKeyEventNoInputCandidateShown(ev);
   1447                 }
   1448             } else {
   1449                 switch (key) {
   1450                 case KeyEvent.KEYCODE_BACK:
   1451                     /*
   1452                      * If 'BACK' key is pressed when the SW-keyboard is shown
   1453                      * and the candidates view is not shown, dismiss the SW-keyboard.
   1454                      */
   1455                     if (isInputViewShown()) {
   1456                         mInputViewManager.closing();
   1457                         requestHideSelf(0);
   1458                         return true;
   1459                     }
   1460                     break;
   1461                 default:
   1462                     break;
   1463                 }
   1464             }
   1465         }
   1466 
   1467         return false;
   1468     }
   1469 
   1470     /**
   1471      * Handle the space key event from the Hardware keyboard.
   1472      *
   1473      * @param ev  The space key event
   1474      */
   1475     private void processHardwareKeyboardSpaceKey(KeyEvent ev) {
   1476         /* H/W space key */
   1477         if (ev.isShiftPressed()) {
   1478             /* change Japanese <-> English mode */
   1479             mHardAlt = 0;
   1480             mHardShift = 0;
   1481             updateMetaKeyStateDisplay();
   1482 
   1483             SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
   1484             if (mEngineState.isEnglish()) {
   1485                 /* English mode to Japanese mode */
   1486                 ((DefaultSoftKeyboardJAJP) mInputViewManager).changeKeyMode(DefaultSoftKeyboard.KEYMODE_JA_FULL_HIRAGANA);
   1487                 mConverter = mConverterJAJP;
   1488 
   1489                 mEnableLearning   = pref.getBoolean("opt_enable_learning_ja", true);
   1490                 mEnablePrediction = pref.getBoolean("opt_prediction_ja", true);
   1491             } else {
   1492                 /* Japanese mode to English mode */
   1493                 ((DefaultSoftKeyboardJAJP) mInputViewManager).changeKeyMode(DefaultSoftKeyboard.KEYMODE_JA_HALF_ALPHABET);
   1494                 mConverter = mConverterEN;
   1495 
   1496                 mEnableLearning   = pref.getBoolean("opt_enable_learning_en", true);
   1497                 mEnablePrediction = pref.getBoolean("opt_prediction_en", false);
   1498                 if (OpenWnn.isXLarge()) {
   1499                     mEnableSpellCorrection = pref.getBoolean("opt_spell_correction_en", false);
   1500                 } else {
   1501                     mEnableSpellCorrection = pref.getBoolean("opt_spell_correction_en", true);
   1502                 }
   1503             }
   1504             mCandidatesViewManager.clearCandidates();
   1505 
   1506         } else if(ev.isAltPressed()){
   1507             /* display the symbol list (G1 specific. same as KEYCODE_SYM) */
   1508             if (!mEngineState.isSymbolList()) {
   1509                 commitAllText();
   1510             }
   1511             changeEngineMode(ENGINE_MODE_SYMBOL);
   1512             mHardAlt = 0;
   1513             updateMetaKeyStateDisplay();
   1514 
   1515         } else if (isEnglishPrediction()) {
   1516             /* Auto commit if English mode */
   1517             if (mComposingText.size(0) == 0) {
   1518                 commitText(" ");
   1519                 mCandidatesViewManager.clearCandidates();
   1520                 breakSequence();
   1521             } else {
   1522                 initCommitInfoForWatchCursor();
   1523                 commitText(true);
   1524                 commitSpaceJustOne();
   1525                 checkCommitInfo();
   1526             }
   1527             mEnableAutoDeleteSpace = false;
   1528         } else if (mEngineState.isRenbun()) {
   1529             if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
   1530                 if (!mCandidatesViewManager.isFocusCandidate()) {
   1531                     processDownKeyEvent();
   1532                 }
   1533                 processRightKeyEvent();
   1534             } else {
   1535                 mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
   1536             }
   1537         } else {
   1538             /* start consecutive clause conversion if Japanese mode */
   1539             if (mComposingText.size(0) == 0) {
   1540                 commitText(" ");
   1541                 mCandidatesViewManager.clearCandidates();
   1542                 breakSequence();
   1543             } else {
   1544                 startConvert(EngineState.CONVERT_TYPE_RENBUN);
   1545             }
   1546         }
   1547     }
   1548 
   1549     /**
   1550      * Handle the character code from the hardware keyboard except the space key.
   1551      *
   1552      * @param str  The input character
   1553      */
   1554     private void processHardwareKeyboardInputChar(StrSegment str) {
   1555         if (isEnableL2Converter()) {
   1556             boolean commit = false;
   1557             if (mPreConverter == null) {
   1558                 Matcher m = mEnglishAutoCommitDelimiter.matcher(str.string);
   1559                 if (m.matches()) {
   1560                     commitText(true);
   1561 
   1562                     commit = true;
   1563                 }
   1564                 appendStrSegment(str);
   1565             } else {
   1566                 appendStrSegment(str);
   1567                 mPreConverter.convert(mComposingText);
   1568             }
   1569 
   1570             if (commit) {
   1571                 commitText(true);
   1572             } else {
   1573                 mStatus = STATUS_INPUT;
   1574                 updateViewStatusForPrediction(true, true);
   1575             }
   1576         } else {
   1577             appendStrSegment(str);
   1578             boolean completed = true;
   1579             if (mPreConverter != null) {
   1580                 completed = mPreConverter.convert(mComposingText);
   1581             }
   1582 
   1583             if (completed) {
   1584                 if (!mEngineState.isEnglish()) {
   1585                     commitTextWithoutLastAlphabet();
   1586                 } else {
   1587                     commitText(false);
   1588                 }
   1589             } else {
   1590                 updateViewStatus(ComposingText.LAYER1, false, true);
   1591             }
   1592         }
   1593     }
   1594 
   1595     /** Thread for updating the candidates view */
   1596     private void updatePrediction() {
   1597         int candidates = 0;
   1598         int cursor = mComposingText.getCursor(ComposingText.LAYER1);
   1599         if (isEnableL2Converter() || mEngineState.isSymbolList()) {
   1600             if (mExactMatchMode) {
   1601                 /* exact matching */
   1602                 candidates = mConverter.predict(mComposingText, 0, cursor);
   1603             } else {
   1604                 /* normal prediction */
   1605                 candidates = mConverter.predict(mComposingText, 0, -1);
   1606             }
   1607         }
   1608 
   1609         /* update the candidates view */
   1610         if (candidates > 0) {
   1611             mHasContinuedPrediction = ((mComposingText.size(ComposingText.LAYER1) == 0)
   1612                                        && !mEngineState.isSymbolList());
   1613             mCandidatesViewManager.displayCandidates(mConverter);
   1614         } else {
   1615             mCandidatesViewManager.clearCandidates();
   1616         }
   1617     }
   1618 
   1619     /**
   1620      * Handle a left key event.
   1621      */
   1622     private void processLeftKeyEvent() {
   1623         if (mCandidatesViewManager.isFocusCandidate()) {
   1624             mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_LEFT);
   1625             return;
   1626         }
   1627 
   1628         if (mEngineState.isConvertState()) {
   1629             if (mEngineState.isEisuKana()) {
   1630                 mExactMatchMode = true;
   1631             }
   1632 
   1633             if (1 < mComposingText.getCursor(ComposingText.LAYER1)) {
   1634                 mComposingText.moveCursor(ComposingText.LAYER1, -1);
   1635             }
   1636         } else if (mExactMatchMode) {
   1637             mComposingText.moveCursor(ComposingText.LAYER1, -1);
   1638         } else {
   1639             if (isEnglishPrediction()) {
   1640                 mComposingText.moveCursor(ComposingText.LAYER1, -1);
   1641             } else {
   1642                 mExactMatchMode = true;
   1643             }
   1644         }
   1645 
   1646         mCommitCount = 0; /* retry consecutive clause conversion if necessary. */
   1647         mStatus = STATUS_INPUT_EDIT;
   1648         updateViewStatus(mTargetLayer, true, true);
   1649     }
   1650 
   1651     /**
   1652      * Handle a right key event.
   1653      */
   1654     private void processRightKeyEvent() {
   1655         if (mCandidatesViewManager.isFocusCandidate()) {
   1656             mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
   1657             return;
   1658         }
   1659 
   1660         int layer = mTargetLayer;
   1661         ComposingText composingText = mComposingText;
   1662         if (mExactMatchMode || (mEngineState.isConvertState())) {
   1663             int textSize = composingText.size(ComposingText.LAYER1);
   1664             if (composingText.getCursor(ComposingText.LAYER1) == textSize) {
   1665                 mExactMatchMode = false;
   1666                 layer = ComposingText.LAYER1; /* convert -> prediction */
   1667                 EngineState state = new EngineState();
   1668                 state.convertType = EngineState.CONVERT_TYPE_NONE;
   1669                 updateEngineState(state);
   1670             } else {
   1671                 if (mEngineState.isEisuKana()) {
   1672                     mExactMatchMode = true;
   1673                 }
   1674                 composingText.moveCursor(ComposingText.LAYER1, 1);
   1675             }
   1676         } else {
   1677             if (composingText.getCursor(ComposingText.LAYER1)
   1678                     < composingText.size(ComposingText.LAYER1)) {
   1679                 composingText.moveCursor(ComposingText.LAYER1, 1);
   1680             }
   1681         }
   1682 
   1683         mCommitCount = 0; /* retry consecutive clause conversion if necessary. */
   1684         mStatus = STATUS_INPUT_EDIT;
   1685 
   1686         updateViewStatus(layer, true, true);
   1687     }
   1688 
   1689     /**
   1690      * Handle a down key event.
   1691      */
   1692     private void processDownKeyEvent() {
   1693         mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN);
   1694     }
   1695 
   1696     /**
   1697      * Handle a up key event.
   1698      */
   1699     private void processUpKeyEvent() {
   1700         mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_UP);
   1701     }
   1702 
   1703     /**
   1704      * Handle a key event which is not right or left key when the
   1705      * composing text is empty and some candidates are shown.
   1706      *
   1707      * @param ev        A key event
   1708      * @return          {@code true} if this consumes the event; {@code false} if not.
   1709      */
   1710     boolean processKeyEventNoInputCandidateShown(KeyEvent ev) {
   1711         boolean ret = true;
   1712         int key = ev.getKeyCode();
   1713 
   1714         switch (key) {
   1715         case KeyEvent.KEYCODE_DEL:
   1716             ret = true;
   1717             break;
   1718         case KeyEvent.KEYCODE_ENTER:
   1719         case KeyEvent.KEYCODE_NUMPAD_ENTER:
   1720         case KeyEvent.KEYCODE_DPAD_UP:
   1721         case KeyEvent.KEYCODE_DPAD_DOWN:
   1722         case KeyEvent.KEYCODE_MENU:
   1723             ret = false;
   1724             break;
   1725 
   1726         case KeyEvent.KEYCODE_CALL:
   1727         case KeyEvent.KEYCODE_VOLUME_DOWN:
   1728         case KeyEvent.KEYCODE_VOLUME_UP:
   1729             return false;
   1730 
   1731         case KeyEvent.KEYCODE_DPAD_CENTER:
   1732             ret = true;
   1733             break;
   1734 
   1735         case KeyEvent.KEYCODE_BACK:
   1736             if (mCandidatesViewManager.getViewType() == CandidatesViewManager.VIEW_TYPE_FULL) {
   1737                 mStatus &= ~STATUS_CANDIDATE_FULL;
   1738                 mCandidatesViewManager.setViewType(CandidatesViewManager.VIEW_TYPE_NORMAL);
   1739                 mInputViewManager.showInputView();
   1740                 return true;
   1741             } else {
   1742                 ret = true;
   1743             }
   1744             break;
   1745 
   1746         default:
   1747             return !isThroughKeyCode(key);
   1748         }
   1749 
   1750         if (mConverter != null) {
   1751             /* initialize the converter */
   1752             mConverter.init();
   1753         }
   1754         updateViewStatusForPrediction(true, true);
   1755         return ret;
   1756     }
   1757 
   1758     /**
   1759      * Update views and the display of the composing text for predict mode.
   1760      *
   1761      * @param updateCandidates  {@code true} to update the candidates view
   1762      * @param updateEmptyText   {@code false} to update the composing text if it is not empty; {@code true} to update always.
   1763      */
   1764     private void updateViewStatusForPrediction(boolean updateCandidates, boolean updateEmptyText) {
   1765         EngineState state = new EngineState();
   1766         state.convertType = EngineState.CONVERT_TYPE_NONE;
   1767         updateEngineState(state);
   1768 
   1769         updateViewStatus(ComposingText.LAYER1, updateCandidates, updateEmptyText);
   1770     }
   1771 
   1772     /**
   1773      * Update views and the display of the composing text.
   1774      *
   1775      * @param layer                      Display layer of the composing text
   1776      * @param updateCandidates  {@code true} to update the candidates view
   1777      * @param updateEmptyText   {@code false} to update the composing text if it is not empty; {@code true} to update always.
   1778      */
   1779     private void updateViewStatus(int layer, boolean updateCandidates, boolean updateEmptyText) {
   1780         mTargetLayer = layer;
   1781 
   1782         if (updateCandidates) {
   1783             updateCandidateView();
   1784         }
   1785         /* notice to the input view */
   1786         mInputViewManager.onUpdateState(this);
   1787 
   1788         /* set the text for displaying as the composing text */
   1789         mDisplayText.clear();
   1790         mDisplayText.insert(0, mComposingText.toString(layer));
   1791 
   1792         /* add decoration to the text */
   1793         int cursor = mComposingText.getCursor(layer);
   1794         if ((mInputConnection != null) && (mDisplayText.length() != 0 || updateEmptyText)) {
   1795             if (cursor != 0) {
   1796                 int highlightEnd = 0;
   1797 
   1798                 if ((mExactMatchMode && (!mEngineState.isEisuKana()))
   1799                     || (FIX_CURSOR_TEXT_END && isEnglishPrediction()
   1800                         && (cursor < mComposingText.size(ComposingText.LAYER1)))){
   1801 
   1802                     mDisplayText.setSpan(SPAN_EXACT_BGCOLOR_HL, 0, cursor,
   1803                                          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1804                     highlightEnd = cursor;
   1805 
   1806                 } else if (FIX_CURSOR_TEXT_END && mEngineState.isEisuKana()) {
   1807                     mDisplayText.setSpan(SPAN_EISUKANA_BGCOLOR_HL, 0, cursor,
   1808                                          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1809                     highlightEnd = cursor;
   1810 
   1811                 } else if (layer == ComposingText.LAYER2) {
   1812                     highlightEnd = mComposingText.toString(layer, 0, 0).length();
   1813 
   1814                     /* highlights the first segment */
   1815                     mDisplayText.setSpan(SPAN_CONVERT_BGCOLOR_HL, 0,
   1816                                          highlightEnd,
   1817                                          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1818                 }
   1819 
   1820                 if (FIX_CURSOR_TEXT_END && (highlightEnd != 0)) {
   1821                     /* highlights remaining text */
   1822                     mDisplayText.setSpan(SPAN_REMAIN_BGCOLOR_HL, highlightEnd,
   1823                                          mComposingText.toString(layer).length(),
   1824                                          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1825 
   1826                     /* text color in the highlight */
   1827                     mDisplayText.setSpan(SPAN_TEXTCOLOR, 0,
   1828                                          mComposingText.toString(layer).length(),
   1829                                          Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1830                 }
   1831             }
   1832 
   1833             mDisplayText.setSpan(SPAN_UNDERLINE, 0, mDisplayText.length(),
   1834                                  Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
   1835 
   1836             int displayCursor = mComposingText.toString(layer, 0, cursor - 1).length();
   1837             if (FIX_CURSOR_TEXT_END) {
   1838                 displayCursor = (cursor == 0) ?  0 : 1;
   1839             }
   1840             /* update the composing text on the EditView */
   1841             if ((mDisplayText.length() != 0) || !mHasStartedTextSelection) {
   1842                 mInputConnection.setComposingText(mDisplayText, displayCursor);
   1843             }
   1844         }
   1845     }
   1846 
   1847     /**
   1848      * Update the candidates view.
   1849      */
   1850     private void updateCandidateView() {
   1851         switch (mTargetLayer) {
   1852         case ComposingText.LAYER0:
   1853         case ComposingText.LAYER1: /* prediction */
   1854             if (mEnablePrediction || mEngineState.isSymbolList() || mEngineState.isEisuKana()) {
   1855                 /* update the candidates view */
   1856                 if ((mComposingText.size(ComposingText.LAYER1) != 0)
   1857                     && !mEngineState.isConvertState()) {
   1858 
   1859                     mHandler.removeMessages(MSG_PREDICTION);
   1860                     if (mCandidatesViewManager.getCurrentView().isShown()) {
   1861                         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION),
   1862                                                     PREDICTION_DELAY_MS_SHOWING_CANDIDATE);
   1863                     } else {
   1864                         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PREDICTION),
   1865                                                     PREDICTION_DELAY_MS_1ST);
   1866                     }
   1867                 } else {
   1868                     mHandler.removeMessages(MSG_PREDICTION);
   1869                     updatePrediction();
   1870                 }
   1871             } else {
   1872                 mHandler.removeMessages(MSG_PREDICTION);
   1873                 mCandidatesViewManager.clearCandidates();
   1874             }
   1875             break;
   1876         case ComposingText.LAYER2: /* convert */
   1877             if (mCommitCount == 0) {
   1878                 mHandler.removeMessages(MSG_PREDICTION);
   1879                 mConverter.convert(mComposingText);
   1880             }
   1881 
   1882             int candidates = mConverter.makeCandidateListOf(mCommitCount);
   1883 
   1884             if (candidates != 0) {
   1885                 mComposingText.setCursor(ComposingText.LAYER2, 1);
   1886                 mCandidatesViewManager.displayCandidates(mConverter);
   1887             } else {
   1888                 mComposingText.setCursor(ComposingText.LAYER1,
   1889                                          mComposingText.toString(ComposingText.LAYER1).length());
   1890                 mCandidatesViewManager.clearCandidates();
   1891             }
   1892             break;
   1893         default:
   1894             break;
   1895         }
   1896     }
   1897 
   1898     /**
   1899      * Commit the displaying composing text.
   1900      *
   1901      * @param learn  {@code true} to register the committed string to the learning dictionary.
   1902      * @return          IME's status after commit
   1903      */
   1904     private int commitText(boolean learn) {
   1905         if (isEnglishPrediction()) {
   1906             mComposingText.setCursor(ComposingText.LAYER1,
   1907                                      mComposingText.size(ComposingText.LAYER1));
   1908         }
   1909 
   1910         int layer = mTargetLayer;
   1911         int cursor = mComposingText.getCursor(layer);
   1912         if (cursor == 0) {
   1913             return mStatus;
   1914         }
   1915         String tmp = mComposingText.toString(layer, 0, cursor - 1);
   1916 
   1917         if (mConverter != null) {
   1918             if (learn) {
   1919                 if (mEngineState.isRenbun()) {
   1920                     learnWord(0); /* select the top of the clauses */
   1921                 } else {
   1922                     if (mComposingText.size(ComposingText.LAYER1) != 0) {
   1923                         String stroke = mComposingText.toString(ComposingText.LAYER1, 0, mComposingText.getCursor(layer) - 1);
   1924                         WnnWord word = new WnnWord(tmp, stroke);
   1925 
   1926                         learnWord(word);
   1927                     }
   1928                 }
   1929             } else {
   1930                 breakSequence();
   1931             }
   1932         }
   1933         return commitTextThroughInputConnection(tmp);
   1934     }
   1935 
   1936     /**
   1937      * Commit the composing text except the alphabet character at the tail.
   1938      */
   1939     private void commitTextWithoutLastAlphabet() {
   1940         int layer = mTargetLayer;
   1941         String tmp = mComposingText.getStrSegment(layer, -1).string;
   1942 
   1943         if (isAlphabetLast(tmp)) {
   1944             mComposingText.moveCursor(ComposingText.LAYER1, -1);
   1945             commitText(false);
   1946             mComposingText.moveCursor(ComposingText.LAYER1, 1);
   1947         } else {
   1948             commitText(false);
   1949         }
   1950     }
   1951 
   1952     /**
   1953      * Commit all uncommitted words.
   1954      */
   1955     private void commitAllText() {
   1956         initCommitInfoForWatchCursor();
   1957         if (mEngineState.isConvertState()) {
   1958             commitConvertingText();
   1959         } else {
   1960             mComposingText.setCursor(ComposingText.LAYER1,
   1961                                      mComposingText.size(ComposingText.LAYER1));
   1962             mStatus = commitText(true);
   1963         }
   1964         checkCommitInfo();
   1965     }
   1966 
   1967     /**
   1968      * Commit a word.
   1969      *
   1970      * @param word              A word to commit
   1971      * @return                  IME's status after commit
   1972      */
   1973     private int commitText(WnnWord word) {
   1974         if (mConverter != null) {
   1975             learnWord(word);
   1976         }
   1977         return commitTextThroughInputConnection(word.candidate);
   1978     }
   1979 
   1980     /**
   1981      * Commit a string.
   1982      *
   1983      * @param str  A string to commit
   1984      */
   1985     private void commitText(String str) {
   1986         mInputConnection.commitText(str, (FIX_CURSOR_TEXT_END ? 1 : str.length()));
   1987         mPrevCommitText.append(str);
   1988         mPrevCommitCount++;
   1989         mEnableAutoDeleteSpace = true;
   1990         updateViewStatusForPrediction(false, false);
   1991     }
   1992 
   1993     /**
   1994      * Commit a string through {@link InputConnection}.
   1995      *
   1996      * @param string  A string to commit
   1997      * @return                  IME's status after commit
   1998      */
   1999     private int commitTextThroughInputConnection(String string) {
   2000         int layer = mTargetLayer;
   2001 
   2002         mInputConnection.commitText(string, (FIX_CURSOR_TEXT_END ? 1 : string.length()));
   2003         mPrevCommitText.append(string);
   2004         mPrevCommitCount++;
   2005 
   2006         int cursor = mComposingText.getCursor(layer);
   2007         if (cursor > 0) {
   2008             mComposingText.deleteStrSegment(layer, 0, mComposingText.getCursor(layer) - 1);
   2009             mComposingText.setCursor(layer, mComposingText.size(layer));
   2010         }
   2011         mExactMatchMode = false;
   2012         mCommitCount++;
   2013 
   2014         if ((layer == ComposingText.LAYER2) && (mComposingText.size(layer) == 0)) {
   2015             layer = 1; /* for connected prediction */
   2016         }
   2017 
   2018         boolean committed = autoCommitEnglish();
   2019         mEnableAutoDeleteSpace = true;
   2020 
   2021         if (layer == ComposingText.LAYER2) {
   2022             EngineState state = new EngineState();
   2023             state.convertType = EngineState.CONVERT_TYPE_RENBUN;
   2024             updateEngineState(state);
   2025             updateViewStatus(layer, !committed, false);
   2026         } else {
   2027             updateViewStatusForPrediction(!committed, false);
   2028         }
   2029 
   2030         if (mComposingText.size(ComposingText.LAYER0) == 0) {
   2031             return STATUS_INIT;
   2032         } else {
   2033             return STATUS_INPUT_EDIT;
   2034         }
   2035     }
   2036 
   2037     /**
   2038      * Returns whether it is English prediction mode or not.
   2039      *
   2040      * @return  {@code true} if it is English prediction mode; otherwise, {@code false}.
   2041      */
   2042     private boolean isEnglishPrediction() {
   2043         return (mEngineState.isEnglish() && isEnableL2Converter());
   2044     }
   2045 
   2046     /**
   2047      * Change the conversion engine and the letter converter(Romaji-to-Kana converter).
   2048      *
   2049      * @param mode  Engine's mode to be changed
   2050      * @see jp.co.omronsoft.openwnn.OpenWnnEvent.Mode
   2051      * @see jp.co.omronsoft.openwnn.JAJP.DefaultSoftKeyboardJAJP
   2052      */
   2053     private void changeEngineMode(int mode) {
   2054         EngineState state = new EngineState();
   2055 
   2056         switch (mode) {
   2057         case ENGINE_MODE_OPT_TYPE_QWERTY:
   2058             state.keyboard = EngineState.KEYBOARD_QWERTY;
   2059             updateEngineState(state);
   2060             clearCommitInfo();
   2061             return;
   2062 
   2063         case ENGINE_MODE_OPT_TYPE_12KEY:
   2064             state.keyboard = EngineState.KEYBOARD_12KEY;
   2065             updateEngineState(state);
   2066             clearCommitInfo();
   2067             return;
   2068 
   2069         case ENGINE_MODE_EISU_KANA:
   2070             if (mEngineState.isEisuKana()) {
   2071                 state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
   2072                 updateEngineState(state);
   2073                 updateViewStatusForPrediction(true, true); /* prediction only */
   2074             } else {
   2075                 startConvert(EngineState.CONVERT_TYPE_EISU_KANA);
   2076             }
   2077             return;
   2078 
   2079         case ENGINE_MODE_SYMBOL:
   2080             if (mEnableSymbolList && !mDirectInputMode) {
   2081                 state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_SYMBOL;
   2082                 updateEngineState(state);
   2083                 updateViewStatusForPrediction(true, true);
   2084             }
   2085             return;
   2086 
   2087         case ENGINE_MODE_SYMBOL_KAO_MOJI:
   2088             changeSymbolEngineState(state, ENGINE_MODE_SYMBOL_KAO_MOJI);
   2089             return;
   2090 
   2091         default:
   2092             break;
   2093         }
   2094 
   2095         state = new EngineState();
   2096         state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
   2097         updateEngineState(state);
   2098 
   2099         SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
   2100         state = new EngineState();
   2101         switch (mode) {
   2102         case OpenWnnEvent.Mode.DIRECT:
   2103             /* Full/Half-width number or Full-width alphabet */
   2104             mConverter = null;
   2105             mPreConverter = null;
   2106             break;
   2107 
   2108         case OpenWnnEvent.Mode.NO_LV1_CONV:
   2109             /* no Romaji-to-Kana conversion (=English prediction mode) */
   2110             state.dictionarySet = EngineState.DICTIONARYSET_EN;
   2111             updateEngineState(state);
   2112             mConverter = mConverterEN;
   2113             mPreConverter = null;
   2114 
   2115             mEnableLearning   = pref.getBoolean("opt_enable_learning_en", true);
   2116             mEnablePrediction = pref.getBoolean("opt_prediction_en", false);
   2117             if (OpenWnn.isXLarge()) {
   2118                 mEnableSpellCorrection = pref.getBoolean("opt_spell_correction_en", false);
   2119             } else {
   2120                 mEnableSpellCorrection = pref.getBoolean("opt_spell_correction_en", true);
   2121             }
   2122             break;
   2123 
   2124         case OpenWnnEvent.Mode.NO_LV2_CONV:
   2125             mConverter = null;
   2126             mPreConverter = mPreConverterHiragana;
   2127             break;
   2128 
   2129         case ENGINE_MODE_FULL_KATAKANA:
   2130             mConverter = null;
   2131             mPreConverter = mPreConverterFullKatakana;
   2132             break;
   2133 
   2134         case ENGINE_MODE_HALF_KATAKANA:
   2135             mConverter = null;
   2136             mPreConverter = mPreConverterHalfKatakana;
   2137             break;
   2138 
   2139         default:
   2140             /* HIRAGANA input mode */
   2141             state.dictionarySet = EngineState.DICTIONARYSET_JP;
   2142             updateEngineState(state);
   2143             mConverter = mConverterJAJP;
   2144             mPreConverter = mPreConverterHiragana;
   2145 
   2146             mEnableLearning   = pref.getBoolean("opt_enable_learning_ja", true);
   2147             mEnablePrediction = pref.getBoolean("opt_prediction_ja", true);
   2148             break;
   2149         }
   2150 
   2151         mPreConverterBack = mPreConverter;
   2152         mConverterBack = mConverter;
   2153     }
   2154 
   2155     /**
   2156      * Update the conversion engine's state.
   2157      *
   2158      * @param state  Engine's state to be updated
   2159      */
   2160     private void updateEngineState(EngineState state) {
   2161         EngineState myState = mEngineState;
   2162 
   2163         /* language */
   2164         if ((state.dictionarySet != EngineState.INVALID)
   2165             && (myState.dictionarySet != state.dictionarySet)) {
   2166 
   2167             switch (state.dictionarySet) {
   2168             case EngineState.DICTIONARYSET_EN:
   2169                 setDictionary(OpenWnnEngineJAJP.DIC_LANG_EN);
   2170                 break;
   2171 
   2172             case EngineState.DICTIONARYSET_JP:
   2173             default:
   2174                 setDictionary(OpenWnnEngineJAJP.DIC_LANG_JP);
   2175                 break;
   2176             }
   2177             myState.dictionarySet = state.dictionarySet;
   2178             breakSequence();
   2179 
   2180             /* update keyboard setting */
   2181             if (state.keyboard == EngineState.INVALID) {
   2182                 state.keyboard = myState.keyboard;
   2183             }
   2184         }
   2185 
   2186         /* type of conversion */
   2187         if ((state.convertType != EngineState.INVALID)
   2188             && (myState.convertType != state.convertType)) {
   2189 
   2190             switch (state.convertType) {
   2191             case EngineState.CONVERT_TYPE_NONE:
   2192                 setDictionary(mPrevDictionarySet);
   2193                 break;
   2194 
   2195             case EngineState.CONVERT_TYPE_EISU_KANA:
   2196                 setDictionary(OpenWnnEngineJAJP.DIC_LANG_JP_EISUKANA);
   2197                 break;
   2198 
   2199             case EngineState.CONVERT_TYPE_RENBUN:
   2200             default:
   2201                 setDictionary(OpenWnnEngineJAJP.DIC_LANG_JP);
   2202                 break;
   2203             }
   2204             myState.convertType = state.convertType;
   2205         }
   2206 
   2207         /* temporary dictionary */
   2208         if (state.temporaryMode != EngineState.INVALID) {
   2209 
   2210             switch (state.temporaryMode) {
   2211             case EngineState.TEMPORARY_DICTIONARY_MODE_NONE:
   2212                 if (myState.temporaryMode != EngineState.TEMPORARY_DICTIONARY_MODE_NONE) {
   2213                     setDictionary(mPrevDictionarySet);
   2214                     mCurrentSymbol = -1;
   2215                     mPreConverter = mPreConverterBack;
   2216                     mConverter = mConverterBack;
   2217                     mDisableAutoCommitEnglishMask &= ~AUTO_COMMIT_ENGLISH_SYMBOL;
   2218                     ((DefaultSoftKeyboard)mInputViewManager).setNormalKeyboard();
   2219                     mTextCandidatesViewManager.setSymbolMode(false, ENGINE_MODE_SYMBOL_NONE);
   2220                     if (OpenWnn.isXLarge()) {
   2221                         mCandidatesViewManager = mTextCandidates1LineViewManager;
   2222                         View view = mTextCandidates1LineViewManager.getCurrentView();
   2223                         if (view != null) {
   2224                             setCandidatesView(view);
   2225                         }
   2226                     }
   2227                 }
   2228                 break;
   2229 
   2230             case EngineState.TEMPORARY_DICTIONARY_MODE_SYMBOL:
   2231                 if (++mCurrentSymbol >= SYMBOL_LISTS.length) {
   2232                     mCurrentSymbol = 0;
   2233                 }
   2234                 if (mEnableSymbolListNonHalf) {
   2235                     mConverterSymbolEngineBack.setDictionary(SYMBOL_LISTS[mCurrentSymbol]);
   2236                 } else {
   2237                     mConverterSymbolEngineBack.setDictionary(SymbolList.SYMBOL_ENGLISH);
   2238                 }
   2239                 mConverter = mConverterSymbolEngineBack;
   2240                 mDisableAutoCommitEnglishMask |= AUTO_COMMIT_ENGLISH_SYMBOL;
   2241                 int engineModeSymbol = 0;
   2242 
   2243                 if (SYMBOL_LISTS[mCurrentSymbol] == SymbolList.SYMBOL_JAPANESE) {
   2244                     engineModeSymbol = ENGINE_MODE_SYMBOL;
   2245                 } else if (SYMBOL_LISTS[mCurrentSymbol] == SymbolList.SYMBOL_JAPANESE_FACE) {
   2246                     engineModeSymbol = ENGINE_MODE_SYMBOL_KAO_MOJI;
   2247                 } else {
   2248                 }
   2249 
   2250                 mTextCandidatesViewManager.setSymbolMode(true, engineModeSymbol);
   2251                 if (OpenWnn.isXLarge()) {
   2252                     mCandidatesViewManager = mTextCandidatesViewManager;
   2253                     View view = mTextCandidatesViewManager.getCurrentView();
   2254                     if (view != null) {
   2255                         setCandidatesView(view);
   2256                     }
   2257                 }
   2258                 breakSequence();
   2259                 ((DefaultSoftKeyboard)mInputViewManager).setSymbolKeyboard();
   2260                 break;
   2261 
   2262             default:
   2263                 break;
   2264             }
   2265             myState.temporaryMode = state.temporaryMode;
   2266         }
   2267 
   2268         /* preference dictionary */
   2269         if ((state.preferenceDictionary != EngineState.INVALID)
   2270             && (myState.preferenceDictionary != state.preferenceDictionary)) {
   2271 
   2272             myState.preferenceDictionary = state.preferenceDictionary;
   2273             setDictionary(mPrevDictionarySet);
   2274         }
   2275 
   2276         /* keyboard type */
   2277         if (state.keyboard != EngineState.INVALID) {
   2278             switch (state.keyboard) {
   2279             case EngineState.KEYBOARD_12KEY:
   2280                 mConverterJAJP.setKeyboardType(OpenWnnEngineJAJP.KEYBOARD_KEYPAD12);
   2281                 mConverterEN.setDictionary(OpenWnnEngineEN.DICT_DEFAULT);
   2282                 break;
   2283 
   2284             case EngineState.KEYBOARD_QWERTY:
   2285             default:
   2286                 mConverterJAJP.setKeyboardType(OpenWnnEngineJAJP.KEYBOARD_QWERTY);
   2287                 if (mEnableSpellCorrection) {
   2288                     mConverterEN.setDictionary(OpenWnnEngineEN.DICT_FOR_CORRECT_MISTYPE);
   2289                 } else {
   2290                     mConverterEN.setDictionary(OpenWnnEngineEN.DICT_DEFAULT);
   2291                 }
   2292                 break;
   2293             }
   2294             myState.keyboard = state.keyboard;
   2295         }
   2296     }
   2297 
   2298     /**
   2299      * Set dictionaries to be used.
   2300      *
   2301      * @param mode  Definition of dictionaries
   2302      */
   2303     private void setDictionary(int mode) {
   2304         int target = mode;
   2305         switch (target) {
   2306 
   2307         case OpenWnnEngineJAJP.DIC_LANG_JP:
   2308 
   2309             switch (mEngineState.preferenceDictionary) {
   2310             case EngineState.PREFERENCE_DICTIONARY_PERSON_NAME:
   2311                 target = OpenWnnEngineJAJP.DIC_LANG_JP_PERSON_NAME;
   2312                 break;
   2313             case EngineState.PREFERENCE_DICTIONARY_POSTAL_ADDRESS:
   2314                 target = OpenWnnEngineJAJP.DIC_LANG_JP_POSTAL_ADDRESS;
   2315                 break;
   2316             default:
   2317                 break;
   2318             }
   2319 
   2320             break;
   2321 
   2322         case OpenWnnEngineJAJP.DIC_LANG_EN:
   2323 
   2324             switch (mEngineState.preferenceDictionary) {
   2325             case EngineState.PREFERENCE_DICTIONARY_EMAIL_ADDRESS_URI:
   2326                 target = OpenWnnEngineJAJP.DIC_LANG_EN_EMAIL_ADDRESS;
   2327                 break;
   2328             default:
   2329                 break;
   2330             }
   2331 
   2332             break;
   2333 
   2334         default:
   2335             break;
   2336         }
   2337 
   2338         switch (mode) {
   2339         case OpenWnnEngineJAJP.DIC_LANG_JP:
   2340         case OpenWnnEngineJAJP.DIC_LANG_EN:
   2341             mPrevDictionarySet = mode;
   2342             break;
   2343         default:
   2344             break;
   2345         }
   2346 
   2347         mConverterJAJP.setDictionary(target);
   2348     }
   2349 
   2350     /**
   2351      * Handle a toggle key input event.
   2352      *
   2353      * @param table  Table of toggle characters
   2354      */
   2355     private void processSoftKeyboardToggleChar(String[] table) {
   2356         if (table == null) {
   2357             return;
   2358         }
   2359 
   2360         commitConvertingText();
   2361 
   2362         boolean toggled = false;
   2363         if ((mStatus & ~STATUS_CANDIDATE_FULL) == STATUS_INPUT) {
   2364             int cursor = mComposingText.getCursor(ComposingText.LAYER1);
   2365             if (cursor > 0) {
   2366                 String prevChar = mComposingText.getStrSegment(ComposingText.LAYER1,
   2367                                                                cursor - 1).string;
   2368                 String c = searchToggleCharacter(prevChar, table, false);
   2369                 if (c != null) {
   2370                     mComposingText.delete(ComposingText.LAYER1, false);
   2371                     appendStrSegment(new StrSegment(c));
   2372                     toggled = true;
   2373                 }
   2374             }
   2375         }
   2376 
   2377         if (!toggled) {
   2378             if (!isEnableL2Converter()) {
   2379                 commitText(false);
   2380             }
   2381 
   2382             String str = table[0];
   2383             /* shift on */
   2384             if (mAutoCaps && (getShiftKeyState(getCurrentInputEditorInfo()) == 1)) {
   2385                 char top = table[0].charAt(0);
   2386                 if (Character.isLowerCase(top)) {
   2387                     str = Character.toString(Character.toUpperCase(top));
   2388                 }
   2389             }
   2390             appendStrSegment(new StrSegment(str));
   2391         }
   2392 
   2393         mStatus = STATUS_INPUT;
   2394 
   2395         updateViewStatusForPrediction(true, true);
   2396     }
   2397 
   2398     /**
   2399      * Handle character input from the software keyboard without listing candidates.
   2400      *
   2401      * @param chars  The input character(s)
   2402      */
   2403     private void processSoftKeyboardCodeWithoutConversion(char[] chars) {
   2404         if (chars == null) {
   2405             return;
   2406         }
   2407 
   2408         ComposingText text = mComposingText;
   2409         appendStrSegment(new StrSegment(chars));
   2410 
   2411         if (!isAlphabetLast(text.toString(ComposingText.LAYER1))) {
   2412             /* commit if the input character is not alphabet */
   2413             commitText(false);
   2414         } else {
   2415             boolean completed = mPreConverter.convert(text);
   2416             if (completed) {
   2417                 commitTextWithoutLastAlphabet();
   2418             } else {
   2419                 mStatus = STATUS_INPUT;
   2420                 updateViewStatusForPrediction(true, true);
   2421             }
   2422         }
   2423     }
   2424 
   2425     /**
   2426      * Handle character input from the software keyboard.
   2427      *
   2428      * @param chars   The input character(s)
   2429      */
   2430     private void processSoftKeyboardCode(char[] chars) {
   2431         if (chars == null) {
   2432             return;
   2433         }
   2434 
   2435         if ((chars[0] == ' ') || (chars[0] == '\u3000' /* Full-width space */)) {
   2436             if (mComposingText.size(0) == 0) {
   2437                 mCandidatesViewManager.clearCandidates();
   2438                 commitText(new String(chars));
   2439                 breakSequence();
   2440             } else {
   2441                 if (isEnglishPrediction()) {
   2442                     initCommitInfoForWatchCursor();
   2443                     commitText(true);
   2444                     commitSpaceJustOne();
   2445                     checkCommitInfo();
   2446                 } else {
   2447                     if (mEngineState.isRenbun()) {
   2448                         if (mCandidatesViewManager instanceof TextCandidatesViewManager) {
   2449                             if (!mCandidatesViewManager.isFocusCandidate()) {
   2450                                 processDownKeyEvent();
   2451                             }
   2452                             processRightKeyEvent();
   2453                         } else {
   2454                             mCandidatesViewManager.processMoveKeyEvent(KeyEvent.KEYCODE_DPAD_RIGHT);
   2455                         }
   2456                     } else {
   2457                         startConvert(EngineState.CONVERT_TYPE_RENBUN);
   2458                     }
   2459                 }
   2460             }
   2461             mEnableAutoDeleteSpace = false;
   2462         } else {
   2463             commitConvertingText();
   2464 
   2465             /* Auto-commit a word if it is English and Qwerty mode */
   2466             boolean commit = false;
   2467             if (isEnglishPrediction()
   2468                 && (mEngineState.keyboard == EngineState.KEYBOARD_QWERTY)) {
   2469 
   2470                 Matcher m = mEnglishAutoCommitDelimiter.matcher(new String(chars));
   2471                 if (m.matches()) {
   2472                     commit = true;
   2473                 }
   2474             }
   2475 
   2476             if (commit) {
   2477                 commitText(true);
   2478 
   2479                 appendStrSegment(new StrSegment(chars));
   2480                 commitText(true);
   2481             } else {
   2482                 appendStrSegment(new StrSegment(chars));
   2483                 if (mPreConverter != null) {
   2484                     mPreConverter.convert(mComposingText);
   2485                     mStatus = STATUS_INPUT;
   2486                 }
   2487                 updateViewStatusForPrediction(true, true);
   2488             }
   2489         }
   2490     }
   2491 
   2492     /**
   2493      * Start consecutive clause conversion or EISU-KANA conversion mode.
   2494      *
   2495      * @param convertType               The conversion type({@code EngineState.CONVERT_TYPE_*})
   2496      */
   2497     private void startConvert(int convertType) {
   2498         if (!isEnableL2Converter()) {
   2499             return;
   2500         }
   2501 
   2502         if (mEngineState.convertType != convertType) {
   2503             /* adjust the cursor position */
   2504             if (!mExactMatchMode) {
   2505                 if (convertType == EngineState.CONVERT_TYPE_RENBUN) {
   2506                     /* not specify */
   2507                     mComposingText.setCursor(ComposingText.LAYER1, 0);
   2508                 } else {
   2509                     if (mEngineState.isRenbun()) {
   2510                         /* EISU-KANA conversion specifying the position of the segment if previous mode is conversion mode */
   2511                         mExactMatchMode = true;
   2512                     } else {
   2513                         /* specify all range */
   2514                         mComposingText.setCursor(ComposingText.LAYER1,
   2515                                                  mComposingText.size(ComposingText.LAYER1));
   2516                     }
   2517                 }
   2518             }
   2519 
   2520             if (convertType == EngineState.CONVERT_TYPE_RENBUN) {
   2521                 /* clears variables for the prediction */
   2522                 mExactMatchMode = false;
   2523             }
   2524             /* clears variables for the convert */
   2525             mCommitCount = 0;
   2526 
   2527             int layer;
   2528             if (convertType == EngineState.CONVERT_TYPE_EISU_KANA) {
   2529                 layer = ComposingText.LAYER1;
   2530             } else {
   2531                 layer = ComposingText.LAYER2;
   2532             }
   2533 
   2534             EngineState state = new EngineState();
   2535             state.convertType = convertType;
   2536             updateEngineState(state);
   2537 
   2538             updateViewStatus(layer, true, true);
   2539         }
   2540     }
   2541 
   2542     /**
   2543      * Auto commit a word in English (on half-width alphabet mode).
   2544      *
   2545      * @return  {@code true} if auto-committed; otherwise, {@code false}.
   2546      */
   2547     private boolean autoCommitEnglish() {
   2548         if (isEnglishPrediction() && (mDisableAutoCommitEnglishMask == AUTO_COMMIT_ENGLISH_ON)) {
   2549             CharSequence seq = mInputConnection.getTextBeforeCursor(2, 0);
   2550             Matcher m = mEnglishAutoCommitDelimiter.matcher(seq);
   2551             if (m.matches()) {
   2552                 if ((seq.charAt(0) == ' ') && mEnableAutoDeleteSpace) {
   2553                     mInputConnection.deleteSurroundingText(2, 0);
   2554                     CharSequence str = seq.subSequence(1, 2);
   2555                     mInputConnection.commitText(str, 1);
   2556                     mPrevCommitText.append(str);
   2557                     mPrevCommitCount++;
   2558                 }
   2559 
   2560                 mHandler.removeMessages(MSG_PREDICTION);
   2561                 mCandidatesViewManager.clearCandidates();
   2562                 return true;
   2563             }
   2564         }
   2565         return false;
   2566     }
   2567 
   2568     /**
   2569      * Insert a white space if the previous character is not a white space.
   2570      */
   2571     private void commitSpaceJustOne() {
   2572         CharSequence seq = mInputConnection.getTextBeforeCursor(1, 0);
   2573         if (seq.charAt(0) != ' ') {
   2574             commitText(" ");
   2575         }
   2576     }
   2577 
   2578     /**
   2579      * Get the shift key state from the editor.
   2580      *
   2581      * @param editor    The editor
   2582      * @return          State ID of the shift key (0:off, 1:on)
   2583      */
   2584     protected int getShiftKeyState(EditorInfo editor) {
   2585         return (getCurrentInputConnection().getCursorCapsMode(editor.inputType) == 0) ? 0 : 1;
   2586     }
   2587 
   2588     /**
   2589      * Display current meta-key state.
   2590      */
   2591     private void updateMetaKeyStateDisplay() {
   2592         int mode = 0;
   2593         if(mHardShift == 0 && mHardAlt == 0){
   2594             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_OFF;
   2595         }else if(mHardShift == 1 && mHardAlt == 0){
   2596             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_OFF;
   2597         }else if(mHardShift == 2  && mHardAlt == 0){
   2598             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_OFF;
   2599         }else if(mHardShift == 0 && mHardAlt == 1){
   2600             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_ON;
   2601         }else if(mHardShift == 0 && mHardAlt == 2){
   2602             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_LOCK;
   2603         }else if(mHardShift == 1 && mHardAlt == 1){
   2604             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_ON;
   2605         }else if(mHardShift == 1 && mHardAlt == 2){
   2606             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_ON_ALT_LOCK;
   2607         }else if(mHardShift == 2 && mHardAlt == 1){
   2608             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_ON;
   2609         }else if(mHardShift == 2 && mHardAlt == 2){
   2610             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_LOCK_ALT_LOCK;
   2611         }else{
   2612             mode = DefaultSoftKeyboard.HARD_KEYMODE_SHIFT_OFF_ALT_OFF;
   2613         }
   2614         ((DefaultSoftKeyboard) mInputViewManager).updateIndicator(mode);
   2615     }
   2616 
   2617     /**
   2618      * Memory a selected word.
   2619      *
   2620      * @param word  A selected word
   2621      */
   2622     private void learnWord(WnnWord word) {
   2623         if (mEnableLearning && word != null) {
   2624             mConverter.learn(word);
   2625         }
   2626     }
   2627 
   2628     /**
   2629      * Memory a clause which is generated by consecutive clause conversion.
   2630      *
   2631      * @param index  Index of a clause
   2632      */
   2633     private void learnWord(int index) {
   2634         ComposingText composingText = mComposingText;
   2635 
   2636         if (mEnableLearning && composingText.size(ComposingText.LAYER2) > index) {
   2637             StrSegment seg = composingText.getStrSegment(ComposingText.LAYER2, index);
   2638             if (seg instanceof StrSegmentClause) {
   2639                 mConverter.learn(((StrSegmentClause)seg).clause);
   2640             } else {
   2641                 String stroke = composingText.toString(ComposingText.LAYER1, seg.from, seg.to);
   2642                 mConverter.learn(new WnnWord(seg.string, stroke));
   2643             }
   2644         }
   2645     }
   2646 
   2647     /**
   2648      * Fits an editor info.
   2649      *
   2650      * @param preferences  The preference data.
   2651      * @param info              The editor info.
   2652      */
   2653     private void fitInputType(SharedPreferences preference, EditorInfo info) {
   2654         if (info.inputType == EditorInfo.TYPE_NULL) {
   2655             mDirectInputMode = true;
   2656             return;
   2657         }
   2658 
   2659         if (mConverter == mConverterEN) {
   2660             mEnableLearning   = preference.getBoolean("opt_enable_learning_en", true);
   2661             mEnablePrediction = preference.getBoolean("opt_prediction_en", false);
   2662             if (OpenWnn.isXLarge()) {
   2663                 mEnableSpellCorrection = preference.getBoolean("opt_spell_correction_en", false);
   2664             } else {
   2665                 mEnableSpellCorrection = preference.getBoolean("opt_spell_correction_en", true);
   2666             }
   2667         } else {
   2668             mEnableLearning   = preference.getBoolean("opt_enable_learning_ja", true);
   2669             mEnablePrediction = preference.getBoolean("opt_prediction_ja", true);
   2670         }
   2671         mDisableAutoCommitEnglishMask &= ~AUTO_COMMIT_ENGLISH_OFF;
   2672         int preferenceDictionary = EngineState.PREFERENCE_DICTIONARY_NONE;
   2673         mEnableConverter = true;
   2674         mEnableSymbolList = true;
   2675         mEnableSymbolListNonHalf = true;
   2676         setEnabledTabs(true);
   2677         mAutoCaps = preference.getBoolean("auto_caps", true);
   2678         mFilter.filter = 0;
   2679         mEnableAutoInsertSpace = true;
   2680         mEnableAutoHideKeyboard = false;
   2681 
   2682         switch (info.inputType & EditorInfo.TYPE_MASK_CLASS) {
   2683         case EditorInfo.TYPE_CLASS_NUMBER:
   2684         case EditorInfo.TYPE_CLASS_DATETIME:
   2685             mEnableConverter = false;
   2686             break;
   2687 
   2688         case EditorInfo.TYPE_CLASS_PHONE:
   2689             mEnableSymbolList = false;
   2690             mEnableConverter = false;
   2691             break;
   2692 
   2693         case EditorInfo.TYPE_CLASS_TEXT:
   2694 
   2695             switch (info.inputType & EditorInfo.TYPE_MASK_VARIATION) {
   2696             case EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME:
   2697                 preferenceDictionary = EngineState.PREFERENCE_DICTIONARY_PERSON_NAME;
   2698                 break;
   2699 
   2700             case EditorInfo.TYPE_TEXT_VARIATION_PASSWORD:
   2701             case EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD:
   2702                 mEnableLearning = false;
   2703                 mEnableConverter = false;
   2704                 mEnableSymbolListNonHalf = false;
   2705                 mFilter.filter = CandidateFilter.FILTER_NON_ASCII;
   2706                 mDisableAutoCommitEnglishMask |= AUTO_COMMIT_ENGLISH_OFF;
   2707                 mTextCandidatesViewManager.setEnableEmoticon(false);
   2708                 break;
   2709 
   2710             case EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:
   2711                 mEnableAutoInsertSpace = false;
   2712                 mDisableAutoCommitEnglishMask |= AUTO_COMMIT_ENGLISH_OFF;
   2713                 preferenceDictionary = EngineState.PREFERENCE_DICTIONARY_EMAIL_ADDRESS_URI;
   2714                 break;
   2715 
   2716             case EditorInfo.TYPE_TEXT_VARIATION_URI:
   2717                 mEnableAutoInsertSpace = false;
   2718                 mDisableAutoCommitEnglishMask |= AUTO_COMMIT_ENGLISH_OFF;
   2719                 preferenceDictionary = EngineState.PREFERENCE_DICTIONARY_EMAIL_ADDRESS_URI;
   2720                 break;
   2721 
   2722             case EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS:
   2723                 preferenceDictionary = EngineState.PREFERENCE_DICTIONARY_POSTAL_ADDRESS;
   2724                 break;
   2725 
   2726             case EditorInfo.TYPE_TEXT_VARIATION_PHONETIC:
   2727                 mEnableLearning = false;
   2728                 mEnableConverter = false;
   2729                 mEnableSymbolList = false;
   2730                 break;
   2731 
   2732             default:
   2733                 break;
   2734             }
   2735             break;
   2736 
   2737         default:
   2738             break;
   2739         }
   2740 
   2741         if (mFilter.filter == 0) {
   2742             mConverterEN.setFilter(null);
   2743             mConverterJAJP.setFilter(null);
   2744         } else {
   2745             mConverterEN.setFilter(mFilter);
   2746             mConverterJAJP.setFilter(mFilter);
   2747         }
   2748 
   2749         EngineState state = new EngineState();
   2750         state.preferenceDictionary = preferenceDictionary;
   2751         state.convertType = EngineState.CONVERT_TYPE_NONE;
   2752         state.keyboard = mEngineState.keyboard;
   2753         updateEngineState(state);
   2754         updateMetaKeyStateDisplay();
   2755 
   2756         if (!OpenWnn.isXLarge()) {
   2757             checkTutorial(info.privateImeOptions);
   2758         }
   2759     }
   2760 
   2761     /**
   2762      * Append a {@link StrSegment} to the composing text
   2763      * <br>
   2764      * If the length of the composing text exceeds
   2765      * {@code LIMIT_INPUT_NUMBER}, the appending operation is ignored.
   2766      *
   2767      * @param  str  Input segment
   2768      */
   2769     private void appendStrSegment(StrSegment str) {
   2770         ComposingText composingText = mComposingText;
   2771 
   2772         if (composingText.size(ComposingText.LAYER1) >= LIMIT_INPUT_NUMBER) {
   2773             return; /* do nothing */
   2774         }
   2775         composingText.insertStrSegment(ComposingText.LAYER0, ComposingText.LAYER1, str);
   2776         return;
   2777     }
   2778 
   2779     /**
   2780      * Commit the consecutive clause conversion.
   2781      */
   2782     private void commitConvertingText() {
   2783         if (mEngineState.isConvertState()) {
   2784             int size = mComposingText.size(ComposingText.LAYER2);
   2785             for (int i = 0; i < size; i++) {
   2786                 learnWord(i);
   2787             }
   2788 
   2789             String text = mComposingText.toString(ComposingText.LAYER2);
   2790             mInputConnection.commitText(text, (FIX_CURSOR_TEXT_END ? 1 : text.length()));
   2791             mPrevCommitText.append(text);
   2792             mPrevCommitCount++;
   2793             initializeScreen();
   2794         }
   2795     }
   2796 
   2797     /**
   2798      * Initialize the screen displayed by IME
   2799      */
   2800     private void initializeScreen() {
   2801         if (mComposingText.size(ComposingText.LAYER0) != 0) {
   2802             mInputConnection.setComposingText("", 0);
   2803         }
   2804         mComposingText.clear();
   2805         mExactMatchMode = false;
   2806         mStatus = STATUS_INIT;
   2807         mHandler.removeMessages(MSG_PREDICTION);
   2808         View candidateView = mCandidatesViewManager.getCurrentView();
   2809         if ((candidateView != null) && candidateView.isShown()) {
   2810             mCandidatesViewManager.clearCandidates();
   2811         }
   2812         mInputViewManager.onUpdateState(this);
   2813 
   2814         EngineState state = new EngineState();
   2815         state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_NONE;
   2816         updateEngineState(state);
   2817     }
   2818 
   2819     /**
   2820      * Whether the tail of the string is alphabet or not.
   2821      *
   2822      * @param  str      The string
   2823      * @return          {@code true} if the tail is alphabet; {@code false} if otherwise.
   2824      */
   2825     private boolean isAlphabetLast(String str) {
   2826         Matcher m = ENGLISH_CHARACTER_LAST.matcher(str);
   2827         return m.matches();
   2828     }
   2829 
   2830     /** @see jp.co.omronsoft.openwnn.OpenWnn#onFinishInput */
   2831     @Override public void onFinishInput() {
   2832         if (mInputConnection != null) {
   2833             initializeScreen();
   2834         }
   2835         super.onFinishInput();
   2836     }
   2837 
   2838     /**
   2839      * Check whether or not the converter is active.
   2840      *
   2841      * @return {@code true} if the converter is active.
   2842      */
   2843     private boolean isEnableL2Converter() {
   2844         if (mConverter == null || !mEnableConverter) {
   2845             return false;
   2846         }
   2847 
   2848         if (mEngineState.isEnglish() && !mEnablePrediction) {
   2849             return false;
   2850         }
   2851 
   2852         return true;
   2853     }
   2854 
   2855     /**
   2856      * Handling KeyEvent(KEYUP)
   2857      * <br>
   2858      * This method is called from {@link #onEvent()}.
   2859      *
   2860      * @param ev   An up key event
   2861      */
   2862     private void onKeyUpEvent(KeyEvent ev) {
   2863         int key = ev.getKeyCode();
   2864         if(!mShiftPressing){
   2865             if(key == KeyEvent.KEYCODE_SHIFT_LEFT || key == KeyEvent.KEYCODE_SHIFT_RIGHT){
   2866                 mHardShift = 0;
   2867                 mShiftPressing = true;
   2868                 updateMetaKeyStateDisplay();
   2869             }
   2870         }
   2871         if(!mAltPressing ){
   2872             if(key == KeyEvent.KEYCODE_ALT_LEFT || key == KeyEvent.KEYCODE_ALT_RIGHT){
   2873                 mHardAlt = 0;
   2874                 mAltPressing   = true;
   2875                 updateMetaKeyStateDisplay();
   2876             }
   2877         }
   2878         if (mEnableHardware12Keyboard && !mDirectInputMode) {
   2879             if (isHardKeyboard12KeyLongPress(key)
   2880                     && ((ev.getFlags() & KeyEvent.FLAG_CANCELED_LONG_PRESS) == 0)) {
   2881                 switch (key) {
   2882                 case KeyEvent.KEYCODE_SOFT_LEFT:
   2883                     if (mEngineState.isSymbolList()) {
   2884                         switchSymbolList();
   2885                     } else if ((mComposingText.size(0) != 0) && !mEngineState.isRenbun()
   2886                             && (((DefaultSoftKeyboardJAJP)mInputViewManager).getKeyMode()
   2887                                      == DefaultSoftKeyboardJAJP.KEYMODE_JA_FULL_HIRAGANA)) {
   2888                         startConvert(EngineState.CONVERT_TYPE_RENBUN);
   2889                     } else {
   2890                         ((DefaultSoftKeyboard) mInputViewManager).onKey(
   2891                                 DefaultSoftKeyboard.KEYCODE_JP12_EMOJI, null);
   2892                     }
   2893                     break;
   2894 
   2895                 case KeyEvent.KEYCODE_SOFT_RIGHT:
   2896                     ((DefaultSoftKeyboardJAJP) mInputViewManager).showInputModeSwitchDialog();
   2897                     break;
   2898 
   2899                 case KeyEvent.KEYCODE_DEL:
   2900                     int newKeyCode = KeyEvent.KEYCODE_FORWARD_DEL;
   2901                     int composingTextSize = mComposingText.size(ComposingText.LAYER1);
   2902                     if (composingTextSize > 0) {
   2903                         if (mComposingText.getCursor(ComposingText.LAYER1) > (composingTextSize - 1)) {
   2904                             newKeyCode = KeyEvent.KEYCODE_DEL;
   2905                         }
   2906                         KeyEvent keyEvent = new KeyEvent(ev.getAction(), newKeyCode);
   2907                         if (!processKeyEvent(keyEvent)) {
   2908                             sendDownUpKeyEvents(keyEvent.getKeyCode());
   2909                         }
   2910                     } else {
   2911                         if (mInputConnection != null) {
   2912                             CharSequence text = mInputConnection.getTextAfterCursor(1, 0);
   2913                             if ((text == null) || (text.length() == 0)) {
   2914                                 newKeyCode = KeyEvent.KEYCODE_DEL;
   2915                             }
   2916                         }
   2917                         sendDownUpKeyEvents(newKeyCode);
   2918                     }
   2919                     break;
   2920 
   2921                 default:
   2922                     break;
   2923 
   2924                 }
   2925             }
   2926         }
   2927     }
   2928 
   2929     /**
   2930      * Handling KeyEvent(KEYLONGPRESS)
   2931      * <br>
   2932      * This method is called from {@link #handleEvent}.
   2933      *
   2934      * @param ev   An long press key event
   2935      * @return    {@code true} if the event is processed in this method; {@code false} if not.
   2936      */
   2937     private boolean onKeyLongPressEvent(KeyEvent ev) {
   2938         if (mEnableHardware12Keyboard) {
   2939             int keyCode = 0;
   2940             if (ev != null) {
   2941                 keyCode = ev.getKeyCode();
   2942             }
   2943             switch (keyCode) {
   2944             case KeyEvent.KEYCODE_DEL:
   2945                 initializeScreen();
   2946                 if (mInputConnection != null) {
   2947                     mInputConnection.deleteSurroundingText(Integer.MAX_VALUE, Integer.MAX_VALUE);
   2948                 }
   2949                 return true;
   2950 
   2951             default:
   2952                 break;
   2953 
   2954             }
   2955         }
   2956         return false;
   2957     }
   2958 
   2959     /**
   2960      * Initialize the committed text's information.
   2961      */
   2962     private void initCommitInfoForWatchCursor() {
   2963         if (!isEnableL2Converter()) {
   2964             return;
   2965         }
   2966 
   2967         mCommitStartCursor = mComposingStartCursor;
   2968         mPrevCommitText.delete(0, mPrevCommitText.length());
   2969     }
   2970 
   2971     /**
   2972      * Clear the commit text's info.
   2973      * @return {@code true}:cleared, {@code false}:has already cleared.
   2974      */
   2975     private boolean clearCommitInfo() {
   2976         if (mCommitStartCursor < 0) {
   2977             return false;
   2978         }
   2979 
   2980         mCommitStartCursor = -1;
   2981         return true;
   2982     }
   2983 
   2984     /**
   2985      * Verify the commit text.
   2986      */
   2987     private void checkCommitInfo() {
   2988         if (mCommitStartCursor < 0) {
   2989             return;
   2990         }
   2991 
   2992         int composingLength = mComposingText.toString(mTargetLayer).length();
   2993         CharSequence seq = mInputConnection.getTextBeforeCursor(mPrevCommitText.length() + composingLength, 0);
   2994         seq = seq.subSequence(0, seq.length() - composingLength);
   2995         if (!seq.equals(mPrevCommitText.toString())) {
   2996             mPrevCommitCount = 0;
   2997             clearCommitInfo();
   2998         }
   2999     }
   3000 
   3001     /**
   3002      * Check and start the tutorial if it is the tutorial mode.
   3003      *
   3004      * @param privateImeOptions IME's options
   3005      */
   3006     private void checkTutorial(String privateImeOptions) {
   3007         if (privateImeOptions == null) return;
   3008         if (privateImeOptions.equals("com.google.android.setupwizard:ShowTutorial")) {
   3009             if ((mTutorial == null) && mEnableTutorial) startTutorial();
   3010         } else if (privateImeOptions.equals("com.google.android.setupwizard:HideTutorial")) {
   3011             if (mTutorial != null) {
   3012                 if (mTutorial.close()) {
   3013                     mTutorial = null;
   3014                 }
   3015             }
   3016         }
   3017     }
   3018 
   3019     /**
   3020      * Start the tutorial
   3021      */
   3022     private void startTutorial() {
   3023         DefaultSoftKeyboardJAJP manager = (DefaultSoftKeyboardJAJP) mInputViewManager;
   3024         manager.setDefaultKeyboard();
   3025         if (mEngineState.keyboard == EngineState.KEYBOARD_QWERTY) {
   3026             manager.changeKeyboardType(DefaultSoftKeyboard.KEYBOARD_12KEY);
   3027         }
   3028 
   3029         DefaultSoftKeyboardJAJP inputManager = ((DefaultSoftKeyboardJAJP) mInputViewManager);
   3030         View v = inputManager.getKeyboardView();
   3031         v.setOnTouchListener(new View.OnTouchListener() {
   3032                 public boolean onTouch(View v, MotionEvent event) {
   3033                     return true;
   3034                 }});
   3035         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_TUTORIAL), 500);
   3036     }
   3037 
   3038     /**
   3039      * Close the tutorial
   3040      */
   3041     public void tutorialDone() {
   3042         mTutorial = null;
   3043     }
   3044 
   3045     /** @see OpenWnn#close */
   3046     @Override protected void close() {
   3047         mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLOSE), 0);
   3048     }
   3049 
   3050     /**
   3051      * Break the sequence of words.
   3052      */
   3053     private void breakSequence() {
   3054         mEnableAutoDeleteSpace = false;
   3055         mConverterJAJP.breakSequence();
   3056         mConverterEN.breakSequence();
   3057     }
   3058 
   3059     /**
   3060      * Switch symbol list.
   3061      */
   3062     private void switchSymbolList(){
   3063         changeSymbolEngineState(new EngineState(), ENGINE_MODE_SYMBOL);
   3064         mHardAlt = 0;
   3065         updateMetaKeyStateDisplay();
   3066     }
   3067 
   3068     /**
   3069      * Change symbol engine state.
   3070      *
   3071      * @param  state  Engine state
   3072      * @param  mode   Engine mode
   3073      */
   3074     private void changeSymbolEngineState(EngineState state, int mode) {
   3075         state.temporaryMode = EngineState.TEMPORARY_DICTIONARY_MODE_SYMBOL;
   3076         updateEngineState(state);
   3077     }
   3078 
   3079     /**
   3080      * Set enable tabs.
   3081      *
   3082      * @param enableEmoticon {@code true}  - Emoticon is enabled.
   3083      *                       {@code false} - Emoticon is disabled.
   3084      */
   3085     private void setEnabledTabs(boolean enableEmoticon) {
   3086         mTextCandidatesViewManager.setEnableEmoticon(enableEmoticon);
   3087     }
   3088 
   3089     /**
   3090      * Is enable hard keyboard 12Key long press keycode.
   3091      *
   3092      * @param  keyCode  keycode.
   3093      * @return  {@code true} if enable long press keycode; {@code false} if not.
   3094      */
   3095     private boolean isHardKeyboard12KeyLongPress(int keyCode) {
   3096         boolean isLongPress = false;
   3097         switch (keyCode) {
   3098         case KeyEvent.KEYCODE_SOFT_LEFT:
   3099         case KeyEvent.KEYCODE_SOFT_RIGHT:
   3100         case KeyEvent.KEYCODE_DEL:
   3101             isLongPress = true;
   3102             break;
   3103 
   3104         default:
   3105             break;
   3106         }
   3107         return isLongPress;
   3108     }
   3109 
   3110     /**
   3111      * Key event handler for hardware 12Keyboard.
   3112      *
   3113      * @param keyEvent A key event
   3114      * @return  {@code true} if the event is handled in this method.
   3115      */
   3116     private boolean processHardware12Keyboard(KeyEvent keyEvent) {
   3117         boolean ret = false;
   3118         if (mEnableHardware12Keyboard && (keyEvent != null)) {
   3119             int keyCode = keyEvent.getKeyCode();
   3120 
   3121             if (isHardKeyboard12KeyLongPress(keyCode)) {
   3122                 if (keyEvent.getRepeatCount() == 0) {
   3123                     keyEvent.startTracking();
   3124                 }
   3125                 ret = true;
   3126             } else {
   3127                 Integer code = HW12KEYBOARD_KEYCODE_REPLACE_TABLE.get(keyCode);
   3128                 if (code != null) {
   3129                     if (keyEvent.getRepeatCount() == 0) {
   3130                         ((DefaultSoftKeyboard) mInputViewManager).onKey(code.intValue(), null);
   3131                     }
   3132                     ret = true;
   3133                 }
   3134             }
   3135         }
   3136         return ret;
   3137     }
   3138 }
   3139