本文主要是介绍android输入法02:openwnn源码解析02—Keyboard和KeyboardView,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这一部分主要涉及三个类:InputViewManager.java,DefaultSoftKeyboard.java,DefaultSoftKeyboardJAJP.java。其中InputViewManager是与键盘相关的对外接口,DefaultSoftKeyboard是通用类,DefaultSoftKeyboardJAJP是日文定制类。
1、InputViewManager
第一步我们先来看看InputViewManager。这个接口类代码很简单:
- /**
- * The interface of input view manager used by OpenWnn.
- *
- * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD. All Rights Reserved.
- */
- public interface InputViewManager {
- /**
- * Initialize the input view.
- *
- * @param parent The OpenWnn object
- * @param width The width of the display
- * @param height The height of the display
- *
- * @return The input view created in the initialize process; {@code null} if cannot create a input view.
- */
- public View initView(OpenWnn parent, int width, int height);
- /**
- * Get the input view being used currently.
- *
- * @return The input view; {@code null} if no input view is used currently.
- */
- public View getCurrentView();
- /**
- * Notification of updating parent's state.
- *
- * @param parent The OpenWnn object using this manager
- */
- public void onUpdateState(OpenWnn parent);
- /**
- * Reflect the preferences in the input view.
- *
- * @param pref The preferences
- * @param editor The information about the editor
- */
- public void setPreferences(SharedPreferences pref, EditorInfo editor);
- /**
- * Close the input view.
- */
- public void closing();
- }
- /**
- * The interface of input view manager used by OpenWnn.
- *
- * @author Copyright (C) 2009 OMRON SOFTWARE CO., LTD. All Rights Reserved.
- */
- public interface InputViewManager {
- /**
- * Initialize the input view.
- *
- * @param parent The OpenWnn object
- * @param width The width of the display
- * @param height The height of the display
- *
- * @return The input view created in the initialize process; {@code null} if cannot create a input view.
- */
- public View initView(OpenWnn parent, int width, int height);
- /**
- * Get the input view being used currently.
- *
- * @return The input view; {@code null} if no input view is used currently.
- */
- public View getCurrentView();
- /**
- * Notification of updating parent's state.
- *
- * @param parent The OpenWnn object using this manager
- */
- public void onUpdateState(OpenWnn parent);
- /**
- * Reflect the preferences in the input view.
- *
- * @param pref The preferences
- * @param editor The information about the editor
- */
- public void setPreferences(SharedPreferences pref, EditorInfo editor);
- /**
- * Close the input view.
- */
- public void closing();
- }
2、配置项
这里我们先从简单的部分开始研究。第一个是setPreferences,这只配置项。这一步的工作是读取与键盘部分有关的配置项,在生成键盘(改变键盘)时进行设置。代码中设计到的配置项很减少,只有:震动、声音、是否自动切换大写。在DefaultSoftKeyboard.java中只设置了震动和声音,在DefaultSoftKeyboardJAJP.java添加了是否自动切换为大写。具体大家可以看代码,对于是否自动切换大写,从代码上看,我猜测,有些输入框默认是输入大写的。(这一部分我想不到例子,谁有例子可以share一下)
3、KeyboardView
在InputViewManager中有initView这个函数,实际上使用来生成KeyboardView的。其源码如下:
在DefaultSoftKeyboard.java中:
- /** @see jp.co.omronsoft.openwnn.InputViewManager#initView */
- public View initView(OpenWnn parent, int width, int height) {
- mWnn = parent;
- mDisplayMode = (width == 320)? PORTRAIT : LANDSCAPE;
- /*
- * create keyboards & the view.
- * To re-display the input view when the display mode is changed portrait <-> landscape,
- * create keyboards every time.
- */
- createKeyboards(parent);
- SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(parent);
- String skin = pref.getString("keyboard_skin",
- mWnn.getResources().getString(R.string.keyboard_skin_id_default));
- Log.d("OpenWnn", "keyboard_skin="+skin);
- int id = parent.getResources().getIdentifier(skin, "layout", "jp.co.omronsoft.openwnn");
- mKeyboardView = (KeyboardView) mWnn.getLayoutInflater().inflate(id, null);
- mKeyboardView.setOnKeyboardActionListener(this);
- mCurrentKeyboard = null;
- mMainView = (ViewGroup) parent.getLayoutInflater().inflate(R.layout.keyboard_default_main, null);
- mSubView = (ViewGroup) parent.getLayoutInflater().inflate(R.layout.keyboard_default_sub, null);
- if (mDisplayMode == LANDSCAPE && !mHardKeyboardHidden) {
- mMainView.addView(mSubView);
- }
- if (mKeyboardView != null) {
- mMainView.addView(mKeyboardView);
- }
- return mMainView;
- }
- /** @see jp.co.omronsoft.openwnn.InputViewManager#initView */
- public View initView(OpenWnn parent, int width, int height) {
- mWnn = parent;
- mDisplayMode = (width == 320)? PORTRAIT : LANDSCAPE;
- /*
- * create keyboards & the view.
- * To re-display the input view when the display mode is changed portrait <-> landscape,
- * create keyboards every time.
- */
- createKeyboards(parent);
- SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(parent);
- String skin = pref.getString("keyboard_skin",
- mWnn.getResources().getString(R.string.keyboard_skin_id_default));
- Log.d("OpenWnn", "keyboard_skin="+skin);
- int id = parent.getResources().getIdentifier(skin, "layout", "jp.co.omronsoft.openwnn");
- mKeyboardView = (KeyboardView) mWnn.getLayoutInflater().inflate(id, null);
- mKeyboardView.setOnKeyboardActionListener(this);
- mCurrentKeyboard = null;
- mMainView = (ViewGroup) parent.getLayoutInflater().inflate(R.layout.keyboard_default_main, null);
- mSubView = (ViewGroup) parent.getLayoutInflater().inflate(R.layout.keyboard_default_sub, null);
- if (mDisplayMode == LANDSCAPE && !mHardKeyboardHidden) {
- mMainView.addView(mSubView);
- }
- if (mKeyboardView != null) {
- mMainView.addView(mKeyboardView);
- }
- return mMainView;
- }
另外,从SoftKeyboard项目中我们知道,KeyboardView实际上是装着一个Keyboard。但在这一段代码中只有生成Keyboard,并未将Keyboard封装到KeyboardView里面,因为当前键盘变量mCurrentKeyboard是空的。这里我们猜测在继承类中会做封装Keyboard的操作。我们看DefaultSoftKeyboardJAJP.java的代码:
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#initView */
- @Override public View initView(OpenWnn parent, int width, int height) {
- View view = super.initView(parent, width, height);
- changeKeyboard(mKeyboard[mCurrentLanguage][mDisplayMode][mCurrentKeyboardType][mShiftOn][mCurrentKeyMode][0]);
- return view;
- }
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#initView */
- @Override public View initView(OpenWnn parent, int width, int height) {
- View view = super.initView(parent, width, height);
- changeKeyboard(mKeyboard[mCurrentLanguage][mDisplayMode][mCurrentKeyboardType][mShiftOn][mCurrentKeyMode][0]);
- return view;
- }
- /**
- * Change the keyboard.
- *
- * @param keyboard The new keyboard
- * @return {@code true} if the keyboard is changed; {@code false} if not changed.
- */
- protected boolean changeKeyboard(Keyboard keyboard) {
- if (keyboard == null) {
- return false;
- }
- if (mCurrentKeyboard != keyboard) {
- mKeyboardView.setKeyboard(keyboard);
- mKeyboardView.setShifted((mShiftOn == 0) ? false : true);
- mCurrentKeyboard = keyboard;
- return true;
- } else {
- mKeyboardView.setShifted((mShiftOn == 0) ? false : true);
- return false;
- }
- }
- /**
- * Change the keyboard.
- *
- * @param keyboard The new keyboard
- * @return {@code true} if the keyboard is changed; {@code false} if not changed.
- */
- protected boolean changeKeyboard(Keyboard keyboard) {
- if (keyboard == null) {
- return false;
- }
- if (mCurrentKeyboard != keyboard) {
- mKeyboardView.setKeyboard(keyboard);
- mKeyboardView.setShifted((mShiftOn == 0) ? false : true);
- mCurrentKeyboard = keyboard;
- return true;
- } else {
- mKeyboardView.setShifted((mShiftOn == 0) ? false : true);
- return false;
- }
- }
4、Keyboard
这里的Keyboard异常复杂,以至于需要一个5维数组来维护。
- /**
- * Keyboard surfaces
- * <br>
- * Keyboard[language][portrait/landscape][keyboard type][shift off/on][key-mode]
- */
- protected Keyboard[][][][][][] mKeyboard;
- /**
- * Keyboard surfaces
- * <br>
- * Keyboard[language][portrait/landscape][keyboard type][shift off/on][key-mode]
- */
- protected Keyboard[][][][][][] mKeyboard;
键盘的处理还是比复杂,因为根据不同的输入框,需要显示不同的键盘;同时用户可以选择不同的输入法模式,此时又需要显示不同的键盘。这一点从onUpdateState 函数,以及onKey函数等可以看出。
另外,有些手机不是纯触摸屏的,也就是带有键盘的手机。对于这些手机是不会显示软键盘的(我猜测),对此需要对硬件盘信息进行设置。其中setHardKeyboardHidden函数就是用于做这些事情的。
5、onUpdateState
从函数名我们可以看出这一函数的目的是用于更新状态,主要是用户更新键盘状态(或者是切换键盘)。从DefaultSoftKeyboard类中代码可以看出:
- /** @see jp.co.omronsoft.openwnn.InputViewManager#onUpdateState */
- public void onUpdateState(OpenWnn parent) {
- try {
- if (parent.mComposingText.size(1) == 0) {
- if (!mNoInput) {
- /* when the mode changed to "no input" */
- mNoInput = true;
- Keyboard newKeyboard = getKeyboardInputed(false);
- if (mCurrentKeyboard != newKeyboard) {
- changeKeyboard(newKeyboard);
- }
- }
- } else {
- if (mNoInput) {
- /* when the mode changed to "input some characters" */
- mNoInput = false;
- Keyboard newKeyboard = getKeyboardInputed(true);
- if (mCurrentKeyboard != newKeyboard) {
- changeKeyboard(newKeyboard);
- }
- }
- }
- } catch (Exception ex) {
- }
- }
- /** @see jp.co.omronsoft.openwnn.InputViewManager#onUpdateState */
- public void onUpdateState(OpenWnn parent) {
- try {
- if (parent.mComposingText.size(1) == 0) {
- if (!mNoInput) {
- /* when the mode changed to "no input" */
- mNoInput = true;
- Keyboard newKeyboard = getKeyboardInputed(false);
- if (mCurrentKeyboard != newKeyboard) {
- changeKeyboard(newKeyboard);
- }
- }
- } else {
- if (mNoInput) {
- /* when the mode changed to "input some characters" */
- mNoInput = false;
- Keyboard newKeyboard = getKeyboardInputed(true);
- if (mCurrentKeyboard != newKeyboard) {
- changeKeyboard(newKeyboard);
- }
- }
- }
- } catch (Exception ex) {
- }
- }
- /**
- * Status of the composing text
- * <br>
- * {@code true} if there is no composing text.
- */
- protected boolean mNoInput = true;
- /**
- * Status of the composing text
- * <br>
- * {@code true} if there is no composing text.
- */
- protected boolean mNoInput = true;
这一段代码主要是根据当前的输入状态,来更新键盘的。程序判断当前输入串(这里指输入时,带有下划线的输入串)是否为空。若输入串为空,判断mNoInput是否为有输入串(false),若是,则mNoInput改为true,同时键盘改为没有输入串的状态;若输入串不为空,此时若未没有输入串的状态,则要改为有输入串的状态,并相应修改键盘。
而DefaultSoftKeyboardJAJP中的这段代码则较为简单:
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#onUpdateState */
- @Override public void onUpdateState(OpenWnn parent) {
- super.onUpdateState(parent);
- setShiftByEditorInfo();
- }
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#onUpdateState */
- @Override public void onUpdateState(OpenWnn parent) {
- super.onUpdateState(parent);
- setShiftByEditorInfo();
- }
- /**
- * Set the shift key state from {@link EditorInfo}.
- */
- private void setShiftByEditorInfo() {
- if (mEnableAutoCaps && (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)) {
- int shift = getShiftKeyState(mWnn.getCurrentInputEditorInfo());
- mShiftOn = shift;
- changeKeyboard(getShiftChangeKeyboard(shift));
- }
- }
- /**
- * Set the shift key state from {@link EditorInfo}.
- */
- private void setShiftByEditorInfo() {
- if (mEnableAutoCaps && (mCurrentKeyMode == KEYMODE_JA_HALF_ALPHABET)) {
- int shift = getShiftKeyState(mWnn.getCurrentInputEditorInfo());
- mShiftOn = shift;
- changeKeyboard(getShiftChangeKeyboard(shift));
- }
- }
6、输入方式(直接上屏或者参与变换)
另外,在使用输入法输入时,通常会有两种方式,一种是参与变换,一种是直接上屏。参与变换是指,你输入的内容与你需要选择的内容不是一致的,而是通过一系列复杂的变换得到的,比如你输入”kawai“得到”可愛“,就是通过变换而来的;而你在输入字符或者数字时,通常是直接上屏的。前者需要显示CandidateView的,而后者不要。
这一点可能影响的地方包括:不同的输入框(如密码输入框)和不同的输入模式(或者说是输入内容),比如输入数字和字符时,通常就是直接上屏的。
对于这一部分的技术处理,我们从DefaultSoftKeyboardJAJP类中的changeKeyMode函数可以看出一点端倪。由于该函数代码有点长,就不展现出来了。我们看其中几行代码:
- case KEYMODE_JA_HALF_ALPHABET:
- if (USE_ENGLISH_PREDICT) {
- mInputType = INPUT_TYPE_TOGGLE;
- mode = OpenWnnEvent.Mode.NO_LV1_CONV;
- } else {
- mInputType = INPUT_TYPE_TOGGLE;
- mode = OpenWnnEvent.Mode.DIRECT;
- }
- break;
- case KEYMODE_JA_HALF_ALPHABET:
- if (USE_ENGLISH_PREDICT) {
- mInputType = INPUT_TYPE_TOGGLE;
- mode = OpenWnnEvent.Mode.NO_LV1_CONV;
- } else {
- mInputType = INPUT_TYPE_TOGGLE;
- mode = OpenWnnEvent.Mode.DIRECT;
- }
- break;
另外changeKeyMode函数的前两行是
- int targetMode = keyMode;
- commitText();
- int targetMode = keyMode;
- commitText();
另外,需要提一下,在openwnn日文输入法中,有一个功能是切换输入模式,如下图
左下角那个“文字”按钮,你按一下他会不断变换,从假名输入、英文输入、数字输入循环切换。
其实现方式如下:
- /** Input mode toggle cycle table */
- private static final int[] JP_MODE_CYCLE_TABLE = {
- KEYMODE_JA_FULL_HIRAGANA, KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER
- };
- /** Input mode toggle cycle table */
- private static final int[] JP_MODE_CYCLE_TABLE = {
- KEYMODE_JA_FULL_HIRAGANA, KEYMODE_JA_HALF_ALPHABET, KEYMODE_JA_HALF_NUMBER
- };
- /**
- * Change to the next input mode
- */
- private 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 */
- index++;
- if (JP_MODE_CYCLE_TABLE.length <= index) {
- index = 0;
- }
- changeKeyMode(JP_MODE_CYCLE_TABLE[index]);
- }
- }
- /**
- * Change to the next input mode
- */
- private 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 */
- index++;
- if (JP_MODE_CYCLE_TABLE.length <= index) {
- index = 0;
- }
- changeKeyMode(JP_MODE_CYCLE_TABLE[index]);
- }
- }
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#onKey */
- @Override public void onKey(int primaryCode, int[] keyCodes) {
- switch (primaryCode) {
- case KEYCODE_JP12_TOGGLE_MODE:
- case KEYCODE_QWERTY_TOGGLE_MODE:
- nextKeyMode();
- break;
- /** @see jp.co.omronsoft.openwnn.DefaultSoftKeyboard#onKey */
- @Override public void onKey(int primaryCode, int[] keyCodes) {
- switch (primaryCode) {
- case KEYCODE_JP12_TOGGLE_MODE:
- case KEYCODE_QWERTY_TOGGLE_MODE:
- nextKeyMode();
- break;
7、输入变换
7.1 12key键盘
在12key的键盘中,是无法显示所有输入内容的。于是你按一个键,可能包含多个信息。比如诺基亚的12键键盘:
在这种键盘中,你要输入c,则要按三下”2“键才可以。
同样的,在日文输入法中,如下键盘(软键盘),你是无法显示所有输入内容的,因此,你可能也像用诺基亚键盘一样,需要按多次才可以输入一个内容。
比如,在如上键盘中,你按”か“键,则按1下、2下、3下、4下,5下,6下……显示的内容分别是:"か","き", "く", "け", "こ","か",……。(注意需要在假名输入模式下)
这里的程序实现是比较巧妙,其中涉及的代码如下:
- /** 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"},
- };
- /** 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"},
- };
- {"あ", "い", "う", "え", "お", "ぁ", "ぃ", "ぅ", "ぇ", "ぉ"},
- {"か", "き", "く", "け", "こ"},
- {"さ", "し", "す", "せ", "そ"},
- {"た", "ち", "つ", "て", "と", "っ"},
- {"な", "に", "ぬ", "ね", "の"},
- {"は", "ひ", "ふ", "へ", "ほ"},
- {"ま", "み", "む", "め", "も"},
- {"や", "ゆ", "よ", "ゃ", "ゅ", "ょ"},
- {"ら", "り", "る", "れ", "ろ"},
- {"わ", "を", "ん", "ゎ", "ー"},
- {"、", "。", "?", "!", "・", " "},
- {"あ", "い", "う", "え", "お", "ぁ", "ぃ", "ぅ", "ぇ", "ぉ"},
- {"か", "き", "く", "け", "こ"},
- {"さ", "し", "す", "せ", "そ"},
- {"た", "ち", "つ", "て", "と", "っ"},
- {"な", "に", "ぬ", "ね", "の"},
- {"は", "ひ", "ふ", "へ", "ほ"},
- {"ま", "み", "む", "め", "も"},
- {"や", "ゆ", "よ", "ゃ", "ゅ", "ょ"},
- {"ら", "り", "る", "れ", "ろ"},
- {"わ", "を", "ん", "ゎ", "ー"},
- {"、", "。", "?", "!", "・", " "},
在@Override public void onKey(int primaryCode, int[] keyCodes)函数中:
- 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 OpenWnnEvent(OpenWnnEvent.INPUT_CHAR,
- mCurrentInstantTable[getTableIndex(primaryCode)]));
- } else {
- if ((mPrevInputKeyCode != primaryCode)) {
- 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 */
- String[][] cycleTable = getCycleTable();
- if (cycleTable == null) {
- Log.e("OpenWnn", "not founds cycle table");
- } else {
- int index = getTableIndex(primaryCode);
- mWnn.onEvent(new OpenWnnEvent(OpenWnnEvent.TOGGLE_CHAR, cycleTable[index]));
- mCurrentCycleTable = cycleTable[index];
- }
- mPrevInputKeyCode = primaryCode;
- }
- break;
这篇关于android输入法02:openwnn源码解析02—Keyboard和KeyboardView的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!