/*
 * Copyright (C) 2008,2009  OMRON SOFTWARE Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.

 * test message
 */

package net.gorry.android.input.nicownng.JAJP;

import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import net.gorry.android.input.nicownng.ComposingText;
import net.gorry.android.input.nicownng.DefaultSoftKeyboard;
import net.gorry.android.input.nicownng.MyHeightKeyboard;
import net.gorry.android.input.nicownng.NicoWnnG;
import net.gorry.android.input.nicownng.NicoWnnGEvent;
import net.gorry.android.input.nicownng.NicoWnnGJAJP;
import net.gorry.android.input.nicownng.R;
import android.content.SharedPreferences;
import android.inputmethodservice.Keyboard;
import android.preference.PreferenceManager;
import android.text.InputType;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;

/**
 * The default Software Keyboard class for Japanese IME.
 *
 * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD.  All Rights Reserved.
 */
public class DefaultSoftKeyboardNico extends DefaultSoftKeyboard {

	/** Enable English word prediction on half-width alphabet mode */
	private static final boolean USE_ENGLISH_PREDICT = true;

	/** Key code for switching to full-width HIRAGANA mode */
	private static final int KEYCODE_SWITCH_FULL_HIRAGANA = -301;

	/** Key code for switching to full-width KATAKANA mode */
	private static final int KEYCODE_SWITCH_FULL_KATAKANA = -302;

	/** Key code for switching to full-width alphabet mode */
	private static final int KEYCODE_SWITCH_FULL_ALPHABET = -303;

	/** Key code for switching to full-width number mode */
	private static final int KEYCODE_SWITCH_FULL_NUMBER = -304;

	/** Key code for switching to half-width KATAKANA mode */
	private static final int KEYCODE_SWITCH_HALF_KATAKANA = -306;

	/** Key code for switching to half-width alphabet mode */
	private static final int KEYCODE_SWITCH_HALF_ALPHABET = -307;

	/** Key code for switching to half-width number mode */
	private static final int KEYCODE_SWITCH_HALF_NUMBER = -308;

	/** Key code for case toggle key */
	private static final int KEYCODE_SELECT_CASE = -309;

	/** Key code for EISU-KANA conversion */
	// private static final int KEYCODE_EISU_KANA = -305;

	/** Key code for switching to full-width Nicotouch mode */
	private static final int KEYCODE_SWITCH_FULL_NICO = -400;

	/** Key code for switching to full-width Nicotouch katakana mode */
	private static final int KEYCODE_SWITCH_FULL_NICO_KATAKANA = -401;

	/** Key code for switching to half-width Nicotouch katakana mode */
	private static final int KEYCODE_SWITCH_HALF_NICO_KATAKANA = -402;

	/** Key code for NOP (no-operation) */
	private static final int KEYCODE_NOP = -310;

	/** Key code for DAKUTEN/HANDAKUTEN conversion */
	private static final int KEYCODE_DAKUTEN = -900;
	private static final int KEYCODE_HANDAKUTEN = -901;

	/** Key code for preference setting */
	private static final int KEYCODE_PREFERENCE_SETTING = -999;

	/** Key code for help */
	private static final int KEYCODE_SHOW_HELP = -998;

	/** Key code for Mushroom */
	private static final int KEYCODE_MUSHROOM = -997;

	private NicoWnnG mNicoWnnG;


	/** Input mode toggle cycle table */
	private static final int[] JP_MODE_CYCLE_TABLE = {
		KEYMODE_JA_FULL_NICO, KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER,
	};

	/** Definition for {@code mInputType} (toggle) */
	private static final int INPUT_TYPE_TOGGLE = 1;

	/** Definition for {@code mInputType} (commit instantly) */
	private static final int INPUT_TYPE_INSTANT = 2;

	/** Max key number of the 12 key keyboard (depends on the definition of keyboards) */
	private static final int KEY_NUMBER_12KEY = 20;

	/** Kana Mode */
	private static final int KANAMODE_ROMAN = 0;
	private static final int KANAMODE_JIS = 1;
	private static final int KANAMODE_50ON = 2;
	private static final int KANAMODE_MAX = 3;

	/** Character table for full-width number */
	private static final char[] INSTANT_CHAR_CODE_FULL_NUMBER =
		"\uff11\uff12\uff13\uff14\uff15\uff16\uff17\uff18\uff19\uff10\uff03\uff0a".toCharArray();

	/** Character table for half-width number */
	private static final char[] INSTANT_CHAR_CODE_HALF_NUMBER =
		"1234567890#*".toCharArray();

	/** The constant for mFixedKeyMode. It means that input mode is not fixed. */
	private static final int INVALID_KEYMODE = -1;

	/** KeyIndex of "Moji" key on 12 keyboard (depends on the definition of keyboards) */
	private static final int KEY_INDEX_CHANGE_MODE_12KEY = 15;

	/** KeyIndex of "Moji" key on QWERTY keyboard (depends on the definition of keyboards) */
	private static final int KEY_INDEX_CHANGE_MODE_QWERTY = 29;

	/** Type of input mode */
	private int mInputType = INPUT_TYPE_TOGGLE;


	private static final NicoWnnGEvent mEventResetStatus      = new NicoWnnGEvent(NicoWnnGEvent.RESET_STATUS);
	private static final NicoWnnGEvent mEventTouchOtherKey    = new NicoWnnGEvent(NicoWnnGEvent.TOUCH_OTHER_KEY);
	private static final NicoWnnGEvent mEventCommitText       = new NicoWnnGEvent(NicoWnnGEvent.COMMIT_COMPOSING_TEXT);
	private static final NicoWnnGEvent mEventConvert          = new NicoWnnGEvent(NicoWnnGEvent.CONVERT);
	private static final NicoWnnGEvent mEventConvertPredict   = new NicoWnnGEvent(NicoWnnGEvent.CONVERT_PREDICT);
	private static final NicoWnnGEvent mEventConvertPredictBackward   = new NicoWnnGEvent(NicoWnnGEvent.CONVERT_PREDICT_BACKWARD);

