4、SoftKeyboard


[java]  view plain copy

    1. /**
    2.  * Example of writing an input method for a soft keyboard.  This code is
    3.  * focused on simplicity over completeness, so it should in no way be considered
    4.  * to be a complete soft keyboard implementation.  Its purpose is to provide
    5.  * a basic example for how you would get started writing an input method, to
    6.  * be fleshed out as appropriate.
    7.  */  
    8. public class SoftKeyboard extends InputMethodService   
    9. implements KeyboardView.OnKeyboardActionListener {  
    10. static final boolean DEBUG = false;  
    11.       
    12. /**
    13.      * This boolean indicates the optional example code for performing
    14.      * processing of hard keys in addition to regular text generation
    15.      * from on-screen interaction.  It would be used for input methods that
    16.      * perform language translations (such as converting text entered on 
    17.      * a QWERTY keyboard to Chinese), but may not be used for input methods
    18.      * that are primarily intended to be used for on-screen text entry.
    19.      */  
    20. //是否在用硬键盘,这里默认的是总可以使用,费柴变量  
    21. static final boolean PROCESS_HARD_KEYS = true;  
    22.       
    23. //键盘view对象,但不是自己定义的类latinkeyboardview....   
    24. private KeyboardView mInputView;  
    25. //候选栏对象  
    26. private CandidateView mCandidateView;  
    27. //候选串之串  
    28. private CompletionInfo[] mCompletions;  
    29.       
    30. private StringBuilder mComposing = new StringBuilder();  
    31. //这东西是决定能不能有候选条  
    32. private boolean mPredictionOn;  
    33. //决定auto是否需要显示在候选栏  
    34. private boolean mCompletionOn;  
    35.       
    36. private int mLastDisplayWidth;  
    37. private boolean mCapsLock;  
    38. private long mLastShiftTime;  
    39. //matakey的按下状态,猜测是每种组合对应一个此值?  
    40. private long mMetaState;  
    41.       
    42. private LatinKeyboard mSymbolsKeyboard;  
    43. private LatinKeyboard mSymbolsShiftedKeyboard;  
    44. private LatinKeyboard mQwertyKeyboard;  
    45.       
    46. //当前键盘  
    47. private LatinKeyboard mCurKeyboard;  
    48.       
    49. //默认的使得输入中断的字符  
    50. private String mWordSeparators;  
    51.       
    52. /**
    53.      * Main initialization of the input method component.  Be sure to call
    54.      * to super class.
    55.      */  
    56. @Override public void onCreate() {  
    57. super.onCreate();  
    58. //对resource这个东西有了一些了解:getResources是contextWrapper类的函数,contextWrapper而是inputmethodservice  
    59. //的间接基类  
    60.         mWordSeparators = getResources().getString(R.string.word_separators);  
    61. "mytest", "SoftKeyboard_onCreate");  
    62.     }  
    63.       
    64. /**
    65.      * This is the point where you can do all of your UI initialization.  It
    66.      * is called after creation and any configuration change.
    67.      */  
    68. @Override public void onInitializeInterface() {  
    69. "mytest", "SoftKeyboard_onInitializeInterface");  
    70. //这只加载键盘,类似于findViewById,离真正生成界面还早  
    71. if (mQwertyKeyboard != null) {  
    72. // Configuration changes can happen after the keyboard gets recreated,  
    73. // so we need to be able to re-build the keyboards if the available  
    74. // space has changed.  
    75. //可用的,最大屏幕宽度,好像也没什么用  
    76. int displayWidth = getMaxWidth();  
    77. if (displayWidth == mLastDisplayWidth) return;  
    78. //难道就是为了记录最大宽度于mLastDisplayWidth?  
    79.             mLastDisplayWidth = displayWidth;  
    80.         }  
    81. new LatinKeyboard(this, R.xml.qwerty);  
    82. new LatinKeyboard(this, R.xml.symbols);  
    83. new LatinKeyboard(this, R.xml.symbols_shift);  
    84.     }  
    85.       
    86. /**
    87.      * Called by the framework when your view for creating input needs to
    88.      * be generated.  This will be called the first time your input method
    89.      * is displayed, and every time it needs to be re-created such as due to
    90.      * a configuration change.
    91.      */  
    92. @Override public View onCreateInputView() {  
    93. "mytest", "SoftKeyboard_onCreateInputView");  
    94.         mInputView = (KeyboardView) getLayoutInflater().inflate(  
    95. null);  
    96. //上边的函数findViewById对于keyboardView是不能用的  
    97. //只对TextView等可以用  
    98. this);  
    99.         mInputView.setKeyboard(mQwertyKeyboard);  
    100. //通过这个return,自己定义的keyboardview类对象就与这个类绑定了  
    101. return mInputView;  
    102.     }  
    103.   
    104. /**
    105.      * Called by the framework when your view for showing candidates needs to
    106.      * be generated, like {@link #onCreateInputView}.
    107.      */  
    108. @Override public View onCreateCandidatesView() {  
    109. "mytest", "SoftKeyboard_onCreateCandidatesView");  
    110. new CandidateView(this);  
    111. //为什么参数是this??因为activity,inputmethodservice,这都是context的派生类  
    112. this);//在CandidateView类里面对这个类的描述中,参数就是个  
    113. return mCandidateView; //这一步很重要,后面的setCandidatesViewShown(false);就是个返回的结果造成的?  
    114.     }  
    115.   
    116. /**
    117.      * This is the main point where we do our initialization of the input method
    118.      * to begin operating on an application.  At this point we have been
    119.      * bound to the client, and are now receiving all of the detailed information
    120.      * about the target of our edits.
    121.      */  
    122. @Override public void onStartInput(EditorInfo attribute, boolean restarting) {  
    123. super.onStartInput(attribute, restarting);  
    124. "mytest", "SoftKeyboard_onStartInput");  
    125. // Reset our state.  We want to do this even if restarting, because  
    126. // the underlying state of the text editor could have changed in any way.  
    127. //一个StringBuilder,前面定义的  
    128. 0);  
    129. //可知此处的candidateview注定还不显示  
    130.           
    131. if (!restarting) {  
    132. // Clear shift states.  
    133. 0;  
    134.         }  
    135.           
    136. false; //猜测:是否需要显示候选词条,证实确实如此  
    137. false; //允许auto的内容显示在后选栏中  
    138. null;  
    139.           
    140. // We are now going to initialize our state based on the type of  
    141. // text being edited.  
    142. //一个靠谱的猜测:inputtype的给定值里面有那么几个掩码,但是从参数传来的具体inputtype值里面包含了所有的信息,不同的掩码能够得出不同的信息  
    143. //例如TYPE_MASK_CLASS就能得出下面四种,这四种属于同一类期望信息,这个信息叫做CLASS,下面一个掩码TYPE_MASK_VARIATION按位与出来的是一类  
    144. //叫做VARIATION的信息  
    145. switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {  
    146. case EditorInfo.TYPE_CLASS_NUMBER:  
    147. case EditorInfo.TYPE_CLASS_DATETIME:  
    148. // Numbers and dates default to the symbols keyboard, with  
    149. // no extra features.  
    150.                 mCurKeyboard = mSymbolsKeyboard;  
    151. break;  
    152.                   
    153. case EditorInfo.TYPE_CLASS_PHONE:  
    154. // Phones will also default to the symbols keyboard, though  
    155. // often you will want to have a dedicated phone keyboard.  
    156.                 mCurKeyboard = mSymbolsKeyboard;  
    157. break;  
    158.                   
    159. case EditorInfo.TYPE_CLASS_TEXT:  
    160. // This is general text editing.  We will default to the  
    161. // normal alphabetic keyboard, and assume that we should  
    162. // be doing predictive text (showing candidates as the  
    163. // user types).  
    164.                 mCurKeyboard = mQwertyKeyboard;  
    165. true;  
    166.                   
    167. // We now look for a few special variations of text that will  
    168. // modify our behavior.  
    169. int variation = attribute.inputType &  EditorInfo.TYPE_MASK_VARIATION;  
    170. if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||  
    171.                         variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {  
    172. // Do not display predictions / what the user is typing  
    173. // when they are entering a password.  
    174. false; //密码框的输入是不需要候选词条的  
    175.                 }  
    176.                   
    177. if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS   
    178.                         || variation == EditorInfo.TYPE_TEXT_VARIATION_URI  
    179.                         || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {  
    180. // Our predictions are not useful for e-mail addresses  
    181. // or URIs.  
    182. false;   //如果是网站或者是邮箱地址,不用候选词条  
    183.                 }  
    184.                   
    185. if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {  
    186. //开始界面的那个输入框,就是自动生成的  
    187. // If this is an auto-complete text view, then our predictions  
    188. // will not be shown and instead we will allow the editor  
    189. // to supply their own.  We only show the editor's  
    190. // candidates when in fullscreen mode, otherwise relying  
    191. // own it displaying its own UI.  
    192. false;  
    193. //经过测试,当输入法处在全屏模式的时候,原本auto的候选词会显示在输入法的候选栏中  
    194. //这是mCompletiOn的作用,这个值初始化设为false.  
    195. //如果把这里的两个值都设置为true则可以发现再输入任意auto的时候都会在候选栏中显示auto的词语  
    196. //所以,变量mCompletionOn的后续作用需要监视  
    197.   
    198. //这两行做后续测试: 真值:false,isFullscreenMode()  
    199.                     mCompletionOn = isFullscreenMode();  
    200.                 }  
    201.                   
    202. // We also want to look at the current state of the editor  
    203. // to decide whether our alphabetic keyboard should start out  
    204. // shifted.  
    205.                 updateShiftKeyState(attribute);  
    206. break;  
    207.                   
    208. default:  
    209. // For all unknown input types, default to the alphabetic  
    210. // keyboard with no special features.  
    211.                 mCurKeyboard = mQwertyKeyboard;  
    212. //决定是否需要初始大写状态  
    213.         }  
    214.           
    215. // Update the label on the enter key, depending on what the application  
    216. // says it will do.  
    217. //根据输入目标设置回车键  
    218.     }  
    219.   
    220. /**
    221.      * This is called when the user is done editing a field.  We can use
    222.      * this to reset our state.
    223.      */  
    224. @Override public void onFinishInput() {  
    225. super.onFinishInput();  
    226. "mytest", "SoftKeyboard_onFinishInput");  
    227. //经测试,终于发现,start与finish,在输入框切换的时候,平时这俩结束函数并不调用,或许输入框只是隐藏。  
    228.   
    229. //测试语句      mInputView=null;  
    230. // Clear current composing text and candidates.  
    231. 0);  
    232.         updateCandidates();  
    233.           
    234. // We only hide the candidates window when finishing input on  
    235. // a particular editor, to avoid popping the underlying application  
    236. // up and down if the user is entering text into the bottom of  
    237. // its window.  
    238. false);//默认的就是不可见的  
    239.           
    240.         mCurKeyboard = mQwertyKeyboard;  
    241. if (mInputView != null) {  
    242. //据分析,关闭输入界面和收起输入界面还不是一回事?  
    243.         }  
    244.     }  
    245.       
    246. @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {  
    247. super.onStartInputView(attribute, restarting);  
    248. //如果没有这个函数的作用,在切换输入目标的时候不会发生键盘的变化  
    249. //而且经过测试,这个函数执行的时间是开始输入的时候  
    250. // Apply the selected keyboard to the input view.  
    251. "mytest", "SoftKeyboard_onStartInputView");  
    252.         mInputView.setKeyboard(mCurKeyboard);  
    253. //这个是转换键盘的关键  
    254. //mInputView是自己定义的一个键盘  
    255. //这个语句能让整个需要输入的目标关闭?到底是干什么用的??疑问?  
    256.     }  
    257.       
    258. /**
    259.      * Deal with the editor reporting movement of its cursor.
    260.      */  
    261. @Override public void onUpdateSelection(int oldSelStart, int oldSelEnd,  
    262. int newSelStart, int newSelEnd,  
    263. int candidatesStart, int candidatesEnd) {  
    264. //光标!  
    265. super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,  
    266.                 candidatesStart, candidatesEnd);  
    267. "mytest", "SoftKeyboard_onUpdateSelection");  
    268. // If the current selection in the text view changes, we should  
    269. // clear whatever candidate text we have.  
    270. //当输入框向输入法报告用户移动了光标时调用。,当用户移动输入框中的光标的时候,它就默认的表示本次输入完成了,  
    271. //然后将候选词以及正在输入的文本复位,并且向编辑器报告输入法已经完成了一个输入。  
    272. //四个整形都是坐标?  
    273. if (mComposing.length() > 0 && (newSelStart != candidatesEnd  
    274.                 || newSelEnd != candidatesEnd)) {  
    275. 0);//这才是候选栏置空的精义所在  
    276. //候选栏置空  
    277. //这个语句和下面if里面那个,决定了结束输入的全过程  
    278. if (ic != null) {  
    279. //这个语句的作用是,让输入目标内的下划线去掉,完成一次编辑  
    280.             }  
    281.         }  
    282.     }  
    283.   
    284. /**
    285.      * This tells us about completions that the editor has determined based
    286.      * on the current text in it.  We want to use this in fullscreen mode
    287.      * to show the completions ourself, since the editor can not be seen
    288.      * in that situation.
    289.      */  
    290. @Override public void onDisplayCompletions(CompletionInfo[] completions) {  
    291. //当需要在候选栏里面显示auto的内容  
    292. //此函数作用,猜测:当全屏幕模式的时候,mCompletionOn置true,可以通过候选栏来显示auto  
    293. "mytest", "SoftKeyboard_onDisplayCompletions");  
    294. if (mCompletionOn) { //必须这个变量允许  
    295. //赋值给本来里面专门记录候选值的变量  
    296. if (completions == null) {  
    297. null, false, false); //如果没有候选词,就这样处置  
    298. return;  
    299.             }  
    300.               
    301. new ArrayList<String>();  
    302. for (int i=0; i<(completions != null ? completions.length : 0); i++) {  
    303.                 CompletionInfo ci = completions[i];  
    304. if (ci != null) stringList.add(ci.getText().toString());  
    305.             }  
    306. true, true);  
    307.         }  
    308.     }  
    309.       
    310. /**
    311.      * This translates incoming hard key events in to edit operations on an
    312.      * InputConnection.  It is only needed when using the
    313.      * PROCESS_HARD_KEYS option.
    314.      */  
    315. private boolean translateKeyDown(int keyCode, KeyEvent event) {  
    316. //这个函数在OnKeyDown中用到了  
    317. //这个是当组合键时候用,shift+A或者别的Alt+A之类  
    318. "mytest", "SoftKeyboard_translateKeyDown");  
    319.         mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,  
    320.                 keyCode, event);  
    321. //处理matakey的按下,猜测:每一个long型的mMetaState值都代表着一个meta键组合值。8成是对的  
    322. int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState)); //如果没这套组合键,就返回0  
    323. //这又是在干什么?猜测:每一个mMetaState值,对应着一个unicode值,这一步就是为了得到它,此猜测正确  
    324. //重置这个元状态。当取得了C值之后,完全可以重置元状态了,后面的语句不会出现任何问题。  
    325. //上面这三行有点疑问  
    326.         mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);  
    327.           
    328. //后边这函数是inputmethodservice自己的,获得当前的链接  
    329.         InputConnection ic = getCurrentInputConnection();  
    330. if (c == 0 || ic == null) {  
    331. return false;  
    332.         }  
    333.           
    334. //一个dead=true意味着是一个有定义的组合键  
    335. boolean dead = false;  
    336.   
    337. //看看c所昭示的这个键能不能被允许组合键  
    338. if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {  
    339. //定义下来看能否使用这个组合键  
    340. true;  
    341. //这样就得到了真正的码值  
    342.             c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;  
    343.         }  
    344.           
    345. //这是处理“编辑中最后字符越变”的情况   
    346. if (mComposing.length() > 0) {  
    347. char accent = mComposing.charAt(mComposing.length() -1 );//返回正在编辑的字串的最后一个字符  
    348. //这种情况下最后是返回了新的阿斯课码。composed最终还是要还给c.作为onKey的参数。  
    349. int composed = KeyEvent.getDeadChar(accent, c);  
    350.   
    351. if (composed != 0) {  
    352.                 c = composed;  
    353. 1); // 要把最后一个字符去掉,才能够在下一步中越变成为新的字符  
    354.             }  
    355.         }  
    356.           
    357. null); //强制输入C,这样就实现了组合键的功效  
    358.           
    359. return true;  
    360.     }  
    361.       
    362. /**
    363.      * Use this to monitor key events being delivered to the application.
    364.      * We get first crack at them, and can either resume them or let them
    365.      * continue to the app.
    366.      */  
    367. @Override public boolean onKeyDown(int keyCode, KeyEvent event) {  
    368. "mytest", "SoftKeyboard_onKeyDown");  
    369. //这是重载了基类的,经测试确定,只有在硬件盘被敲击时候才调用,除了那个键本身的功效,还有这里定义的这些  
    370. //是对输入法的影响  
    371. switch (keyCode) {  
    372. case KeyEvent.KEYCODE_BACK: //这就是那个破箭头,扭曲的  
    373. // The InputMethodService already takes care of the back  
    374. // key for us, to dismiss the input method if it is shown.  
    375. // However, our keyboard could be showing a pop-up window  
    376. // that back should dismiss, so we first allow it to do that.  
    377. //mInputView类是自己定义的keyBoardView类  
    378. if (event.getRepeatCount() == 0 && mInputView != null) {  
    379. if (mInputView.handleBack()) {//通过弯钩键来关闭键盘的元凶在这里  
    380. //这函数干吗呢?猜测:如果成功地荡掉了键盘,就返回真  
    381. return true;  
    382.                     }  
    383.                 }  
    384. break;  
    385.                   
    386. case KeyEvent.KEYCODE_DEL:  
    387. // Special handling of the delete key: if we currently are  
    388. // composing text for the user, we want to modify that instead  
    389. // of let the application to the delete itself.  
    390. if (mComposing.length() > 0) {  
    391. null); //所以,onkey定义中的事情才是软键盘的事件  
    392. return true;  
    393.                 }  
    394. break;  
    395.                   
    396. case KeyEvent.KEYCODE_ENTER:  
    397. // Let the underlying text editor always handle these.  
    398. return false;  
    399.                   
    400. default:  
    401. // For all other keys, if we want to do transformations on  
    402. // text being entered with a hard keyboard, we need to process  
    403. // it and do the appropriate action.  
    404. if (PROCESS_HARD_KEYS) {  //这个是个废柴变量,因为在前面赋值了,永远是true  
    405. if (keyCode == KeyEvent.KEYCODE_SPACE  
    406. 0) {  
    407. //为什么有这个按位与?因为这个META_ALT_ON就是用来按位与来判断是否按下alt  
    408. //条件:alt+空格  
    409. // A silly example: in our input method, Alt+Space  
    410. // is a shortcut for 'android' in lower case.  
    411.                         InputConnection ic = getCurrentInputConnection();  
    412. if (ic != null) {  
    413. // First, tell the editor that it is no longer in the  
    414. // shift state, since we are consuming this.  
    415. // 清除组合键状态,如果不清除,出来的字符就不是Android  
    416. //由此可知,这些函数才是控制显示字符的,但貌似没那么简单  
    417.                             keyDownUp(KeyEvent.KEYCODE_A);  
    418.                             keyDownUp(KeyEvent.KEYCODE_N);  
    419.                             keyDownUp(KeyEvent.KEYCODE_D);  
    420.                             keyDownUp(KeyEvent.KEYCODE_R);  
    421.                             keyDownUp(KeyEvent.KEYCODE_O);  
    422.                             keyDownUp(KeyEvent.KEYCODE_I);  
    423.                             keyDownUp(KeyEvent.KEYCODE_D);  
    424. // And we consume this event.  
    425. return true;  
    426.                         }  
    427.                     }  
    428. if (mPredictionOn && translateKeyDown(keyCode, event)) {  
    429. return true;  
    430.                     }  
    431.                 }  
    432.         }  
    433.           
    434. return super.onKeyDown(keyCode, event);  
    435.     }  
    436.   
    437. /**
    438.      * Use this to monitor key events being delivered to the application.
    439.      * We get first crack at them, and can either resume them or let them
    440.      * continue to the app.
    441.      */  
    442. @Override public boolean onKeyUp(int keyCode, KeyEvent event) {  
    443. // If we want to do transformations on text being entered with a hard  
    444. // keyboard, we need to process the up events to update the meta key  
    445. // state we are tracking.  
    446. "mytest", "SoftKeyboard_onKeyUp");  
    447. if (PROCESS_HARD_KEYS) {  
    448. //哈哈,判断是不在使用硬件输入  
    449. //要懂得,mete keys意味着shift和alt这类的键  
    450. if (mPredictionOn) {  
    451. //处理matakey的释放  
    452.                 mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,  
    453.                         keyCode, event);  
    454.             }  
    455.         }  
    456. //只有在一个键被放起时候执行,但经过测试,他不是执行输入的,仅仅是再输入之前做些事务,  
    457. return super.onKeyUp(keyCode, event);  
    458.     }  
    459.   
    460. /**
    461.      * Helper function to commit any text being composed in to the editor.
    462.      */  
    463. private void commitTyped(InputConnection inputConnection) {  
    464. "mytest", "SoftKeyboard_commitTyped");  
    465. if (mComposing.length() > 0) {  
    466. //后边的参数决定了光标的应有位置  
    467. 0);  
    468. //这两行联手,一般能造成候选栏置空与候选词条串置空的效果  
    469.         }  
    470.     }  
    471.   
    472. /**
    473.      * Helper to update the shift state of our keyboard based on the initial
    474.      * editor state.
    475.      */  
    476. private void updateShiftKeyState(EditorInfo attr) {  
    477. //但是,这个函数每次输入一个字母都要执行  
    478. //用于在开始输入前切换大写  
    479. //它首先是判断是否输入视图存在,并且输入框要求有输入法,然后根据输入框的输入类型来获得是否需要大小写,最后定义在输入视图上。  
    480. //经测试,每当键盘刚出来的时候会有,每输入一个字符都会有这个函数的作用  
    481. "mytest", "SoftKeyboard_updateShiftKeyState");  
    482. //getKeyboard又是个可得私有变量的公有函数  
    483. //条件的含义是:当有字母键盘存在的时候  
    484. if (attr != null   
    485. null && mQwertyKeyboard == mInputView.getKeyboard()) {  
    486. int caps = 0;  
    487. //获得当前输入框的信息?本.java中,大多数的attr参数于这个东西等同  
    488. //这个破inputtype类型是全0,一般不会有这种破类型  
    489. if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) {  
    490. //返回的东西不是光标位置,得到的是  
    491. //是否需要大写的判断,但是返回值是怎么弄的??  
    492.             }  
    493. 0);  
    494.         }  
    495.     }  
    496.       
    497. /**
    498.      * Helper to determine if a given character code is alphabetic.
    499.      */  
    500. private boolean isAlphabet(int code) {  
    501. //看看是不是字母  
    502. "mytest", "SoftKeyboard_isAlphabet");  
    503. if (Character.isLetter(code)) {  
    504. return true;  
    505. else {  
    506. return false;  
    507.         }  
    508.     }  
    509.       
    510. /**
    511.      * Helper to send a key down / key up pair to the current editor.
    512.      */  
    513. private void keyDownUp(int keyEventCode) {  
    514. "mytest", "SoftKeyboard_keyDownUp");  
    515.         getCurrentInputConnection().sendKeyEvent(  
    516. new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); //参见文档中KeyEvent  
    517.         getCurrentInputConnection().sendKeyEvent(  
    518. new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));  
    519. //明白了,这个函数是用来特殊输出的,就好像前面定义的“android”输出,但如果简单地从键盘输入字符,是不会经过这一步的     
    520. //一点都没错,强制输出,特殊输出,就这里  
    521. //  keyDownUp(KeyEvent.KEYCODE_N);  
    522. //  keyDownUp(KeyEvent.KEYCODE_B);  
    523.     }  
    524.       
    525. /**
    526.      * Helper to send a character to the editor as raw key events.
    527.      */  
    528. private void sendKey(int keyCode) {  
    529. //传入的参数是阿斯课码  
    530. //处理中断符的时候使用到了  
    531. "mytest", "SoftKeyboard_sendKey");  
    532. switch (keyCode) {  
    533. case '\n':  
    534.                 keyDownUp(KeyEvent.KEYCODE_ENTER);  
    535. break;  
    536. default:  
    537. if (keyCode >= '0' && keyCode <= '9') {  
    538. '0' + KeyEvent.KEYCODE_0);  
    539. else {  
    540. char) keyCode), 1);  
    541.                 }  
    542. break;  
    543.         }  
    544.     }  
    545.   
    546. // Implementation of KeyboardViewListener  
    547. // Implementation of KeyboardViewListener  
    548. //你难道没看见这个类定义时候的接口吗?那个接口定义的监听函数就是为了监听这种On事件的,这就是软键盘按压事件  
    549. public void onKey(int primaryCode, int[] keyCodes) {  
    550. "mytest", "SoftKeyboard_onKey");  
    551. //后面定义的函数  
    552. //当输入被中断符号中断  
    553. if (isWordSeparator(primaryCode)) {  
    554. // Handle separator  
    555. if (mComposing.length() > 0) {  
    556.                 commitTyped(getCurrentInputConnection());  
    557.             }  
    558. //提交完了输出之后,还必须要把这个特殊字符写上  
    559. //看看是否到了特殊的位置,需要改变大小写状态  
    560. else if (primaryCode == Keyboard.KEYCODE_DELETE) {  
    561.             handleBackspace();  
    562. else if (primaryCode == Keyboard.KEYCODE_SHIFT) {  
    563.             handleShift();  
    564. else if (primaryCode == Keyboard.KEYCODE_CANCEL) { //左下角那个键,关闭  
    565.             handleClose();  
    566. return;  
    567. else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {  
    568. //这个键,是这样的,前面的LatinKeyboardView这个类里面定义了KEYCODE_OPTIONS  
    569. //用来描述长按左下角关闭键的代替。经测试,千真万确  
    570. // Show a menu or somethin'  
    571. else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE  
    572. null) { //就是显示着“abc”或者"123"的那个键  
    573.             Keyboard current = mInputView.getKeyboard();  
    574. if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {  
    575.                 current = mQwertyKeyboard;  
    576. else {  
    577.                 current = mSymbolsKeyboard;  
    578.             }  
    579. //改变键盘的根本操作,但是对于具体输入的是大写字母这件事情,还要等按下了之后在做定论  
    580.             mInputView.setKeyboard(current);  
    581. if (current == mSymbolsKeyboard) {  
    582. false); //测试,这里要是设置为true,打开之后只是shift键的绿点变亮,但是并没有变成另一个符号键盘  
    583.             }  
    584. else {  
    585. //这就是处理真正的字符处理函数,不是那些其他的控制键  
    586.         }  
    587.     }  
    588.   
    589. public void onText(CharSequence text) { //这也是接口类的触发的函数。什么时候响应,有待考证  
    590. "mytest", "SoftKeyboard_onText");  
    591.         InputConnection ic = getCurrentInputConnection();  
    592. if (ic == null) return;  
    593.         ic.beginBatchEdit();  
    594. if (mComposing.length() > 0) {  
    595.             commitTyped(ic);  
    596.         }  
    597. 0);  
    598.         ic.endBatchEdit();  
    599. //看是否需要切换大小写  
    600.     }  
    601.   
    602. /**
    603.      * Update the list of available candidates from the current composing
    604.      * text.  This will need to be filled in by however you are determining
    605.      * candidates.
    606.      */  
    607. private void updateCandidates() {//此函数处理的是不允许从auto获取的情况,应该是大多数情况  
    608. "mytest", "SoftKeyboard_updateCandidates");  
    609. if (!mCompletionOn) {  
    610. if (mComposing.length() > 0) { //mComposing记录着候选字符串之串,待考证  
    611. new ArrayList<String>();  
    612.                 list.add(mComposing.toString());  
    613. true, true);  
    614. else {  
    615. null, false, false);  
    616.             }  
    617.         }  
    618.     }  
    619.       
    620. public void setSuggestions(List<String> suggestions, boolean completions,  
    621. boolean typedWordValid) {  
    622. //这第三个参数是前面函数调用的时候人为给的,没什么玄妙  
    623. "mytest", "SoftKeyboard_setSuggestions");  
    624. if (suggestions != null && suggestions.size() > 0) {  
    625. true);  
    626. else if (isExtractViewShown()) {  
    627. true);  
    628.         }  
    629. if (mCandidateView != null) {  
    630.             mCandidateView.setSuggestions(suggestions, completions, typedWordValid);  
    631. //就是改变了一下suggestion,在candidateView里面真正靠的是onDraw  
    632.         }  
    633.     }  
    634. //删除一个字,用的就是他  
    635. private void handleBackspace() {  
    636. "mytest", "SoftKeyboard_handleBackspace");  
    637. final int length = mComposing.length();  
    638. if (length > 1) {//就是在说等于1的时候  
    639. 1, length);  
    640. 1);  
    641.             updateCandidates();  
    642. else if (length > 0) {  
    643. 0);  
    644. "", 0);  
    645.             updateCandidates();  
    646. else {  
    647.             keyDownUp(KeyEvent.KEYCODE_DEL);  
    648.         }  
    649.         updateShiftKeyState(getCurrentInputEditorInfo());  
    650.     }  
    651.   
    652. private void handleShift() {//这才是大小写的切换,是正常切换(通过转换键)  
    653. "mytest", "SoftKeyboard_handleShift");  
    654. if (mInputView == null) {  
    655. return;  
    656.         }  
    657.           
    658.         Keyboard currentKeyboard = mInputView.getKeyboard();  
    659. if (mQwertyKeyboard == currentKeyboard) {  
    660. // Alphabet keyboard  
    661. //只有当键盘是字母键盘的时候,需要检验锁(控制变幻频率,不能过快)  
    662.             mInputView.setShifted(mCapsLock || !mInputView.isShifted());  
    663. else if (currentKeyboard == mSymbolsKeyboard) {  
    664. true);   
    665. //所谓的setShift,仅仅指的是那个键盘的大小写键变化,经测试,只要android:code=-1就有这种绿点效果  
    666.             mInputView.setKeyboard(mSymbolsShiftedKeyboard);  
    667. true);  
    668. else if (currentKeyboard == mSymbolsShiftedKeyboard) {  
    669. false);  
    670.             mInputView.setKeyboard(mSymbolsKeyboard);  
    671. false);  
    672.         }  
    673.     }  
    674.       
    675. private void handleCharacter(int primaryCode, int[] keyCodes) {  //primayCode是键的阿斯课码值  
    676. "mytest", "SoftKeyboard_handleCharacter");  
    677. if (isInputViewShown()) {  
    678. if (mInputView.isShifted()) {  
    679.                 primaryCode = Character.toUpperCase(primaryCode);  
    680. //这才真正把这个字符变成了大写的效果,经测试,没有就不行  
    681. //把键盘换成大写的了还不够,那只是从View上解决了问题,一定要这样一句才行  
    682.             }  
    683.         }  
    684. if (isAlphabet(primaryCode) && mPredictionOn) {  //输入的是个字母,而且允许候选栏显示  
    685. char) primaryCode); //append(添加)就是把当前的输入的一个字符放到mComposing里面来  
    686. 1);//在输入目标中也显示最新得到的mComposing.  
    687. //每当输入完结,都要检验是否需要变到大写        
    688.             updateCandidates();  
    689. else {  
    690. //比如说当输入的是“‘”这个符号的时候,就会掉用这个  
    691. //结果就是remove掉所有编辑中的字符,第二个参数的正负,决定着  
    692. //光标位置的不同  
    693.             getCurrentInputConnection().commitText(  
    694. char) primaryCode), 1);  
    695.         }  
    696.     }  
    697.   
    698. private void handleClose() {  
    699. "mytest", "SoftKeyboard_handleClose");  
    700. //关闭键盘件的作用就在这里,左下角那个.,记住!!!!!左下角那个,不是弯钩键!!!!  
    701.         commitTyped(getCurrentInputConnection());  
    702. 0); //关掉输入法的区域,这才是关闭的王道.似乎这句包含了上面那句的作用(测试结果)  
    703. //这个函数不懂什么意思待问?? 哪里都测试,哪里都没有用处??  
    704.     }  
    705.   
    706. private void checkToggleCapsLock() {  
    707. "mytest", "SoftKeyboard_checkToggleCapsLock");  
    708. long now = System.currentTimeMillis();//记录上次变幻的时间  
    709. if (mLastShiftTime + 800 > now) {//不允许频繁地换大小写?  
    710.             mCapsLock = !mCapsLock;  
    711. 0;  
    712. else {  
    713.             mLastShiftTime = now;  
    714.         }  
    715.     }  
    716.       
    717. private String getWordSeparators() {  
    718. "mytest", "SoftKeyboard_getWordSeparators");  
    719. return mWordSeparators;  
    720.     }  
    721.       
    722. public boolean isWordSeparator(int code) {  
    723. "mytest", "SoftKeyboard_isWordSeparator");  
    724. //检查所属入的字符有没有在这些字符里面  
    725. return separators.contains(String.valueOf((char)code));  
    726.     }  
    727.   
    728. public void pickDefaultCandidate() {  
    729. "mytest", "SoftKeyboard_pickDefaultCandidate");  
    730. 0);  
    731.     }  
    732.       
    733. public void pickSuggestionManually(int index) {  
    734. "mytest", "SoftKeyboard_pickSuggestionManually");  
    735. if (mCompletionOn && mCompletions != null && index >= 0  
    736.                 && index < mCompletions.length) {  
    737.             CompletionInfo ci = mCompletions[index];  
    738.             getCurrentInputConnection().commitCompletion(ci);  
    739. if (mCandidateView != null) {  
    740.                 mCandidateView.clear();  
    741.             }  
    742.             updateShiftKeyState(getCurrentInputEditorInfo());  
    743. else if (mComposing.length() > 0) {  
    744. // If we were generating candidate suggestions for the current  
    745. // text, we would commit one of them here.  But for this sample,  
    746. // we will just commit the current text.  
    747.             commitTyped(getCurrentInputConnection());  
    748.         }  
    749.     }  
    750.       
    751. //着下面6个函数,完全是因为声明了那个接口类,所以必须要包含这几个函数,还有上面的几个函数,但是实际上这些函数可以没有意义  
    752. public void swipeRight() {  
    753. "mytest", "SoftKeyboard_swipeRight");  
    754. if (mCompletionOn) {  
    755.             pickDefaultCandidate();  
    756.         }  
    757.     }  
    758.       
    759. public void swipeLeft() {  
    760. "mytest", "SoftKeyboard_swipeLeft");  
    761.         handleBackspace();  
    762.     }  
    763.   
    764. public void swipeDown() {  
    765. "mytest", "SoftKeyboard_swipeDown");  
    766.         handleClose();  
    767.     }  
    768.   
    769. public void swipeUp() {  
    770. "mytest", "SoftKeyboard_swipeUp");  
    771.     }  
    772.       
    773. public void onPress(int primaryCode) {  
    774. "mytest", "SoftKeyboard_onPress");  
    775.     }  
    776.       
    777. public void onRelease(int primaryCode) {  
    778. "mytest", "SoftKeyboard_onRelease");  
    779.     }  
    780. }

    参考文献:

    android sdk中 softkeyboard的自己解析(1)android sdk中 softkeyboard的自己解析(2)android sdk中 softkeyboard的自己解析(3)android sdk中 softkeyboard的自己解析(4)