	private static final NicoWnnGEvent mEventChangeMode12Key    = new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, NicoWnnGJAJP.ENGINE_MODE_OPT_TYPE_12KEY);
	private static final NicoWnnGEvent mEventChangeModeQwerty   = new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, NicoWnnGJAJP.ENGINE_MODE_OPT_TYPE_QWERTY);
	private static final NicoWnnGEvent mEventChangeModeSymbol   = new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, NicoWnnGJAJP.ENGINE_MODE_SYMBOL);
	private static final NicoWnnGEvent mEventChangeModeDocomo   = new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, NicoWnnGJAJP.ENGINE_MODE_DOCOMOSYMBOL);
	private static final NicoWnnGEvent mEventChangeModeEisuKana = new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, NicoWnnGJAJP.ENGINE_MODE_EISU_KANA);

	private static final NicoWnnGEvent mEventInputShiftLeft   = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT));

	private static final NicoWnnGEvent mEventInputKeyDel      = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL));
	private static final NicoWnnGEvent mEventInputEnter       = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER));
	private static final NicoWnnGEvent mEventInputBack        = new NicoWnnGEvent(NicoWnnGEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK));
	private static final NicoWnnGEvent mEventInputDpadLeft    = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT));
	private static final NicoWnnGEvent mEventInputDpadRight   = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT));
	private static final NicoWnnGEvent mEventInputDpadUp      = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP));
	private static final NicoWnnGEvent mEventInputDpadDown    = new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN));


	/**
	 * Character table to input when mInputType becomes INPUT_TYPE_INSTANT.
	 * (Either INSTANT_CHAR_CODE_FULL_NUMBER or INSTANT_CHAR_CODE_HALF_NUMBER)
	 */
	private char[] mCurrentInstantTable = null;

	/** Input mode that is not able to be changed. If ENABLE_CHANGE_KEYMODE is set, input mode can change. */
	private int[] mLimitedKeyMode = null;

	/** Input mode that is given the first priority. If ENABLE_CHANGE_KEYMODE is set, input mode can change. */
	private int mPreferenceKeyMode = INVALID_KEYMODE;

	/** The last input type */
	private int mLastInputType = 0;

	/** Auto caps mode */
	private boolean mEnableAutoCaps = true;

	/** PopupResId of "Moji" key (this is used for canceling long-press) */
	private int mPopupResId = 0;

	/** Whether the InputType is null */
	private boolean mIsInputTypeNull = false;

	/** {@code SharedPreferences} for save the keyboard type */
	private SharedPreferences.Editor mPrefEditor = null;

	/** "Moji" key (this is used for canceling long-press) */
	private Keyboard.Key mChangeModeKey = null;

	private MyHeightKeyboard[][][] mNicoKeyboard;
	private int mNicoKeyMode = 0;

	/** option bell type **/
	private final int ALPHAMODE_SMALL = 0;
	private final int ALPHAMODE_BIG   = 1;
	private int mChangeAlphaBigMode = ALPHAMODE_SMALL;

	private int mRecursiveOnKeyNico = 0;

	/******************************************************************************************/
	/******************************************************************************************/
	/** Default constructor */
	public DefaultSoftKeyboardNico(final SetupKeyboard keyboard) {
		mSetupKeyboard       = keyboard;
		mCycleTable   = keyboard.SetupCycleTable();

		mCurrentLanguage     = LANG_JA;
		mShiftOn             = KEYBOARD_SHIFT_OFF;
		mCurrentKeyMode      = KEYMODE_JA_FULL_NICO;
		mCurrentSlide        = NICO_SLIDE_MODE_TOP;
		mNicoKeyMode         = NICO_MODE_FULL_HIRAGANA;
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#createKeyboards */
	@Override protected void createKeyboards(final NicoWnnG parent) {
		mNicoWnnG = parent;

		/* Keyboard[# of Languages][portrait/landscape][# of keyboard type][shift off/on][max # of key-modes][noinput/input] */
		mKeyboard = new MyHeightKeyboard[LANG_MAX][PORTRAIT_LANDSCAPE][KEYBOARD_MAX][KEYBOARD_SHIFT_MAX][KEYMODE_JA_MAX][2];

		final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(parent);
		mQwertyMatrixMode      = mWnn.getOrientPrefBoolean(pref, "qwerty_matrix_mode", false);
		mNoAlphaMode           = mWnn.getOrientPrefBoolean(pref, "change_noalpha_qwerty", false);
		mNoNumberMode          = mWnn.getOrientPrefBoolean(pref, "change_nonumber_qwerty", false);
		final boolean getalphamode  = mWnn.getOrientPrefBoolean(pref, "change_alphamode", false);
		mGetNoFlipScreen       = mWnn.getOrientPrefBoolean(pref, "no_flip_screen", false);
		mFlickNicoInput        = Integer.valueOf(mWnn.getOrientPrefString(pref, "nicoflick_mode", "0"));
		mFlickGuide            = mWnn.getOrientPrefBoolean(pref, "flick_guide", true);
		mHiddenSoftKeyboard    = Integer.valueOf(mWnn.getOrientPrefString(pref, "hidden_softkeyboard2", "0"));

		if (false == getalphamode) {
			mChangeAlphaBigMode = ALPHAMODE_SMALL;
		}
		else{
			mChangeAlphaBigMode = ALPHAMODE_BIG;
		}

		if (true == mGetNoFlipScreen) {
			mNoFlipScreen = true;
		}
		else{
			mNoFlipScreen = false;
		}

		mKana12Key = mWnn.getOrientPrefBoolean(pref, "change_kana_12key", false);
		mAnum12Key = mWnn.getOrientPrefBoolean(pref, "change_alphanum_12key", false);
		setM12KeyTable();

		/* Create the suitable keyboard object */
		if (mDisplayMode == DefaultSoftKeyboard.PORTRAIT) {
			createKeyboardsPortrait(parent);
		} else {
			createKeyboardsLandscape(parent);
		}

		if (m12keyTable[mCurrentKeyMode] == KEYBOARD_12KEY) {
			mWnn.onEvent(mEventChangeMode12Key);
			NicoWnnGJAJP.getInstance().setSpecialCandidateOnKana12KeyToggleMode((mFlickNicoInput > 0) ? 2 : 0);
		} else {
			mWnn.onEvent(mEventChangeModeQwerty);
			NicoWnnGJAJP.getInstance().setSpecialCandidateOnKana12KeyToggleMode(0);
		}
	}

	public void setM12KeyTable() {
		m12keyTable[KEYMODE_JA_FULL_NICO]          = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_FULL_HIRAGANA]      = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_FULL_ALPHABET]      = mAnum12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_FULL_NUMBER]        = mAnum12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_FULL_KATAKANA]      = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_HALF_ALPHABET]      = mAnum12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_HALF_NUMBER]        = mAnum12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_HALF_KATAKANA]      = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_HALF_PHONE]         = mAnum12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_FULL_NICO_KATAKANA] = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
		m12keyTable[KEYMODE_JA_HALF_NICO_KATAKANA] = mKana12Key ? KEYBOARD_12KEY : KEYBOARD_QWERTY;
	}

	/**
	 *
	 */
	@Override public void checkHiddenKeyboard() {
		super.checkHiddenKeyboard();
	}

	/**
	 * Commit the pre-edit string for committing operation that is not explicit
	 * (ex. when a candidate is selected)
	 */
	private void commitText() {
		if (!mNoInput) {
			mWnn.onEvent(mEventCommitText);
		}
	}

	/**
	 * Change input mode
	 * <br>
	 * @param keyMode   The type of input mode
	 */
	@Override
	public void changeKeyMode(final int keyMode) {
		final int targetMode = filterKeyMode(keyMode);
		if (targetMode == INVALID_KEYMODE) {
			return;
		}

		commitText();

		if (mCapsLock) {
			mWnn.onEvent(mEventInputShiftLeft);
			mCapsLock = false;
		}
		mShiftOn = KEYBOARD_SHIFT_OFF;
		final MyHeightKeyboard kbd = getModeChangeKeyboard(targetMode);
		mCurrentKeyMode = targetMode;
		mPrevInputKeyCode = 0;
		mCurrentSlide = 0;
		mNicoKeyMode = NICO_MODE_FULL_HIRAGANA;

		int mode = NicoWnnGEvent.Mode.DIRECT;

		switch (targetMode) {
			case KEYMODE_JA_HALF_ALPHABET:
				if (USE_ENGLISH_PREDICT) {
					mInputType = INPUT_TYPE_TOGGLE;
					mode = NicoWnnGEvent.Mode.NO_LV1_CONV;
				} else {
					mInputType = INPUT_TYPE_TOGGLE;
					mode = NicoWnnGEvent.Mode.DIRECT;
				}
				break;

			case KEYMODE_JA_FULL_NUMBER:
				mInputType = INPUT_TYPE_INSTANT;
				mode = NicoWnnGEvent.Mode.DIRECT;
				mCurrentInstantTable = INSTANT_CHAR_CODE_FULL_NUMBER;
				break;

			case KEYMODE_JA_HALF_NUMBER:
				mInputType = INPUT_TYPE_INSTANT;
				mode = NicoWnnGEvent.Mode.DIRECT;
				mCurrentInstantTable = INSTANT_CHAR_CODE_HALF_NUMBER;
				break;

			case KEYMODE_JA_FULL_ALPHABET:
				mInputType = INPUT_TYPE_TOGGLE;
				mode = NicoWnnGEvent.Mode.DIRECT;
				break;

			case KEYMODE_JA_FULL_NICO:
				mInputType = INPUT_TYPE_TOGGLE;
				mode = NicoWnnGEvent.Mode.DEFAULT;
				mNicoFirst = false;
				mNicoFlick = false;
				break;

			case KEYMODE_JA_FULL_NICO_KATAKANA:
				mInputType = INPUT_TYPE_TOGGLE;
				mNicoKeyMode = NICO_MODE_FULL_KATAKANA;
				mode = NicoWnnGEvent.Mode.DEFAULT;
				mNicoFirst = false;
				mNicoFlick = false;
				break;

			case KEYMODE_JA_HALF_NICO_KATAKANA:
				mInputType = INPUT_TYPE_TOGGLE;
				mNicoKeyMode = NICO_MODE_HALF_KATAKANA;
				mode = NicoWnnGEvent.Mode.DEFAULT;
				mNicoFirst = false;
				mNicoFlick = false;
				break;

			case KEYMODE_JA_FULL_HIRAGANA:
				mInputType = INPUT_TYPE_TOGGLE;
				mode = NicoWnnGEvent.Mode.DEFAULT;
				break;

			case KEYMODE_JA_FULL_KATAKANA:
				mInputType = INPUT_TYPE_TOGGLE;
				mNicoKeyMode = NICO_MODE_FULL_KATAKANA;
				mode = NicoWnnGJAJP.ENGINE_MODE_FULL_KATAKANA;
				break;

			case KEYMODE_JA_HALF_KATAKANA:
				mInputType = INPUT_TYPE_TOGGLE;
				mNicoKeyMode = NICO_MODE_HALF_KATAKANA;
				mode = NicoWnnGJAJP.ENGINE_MODE_HALF_KATAKANA;
				break;

			default:
				break;
		}

		setStatusIcon();
		changeKeyboard(kbd);
		mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.CHANGE_MODE, mode));
		changeKeyboardType(m12keyTable[targetMode]);
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#initView */
	@Override public View initView(final NicoWnnG parent, final int width, final int height) {
		final View view = super.initView(parent, width, height);
		changeKeyboard(mKeyboard[mCurrentLanguage][mDisplayMode][m12keyTable[mCurrentKeyMode]][mShiftOn][mCurrentKeyMode][0]);
		return view;
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#changeKeyboard */
	@Override protected boolean changeKeyboard(final MyHeightKeyboard keyboard) {
		resetKeyRepeat();

		if (keyboard != null) {
			if (mIsInputTypeNull) {
				if (mChangeModeKey != null) {
					mChangeModeKey.popupResId = mPopupResId;
				}
			}

			final List<Keyboard.Key> keys = keyboard.getKeys();
			final int keyIndex = (KEY_NUMBER_12KEY < keys.size())
			? KEY_INDEX_CHANGE_MODE_QWERTY : KEY_INDEX_CHANGE_MODE_12KEY;
			mChangeModeKey = keys.get(keyIndex);

			if (mIsInputTypeNull) {
				if (mChangeModeKey != null) {
					mPopupResId = mChangeModeKey.popupResId;
					mChangeModeKey.popupResId = 0;
				}
			}
		}
		return super.changeKeyboard(keyboard);
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#changeKeyboardType */
	@Override public void changeKeyboardType(final int type) {
		commitText();
		m12keyTable[mCurrentKeyMode] = type;
		final MyHeightKeyboard kbd = getTypeChangeKeyboard(type);
		if (kbd != null) {
			/*
			mPrefEditor.putBoolean("opt_enable_qwerty", type == KEYBOARD_QWERTY);
			mPrefEditor.commit();
			 */
			changeKeyboard(kbd);
		}
		if (m12keyTable[mCurrentKeyMode] == KEYBOARD_12KEY) {
			mWnn.onEvent(mEventChangeMode12Key);
		} else {
			mWnn.onEvent(mEventChangeModeQwerty);
		}
	}
	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#setPreferences */
	@Override public void setPreferences(final SharedPreferences pref, final EditorInfo editor) {
		mPrefEditor = pref.edit();
		/*
		final boolean isQwerty = pref.getBoolean("opt_enable_qwerty", false);
		if (isQwerty && (mCurrentKeyboardType != KEYBOARD_QWERTY)) {
			changeKeyboardType(KEYBOARD_QWERTY);
		}
		 */

		super.setPreferences(pref, editor);

		final int inputType = editor.inputType;
		if (mHardKeyboardHidden) {
			if (inputType == InputType.TYPE_NULL) {
				if (!mIsInputTypeNull) {
					mIsInputTypeNull = true;
					if (mChangeModeKey != null) {
						mPopupResId = mChangeModeKey.popupResId;
						mChangeModeKey.popupResId = 0;
					}
				}
				return;
			}

			if (mIsInputTypeNull) {
				mIsInputTypeNull = false;
				if (mChangeModeKey != null) {
					mChangeModeKey.popupResId = mPopupResId;
				}
			}
		}

		mEnableAutoCaps = mWnn.getOrientPrefBoolean(pref, "auto_caps", false);
		mLimitedKeyMode = null;
		mPreferenceKeyMode = INVALID_KEYMODE;
		mNoInput = true;
		mDisableKeyInput = false;
		mCapsLock = false;

		switch (inputType & InputType.TYPE_MASK_CLASS) {

			case InputType.TYPE_CLASS_NUMBER:
			case InputType.TYPE_CLASS_DATETIME:
				mPreferenceKeyMode = KEYMODE_JA_HALF_NUMBER;
				break;

			case InputType.TYPE_CLASS_PHONE:
				if (mHardKeyboardHidden) {
					//mLimitedKeyMode = new int[] {KEYMODE_JA_FULL_NICO};
					mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
				} else {
					//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET};
					mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
				}
				break;

			case InputType.TYPE_CLASS_TEXT:
				switch (inputType & InputType.TYPE_MASK_VARIATION) {

					case InputType.TYPE_TEXT_VARIATION_PASSWORD:
						//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER};
						break;

					case InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS:
						//mLimitedKeyMode = new int[] {KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER};
						break;
					case InputType.TYPE_TEXT_VARIATION_URI:
						//mPreferenceKeyMode = KEYMODE_JA_HALF_ALPHABET;
						mPreferenceKeyMode = KEYMODE_JA_FULL_NICO;
						break;

					default:
						break;
				}
				break;

			default:
				break;
		}

		boolean restartkey = false;
		final boolean oldKana12key = mKana12Key;
		final boolean oldAnum12key = mAnum12Key;

		mQwertyMatrixMode      = mWnn.getOrientPrefBoolean(pref, "qwerty_matrix_mode", false);
		mKana12Key = mWnn.getOrientPrefBoolean(pref, "change_kana_12key", false);
		mAnum12Key = mWnn.getOrientPrefBoolean(pref, "change_alphanum_12key", false);
		mNoAlphaMode           = mWnn.getOrientPrefBoolean(pref, "change_noalpha_qwerty", false);
		mNoNumberMode          = mWnn.getOrientPrefBoolean(pref, "change_nonumber_qwerty", false);
		final boolean getalphamode  = mWnn.getOrientPrefBoolean(pref, "change_alphamode", false);
		mGetNoFlipScreen       = mWnn.getOrientPrefBoolean(pref, "no_flip_screen", false);
		mFlickNicoInput        = Integer.valueOf(mWnn.getOrientPrefString(pref, "nicoflick_mode", "0"));
		mFlickGuide            = mWnn.getOrientPrefBoolean(pref, "flick_guide", true);
		mHiddenSoftKeyboard    = Integer.valueOf(mWnn.getOrientPrefString(pref, "hidden_softkeyboard2", "0"));

		if (false == getalphamode) {
			mChangeAlphaBigMode = ALPHAMODE_SMALL;
		}
		else{
			mChangeAlphaBigMode = ALPHAMODE_BIG;
		}

		if (true == mGetNoFlipScreen) {
			mNoFlipScreen = true;
		}
		else{
			mNoFlipScreen = false;
		}

		if ((oldKana12key != mKana12Key) || (oldAnum12key != mAnum12Key)) {
			restartkey = true;
			setM12KeyTable();
		}
		if (inputType != mLastInputType) {
			setDefaultKeyboard();
			mLastInputType = inputType;
		}
		else if (true == restartkey) {
			setDefaultKeyboard();
		}

		setStatusIcon();
		setShiftByEditorInfo();
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#onUpdateState */
	@Override public void onUpdateState(final NicoWnnG parent) {
		super.onUpdateState(parent);
		if (!mCapsLock) {
			setShiftByEditorInfo();
			if ((true == mNoInput) && (true == mNicoFirst)) {
				resetNicoKeyboard();
			}
		}
	}
	/**
	 * Change the keyboard to default
	 */
	@Override public void setDefaultKeyboard() {
		final Locale locale = Locale.getDefault();
		int keymode = KEYMODE_JA_FULL_NICO;


		if (mPreferenceKeyMode != INVALID_KEYMODE) {
			keymode = mPreferenceKeyMode;
		} else if (mLimitedKeyMode != null) {
			keymode = mLimitedKeyMode[0];
		} else {
			if (!locale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
				keymode = KEYMODE_JA_HALF_ALPHABET;
			}
		}

		changeKeyMode(keymode);
	}


	/**
	 * Change to the next input mode
	 */
	@Override public void nextKeyMode() {
		/* Search the current mode in the toggle table */
		boolean found = false;
		int index;
		for (index = 0; index < JP_MODE_CYCLE_TABLE.length; index++) {
			if (JP_MODE_CYCLE_TABLE[index] == mCurrentKeyMode) {
				found = true;
				break;
			}
		}

		if (!found) {
			/* If the current mode not exists, set the default mode */
			setDefaultKeyboard();
		} else {
			/* If the current mode exists, set the next input mode */
			final int size = JP_MODE_CYCLE_TABLE.length;
			int keyMode = INVALID_KEYMODE;
			for (int i = 0; i < size; i++) {
				index = (++index) % size;
				keyMode = filterKeyMode(JP_MODE_CYCLE_TABLE[index]);
				if (keyMode == INVALID_KEYMODE) {
					continue;
				}
				if (m12keyTable[keyMode] == KEYBOARD_QWERTY) {
					if (mNoAlphaMode) {
						if (JP_MODE_CYCLE_TABLE[index] == KEYMODE_JA_HALF_ALPHABET) {
							continue;
						}
					}
					if (mNoNumberMode) {
						if (JP_MODE_CYCLE_TABLE[index] == KEYMODE_JA_HALF_NUMBER) {
							continue;
						}
					}
				}
				break;
			}

			if (keyMode != INVALID_KEYMODE) {
				changeKeyMode(keyMode);
			}
		}
	}

	/**
	 * Create the keyboard for portrait mode
	 * <br>
	 * @param parent  The context
	 */
	private void createKeyboardsPortrait(final NicoWnnG parent) {
		mNicoKeyboard = mSetupKeyboard.SetupSoftKeyboard(parent, PORTRAIT, mInputViewHeightIndex, mFlickNicoInput, mFlickGuide);

		if (true == isHideSoftKeyboardByHardKeyboard()) {
			return;				// not create soft keyboard
		}

		int[] keyTable = selectQwertyPortKeyTable;
		if (mQwertyMatrixMode) {
			switch (mQwertyKanaMode) {
				case KANAMODE_ROMAN:
				default:
					keyTable = selectQwertyPortKeyTable;
					break;
				case KANAMODE_JIS:
					keyTable = selectKanaJisPortKeyTable;
					break;
				case KANAMODE_50ON:
					keyTable = selectKana50onPortKeyTable;
					break;
			}
		} else {
			switch (mQwertyKanaMode) {
				case KANAMODE_ROMAN:
				default:
					keyTable = selectQwertySlantPortKeyTable;
					break;
				case KANAMODE_JIS:
					keyTable = selectKanaJisSlantPortKeyTable;
					break;
				case KANAMODE_50ON:
					keyTable = selectKana50onSlantPortKeyTable;
					break;
			}
		}

		int[] keyTable2 = selectOtherPortKeyTable;
		if (mFlickNicoInput != NICOFLICK_NONE) {
			keyTable2 = selectFlickPortKeyTable;
		}

		MyHeightKeyboard[][] keyList;
		/* qwerty shift_off (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_FULL_HIRAGANA][0] = new MyHeightKeyboard(parent, keyTable[0], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[2], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[4], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[6], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[8], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[10], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[12], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_FULL_NICO][0]     = keyList[KEYMODE_JA_FULL_HIRAGANA][0];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_FULL_KATAKANA][0];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_HALF_KATAKANA][0];

		/* qwerty shift_on (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_QWERTY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_HIRAGANA][0] = new MyHeightKeyboard(parent, keyTable[1], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[3], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[5], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_FULL_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[7], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[9], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[11], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[13], mInputViewHeightIndex, KEYTYPE_QWERTY, true);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_FULL_NICO][0]     = keyList[KEYMODE_JA_FULL_HIRAGANA][0];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_FULL_KATAKANA][0];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_HALF_KATAKANA][0];

		/* 12-keys shift_off (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable2[1], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_FULL_ALPHABET][1] = new MyHeightKeyboard(parent, keyTable2[2], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable2[3], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable2[4], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_HALF_ALPHABET][1] = new MyHeightKeyboard(parent, keyTable2[5], mInputViewHeightIndex, KEYTYPE_12KEY, true);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable2[6], mInputViewHeightIndex, KEYTYPE_12KEY, true);

		/* 12-keys shift_on (portrait) */
		keyList = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_HALF_PHONE]    = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE];
		keyList[KEYMODE_JA_FULL_ALPHABET] = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_ALPHABET];
		keyList[KEYMODE_JA_FULL_NUMBER]   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_NUMBER];
		keyList[KEYMODE_JA_HALF_ALPHABET] = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_ALPHABET];;
		keyList[KEYMODE_JA_HALF_NUMBER]   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_NUMBER];

		MyHeightKeyboard[][] keyListOn;
		keyList   = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyListOn = mKeyboard[LANG_JA][PORTRAIT][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_NICO]     = mNicoKeyboard[NICO_MODE_FULL_HIRAGANA][NICO_SLIDE_MODE_TOP];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA]     = mNicoKeyboard[NICO_MODE_FULL_KATAKANA][NICO_SLIDE_MODE_TOP];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA]     = mNicoKeyboard[NICO_MODE_HALF_KATAKANA][NICO_SLIDE_MODE_TOP];
		keyListOn[KEYMODE_JA_FULL_NICO]   = mNicoKeyboard[NICO_MODE_FULL_HIRAGANA][NICO_SLIDE_MODE_A];
		keyListOn[KEYMODE_JA_FULL_NICO_KATAKANA]   = mNicoKeyboard[NICO_MODE_FULL_KATAKANA][NICO_SLIDE_MODE_A];
		keyListOn[KEYMODE_JA_HALF_NICO_KATAKANA]   = mNicoKeyboard[NICO_MODE_HALF_KATAKANA][NICO_SLIDE_MODE_A];
	}

	/**
	 * Create the keyboard for landscape mode
	 * <br>
	 * @param parent  The context
	 */
	private void createKeyboardsLandscape(final NicoWnnG parent) {
		mNicoKeyboard = mSetupKeyboard.SetupSoftKeyboard(parent, LANDSCAPE, mInputViewHeightIndex, mFlickNicoInput, mFlickGuide);

		if (true == isHideSoftKeyboardByHardKeyboard()) {
			return;				// not create soft keyboard
		}

		int[] keyTable = selectQwertyLandKeyTable;
		if (mQwertyMatrixMode) {
			switch (mQwertyKanaMode) {
				case KANAMODE_ROMAN:
				default:
					keyTable = selectQwertyLandKeyTable;
					break;
				case KANAMODE_JIS:
					keyTable = selectKanaJisLandKeyTable;
					break;
				case KANAMODE_50ON:
					keyTable = selectKana50onLandKeyTable;
					break;
			}
		} else {
			switch (mQwertyKanaMode) {
				case KANAMODE_ROMAN:
				default:
					keyTable = selectQwertySlantLandKeyTable;
					break;
				case KANAMODE_JIS:
					keyTable = selectKanaJisSlantLandKeyTable;
					break;
				case KANAMODE_50ON:
					keyTable = selectKana50onSlantLandKeyTable;
					break;
			}
		}

		int[] keyTable2 = selectOtherLandKeyTable;
		if (mFlickNicoInput != NICOFLICK_NONE) {
			keyTable2 = selectFlickLandKeyTable;
		}

		MyHeightKeyboard[][] keyList;
		/* qwerty shift_off (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_QWERTY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_FULL_HIRAGANA][0] = new MyHeightKeyboard(parent, keyTable[0], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[2], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[4], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[6], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[8], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[10], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[12], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_FULL_NICO][0]     = keyList[KEYMODE_JA_FULL_HIRAGANA][0];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_FULL_KATAKANA][0];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_HALF_KATAKANA][0];

		/* qwerty shift_on (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_QWERTY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_HIRAGANA][0] = new MyHeightKeyboard(parent, keyTable[1], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[3], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[5], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_FULL_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[7], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable[9], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable[11], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_KATAKANA][0] = new MyHeightKeyboard(parent, keyTable[13], mInputViewHeightIndex, KEYTYPE_QWERTY, false);
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_FULL_NICO][0]     = keyList[KEYMODE_JA_FULL_HIRAGANA][0];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_FULL_KATAKANA][0];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA][0]     = keyList[KEYMODE_JA_HALF_KATAKANA][0];

		/* 12-keys shift_off (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyList[KEYMODE_JA_HALF_PHONE][0]    = new MyHeightKeyboard(parent, keyTable2[0], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_FULL_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable2[1], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_FULL_ALPHABET][1] = new MyHeightKeyboard(parent, keyTable2[2], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_FULL_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable2[3], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_HALF_ALPHABET][0] = new MyHeightKeyboard(parent, keyTable2[4], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_HALF_ALPHABET][1] = new MyHeightKeyboard(parent, keyTable2[5], mInputViewHeightIndex, KEYTYPE_12KEY, false);
		keyList[KEYMODE_JA_HALF_NUMBER][0]   = new MyHeightKeyboard(parent, keyTable2[6], mInputViewHeightIndex, KEYTYPE_12KEY, false);

		/* 12-keys shift_on (landscape) */
		keyList = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_HALF_PHONE]    = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_PHONE];
		keyList[KEYMODE_JA_FULL_ALPHABET] = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_ALPHABET];
		keyList[KEYMODE_JA_FULL_NUMBER]   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_FULL_NUMBER];
		keyList[KEYMODE_JA_HALF_ALPHABET] = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_ALPHABET];;
		keyList[KEYMODE_JA_HALF_NUMBER]   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF][KEYMODE_JA_HALF_NUMBER];

		MyHeightKeyboard[][] keyListOn;
		keyList   = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_OFF];
		keyListOn = mKeyboard[LANG_JA][LANDSCAPE][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];
		keyList[KEYMODE_JA_FULL_NICO]     = mNicoKeyboard[NICO_MODE_FULL_HIRAGANA][NICO_SLIDE_MODE_TOP];
		keyList[KEYMODE_JA_FULL_NICO_KATAKANA]     = mNicoKeyboard[NICO_MODE_FULL_KATAKANA][NICO_SLIDE_MODE_TOP];
		keyList[KEYMODE_JA_HALF_NICO_KATAKANA]     = mNicoKeyboard[NICO_MODE_HALF_KATAKANA][NICO_SLIDE_MODE_TOP];
		keyListOn[KEYMODE_JA_FULL_NICO]   = mNicoKeyboard[NICO_MODE_FULL_HIRAGANA][NICO_SLIDE_MODE_A];
		keyListOn[KEYMODE_JA_FULL_NICO_KATAKANA]   = mNicoKeyboard[NICO_MODE_FULL_KATAKANA][NICO_SLIDE_MODE_A];
		keyListOn[KEYMODE_JA_HALF_NICO_KATAKANA]   = mNicoKeyboard[NICO_MODE_HALF_KATAKANA][NICO_SLIDE_MODE_A];
	}

	/**
	 * Convert the key code to the index of table
	 * <br>
	 * @param index     The key code
	 * @return          The index of the toggle table for input
	 */
	@Override public int getTableIndex(final int keyCode) {
		final int index =
			(keyCode == KEYCODE_JP12_1)     ?  0 :
				(keyCode == KEYCODE_JP12_2)     ?  1 :
					(keyCode == KEYCODE_JP12_3)     ?  2 :
						(keyCode == KEYCODE_JP12_4)     ?  3 :
							(keyCode == KEYCODE_JP12_5)     ?  4 :
								(keyCode == KEYCODE_JP12_6)     ?  5 :
									(keyCode == KEYCODE_JP12_7)     ?  6 :
										(keyCode == KEYCODE_JP12_8)     ?  7 :
											(keyCode == KEYCODE_JP12_9)     ?  8 :
												(keyCode == KEYCODE_JP12_0)     ?  9 :
													(keyCode == KEYCODE_JP12_SHARP) ? 10 :
														(keyCode == KEYCODE_JP12_ASTER) ? 11 :
															0;

		return index;
	}
	private int checkTableIndex(final int keyCode) {
		final int index =
			(keyCode == KEYCODE_JP12_1)     ?  0 :
				(keyCode == KEYCODE_JP12_2)     ?  1 :
					(keyCode == KEYCODE_JP12_3)     ?  2 :
						(keyCode == KEYCODE_JP12_4)     ?  3 :
							(keyCode == KEYCODE_JP12_5)     ?  4 :
								(keyCode == KEYCODE_JP12_6)     ?  5 :
									(keyCode == KEYCODE_JP12_7)     ?  6 :
										(keyCode == KEYCODE_JP12_8)     ?  7 :
											(keyCode == KEYCODE_JP12_9)     ?  8 :
												(keyCode == KEYCODE_JP12_0)     ?  9 :
													-1;
		return index;
	}

	/**
	 * Get the toggle table for input that is appropriate in current mode.
	 *
	 * @return      The toggle table for input
	 */
	private String[][] getCycleTable() {
		String[][] cycleTable = null;
		switch (mCurrentKeyMode) {
			case KEYMODE_JA_FULL_HIRAGANA:
				cycleTable = JP_FULL_HIRAGANA_CYCLE_TABLE;
				break;

			case KEYMODE_JA_FULL_KATAKANA:
				cycleTable = JP_FULL_KATAKANA_CYCLE_TABLE;
				break;

			case KEYMODE_JA_FULL_ALPHABET:
				cycleTable = JP_FULL_ALPHABET_CYCLE_TABLE;
				break;

			case KEYMODE_JA_FULL_NUMBER:
			case KEYMODE_JA_HALF_NUMBER:
				/* Because these modes belong to direct input group, No toggle table exists */
				break;

			case KEYMODE_JA_HALF_ALPHABET:
				cycleTable = JP_HALF_ALPHABET_CYCLE_TABLE;
				break;

			case KEYMODE_JA_HALF_KATAKANA:
				cycleTable = JP_HALF_KATAKANA_CYCLE_TABLE;
				break;

			case KEYMODE_JA_FULL_NICO:
			case KEYMODE_JA_FULL_NICO_KATAKANA:
			case KEYMODE_JA_HALF_NICO_KATAKANA:
				cycleTable = mCycleTable[mNicoKeyMode][mChangeAlphaBigMode];
				break;

			default:
				break;
		}
		return cycleTable;
	}

	/**
	 * Get the replace table that is appropriate in current mode.
	 *
	 * @return      The replace table
	 */
	private HashMap<String,String> getReplaceTable() {
		HashMap<String,String> hashTable = null;
		switch (mCurrentKeyMode) {
			case KEYMODE_JA_FULL_HIRAGANA:
				hashTable = JP_FULL_HIRAGANA_REPLACE_TABLE;
				break;
			case KEYMODE_JA_FULL_KATAKANA:
				hashTable = JP_FULL_KATAKANA_REPLACE_TABLE;
				break;

			case KEYMODE_JA_FULL_ALPHABET:
				hashTable = JP_FULL_ALPHABET_REPLACE_TABLE;
				break;

			case KEYMODE_JA_FULL_NUMBER:
			case KEYMODE_JA_HALF_NUMBER:
				/* Because these modes belong to direct input group, No replacing table exists */
				break;

			case KEYMODE_JA_HALF_ALPHABET:
				hashTable = JP_HALF_ALPHABET_REPLACE_TABLE;
				break;

			case KEYMODE_JA_FULL_NICO:
			case KEYMODE_JA_FULL_NICO_KATAKANA:
			case KEYMODE_JA_HALF_NICO_KATAKANA:
				hashTable = mSetupKeyboard.SetupReplaceTable(mTsuMode);

				break;

			case KEYMODE_JA_HALF_KATAKANA:
				hashTable = JP_HALF_KATAKANA_REPLACE_TABLE;
				break;

			default:
				break;
		}
		return hashTable;
	}

	/**
	 * Get the replace table that is appropriate in current mode.
	 *
	 * @return      The replace table
	 */
	private HashMap getReplaceDakutenTable() {
		return JP_FULL_DAKUTEN_REPLACE_TABLE;
	}

	/**
	 * Get the replace table that is appropriate in current mode.
	 *
	 * @return      The replace table
	 */
	private HashMap getReplaceHandakutenTable() {
		return JP_FULL_HANDAKUTEN_REPLACE_TABLE;
	}

	/**
	 * Set the status icon that is appropriate in current mode
	 */
	private void setStatusIcon() {
		int icon = 0;

		switch (mCurrentKeyMode) {
			case KEYMODE_JA_FULL_ALPHABET:
				icon = R.drawable.immodeic_full_alphabet;
				break;
			case KEYMODE_JA_FULL_NUMBER:
				icon = R.drawable.immodeic_full_number;
				break;
			case KEYMODE_JA_HALF_ALPHABET:
				icon = R.drawable.immodeic_half_alphabet;
				break;
			case KEYMODE_JA_HALF_NUMBER:
			case KEYMODE_JA_HALF_PHONE:
				icon = R.drawable.immodeic_half_number;
				break;
			case KEYMODE_JA_FULL_NICO:
			case KEYMODE_JA_FULL_NICO_KATAKANA:
			case KEYMODE_JA_HALF_NICO_KATAKANA:
				icon = mSetupKeyboard.SetupIcon();
				break;

			default:
				break;
		}

		mWnn.showStatusIcon(icon);
	}

	/**
	 * Get the shift key state from the editor.
	 * <br>
	 * @param editor    The editor information
	 * @return          The state id of the shift key (0:off, 1:on)
	 */
	protected int getShiftKeyState(final EditorInfo editor) {
		final InputConnection connection = mWnn.getCurrentInputConnection();
		if (connection != null) {
			final int caps = connection.getCursorCapsMode(editor.inputType);
			return (caps == 0) ? 0 : 1;
		} else {
			return 0;
		}
	}

	/**
	 * Set the shift key state from {@link EditorInfo}.
	 */
	private void setShiftByEditorInfo() {
		if (mEnableAutoCaps && (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)) {
			final int shift = getShiftKeyState(mWnn.getCurrentInputEditorInfo());

			mShiftOn = shift;
			changeKeyboard(getShiftChangeKeyboard(shift));
		}
	}

	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#setHardKeyboardHidden */
	@Override public void setHardKeyboardHidden(final boolean hidden, final boolean hardkey) {
		if (mWnn != null) {
			if (!hidden) {
				mWnn.onEvent(mEventChangeModeQwerty);
			}

			if (mHardKeyboardHidden != hidden) {
				if ((mLimitedKeyMode != null) || (
						(mCurrentKeyMode != KEYMODE_JA_FULL_NICO) &&
						(mCurrentKeyMode != KEYMODE_JA_FULL_NICO_KATAKANA) &&
						(mCurrentKeyMode != KEYMODE_JA_HALF_NICO_KATAKANA) &&
						(mCurrentKeyMode != KEYMODE_JA_HALF_ALPHABET)
				)) {
					mLastInputType = InputType.TYPE_NULL;
					if (mWnn.isInputViewShown()) {
						setDefaultKeyboard();
					}
				}
			}
		}
		super.setHardKeyboardHidden(hidden, hardkey);
	}

	/**
	 * Change the key-mode to the allowed one which is restricted
	 *  by the text input field or the type of the keyboard.
	 * @param keyMode The key-mode
	 * @return the key-mode allowed
	 */
	private int filterKeyMode(final int keyMode) {
		int targetMode = keyMode;
		final int[] limits = mLimitedKeyMode;

		/*
		if (!mHardKeyboardHidden) { // for hardware keyboard
			if ((targetMode != KEYMODE_JA_FULL_NICO) && (targetMode != KEYMODE_JA_HALF_ALPHABET)) {
				Locale locale = Locale.getDefault();
				int keymode = KEYMODE_JA_HALF_ALPHABET;
				if (locale.getLanguage().equals(Locale.JAPANESE.getLanguage())) {
					switch (targetMode) {
					case KEYMODE_JA_FULL_NICO:
						// hiromitsu-s!!! 2009-09-23 12:47:08
						//keymode = KEYMODE_JA_FULL_NICO;
						break;
					default:
						// half-alphabet
						break;
					}
				}
				targetMode = keymode;
			}
		}
		 */

		/* restrict by the type of the text field */
		if (limits != null) {
			boolean hasAccepted = false;
			boolean hasRequiredChange = true;
			final int size = limits.length;
			final int nowMode = mCurrentKeyMode;

			for (int i = 0; i < size; i++) {
				if (targetMode == limits[i]) {
					hasAccepted = true;
					break;
				}
				if (nowMode == limits[i]) {
					hasRequiredChange = false;
				}
			}

			if (!hasAccepted) {
				if (hasRequiredChange) {
					targetMode = mLimitedKeyMode[0];
				} else {
					targetMode = INVALID_KEYMODE;
				}
			}
		}

		return targetMode;
	}

	@Override public String[] convertFlickToKeyString(int flickdir) {
		if (
				(mCurrentKeyMode == KEYMODE_JA_FULL_NICO) ||
				(mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) ||
				(mCurrentKeyMode == KEYMODE_JA_HALF_NICO_KATAKANA)
		) {
			return convertFlickToKeyStringNico(flickdir);
		}

		final int col = getTableIndex(mPrevInputKeyCode);
		final int row = flickdir;
		String[][] cycleTable = null;
		if (mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) {
			cycleTable = JP_FLICK_FULL_HIRAGANA_CYCLE_TABLE[col];
		}
		else if (mCurrentKeyMode == KEYMODE_JA_FULL_KATAKANA) {
			cycleTable = JP_FLICK_FULL_KATAKANA_CYCLE_TABLE[col];
		}
		else if (mCurrentKeyMode == KEYMODE_JA_HALF_KATAKANA) {
			cycleTable = JP_FLICK_HALF_KATAKANA_CYCLE_TABLE[col];
		}
		else if (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET) {
			cycleTable = JP_FLICK_HALF_ALPHABET_CYCLE_TABLE[col];
		}
		else if (mCurrentKeyMode == KEYMODE_JA_FULL_ALPHABET) {
			cycleTable = JP_FLICK_FULL_ALPHABET_CYCLE_TABLE[col];
		}
		if (null != cycleTable) {
			return cycleTable[row];
		}
		return null;
	}

	/*****************************************
	 * onkey (normal)
	 */
	/** @see net.gorry.android.input.nicownng.DefaultSoftKeyboard#onKey */
	@Override public void onKey(final int primaryCode2, final int[] keyCodes) {
		int primaryCode = primaryCode2;
		boolean changeShiftLock = true;

		if (mDisableKeyInput) {
			return;
		}

		if (
				(mCurrentKeyMode == KEYMODE_JA_FULL_NICO) ||
				(mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) ||
				(mCurrentKeyMode == KEYMODE_JA_HALF_NICO_KATAKANA)
		) {
			if (true == onKeyNico(primaryCode, keyCodes)) {
				/* update shift key's state */
				if (!mCapsLock && (primaryCode != DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT)) {
					setShiftByEditorInfo();
				}
				return;
			}
		}

		final int getFlickCode = checkFlickKeyCode(true, false);
		if (getFlickCode >= 0) {
			// get flick keydata
			final String[] keyString = convertFlickToKeyString(getFlickCode);
			if (null != keyString) {
				mWnn.onEvent(mEventTouchOtherKey);
				mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.TOGGLE_CHAR, keyString));
				mNicoFirst = false;
				mNicoFlick = false;
				return;
			}
		} else if (getFlickCode < -1) {
			switch (primaryCode) {
			case KEYCODE_JP12_CONVPREDICT:
			case KEYCODE_JP12_CONVPREDICT_BACKWARD:
				break;
			default:
				primaryCode = getFlickCode;
			}
		}

		switch (primaryCode) {
			case KEYCODE_JP12_TOGGLE_MODE:
			case KEYCODE_QWERTY_TOGGLE_MODE:
				if (!mNoInput) {
					final NicoWnnGJAJP wnn = NicoWnnGJAJP.getInstance();
					wnn.changeKanaDirectPhase();
					break;
				}
				if (!mIsInputTypeNull) {
					nextKeyMode();
				}
				break;

			case DefaultSoftKeyboard.KEYCODE_QWERTY_BACKSPACE:
			case KEYCODE_JP12_BACKSPACE:
				mWnn.onEvent(mEventInputKeyDel);
				changeShiftLock = false;
				break;

			case DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT:
				toggleShiftLock(1);
				changeShiftLock = false;
				break;

			case DefaultSoftKeyboard.KEYCODE_QWERTY_ALT:
				processAltKey();
				break;

			case KEYCODE_QWERTY_ENTER:
			case KEYCODE_JP12_ENTER:
				mWnn.onEvent(mEventInputEnter);
				break;

			case KEYCODE_JP12_REVERSE:
				if (!mNoInput) {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.TOGGLE_REVERSE_CHAR, mCurrentCycleTable));
				}
				break;

			case KEYCODE_QWERTY_KBD:
				changeKeyboardType(KEYBOARD_12KEY);
				break;

			case KEYCODE_JP12_KBD:
				changeKeyboardType(KEYBOARD_QWERTY);
				break;

			case KEYCODE_JP12_EMOJI:
			case KEYCODE_QWERTY_EMOJI:
				commitText();
				mWnn.onEvent(mEventChangeModeSymbol);
				break;

			case KEYCODE_JP12_1:
			case KEYCODE_JP12_2:
			case KEYCODE_JP12_3:
			case KEYCODE_JP12_4:
			case KEYCODE_JP12_5:
			case KEYCODE_JP12_6:
			case KEYCODE_JP12_7:
			case KEYCODE_JP12_8:
			case KEYCODE_JP12_9:
			case KEYCODE_JP12_0:
			case KEYCODE_JP12_SHARP:
				/* Processing to input by ten key */
				if (mInputType == INPUT_TYPE_INSTANT) {
					/* Send a input character directly if instant input type is selected */
					commitText();
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
				} else {
					if ((mPrevInputKeyCode != primaryCode)) {
						mWnn.onEvent(mEventTouchOtherKey);
						if ((mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)
								&& (primaryCode == KEYCODE_JP12_SHARP)) {
							/* Commit text by symbol character (',' '.') when alphabet input mode is selected */
							commitText();
						}
					}

					/* Convert the key code to the table index and send the toggle event with the table index */
					final String[][] cycleTable = getCycleTable();
					if (cycleTable == null) {
						Log.e("NicoWnnG", "not founds cycle table");
					} else {
						final int index = getTableIndex(primaryCode);
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.TOGGLE_CHAR, cycleTable[index]));
						mCurrentCycleTable = cycleTable[index];
					}
					mPrevInputKeyCode = primaryCode;
				}
				break;

			case KEYCODE_JP12_ASTER:
				if (mInputType == INPUT_TYPE_INSTANT) {
					commitText();
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
				} else {
					if (!mNoInput) {
						/* Processing to toggle Dakuten, Handakuten, and capital */
						final HashMap<String,String> replaceTable = getReplaceTable();
						if (replaceTable == null) {
							Log.e("NicoWnnG", "not founds replace table");
						} else {
							mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.REPLACE_CHAR, replaceTable));
							mPrevInputKeyCode = primaryCode;
						}
					} else {
						mWnn.onEvent(mEventInputEnter);
					}
				}
				break;

			case KEYCODE_SWITCH_FULL_HIRAGANA:
				/* Change mode to Full width hiragana */
				changeKeyMode(KEYMODE_JA_FULL_NICO);
				break;

			case KEYCODE_SWITCH_FULL_KATAKANA:
				/* Change mode to Full width katakana */
				changeKeyMode(KEYMODE_JA_FULL_NICO_KATAKANA);
				break;

			case KEYCODE_SWITCH_FULL_ALPHABET:
				/* Change mode to Full width alphabet */
				changeKeyMode(KEYMODE_JA_FULL_ALPHABET);
				break;

			case KEYCODE_SWITCH_FULL_NUMBER:
				/* Change mode to Full width numeric */
				changeKeyMode(KEYMODE_JA_FULL_NUMBER);
				break;

			case KEYCODE_SWITCH_HALF_KATAKANA:
				/* Change mode to Half width katakana */
				changeKeyMode(KEYMODE_JA_HALF_NICO_KATAKANA);
				break;

			case KEYCODE_SWITCH_HALF_ALPHABET:
				/* Change mode to Half width alphabet */
				changeKeyMode(KEYMODE_JA_HALF_ALPHABET);
				break;

			case KEYCODE_SWITCH_HALF_NUMBER:
				/* Change mode to Half width numeric */
				changeKeyMode(KEYMODE_JA_HALF_NUMBER);
				break;

			case KEYCODE_SWITCH_FULL_NICO:
				/* Change mode to Full width nicotouch */
				changeKeyMode(KEYMODE_JA_FULL_NICO);
				break;

			case KEYCODE_SWITCH_FULL_NICO_KATAKANA:
				/* Change mode to Full width nicotouch katakana */
				changeKeyMode(KEYMODE_JA_FULL_NICO_KATAKANA);
				break;

			case KEYCODE_SWITCH_HALF_NICO_KATAKANA:
				/* Change mode to Half width nicotouch katakana */
				changeKeyMode(KEYMODE_JA_HALF_NICO_KATAKANA);
				break;

			case KEYCODE_SELECT_CASE:
				final int shifted = (mShiftOn == 0) ? 1 : 0;
				final MyHeightKeyboard newKeyboard = getShiftChangeKeyboard(shifted);
				if (newKeyboard != null) {
					mShiftOn = shifted;
					changeKeyboard(newKeyboard);
				}
				break;

			case KEYCODE_JP12_SPACE:
				if (NicoWnnGJAJP.getInstance().isRenbun()||NicoWnnGJAJP.getInstance().isPredict()) {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, ' '));
				} else if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				} else if (NicoWnnGJAJP.getInstance().candidatesViewManagerisShown()) {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
				}
				else {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, ' '));
				}
				break;

			case KEYCODE_JP12_ZEN_SPACE:
				if (NicoWnnGJAJP.getInstance().isRenbun()||NicoWnnGJAJP.getInstance().isPredict()) {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
				} else if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				}
				else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) && !mNoInput) {
					mWnn.onEvent(mEventConvert);
				} else if (NicoWnnGJAJP.getInstance().candidatesViewManagerisShown()) {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
				}
				else {
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, '\u3000'));
				}
				break;

			case KEYCODE_EISU_KANA:
				mWnn.onEvent(mEventChangeModeEisuKana);
				break;

			case KEYCODE_JP12_CLOSE:
				mWnn.onEvent(mEventInputBack);
				break;

			case KEYCODE_JP12_LEFT:
				mWnn.onEvent(mEventInputDpadLeft);
				changeShiftLock = false;
				break;

			case KEYCODE_JP12_RIGHT:
				mWnn.onEvent(mEventInputDpadRight);
				changeShiftLock = false;
				break;

			case KEYCODE_JP12_UP:
				mWnn.onEvent(mEventInputDpadUp);
				changeShiftLock = false;
				break;

			case KEYCODE_JP12_DOWN:
				mWnn.onEvent(mEventInputDpadDown);
				changeShiftLock = false;
				break;

			case KEYCODE_NOP:
				break;

			case KEYCODE_PREFERENCE_SETTING:
				if (mNicoWnnG != null) {
					try {
						mNicoWnnG.openPreferenceSetting();
					} catch (final Exception e) {
						//
					}
				}
				break;

			case KEYCODE_SHOW_HELP:
				if (mNicoWnnG != null) {
					//try {
					mNicoWnnG.openHelp();
					//} catch (final Exception e) {
					//
					//}
				}
				break;

			case KEYCODE_MUSHROOM:
				if (mWnn != null) {
					final String str = mWnn.getComposingText(ComposingText.LAYER2);
					mWnn.onEvent(mEventInputBack);
					mWnn.invokeMushroom(str);
				}
				break;

			case KEYCODE_JP12_CONVPREDICT:
				mWnn.onEvent(mEventConvertPredict);
				break;

			case KEYCODE_JP12_CONVPREDICT_BACKWARD:
				mWnn.onEvent(mEventConvertPredictBackward);
				break;

			default:
				if (primaryCode >= 0) {
					if (mKeyboardView.isShifted()) {
						primaryCode = Character.toUpperCase(primaryCode);
					}
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, (char)primaryCode));
				}
				break;
		}

		if (changeShiftLock) {
			toggleShiftLock(2);
		}

		/* update shift key's state */
		if (!mCapsLock && (primaryCode != DefaultSoftKeyboard.KEYCODE_QWERTY_SHIFT)) {
			setShiftByEditorInfo();
		}
	}

	public String[] convertFlickToKeyStringNico(int flickdir) {
		final int col = getTableIndex(mPrevInputKeyCode);
		final int row = flickdir;
		final String[][] cycleTable = getCycleTable();

		if (null != cycleTable) {
			return cycleTable[col * 10 + row];
		}
		return null;
	}

	/*****************************************
	 * onkey nicotouch
	 */
	private boolean onKeyNico(final int primaryCode2, final int[] keyCodes) {
		MyHeightKeyboard newKeyboard = null;
		boolean retcode = false;
		int primaryCode = primaryCode2;

		// �������[�v�΍�
		if (mRecursiveOnKeyNico > 4) return true;
		mRecursiveOnKeyNico++;

		final int getFlickCode = checkFlickKeyCode(false, false);
		if (getFlickCode >= 0) {
			// get flick keydata
			final String keyString[] = convertFlickToKeyString(getFlickCode);
			if (null != keyString) {
				mWnn.onEvent(mEventTouchOtherKey);
				if (keyString[0].equals("\u309b")) {
					retcode = onKeyNico(KEYCODE_DAKUTEN, keyCodes);
					mRecursiveOnKeyNico--;
					return retcode;
				}
				if (keyString[0].equals("\u309c")) {
					retcode = onKeyNico(KEYCODE_HANDAKUTEN, keyCodes);
					mRecursiveOnKeyNico--;
					return retcode;
				}
				mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.TOGGLE_CHAR, keyString));
			}
			mNicoFirst = false;
			mNicoFlick = false;
			mRecursiveOnKeyNico--;
			return true;
		} else if (getFlickCode < -1) {
			switch (primaryCode) {
			case KEYCODE_JP12_CONVPREDICT:
			case KEYCODE_JP12_CONVPREDICT_BACKWARD:
				break;
			default:
				primaryCode = getFlickCode;
			}
		}

		switch (primaryCode) {
			case DefaultSoftKeyboard.KEYCODE_QWERTY_BACKSPACE:
			case KEYCODE_JP12_BACKSPACE:
				if (mNicoFirst == true) {
					resetNicoKeyboard();
				}
				else {
					mWnn.onEvent(mEventInputKeyDel);
				}
				retcode = true;
				break;
			case KEYCODE_QWERTY_ENTER:
			case KEYCODE_JP12_ENTER:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventInputEnter);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_REVERSE:
				if (mNicoFirst == true) {
					resetNicoKeyboard();
				}
				//mWnn.mashUp();
				retcode = true;
				break;

			case KEYCODE_QWERTY_KBD:
			case KEYCODE_JP12_KBD:
				resetNicoKeyboard();
				break;

			case KEYCODE_JP12_EMOJI:
			case KEYCODE_QWERTY_EMOJI:
				if (mNicoFirst == false) {
					commitText();
					mWnn.onEvent(mEventChangeModeSymbol);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_SHARP:
				if ((mNicoFirst == false) && mNoInput) {
					commitText();
					mWnn.onEvent(mEventChangeModeDocomo);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_1:
			case KEYCODE_JP12_2:
			case KEYCODE_JP12_3:
			case KEYCODE_JP12_4:
			case KEYCODE_JP12_5:
			case KEYCODE_JP12_6:
			case KEYCODE_JP12_7:
			case KEYCODE_JP12_8:
			case KEYCODE_JP12_9:
			case KEYCODE_JP12_0:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventTouchOtherKey);
					if (NICOFLICK_NONE == mFlickNicoInput) {
						mPrevInputKeyCode = primaryCode;
					}
					else{
						if (-1 == checkTableIndex(mPrevInputKeyCode)) {
							mPrevInputKeyCode = primaryCode;
						}
					}
					mNicoFirst = true;

					/* change keymap */
					final int index = getTableIndex(mPrevInputKeyCode);
					final MyHeightKeyboard[][] keyList = mKeyboard[LANG_JA][mDisplayMode][KEYBOARD_12KEY][KEYBOARD_SHIFT_ON];

					// keyList[KEYMODE_JA_FULL_NICO] = mNicoKeyboard[mNicoKeyMode][index+1];
					switch (mCurrentKeyMode) {
						case KEYMODE_JA_FULL_NICO:
						case KEYMODE_JA_FULL_NICO_KATAKANA:
						case KEYMODE_JA_HALF_NICO_KATAKANA:
							keyList[mCurrentKeyMode] = mNicoKeyboard[mNicoKeyMode][index+1];
					}
					if (false == mNoFlipScreen) {
						newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_ON);
						mShiftOn = KEYBOARD_SHIFT_ON;
						changeKeyboard(newKeyboard);
					}
				}
				else{
					if (false == mNoFlipScreen) {
						newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
						mShiftOn = KEYBOARD_SHIFT_OFF;
						changeKeyboard(newKeyboard);
					}
					final int col = getTableIndex(mPrevInputKeyCode);
					final int row = getTableIndex(primaryCode);
					final String[][] cycleTable = getCycleTable();
					if (cycleTable == null) {
						Log.e("NicoWnnG", "not founds cycle table");
					}
					else{
						if (cycleTable[col * 10 + row][0].equals("\u309b")) {
							retcode = onKeyNico(KEYCODE_DAKUTEN, keyCodes);
							mRecursiveOnKeyNico--;
							return retcode;
						}
						if (cycleTable[col * 10 + row][0].equals("\u309c")) {
							retcode = onKeyNico(KEYCODE_HANDAKUTEN, keyCodes);
							mRecursiveOnKeyNico--;
							return retcode;
						}
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.TOGGLE_CHAR, cycleTable[col * 10 + row]));
					}
					mNicoFirst = false;
					mNicoFlick = false;
				}
				retcode = true;
				break;

			case KEYCODE_JP12_ASTER:
				if (mNicoFirst == true) {
					resetNicoKeyboard();
				} else{
					if (!mNoInput) {
						/* Processing to toggle Dakuten, Handakuten, and capital */
						final HashMap<String,String> replaceTable = getReplaceTable();
						if (replaceTable == null) {
							Log.e("NicoWnnG", "not founds replace table");
						} else {
							mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.REPLACE_CHAR, replaceTable));
							mPrevInputKeyCode = primaryCode;
						}
					} else {
						mWnn.onEvent(mEventInputEnter);
					}
				}
				retcode = true;
				break;

			case KEYCODE_DAKUTEN:
				if (mInputType == INPUT_TYPE_INSTANT) {
					commitText();
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
				} else {
					char c = 0x309b;
					switch (mCurrentKeyMode) {
						case KEYMODE_JA_HALF_ALPHABET:
						case KEYMODE_JA_HALF_NUMBER:
						case KEYMODE_JA_HALF_PHONE:
						case KEYMODE_JA_HALF_KATAKANA:
						case KEYMODE_JA_HALF_NICO_KATAKANA:
							c = 0xff9e;
							break;
					}
					if (!mNoInput) {
						/* Processing to toggle Dakuten, Handakuten, and capital */
						final HashMap replaceTable = getReplaceDakutenTable();
						if (replaceTable == null) {
							Log.e("NicoWnnG", "not founds replace table");
						} else {
							final boolean f = mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.REPLACE_CHAR, replaceTable));
							if (!f) {
								mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, c));
							}
						}
					} else {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, c));
					}
					mWnn.onEvent(mEventResetStatus);
					if (false == mNoFlipScreen) {
						newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
						mShiftOn = KEYBOARD_SHIFT_OFF;
						changeKeyboard(newKeyboard);
					}
					mPrevInputKeyCode = 0;
					mNicoFirst = false;
					mNicoFlick = false;
				}
				retcode = true;
				break;

			case KEYCODE_HANDAKUTEN:
				if (mInputType == INPUT_TYPE_INSTANT) {
					commitText();
					mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, mCurrentInstantTable[getTableIndex(primaryCode)]));
				} else {
					char c = 0x309c;
					switch (mCurrentKeyMode) {
						case KEYMODE_JA_HALF_ALPHABET:
						case KEYMODE_JA_HALF_NUMBER:
						case KEYMODE_JA_HALF_PHONE:
						case KEYMODE_JA_HALF_KATAKANA:
						case KEYMODE_JA_HALF_NICO_KATAKANA:
							c = 0xff9f;
							break;
					}
					if (!mNoInput) {
						/* Processing to toggle Dakuten, Handakuten, and capital */
						final HashMap replaceTable = getReplaceHandakutenTable();
						if (replaceTable == null) {
							Log.e("NicoWnnG", "not founds replace table");
						} else {
							final boolean f = mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.REPLACE_CHAR, replaceTable));
							if (!f) {
								mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, c));
							}
						}
					} else {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, c));
					}
					mWnn.onEvent(mEventResetStatus);
					if (false == mNoFlipScreen) {
						newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
						mShiftOn = KEYBOARD_SHIFT_OFF;
						changeKeyboard(newKeyboard);
					}
					mPrevInputKeyCode = 0;
					mNicoFirst = false;
					mNicoFlick = false;
				}
				retcode = true;
				break;

			case KEYCODE_JP12_SPACE:
				if (mNicoFirst == false) {
					if (NicoWnnGJAJP.getInstance().isRenbun()||NicoWnnGJAJP.getInstance().isPredict()) {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, ' '));
					} else if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					}
					else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					}
					else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					} else if (NicoWnnGJAJP.getInstance().candidatesViewManagerisShown()) {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
					}
					else {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, ' '));
					}
				}
				retcode = true;
				break;

			case KEYCODE_JP12_ZEN_SPACE:
				if (mNicoFirst == false) {
					if (NicoWnnGJAJP.getInstance().isRenbun()||NicoWnnGJAJP.getInstance().isPredict()) {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
					} else if ((mCurrentKeyMode == KEYMODE_JA_FULL_HIRAGANA) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					}
					else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					}
					else if ((mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) && !mNoInput) {
						mWnn.onEvent(mEventConvert);
					} else if (NicoWnnGJAJP.getInstance().candidatesViewManagerisShown()) {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_SOFT_KEY, new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE)));
					}
					else {
						mWnn.onEvent(new NicoWnnGEvent(NicoWnnGEvent.INPUT_CHAR, '\u3000'));
					}
				}
				retcode = true;
				break;

			case KEYCODE_EISU_KANA:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventChangeModeEisuKana);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_CLOSE:
				mWnn.onEvent(mEventInputBack);
				retcode = true;
				break;

			case KEYCODE_JP12_LEFT:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventInputDpadLeft);
				}
				retcode = true;
				break;
			case KEYCODE_JP12_RIGHT:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventInputDpadRight);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_UP:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventInputDpadUp);
				}
				retcode = true;
				break;

			case KEYCODE_JP12_DOWN:
				if (mNicoFirst == false) {
					mWnn.onEvent(mEventInputDpadDown);
				}
				retcode = true;
				break;

		}
		mRecursiveOnKeyNico--;
		return retcode;
	} // onKeyNico
	/*
	 * reset nicotouch keyboard
	 */
	@Override public void resetNicoKeyboard() {
		final MyHeightKeyboard newKeyboard = getShiftChangeKeyboard(KEYBOARD_SHIFT_OFF);
		if (newKeyboard != null) {
			mShiftOn = KEYBOARD_SHIFT_OFF;
			changeKeyboard(newKeyboard);
		}
		mNicoFirst = false;
		mNicoFlick = false;
	} // resetNicoKeyboard

	/**
	 */
	@Override public void onPress(final int primaryCode) {
		super.onPress(primaryCode);
	}
	/**
	 */
	@Override public void onRelease(final int primaryCode) {
		super.onRelease(primaryCode);
	} // onRelease
	/**
	 */
	@Override public int convertModeFlick(final int prev, final int key) {
		if (mCurrentKeyMode == KEYMODE_JA_FULL_NICO) {
			return mSetupKeyboard.GetFlickKeyCode(prev, key);
		}
		if (mCurrentKeyMode == KEYMODE_JA_FULL_NICO_KATAKANA) {
			return mSetupKeyboard.GetFlickKeyCode(prev, key);
		}
		if (mCurrentKeyMode == KEYMODE_JA_HALF_NICO_KATAKANA) {
			return mSetupKeyboard.GetFlickKeyCode(prev, key);
		}
		if (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET) {
			return flickAlphabetChangeMap[prev][key];
		}
		if (mCurrentKeyMode == KEYMODE_JA_FULL_ALPHABET) {
			return flickAlphabetChangeMap[prev][key];
		}
		return -1;
	}



	/** Toggle cycle table for full-width HIRAGANA */
	private static final String[][] JP_FULL_HIRAGANA_CYCLE_TABLE = {
		{"\u3042", "\u3044", "\u3046", "\u3048", "\u304a", "\u3041", "\u3043", "\u3045", "\u3047", "\u3049"},
		{"\u304b", "\u304d", "\u304f", "\u3051", "\u3053"},
		{"\u3055", "\u3057", "\u3059", "\u305b", "\u305d"},
		{"\u305f", "\u3061", "\u3064", "\u3066", "\u3068", "\u3063"},
		{"\u306a", "\u306b", "\u306c", "\u306d", "\u306e"},
		{"\u306f", "\u3072", "\u3075", "\u3078", "\u307b"},
		{"\u307e", "\u307f", "\u3080", "\u3081", "\u3082"},
		{"\u3084", "\u3086", "\u3088", "\u3083", "\u3085", "\u3087"},
		{"\u3089", "\u308a", "\u308b", "\u308c", "\u308d"},
		{"\u308f", "\u3092", "\u3093", "\u308e", "\u30fc"},
		{"\u3001", "\u3002", "\uff1f", "\uff01", "\u30fb", "\u3000"},
	};

	/** Replace table for full-width HIRAGANA */
	private static final HashMap<String, String> JP_FULL_HIRAGANA_REPLACE_TABLE = new HashMap<String, String>() {{
		put("\u3042", "\u3041"); put("\u3044", "\u3043"); put("\u3046", "\u3045"); put("\u3048", "\u3047"); put("\u304a", "\u3049");
		put("\u3041", "\u3042"); put("\u3043", "\u3044"); put("\u3045", "\u30f4"); put("\u3047", "\u3048"); put("\u3049", "\u304a");
		put("\u304b", "\u304c"); put("\u304d", "\u304e"); put("\u304f", "\u3050"); put("\u3051", "\u3052"); put("\u3053", "\u3054");
		put("\u304c", "\u304b"); put("\u304e", "\u304d"); put("\u3050", "\u304f"); put("\u3052", "\u3051"); put("\u3054", "\u3053");
		put("\u3055", "\u3056"); put("\u3057", "\u3058"); put("\u3059", "\u305a"); put("\u305b", "\u305c"); put("\u305d", "\u305e");
		put("\u3056", "\u3055"); put("\u3058", "\u3057"); put("\u305a", "\u3059"); put("\u305c", "\u305b"); put("\u305e", "\u305d");
		put("\u305f", "\u3060"); put("\u3061", "\u3062"); put("\u3064", "\u3063"); put("\u3066", "\u3067"); put("\u3068", "\u3069");
		put("\u3060", "\u305f"); put("\u3062", "\u3061"); put("\u3063", "\u3065"); put("\u3067", "\u3066"); put("\u3069", "\u3068");
		put("\u3065", "\u3064"); put("\u30f4", "\u3046");
		put("\u306f", "\u3070"); put("\u3072", "\u3073"); put("\u3075", "\u3076"); put("\u3078", "\u3079"); put("\u307b", "\u307c");
		put("\u3070", "\u3071"); put("\u3073", "\u3074"); put("\u3076", "\u3077"); put("\u3079", "\u307a"); put("\u307c", "\u307d");
		put("\u3071", "\u306f"); put("\u3074", "\u3072"); put("\u3077", "\u3075"); put("\u307a", "\u3078"); put("\u307d", "\u307b");
		put("\u3084", "\u3083"); put("\u3086", "\u3085"); put("\u3088", "\u3087");
		put("\u3083", "\u3084"); put("\u3085", "\u3086"); put("\u3087", "\u3088");
		put("\u308f", "\u308e");
		put("\u308e", "\u308f");
		put("\u309b", "\u309c");
		put("\u309c", "\u309b");
	}};

	/** Toggle cycle table for full-width KATAKANA */
	private static final String[][] JP_FULL_KATAKANA_CYCLE_TABLE = {
		{"\u30a2", "\u30a4", "\u30a6", "\u30a8", "\u30aa", "\u30a1", "\u30a3",
			"\u30a5", "\u30a7", "\u30a9"},
			{"\u30ab", "\u30ad", "\u30af", "\u30b1", "\u30b3"},
			{"\u30b5", "\u30b7", "\u30b9", "\u30bb", "\u30bd"},
			{"\u30bf", "\u30c1", "\u30c4", "\u30c6", "\u30c8", "\u30c3"},
			{"\u30ca", "\u30cb", "\u30cc", "\u30cd", "\u30ce"},
			{"\u30cf", "\u30d2", "\u30d5", "\u30d8", "\u30db"},
			{"\u30de", "\u30df", "\u30e0", "\u30e1", "\u30e2"},
			{"\u30e4", "\u30e6", "\u30e8", "\u30e3", "\u30e5", "\u30e7"},
			{"\u30e9", "\u30ea", "\u30eb", "\u30ec", "\u30ed"},
			{"\u30ef", "\u30f2", "\u30f3", "\u30ee", "\u30fc"},
			{"\u3001", "\u3002", "\uff1f", "\uff01", "\u30fb", "\u3000"}
	};

	/** Replace table for full-width KATAKANA */
	private static final HashMap<String,String> JP_FULL_KATAKANA_REPLACE_TABLE = new HashMap<String,String>() {{
		put("\u30a2", "\u30a1"); put("\u30a4", "\u30a3"); put("\u30a6", "\u30a5"); put("\u30a8", "\u30a7"); put("\u30aa", "\u30a9");
		put("\u30a1", "\u30a2"); put("\u30a3", "\u30a4"); put("\u30a5", "\u30f4"); put("\u30a7", "\u30a8"); put("\u30a9", "\u30aa");
		put("\u30ab", "\u30ac"); put("\u30ad", "\u30ae"); put("\u30af", "\u30b0"); put("\u30b1", "\u30b2"); put("\u30b3", "\u30b4");
		put("\u30ac", "\u30ab"); put("\u30ae", "\u30ad"); put("\u30b0", "\u30af"); put("\u30b2", "\u30b1"); put("\u30b4", "\u30b3");
		put("\u30b5", "\u30b6"); put("\u30b7", "\u30b8"); put("\u30b9", "\u30ba"); put("\u30bb", "\u30bc"); put("\u30bd", "\u30be");
		put("\u30b6", "\u30b5"); put("\u30b8", "\u30b7"); put("\u30ba", "\u30b9"); put("\u30bc", "\u30bb"); put("\u30be", "\u30bd");
		put("\u30bf", "\u30c0"); put("\u30c1", "\u30c2"); put("\u30c4", "\u30c3"); put("\u30c6", "\u30c7"); put("\u30c8", "\u30c9");
		put("\u30c0", "\u30bf"); put("\u30c2", "\u30c1"); put("\u30c3", "\u30c5"); put("\u30c7", "\u30c6"); put("\u30c9", "\u30c8");
		put("\u30c5", "\u30c4"); put("\u30f4", "\u30a6");
		put("\u30cf", "\u30d0"); put("\u30d2", "\u30d3"); put("\u30d5", "\u30d6"); put("\u30d8", "\u30d9"); put("\u30db", "\u30dc");
		put("\u30d0", "\u30d1"); put("\u30d3", "\u30d4"); put("\u30d6", "\u30d7"); put("\u30d9", "\u30da"); put("\u30dc", "\u30dd");
		put("\u30d1", "\u30cf"); put("\u30d4", "\u30d2"); put("\u30d7", "\u30d5"); put("\u30da", "\u30d8"); put("\u30dd", "\u30db");
		put("\u30e4", "\u30e3"); put("\u30e6", "\u30e5"); put("\u30e8", "\u30e7");
		put("\u30e3", "\u30e4"); put("\u30e5", "\u30e6"); put("\u30e7", "\u30e8");
		put("\u30ef", "\u30ee");
		put("\u30ee", "\u30ef");
	}};

	/** Toggle cycle table for half-width KATAKANA */
	private static final String[][] JP_HALF_KATAKANA_CYCLE_TABLE = {
		{"\uff71", "\uff72", "\uff73", "\uff74", "\uff75", "\uff67", "\uff68", "\uff69", "\uff6a", "\uff6b"},
		{"\uff76", "\uff77", "\uff78", "\uff79", "\uff7a"},
		{"\uff7b", "\uff7c", "\uff7d", "\uff7e", "\uff7f"},
		{"\uff80", "\uff81", "\uff82", "\uff83", "\uff84", "\uff6f"},
		{"\uff85", "\uff86", "\uff87", "\uff88", "\uff89"},
		{"\uff8a", "\uff8b", "\uff8c", "\uff8d", "\uff8e"},
		{"\uff8f", "\uff90", "\uff91", "\uff92", "\uff93"},
		{"\uff94", "\uff95", "\uff96", "\uff6c", "\uff6d", "\uff6e"},
		{"\uff97", "\uff98", "\uff99", "\uff9a", "\uff9b"},
		{"\uff9c", "\uff66", "\uff9d", "\uff70"},
		{"\uff64", "\uff61", "?", "!", "\uff65", " "},
	};

	/** Replace table for half-width KATAKANA */
	private static final HashMap<String,String> JP_HALF_KATAKANA_REPLACE_TABLE = new HashMap<String,String>() {{
		put("\uff71", "\uff67");  put("\uff72", "\uff68");  put("\uff73", "\uff69");  put("\uff74", "\uff6a");  put("\uff75", "\uff6b");
		put("\uff67", "\uff71");  put("\uff68", "\uff72");  put("\uff69", "\uff73\uff9e");  put("\uff6a", "\uff74");  put("\uff6b", "\uff75");
		put("\uff76", "\uff76\uff9e"); put("\uff77", "\uff77\uff9e"); put("\uff78", "\uff78\uff9e"); put("\uff79", "\uff79\uff9e"); put("\uff7a", "\uff7a\uff9e");
		put("\uff76\uff9e", "\uff76"); put("\uff77\uff9e", "\uff77"); put("\uff78\uff9e", "\uff78"); put("\uff79\uff9e", "\uff79"); put("\uff7a\uff9e", "\uff7a");
		put("\uff7b", "\uff7b\uff9e"); put("\uff7c", "\uff7c\uff9e"); put("\uff7d", "\uff7d\uff9e"); put("\uff7e", "\uff7e\uff9e"); put("\uff7f", "\uff7f\uff9e");
		put("\uff7b\uff9e", "\uff7b"); put("\uff7c\uff9e", "\uff7c"); put("\uff7d\uff9e", "\uff7d"); put("\uff7e\uff9e", "\uff7e"); put("\uff7f\uff9e", "\uff7f");
		put("\uff80", "\uff80\uff9e"); put("\uff81", "\uff81\uff9e"); put("\uff82", "\uff6f");  put("\uff83", "\uff83\uff9e"); put("\uff84", "\uff84\uff9e");
		put("\uff80\uff9e", "\uff80"); put("\uff81\uff9e", "\uff81"); put("\uff6f", "\uff82\uff9e"); put("\uff83\uff9e", "\uff83"); put("\uff84\uff9e", "\uff84");
		put("\uff82\uff9e", "\uff82");
		put("\uff8a", "\uff8a\uff9e"); put("\uff8b", "\uff8b\uff9e"); put("\uff8c", "\uff8c\uff9e"); put("\uff8d", "\uff8d\uff9e"); put("\uff8e", "\uff8e\uff9e");
		put("\uff8a\uff9e", "\uff8a\uff9f");put("\uff8b\uff9e", "\uff8b\uff9f");put("\uff8c\uff9e", "\uff8c\uff9f");put("\uff8d\uff9e", "\uff8d\uff9f");put("\uff8e\uff9e", "\uff8e\uff9f");
		put("\uff8a\uff9f", "\uff8a"); put("\uff8b\uff9f", "\uff8b"); put("\uff8c\uff9f", "\uff8c"); put("\uff8d\uff9f", "\uff8d"); put("\uff8e\uff9f", "\uff8e");
		put("\uff94", "\uff6c");  put("\uff95", "\uff6d");  put("\uff96", "\uff6e");
		put("\uff6c", "\uff94");  put("\uff6d", "\uff95");  put("\uff6e", "\uff96");
		put("\uff9c", "\uff9c"); put("\uff73\uff9e", "\uff73");
	}};

	/** Toggle cycle table for full-width alphabet */
	private static final String[][] JP_FULL_ALPHABET_CYCLE_TABLE = {
		{"\uff0e", "\uff20", "\uff0d", "\uff3f", "\uff0f", "\uff1a", "\uff5e", "\uff11"},
		{"\uff41", "\uff42", "\uff43", "\uff21", "\uff22", "\uff23", "\uff12"},
		{"\uff44", "\uff45", "\uff46", "\uff24", "\uff25", "\uff26", "\uff13"},
		{"\uff47", "\uff48", "\uff49", "\uff27", "\uff28", "\uff29", "\uff14"},
		{"\uff4a", "\uff4b", "\uff4c", "\uff2a", "\uff2b", "\uff2c", "\uff15"},
		{"\uff4d", "\uff4e", "\uff4f", "\uff2d", "\uff2e", "\uff2f", "\uff16"},
		{"\uff50", "\uff51", "\uff52", "\uff53", "\uff30", "\uff31", "\uff32", "\uff33", "\uff17"},
		{"\uff54", "\uff55", "\uff56", "\uff34", "\uff35", "\uff36", "\uff18"},
		{"\uff57", "\uff58", "\uff59", "\uff5a", "\uff37", "\uff38", "\uff39", "\uff3a", "\uff19"},
		{"\uff0d", "\uff10"},
		{"\uff0c", "\uff0e", "\uff1f", "\uff01", "\u30fb", "\u3000"}
	};

	/** Replace table for full-width alphabet */
	private static final HashMap<String,String> JP_FULL_ALPHABET_REPLACE_TABLE = new HashMap<String,String>() {
		/**
		 *
		 */
		private static final long serialVersionUID = 1L;
		{
			put("\uff21", "\uff41"); put("\uff22", "\uff42"); put("\uff23", "\uff43"); put("\uff24", "\uff44"); put("\uff25", "\uff45");
			put("\uff41", "\uff21"); put("\uff42", "\uff22"); put("\uff43", "\uff23"); put("\uff44", "\uff24"); put("\uff45", "\uff25");
			put("\uff26", "\uff46"); put("\uff27", "\uff47"); put("\uff28", "\uff48"); put("\uff29", "\uff49"); put("\uff2a", "\uff4a");
			put("\uff46", "\uff26"); put("\uff47", "\uff27"); put("\uff48", "\uff28"); put("\uff49", "\uff29"); put("\uff4a", "\uff2a");
			put("\uff2b", "\uff4b"); put("\uff2c", "\uff4c"); put("\uff2d", "\uff4d"); put("\uff2e", "\uff4e"); put("\uff2f", "\uff4f");
			put("\uff4b", "\uff2b"); put("\uff4c", "\uff2c"); put("\uff4d", "\uff2d"); put("\uff4e", "\uff2e"); put("\uff4f", "\uff2f");
			put("\uff30", "\uff50"); put("\uff31", "\uff51"); put("\uff32", "\uff52"); put("\uff33", "\uff53"); put("\uff34", "\uff54");
			put("\uff50", "\uff30"); put("\uff51", "\uff31"); put("\uff52", "\uff32"); put("\uff53", "\uff33"); put("\uff54", "\uff34");
			put("\uff35", "\uff55"); put("\uff36", "\uff56"); put("\uff37", "\uff57"); put("\uff38", "\uff58"); put("\uff39", "\uff59");
			put("\uff55", "\uff35"); put("\uff56", "\uff36"); put("\uff57", "\uff37"); put("\uff58", "\uff38"); put("\uff59", "\uff39");
			put("\uff3a", "\uff5a");
			put("\uff5a", "\uff3a");
		}
	};

	/** Toggle cycle table for half-width alphabet */
	private static final String[][] JP_HALF_ALPHABET_CYCLE_TABLE = {
		{".", "@", "-", "_", "/", ":", "~", "1"},
		{"a", "b", "c", "A", "B", "C", "2"},
		{"d", "e", "f", "D", "E", "F", "3"},
		{"g", "h", "i", "G", "H", "I", "4"},
		{"j", "k", "l", "J", "K", "L", "5"},
		{"m", "n", "o", "M", "N", "O", "6"},
		{"p", "q", "r", "s", "P", "Q", "R", "S", "7"},
		{"t", "u", "v", "T", "U", "V", "8"},
		{"w", "x", "y", "z", "W", "X", "Y", "Z", "9"},
		{"-", "0"},
		{",", ".", "?", "!", ";", " "}
	};
	private static final String[][][] JP_FLICK_HALF_ALPHABET_CYCLE_TABLE = {
		{ {"."}, {"@"}, {"-"}, {"_"}, {"/"}, {":"}, {"~"}, {"1"}},
		{ {"a"}, {"b"}, {"c"}, {"A"}, {"B"}, {"C"}, {"2"}, {"\""}},
		{ {"d"}, {"e"}, {"f"}, {"D"}, {"E"}, {"F"}, {"3"}, {"\'"}},
		{ {"g"}, {"h"}, {"i"}, {"G"}, {"H"}, {"I"}, {"4"}, {"<"}},
		{ {"j"}, {"k"}, {"l"}, {"J"}, {"K"}, {"L"}, {"5"}, {"&"}},
		{ {"m"}, {"n"}, {"o"}, {"M"}, {"N"}, {"O"}, {"6"}, {">"}},
		{ {"p"}, {"q"}, {"r"}, {"s"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"7"}},
		{ {"t"}, {"u"}, {"v"}, {"T"}, {"U"}, {"V"}, {"8"}, {"$"}},
		{ {"w"}, {"x"}, {"y"}, {"z"}, {"W"}, {"X"}, {"Y"}, {"Z"}, {"9"}},
		{ {"-"}, {"0"}, {"("}, {")"}},
		{ {","}, {"."}, {"?"}, {"!"}, {";"}, {" "}}
	};

	private static final String[][][] JP_FLICK_FULL_HIRAGANA_CYCLE_TABLE = {
		{{"\u3042"}, {"\u3044"}, {"\u3046"}, {"\u3048"}, {"\u304a"}},
		{{"\u304b"}, {"\u304d"}, {"\u304f"}, {"\u3051"}, {"\u3053"}},
		{{"\u3055"}, {"\u3057"}, {"\u3059"}, {"\u305b"}, {"\u305d"}},
		{{"\u305f"}, {"\u3061"}, {"\u3064"}, {"\u3066"}, {"\u3068"}},
		{{"\u306a"}, {"\u306b"}, {"\u306c"}, {"\u306d"}, {"\u306e"}},
		{{"\u306f"}, {"\u3072"}, {"\u3075"}, {"\u3078"}, {"\u307b"}},
		{{"\u307e"}, {"\u307f"}, {"\u3080"}, {"\u3081"}, {"\u3082"}},
		{{"\u3084"}, {"\u3086"}, {"\u3088"}},
		{{"\u3089"}, {"\u308a"}, {"\u308b"}, {"\u308c"}, {"\u308d"}},
		{{"\u308f"}, {"\u3092"}, {"\u3093"}, {"\u30fc"}},
		{{"\u3001"}, {"\u3002"}, {"\uff1f"}, {"\uff01"}},
	};
	private static final String[][][] JP_FLICK_FULL_KATAKANA_CYCLE_TABLE = {
		{{"\u30a2"}, {"\u30a4"}, {"\u30a6"}, {"\u30a8"}, {"\u30aa"}},
		{{"\u30ab"}, {"\u30ad"}, {"\u30af"}, {"\u30b1"}, {"\u30b3"}},
		{{"\u30b5"}, {"\u30b7"}, {"\u30b9"}, {"\u30bb"}, {"\u30bd"}},
		{{"\u30bf"}, {"\u30c1"}, {"\u30c4"}, {"\u30c6"}, {"\u30c8"}},
		{{"\u30ca"}, {"\u30cb"}, {"\u30cc"}, {"\u30cd"}, {"\u30ce"}},
		{{"\u30cf"}, {"\u30d2"}, {"\u30d5"}, {"\u30d8"}, {"\u30db"}},
		{{"\u30de"}, {"\u30df"}, {"\u30e0"}, {"\u30e1"}, {"\u30e2"}},
		{{"\u30e4"}, {"\u30e6"}, {"\u30e8"}},
		{{"\u30e9"}, {"\u30ea"}, {"\u30eb"}, {"\u30ec"}, {"\u30ed"}},
		{{"\u30ef"}, {"\u30f2"}, {"\u30f3"}, {"\u30fc"}},
		{{"\u3001"}, {"\u3002"}, {"\uff1f"}, {"\uff01"}},
	};
	private static final String[][][] JP_FLICK_HALF_KATAKANA_CYCLE_TABLE = {
		{{"\uff71"}, {"\uff72"}, {"\uff73"}, {"\uff74"}, {"\uff75"}},
		{{"\uff76"}, {"\uff77"}, {"\uff78"}, {"\uff79"}, {"\uff7a"}},
		{{"\uff7b"}, {"\uff7c"}, {"\uff7d"}, {"\uff7e"}, {"\uff7f"}},
		{{"\uff80"}, {"\uff81"}, {"\uff82"}, {"\uff83"}, {"\uff84"}},
		{{"\uff85"}, {"\uff86"}, {"\uff87"}, {"\uff88"}, {"\uff89"}},
		{{"\uff8a"}, {"\uff8b"}, {"\uff8c"}, {"\uff8d"}, {"\uff8e"}},
		{{"\uff8f"}, {"\uff90"}, {"\uff91"}, {"\uff92"}, {"\uff93"}},
		{{"\uff94"}, {"\uff95"}, {"\uff96"}},
		{{"\uff97"}, {"\uff98"}, {"\uff99"}, {"\uff9a"}, {"\uff9b"}},
		{{"\uff9c"}, {"\uff66"}, {"\uff9d"}, {"\uff70"}},
		{{"\uff64"}, {"\uff61"}, {"?"}, {"!"}},
	};

	private static final String[][][] JP_FLICK_FULL_ALPHABET_CYCLE_TABLE = {
		{ {"\uff0e"}, {"\uff20"}, {"\uff0d"}, {"\uff3f"}, {"\uff0f"}, {"\uff1a"}, {"\uff5e"}, {"\uff11"}},
		{ {"\uff41"}, {"\uff42"}, {"\uff43"}, {"\uff21"}, {"\uff22"}, {"\uff23"}, {"\uff12"}, {"\uff02"}},
		{ {"\uff44"}, {"\uff45"}, {"\uff46"}, {"\uff24"}, {"\uff25"}, {"\uff26"}, {"\uff13"}, {"\uff07"}},
		{ {"\uff47"}, {"\uff48"}, {"\uff49"}, {"\uff27"}, {"\uff28"}, {"\uff29"}, {"\uff14"}, {"\uff1c"}},
		{ {"\uff4a"}, {"\uff4b"}, {"\uff4c"}, {"\uff2a"}, {"\uff2b"}, {"\uff2c"}, {"\uff15"}, {"\uff06"}},
		{ {"\uff4d"}, {"\uff4e"}, {"\uff4f"}, {"\uff2d"}, {"\uff2e"}, {"\uff2f"}, {"\uff16"}, {"\uff1e"}},
		{ {"\uff50"}, {"\uff51"}, {"\uff52"}, {"\uff53"}, {"\uff30"}, {"\uff31"}, {"\uff32"}, {"\uff33"}, {"\uff17"}},
		{ {"\uff54"}, {"\uff55"}, {"\uff56"}, {"\uff34"}, {"\uff35"}, {"\uff36"}, {"\uff18"}, {"\uff04"}},
		{ {"\uff57"}, {"\uff58"}, {"\uff59"}, {"\uff5a"}, {"\uff37"}, {"\uff38"}, {"\uff39"}, {"\uff3a"}, {"\uff19"}},
		{ {"\uff0d"}, {"\uff10"}, {"\uff08"}, {"\uff09"}},
		{ {"\uff0c"}, {"\uff0e"}, {"\uff1f"}, {"\uff01"}, {"\u30fb"}, {"\u3000"}},
	};

	/** Replace table for half-width alphabet */
	private static final HashMap<String,String> JP_HALF_ALPHABET_REPLACE_TABLE = new HashMap<String,String>() {
		/**
		 *
		 */
		private static final long serialVersionUID = 1L;
		{
			put("A", "a"); put("B", "b"); put("C", "c"); put("D", "d"); put("E", "e");
			put("a", "A"); put("b", "B"); put("c", "C"); put("d", "D"); put("e", "E");
			put("F", "f"); put("G", "g"); put("H", "h"); put("I", "i"); put("J", "j");
			put("f", "F"); put("g", "G"); put("h", "H"); put("i", "I"); put("j", "J");
			put("K", "k"); put("L", "l"); put("M", "m"); put("N", "n"); put("O", "o");
			put("k", "K"); put("l", "L"); put("m", "M"); put("n", "N"); put("o", "O");
			put("P", "p"); put("Q", "q"); put("R", "r"); put("S", "s"); put("T", "t");
			put("p", "P"); put("q", "Q"); put("r", "R"); put("s", "S"); put("t", "T");
			put("U", "u"); put("V", "v"); put("W", "w"); put("X", "x"); put("Y", "y");
			put("u", "U"); put("v", "V"); put("w", "W"); put("x", "X"); put("y", "Y");
			put("Z", "z");
			put("z", "Z");
		}
	};

	/** Replace table for full-width KANA DAKUTEN */
	private static final HashMap<String, String> JP_FULL_DAKUTEN_REPLACE_TABLE = new HashMap<String, String>() {{
		put("\u304b", "\u304c"); // HIRAGANA KA -> GA
		put("\u304d", "\u304e"); // HIRAGANA KI -> GI
		put("\u304f", "\u3050"); // HIRAGANA KU -> GU
		put("\u3051", "\u3052"); // HIRAGANA KE -> GE
		put("\u3053", "\u3054"); // HIRAGANA KO -> GO
		put("\u3055", "\u3056"); // HIRAGANA SA -> ZA
		put("\u3057", "\u3058"); // HIRAGANA SI -> ZI
		put("\u3059", "\u305a"); // HIRAGANA SU -> ZU
		put("\u305b", "\u305c"); // HIRAGANA SE -> ZE
		put("\u305d", "\u305e"); // HIRAGANA SO -> ZO
		put("\u305f", "\u3060"); // HIRAGANA TA -> DA
		put("\u3061", "\u3062"); // HIRAGANA TI -> DI
		put("\u3064", "\u3065"); // HIRAGANA TU -> DU
		put("\u3066", "\u3067"); // HIRAGANA TE -> DE
		put("\u3068", "\u3069"); // HIRAGANA TO -> DO
		put("\u306f", "\u3070"); // HIRAGANA HA -> BA
		put("\u3072", "\u3073"); // HIRAGANA HI -> BI
		put("\u3075", "\u3076"); // HIRAGANA HU -> BU
		put("\u3078", "\u3079"); // HIRAGANA HE -> BE
		put("\u307b", "\u307c"); // HIRAGANA HO -> BO
		put("\u30a6", "\u30f4"); // KATAKANA U  -> VU
		put("\u30ab", "\u30ac"); // KATAKANA KA -> GA
		put("\u30ad", "\u30ae"); // KATAKANA KI -> GI
		put("\u30af", "\u30b0"); // KATAKANA KU -> GU
		put("\u30b1", "\u30b2"); // KATAKANA KE -> GE
		put("\u30b3", "\u30b4"); // KATAKANA KO -> GO
		put("\u30b5", "\u30b6"); // KATAKANA SA -> ZA
		put("\u30b7", "\u30b8"); // KATAKANA SI -> ZI
		put("\u30b9", "\u30ba"); // KATAKANA SU -> ZU
		put("\u30bb", "\u30bc"); // KATAKANA SE -> ZE
		put("\u30bd", "\u30be"); // KATAKANA SO -> ZO
		put("\u30bf", "\u30c0"); // KATAKANA TA -> DA
		put("\u30c1", "\u30c2"); // KATAKANA TI -> DI
		put("\u30c4", "\u30c5"); // KATAKANA TU -> DU
		put("\u30c6", "\u30c7"); // KATAKANA TE -> DE
		put("\u30c8", "\u30c9"); // KATAKANA TO -> DO
		put("\u30cf", "\u30d0"); // KATAKANA HA -> BA
		put("\u30d2", "\u30d3"); // KATAKANA HI -> BI
		put("\u30d5", "\u30d6"); // KATAKANA HU -> BU
		put("\u30d8", "\u30d9"); // KATAKANA HE -> BE
		put("\u30db", "\u30dc"); // KATAKANA HO -> BO

		put("\u304c", "\u304b"); // HIRAGANA GA -> KA
		put("\u304e", "\u304d"); // HIRAGANA GI -> KI
		put("\u3050", "\u304f"); // HIRAGANA GU -> KU
		put("\u3052", "\u3051"); // HIRAGANA GE -> KE
		put("\u3054", "\u3053"); // HIRAGANA GO -> KO
		put("\u3056", "\u3055"); // HIRAGANA ZA -> SA
		put("\u3058", "\u3057"); // HIRAGANA ZI -> SI
		put("\u305a", "\u3059"); // HIRAGANA ZU -> SU
		put("\u305c", "\u305b"); // HIRAGANA ZE -> SE
		put("\u305e", "\u305d"); // HIRAGANA ZO -> SO
		put("\u3060", "\u305f"); // HIRAGANA DA -> TA
		put("\u3062", "\u3061"); // HIRAGANA DI -> TI
		put("\u3065", "\u3064"); // HIRAGANA DU -> TU
		put("\u3067", "\u3066"); // HIRAGANA DE -> TE
		put("\u3069", "\u3068"); // HIRAGANA DO -> TO
		put("\u3070", "\u306f"); // HIRAGANA BA -> HA
		put("\u3073", "\u3072"); // HIRAGANA BI -> HI
		put("\u3076", "\u3075"); // HIRAGANA BU -> HU
		put("\u3079", "\u3078"); // HIRAGANA BE -> HE
		put("\u307c", "\u307b"); // HIRAGANA BO -> HO
		put("\u30f4", "\u30a6"); // KATAKANA VU -> U
		put("\u30ac", "\u30ab"); // KATAKANA GA -> KA
		put("\u30ae", "\u30ad"); // KATAKANA GI -> KI
		put("\u30b0", "\u30af"); // KATAKANA GU -> KU
		put("\u30b2", "\u30b1"); // KATAKANA GE -> KE
		put("\u30b4", "\u30b3"); // KATAKANA GO -> KO
		put("\u30b6", "\u30b5"); // KATAKANA ZA -> SA
		put("\u30b8", "\u30b7"); // KATAKANA ZI -> SI
		put("\u30ba", "\u30b9"); // KATAKANA ZU -> SU
		put("\u30bc", "\u30bb"); // KATAKANA ZE -> SE
		put("\u30be", "\u30bd"); // KATAKANA ZO -> SO
		put("\u30c0", "\u30bf"); // KATAKANA DA -> TA
		put("\u30c2", "\u30c1"); // KATAKANA DI -> TI
		put("\u30c5", "\u30c4"); // KATAKANA DU -> TU
		put("\u30c7", "\u30c6"); // KATAKANA DE -> TE
		put("\u30c9", "\u30c8"); // KATAKANA DO -> TO
		put("\u30d0", "\u30cf"); // KATAKANA BA -> HA
		put("\u30d3", "\u30d2"); // KATAKANA BI -> HI
		put("\u30d6", "\u30d5"); // KATAKANA BU -> HU
		put("\u30d9", "\u30d8"); // KATAKANA BE -> HE
		put("\u30dc", "\u30db"); // KATAKANA BO -> HO

		put("\u3071", "\u306f"); // HIRAGANA PA -> BA
		put("\u3074", "\u3073"); // HIRAGANA PI -> BI
		put("\u3077", "\u3076"); // HIRAGANA PU -> BU
		put("\u307a", "\u3079"); // HIRAGANA PE -> BE
		put("\u307d", "\u307c"); // HIRAGANA PO -> BO
		put("\u30d1", "\u30cf"); // KATAKANA PA -> BA
		put("\u30d4", "\u30d2"); // KATAKANA PI -> BI
		put("\u30d7", "\u30d5"); // KATAKANA PU -> BU
		put("\u30da", "\u30d8"); // KATAKANA PE -> BE
		put("\u30dd", "\u30db"); // KATAKANA PO -> BO
	}};

	/** Replace table for full-width KANA HANDAKUTEN */
	private static final HashMap<String,String> JP_FULL_HANDAKUTEN_REPLACE_TABLE = new HashMap<String,String>() {{
		put("\u306f", "\u3071"); // HIRAGANA HA -> PA
		put("\u3072", "\u3074"); // HIRAGANA HI -> PI
		put("\u3075", "\u3077"); // HIRAGANA HU -> PU
		put("\u3078", "\u307a"); // HIRAGANA HE -> PE
		put("\u307b", "\u307d"); // HIRAGANA HO -> PO
		put("\u30cf", "\u30d1"); // KATAKANA HA -> PA
		put("\u30d2", "\u30d4"); // KATAKANA HI -> PI
		put("\u30d5", "\u30d7"); // KATAKANA HU -> PU
		put("\u30d8", "\u30da"); // KATAKANA HE -> PE
		put("\u30db", "\u30dd"); // KATAKANA HO -> PO

		put("\u3071", "\u306f"); // HIRAGANA PA -> HA
		put("\u3074", "\u3072"); // HIRAGANA PI -> HI
		put("\u3077", "\u3075"); // HIRAGANA PU -> HU
		put("\u307a", "\u3078"); // HIRAGANA PE -> HE
		put("\u307d", "\u307b"); // HIRAGANA PO -> HO
		put("\u30d1", "\u30cf"); // KATAKANA PA -> HA
		put("\u30d4", "\u30d2"); // KATAKANA PI -> HI
		put("\u30d7", "\u30d5"); // KATAKANA PU -> HU
		put("\u30da", "\u30d8"); // KATAKANA PE -> HE
		put("\u30dd", "\u30db"); // KATAKANA PO -> HO

		put("\u306f", "\u3071"); // HIRAGANA BA -> PA
		put("\u3073", "\u3074"); // HIRAGANA BI -> PI
		put("\u3076", "\u3077"); // HIRAGANA BU -> PU
		put("\u3079", "\u307a"); // HIRAGANA BE -> PE
		put("\u307c", "\u307d"); // HIRAGANA BO -> PO
		put("\u30cf", "\u30d1"); // KATAKANA BA -> PA
		put("\u30d2", "\u30d4"); // KATAKANA BI -> PI
		put("\u30d5", "\u30d7"); // KATAKANA BU -> PU
		put("\u30d8", "\u30da"); // KATAKANA BE -> PE
		put("\u30db", "\u30dd"); // KATAKANA BO -> PO
	}};

	/**
	 * change map
	 */
	private static final int flickAlphabetChangeMap[][] = {
		{  0,  7,  4,  1,  5 }, // .1/@:
		{  0,  6,  1,  2,  7 }, // A2BC"
		{  0,  6,  1,  2,  7 }, // D3EF'
		{  0,  6,  1,  2,  7 }, // G4HI<
		{  0,  6,  1,  2,  7 }, // J5KL&
		{  0,  6,  1,  2,  7 }, // M6NO>
		{  0,  8,  1,  2,  3 }, // P7QRS
		{  0,  6,  1,  2,  7 }, // T8UV$
		{  0,  8,  1,  2,  3 }, // W9XYZ
		{  0, -1,  2,  1,  3 }, // - (0)
		{  0, -1,  1,  2,  3 }, // , .?!
	};
	/* */
	SetupKeyboard              mSetupKeyboard;
	String[][][][]             mCycleTable;
	// HashMap<String, String>    mReplaceTable;


	private static int selectOtherLandKeyTable[] = {
		R.xml.keyboard_12key_phone_0,
		R.xml.keyboard_12key_full_alphabet_0,
		R.xml.keyboard_12key_full_alphabet_input_0,
		R.xml.keyboard_12key_full_num_0,
		R.xml.keyboard_12key_half_alphabet_0,
		R.xml.keyboard_12key_half_alphabet_input_0,
		R.xml.keyboard_12key_half_num_0,
	};
	private static int selectOtherPortKeyTable[] = {
		R.xml.keyboard_12key_phone_0,
		R.xml.keyboard_12key_full_alphabet_0,
		R.xml.keyboard_12key_full_alphabet_input_0,
		R.xml.keyboard_12key_full_num_0,
		R.xml.keyboard_12key_half_alphabet_0,
		R.xml.keyboard_12key_half_alphabet_input_0,
		R.xml.keyboard_12key_half_num_0,
	};

	private static int selectFlickLandKeyTable[] = {
		R.xml.keyboard_12key_phone_0,
		R.xml.keyboard_12key_flick_full_alphabet_0,
		R.xml.keyboard_12key_flick_full_alphabet_input_0,
		R.xml.keyboard_12key_full_num_0,
		R.xml.keyboard_12key_flick_half_alphabet_0,
		R.xml.keyboard_12key_flick_half_alphabet_input_0,
		R.xml.keyboard_12key_half_num_0,
	};
	private static int selectFlickPortKeyTable[] = {
		R.xml.keyboard_12key_phone_0,
		R.xml.keyboard_12key_flick_full_alphabet_0,
		R.xml.keyboard_12key_flick_full_alphabet_input_0,
		R.xml.keyboard_12key_full_num_0,
		R.xml.keyboard_12key_flick_half_alphabet_0,
		R.xml.keyboard_12key_flick_half_alphabet_input_0,
		R.xml.keyboard_12key_half_num_0,
	};

	private static int selectQwertyLandKeyTable[] = {
		R.xml.keyboard_qwerty_jp_0,
		R.xml.keyboard_qwerty_jp_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_qwerty_jp_full_katakana_0,
		R.xml.keyboard_qwerty_jp_full_katakana_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_qwerty_jp_half_katakana_0,
		R.xml.keyboard_qwerty_jp_half_katakana_shift_0,
	};

	private static int selectQwertyPortKeyTable[] = {
		R.xml.keyboard_qwerty_jp_0,
		R.xml.keyboard_qwerty_jp_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_qwerty_jp_full_katakana_0,
		R.xml.keyboard_qwerty_jp_full_katakana_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_qwerty_jp_half_katakana_0,
		R.xml.keyboard_qwerty_jp_half_katakana_shift_0,
	};

	private static int selectKanaJisLandKeyTable[] = {
		R.xml.keyboard_kanajis_jp_full_0,
		R.xml.keyboard_kanajis_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_katakanajis_jp_full_0,
		R.xml.keyboard_katakanajis_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_katakanajis_jp_half_0,
		R.xml.keyboard_katakanajis_jp_half_shift_0,
	};

	private static int selectKanaJisPortKeyTable[] = {
		R.xml.keyboard_kanajis_jp_full_0,
		R.xml.keyboard_kanajis_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_katakanajis_jp_full_0,
		R.xml.keyboard_katakanajis_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_katakanajis_jp_half_0,
		R.xml.keyboard_katakanajis_jp_half_shift_0,
	};

	private static int selectKana50onLandKeyTable[] = {
		R.xml.keyboard_kana50on_jp_full_0,
		R.xml.keyboard_kana50on_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_katakana50on_jp_full_0,
		R.xml.keyboard_katakana50on_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_katakana50on_jp_half_0,
		R.xml.keyboard_katakana50on_jp_half_shift_0,
	};

	private static int selectKana50onPortKeyTable[] = {
		R.xml.keyboard_kana50on_jp_full_0,
		R.xml.keyboard_kana50on_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_full_symbols_0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_0,
		R.xml.keyboard_katakana50on_jp_full_0,
		R.xml.keyboard_katakana50on_jp_full_shift_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_0,
		R.xml.keyboard_qwerty_jp_half_symbols_0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_0,
		R.xml.keyboard_katakana50on_jp_half_0,
		R.xml.keyboard_katakana50on_jp_half_shift_0,
	};

	/** */

	private static int selectQwertySlantLandKeyTable[] = {
		R.xml.keyboard_qwerty_jp_s0,
		R.xml.keyboard_qwerty_jp_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_qwerty_jp_full_katakana_s0,
		R.xml.keyboard_qwerty_jp_full_katakana_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_qwerty_jp_half_katakana_s0,
		R.xml.keyboard_qwerty_jp_half_katakana_shift_s0,
	};

	private static int selectQwertySlantPortKeyTable[] = {
		R.xml.keyboard_qwerty_jp_s0,
		R.xml.keyboard_qwerty_jp_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_qwerty_jp_full_katakana_s0,
		R.xml.keyboard_qwerty_jp_full_katakana_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_qwerty_jp_half_katakana_s0,
		R.xml.keyboard_qwerty_jp_half_katakana_shift_s0,
	};

	private static int selectKanaJisSlantLandKeyTable[] = {
		R.xml.keyboard_kanajis_jp_full_s0,
		R.xml.keyboard_kanajis_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_katakanajis_jp_full_s0,
		R.xml.keyboard_katakanajis_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_katakanajis_jp_half_s0,
		R.xml.keyboard_katakanajis_jp_half_shift_s0,
	};

	private static int selectKanaJisSlantPortKeyTable[] = {
		R.xml.keyboard_kanajis_jp_full_s0,
		R.xml.keyboard_kanajis_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_katakanajis_jp_full_s0,
		R.xml.keyboard_katakanajis_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_katakanajis_jp_half_s0,
		R.xml.keyboard_katakanajis_jp_half_shift_s0,
	};

	private static int selectKana50onSlantLandKeyTable[] = {
		R.xml.keyboard_kana50on_jp_full_s0,
		R.xml.keyboard_kana50on_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_katakana50on_jp_full_s0,
		R.xml.keyboard_katakana50on_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_katakana50on_jp_half_s0,
		R.xml.keyboard_katakana50on_jp_half_shift_s0,
	};

	private static int selectKana50onSlantPortKeyTable[] = {
		R.xml.keyboard_kana50on_jp_full_s0,
		R.xml.keyboard_kana50on_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_s0,
		R.xml.keyboard_qwerty_jp_full_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_s0,
		R.xml.keyboard_qwerty_jp_full_symbols_shift_s0,
		R.xml.keyboard_katakana50on_jp_full_s0,
		R.xml.keyboard_katakana50on_jp_full_shift_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_s0,
		R.xml.keyboard_qwerty_jp_half_alphabet_shift_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_s0,
		R.xml.keyboard_qwerty_jp_half_symbols_shift_s0,
		R.xml.keyboard_katakana50on_jp_half_s0,
		R.xml.keyboard_katakana50on_jp_half_shift_s0,
	};


}
