Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發實例 >> android sdk中 softkeyboard的自己解析(4)

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

編輯:Android開發實例

4.SoftKeyBoard.java



 

  1. /*  
  2. * Copyright (C) 2008-2009 Google Inc.  
  3. *   
  4. * Licensed under the Apache License, Version 2.0 (the "License"); you may not  
  5. * use this file except in compliance with the License. You may obtain a copy of  
  6. * the License at  
  7. *   
  8. * http://www.apache.org/licenses/LICENSE-2.0  
  9. *   
  10. * Unless required by applicable law or agreed to in writing, software  
  11. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT  
  12. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the  
  13. * License for the specific language governing permissions and limitations under  
  14. * the License.  
  15. */ 
  16.  
  17. package com.example.android.softkeyboard;  
  18.  
  19. import android.inputmethodservice.InputMethodService;  
  20. import android.inputmethodservice.Keyboard;  
  21. import android.inputmethodservice.KeyboardView;  
  22. import android.text.method.MetaKeyKeyListener;  
  23. //加入了這個,你就能夠隨意使用metakey的listener  
  24. import android.util.Log;  
  25. import android.view.KeyCharacterMap;  
  26. import android.view.KeyEvent;  
  27. import android.view.View;  
  28. import android.view.inputmethod.CompletionInfo;  
  29. import android.view.inputmethod.EditorInfo;  
  30. import android.view.inputmethod.InputConnection;  
  31. import android.view.inputmethod.InputMethodManager;  
  32.  
  33. import java.util.ArrayList;  
  34. import java.util.List;  
  35.  
  36. /**  
  37. * Example of writing an input method for a soft keyboard.  This code is  
  38. * focused on simplicity over completeness, so it should in no way be considered  
  39. * to be a complete soft keyboard implementation.  Its purpose is to provide  
  40. * a basic example for how you would get started writing an input method, to  
  41. * be fleshed out as appropriate.  
  42. */ 
  43. public class SoftKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener {  
  44. static final boolean DEBUG = false;  
  45.  
  46. /**  
  47. * This boolean indicates the optional example code for performing  
  48. * processing of hard keys in addition to regular text generation  
  49. * from on-screen interaction.  It would be used for input methods that  
  50. * perform language translations (such as converting text entered on   
  51. * a QWERTY keyboard to Chinese), but may not be used for input methods  
  52. * that are primarily intended to be used for on-screen text entry.  
  53. */ 
  54. static final boolean PROCESS_HARD_KEYS = true;   //是否在用硬鍵盤,這裡默認的是總可以使用,費柴變量  
  55.  
  56. private KeyboardView mInputView;       //鍵盤view對象,但不是自己定義的類latinkeyboardview....  
  57. private CandidateView mCandidateView;  //候選欄對象  
  58. private CompletionInfo[] mCompletions; //候選串之串  
  59. private StringBuilder mComposing = new StringBuilder();    //一個字符串  
  60. private boolean mPredictionOn;  //這東西是決定能不能有候選條  
  61. private boolean mCompletionOn;  //決定auto是否需要顯示在候選欄  
  62. private int mLastDisplayWidth;   
  63. private boolean mCapsLock;  
  64. private long mLastShiftTime;  
  65. private long mMetaState;    //matakey的按下狀態,猜測是每種組合對應一個此值?  
  66.  
  67. private LatinKeyboard mSymbolsKeyboard;//符號鍵盤1  
  68. private LatinKeyboard mSymbolsShiftedKeyboard;//符號鍵盤2  
  69. private LatinKeyboard mQwertyKeyboard;//字母鍵盤  
  70.  
  71. private LatinKeyboard mCurKeyboard;//當前鍵盤  
  72.  
  73. private String mWordSeparators;   //默認的使得輸入中斷的字符  
  74.  
  75. /**  
  76. * Main initialization of the input method component.  Be sure to call  
  77. * to super class.  
  78. */ 
  79. @Override public void onCreate() {  
  80. super.onCreate();  
  81. mWordSeparators = getResources().getString(R.string.word_separators);    
  82. //對resource這個東西有了一些了解:getResources是contextWrapper類的函數,contextWrapper而是inputmethodservice  
  83. //的間接基類  
  84. }  
  85.  
  86. /**  
  87. * This is the point where you can do all of your UI initialization.  It  
  88. * is called after creation and any configuration change.  
  89. */ 
  90. @Override public void onInitializeInterface() {  
  91. //這只加載鍵盤,類似於findViewById,離真正生成界面還早  
  92. if (mQwertyKeyboard != null) {                              //什麼時候符合判斷條件??  
  93. // Configuration changes can happen after the keyboard gets recreated,  
  94. // so we need to be able to re-build the keyboards if the available  
  95. // space has changed.  
  96. int displayWidth = getMaxWidth();//可用的,最大屏幕寬度,好像也沒什麼用  
  97. //就這個函數用了一下這個變量  
  98. if (displayWidth == mLastDisplayWidth) return;  
  99. mLastDisplayWidth = displayWidth;     //難道就是為了記錄最大寬度於mLastDisplayWidth?  
  100. }  
  101. //如果是剛開始,那就執行下面的  
  102. mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);  
  103. mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);  
  104. mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);  
  105. }  
  106.  
  107. /**  
  108. * Called by the framework when your view for creating input needs to  
  109. * be generated.  This will be called the first time your input method  
  110. * is displayed, and every time it needs to be re-created such as due to  
  111. * a configuration change.  
  112. */ 
  113. @Override public View onCreateInputView() {  
  114. //    mInputView = (KeyboardView)findViewById(R.layout.input);  
  115. //上邊的函數findViewById對於keyboardView是不能用的  
  116. //只對TextView等可以用  
  117. mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null);  
  118. //這是inputmethodservice類特有的加載資源的過程?  
  119.  
  120. mInputView.setOnKeyboardActionListener(this);  //加載監聽函數,建類的時候已經加載了監聽函數  
  121. mInputView.setKeyboard(mQwertyKeyboard);  
  122. return mInputView;   //通過這個return,自己定義的keyboardview類對象就與這個類綁定了  
  123. }  
  124.  
  125. /**  
  126. * Called by the framework when your view for showing candidates needs to  
  127. * be generated, like [email protected] #onCreateInputView}.  
  128. */ 
  129. @Override public View onCreateCandidatesView() {  
  130. mCandidateView = new CandidateView(this);   //為什麼參數是this??因為activity,inputmethodservice,這都是context的派生類  
  131. mCandidateView.setService(this);            //在CandidateView類裡面對這個類的描述中,參數就是個SoftKeyboard  
  132. //     CandidateView mCandidateView1=new CandidateView(null);  
  133.  
  134. return mCandidateView;                      //這一步很重要,後面的setCandidatesViewShown(false);就是個返回的結果造成的?  
  135. }  
  136.  
  137. /**  
  138. * This is the main point where we do our initialization of the input method  
  139. * to begin operating on an application.  At this point we have been  
  140. * bound to the client, and are now receiving all of the detailed information  
  141. * about the target of our edits.  
  142. */ 
  143. @Override public void onStartInput(EditorInfo attribute, boolean restarting) {  
  144. super.onStartInput(attribute, restarting);  
  145.  
  146. // Reset our state.  We want to do this even if restarting, because  
  147. // the underlying state of the text editor could have changed in any way.  
  148. mComposing.setLength(0);  
  149. //一個StringBuilder,前面定義的  
  150. updateCandidates();  
  151. //可知此處的candidateview注定還不顯示  
  152.  
  153.  
  154. if (!restarting) {  
  155. // Clear shift states.  
  156. mMetaState = 0;  
  157. }  
  158.  
  159. mPredictionOn = false;  //猜測:是否需要顯示候選詞條,證實確實如此  
  160. mCompletionOn = false;  //允許auto的內容顯示在後選欄中  
  161. mCompletions = null;    //候選串之串?  
  162.  
  163. // We are now going to initialize our state based on the type of  
  164. // text being edited.  
  165.  
  166. //一個靠譜的猜測:inputtype的給定值裡面有那麼幾個掩碼,但是從參數傳來的具體inputtype值裡面包含了所有的信息,不同的掩碼能夠得出不同的信息  
  167. //例如TYPE_MASK_CLASS就能得出下面四種,這四種屬於同一類期望信息,這個信息叫做CLASS,下面一個掩碼TYPE_MASK_VARIATION按位與出來的是一類  
  168. //叫做VARIATION的信息  
  169.  
  170. switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {           
  171. //按位與的兩者是同一類型的,attribute是EditorInfo類型的參數                                  
  172. case EditorInfo.TYPE_CLASS_NUMBER:  
  173. case EditorInfo.TYPE_CLASS_DATETIME:  
  174. // Numbers and dates default to the symbols keyboard, with  
  175. // no extra features.  
  176. mCurKeyboard = mSymbolsKeyboard;         //跟據不同的輸入框的類型改變當前的鍵盤類型  
  177. break;  
  178.  
  179. case EditorInfo.TYPE_CLASS_PHONE:  
  180. // Phones will also default to the symbols keyboard, though  
  181. // often you will want to have a dedicated phone keyboard.  
  182. mCurKeyboard = mSymbolsKeyboard;  
  183. break;  
  184.  
  185. case EditorInfo.TYPE_CLASS_TEXT:  
  186. // This is general text editing.  We will default to the  
  187. // normal alphabetic keyboard, and assume that we should  
  188. // be doing predictive text (showing candidates as the  
  189. // user types).  
  190. mCurKeyboard = mQwertyKeyboard;  
  191. mPredictionOn = true;            //設置需要候選詞條  
  192.  
  193. // We now look for a few special variations of text that will  
  194. // modify our behavior.  
  195. int variation = attribute.inputType &  EditorInfo.TYPE_MASK_VARIATION;  
  196. if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {  
  197. // Do not display predictions / what the user is typing  
  198. // when they are entering a password.  
  199. mPredictionOn = false;         //密碼框的輸入是不需要候選詞條的  
  200. }  
  201.  
  202. if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS   
  203. || variation == EditorInfo.TYPE_TEXT_VARIATION_URI  
  204. || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {  
  205. // Our predictions are not useful for e-mail addresses  
  206. // or URIs.  
  207. mPredictionOn = false;          //如果是網站或者是郵箱地址,不用候選詞條  
  208. }  
  209.  
  210. if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { //開始界面的那個輸入框,就是自動生成的  
  211. // If this is an auto-complete text view, then our predictions        //是不是用TYPE_MASK_FLAGS 也可以?我的回答是肯定的  
  212. // will not be shown and instead we will allow the editor  
  213. // to supply their own.  We only show the editor's  
  214. // candidates when in fullscreen mode, otherwise relying  
  215. // own it displaying its own UI.  
  216. mPredictionOn = false;                 //不用候選詞條          
  217. mCompletionOn = isFullscreenMode();  //經過測試,當輸入法處在全屏模式的時候,原本auto的候選詞會顯示在輸入法的候選欄中  
  218. //這是mCompletiOn的作用,這個值初始化設為false.  
  219. //如果把這裡的兩個值都設置為true則可以發現再輸入任意auto的時候都會在候選欄中顯示auto的詞語  
  220. //所以,變量mCompletionOn的後續作用需要監視  
  221.  
  222. //這兩行做後續測試: 真值:false,isFullscreenMode()  
  223. }  
  224.  
  225. // We also want to look at the current state of the editor  
  226. // to decide whether our alphabetic keyboard should start out  
  227. // shifted.  
  228. updateShiftKeyState(attribute);  
  229. break;  
  230.  
  231. default:  
  232. // For all unknown input types, default to the alphabetic  
  233. // keyboard with no special features.  
  234. mCurKeyboard = mQwertyKeyboard;  
  235. updateShiftKeyState(attribute);     //決定是否需要初始大寫狀態  
  236. }  
  237.  
  238. // Update the label on the enter key, depending on what the application  
  239. // says it will do.  
  240. mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions); //根據輸入目標設置回車鍵  
  241. }  
  242.  
  243. /**  
  244. * This is called when the user is done editing a field.  We can use  
  245. * this to reset our state.  
  246. */ 
  247. @Override public void onFinishInput() {   //經測試,終於發現,start與finish,在輸入框切換的時候,平時這倆結束函數並不調用,或許輸入框只是隱藏。  
  248.  
  249. //測試語句      mInputView=null;  
  250. // Clear current composing text and candidates.  
  251. mComposing.setLength(0);  
  252. updateCandidates();  
  253.  
  254. // We only hide the candidates window when finishing input on  
  255. // a particular editor, to avoid popping the underlying application  
  256. // up and down if the user is entering text into the bottom of  
  257. // its window.  
  258. setCandidatesViewShown(false);    //默認的就是不可見的  
  259. //inputmethodservice的函數,能設置候選此條的可見性  
  260.  
  261. mCurKeyboard = mQwertyKeyboard;  
  262.  
  263. if (mInputView != null) {  
  264. mInputView.closing();          //據分析,關閉輸入界面和收起輸入界面還不是一回事?  
  265. }  
  266. }  
  267.  
  268. @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {  
  269. //如果沒有這個函數的作用,在切換輸入目標的時候不會發生鍵盤的變化  
  270. //而且經過測試,這個函數執行的時間是開始輸入的時候  
  271.  
  272. super.onStartInputView(attribute, restarting);  
  273. // Apply the selected keyboard to the input view.  
  274. mInputView.setKeyboard(mCurKeyboard);  //這個是轉換鍵盤的關鍵  
  275. //mInputView是自己定義的一個鍵盤  
  276. mInputView.closing();             //這個語句能讓整個需要輸入的目標關閉?到底是干什麼用的??疑問?  
  277.  
  278. }  
  279.  
  280. /**  
  281. * Deal with the editor reporting movement of its cursor.  
  282. */ 
  283. @Override   
  284. public void onUpdateSelection(int oldSelStart, int oldSelEnd,int newSelStart, int newSelEnd,int candidatesStart, int candidatesEnd) {  
  285. //光標!  
  286. super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,candidatesStart, candidatesEnd);  
  287. //當輸入框向輸入法報告用戶移動了光標時調用。,當用戶移動輸入框中的光標的時候,它就默認的表示本次輸入完成了,  
  288. //然後將候選詞以及正在輸入的文本復位,並且向編輯器報告輸入法已經完成了一個輸入。  
  289. //四個整形都是坐標?  
  290. // If the current selection in the text view changes, we should  
  291. // clear whatever candidate text we have.  
  292.  
  293. if (mComposing.length() > 0 && (newSelStart != candidatesEnd|| newSelEnd != candidatesEnd)) {  
  294. mComposing.setLength(0);                    //這才是候選欄置空的精義所在  
  295. updateCandidates();                         //候選欄置空  
  296. InputConnection ic = getCurrentInputConnection();  //這個語句和下面if裡面那個,決定了結束輸入的全過程  
  297. if (ic != null) {  
  298. ic.finishComposingText();             //這個語句的作用是,讓輸入目標內的下劃線去掉,完成一次編輯  
  299. }  
  300. }  
  301. //      mCompletionOn=false;  
  302. }  
  303.  
  304. /**  
  305. * This tells us about completions that the editor has determined based  
  306. * on the current text in it.  We want to use this in fullscreen mode  
  307. * to show the completions ourself, since the editor can not be seen  
  308. * in that situation.  
  309. */ 
  310. @Override public void onDisplayCompletions(CompletionInfo[] completions) {  //當需要在候選欄裡面顯示auto的內容  
  311. //此函數作用,猜測:當全屏幕模式的時候,mCompletionOn置true,可以通過候選欄來顯示auto  
  312. if (mCompletionOn) {                                  //必須這個變量允許  
  313. mCompletions = completions;                          //賦值給本來裡面專門記錄候選值的變量  
  314. if (completions == null) {  
  315. setSuggestions(null, false, false);           //如果沒有候選詞,就這樣處置  
  316. return;  
  317. }  
  318.  
  319. List<String> stringList = new ArrayList<String>();  
  320. for (int i=0; i<(completions != null ? completions.length : 0); i++) {  
  321. CompletionInfo ci = completions[i];  
  322. if (ci != null) stringList.add(ci.getText().toString());  //由CompletionInfo向String轉變的過程  
  323. }  
  324. setSuggestions(stringList, true, true);             
  325. }  
  326. }  
  327.  
  328. /**  
  329. * This translates incoming hard key events in to edit operations on an  
  330. * InputConnection.  It is only needed when using the  
  331. * PROCESS_HARD_KEYS option.  
  332. */ 
  333. private boolean translateKeyDown(int keyCode, KeyEvent event) {  
  334.  
  335.  
  336. //這個函數在OnKeyDown中用到了  
  337. //這個是當組合鍵時候用,shift+A或者別的Alt+A之類  
  338. mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,keyCode, event);  
  339. //處理matakey的按下,猜測:每一個long型的mMetaState值都代表著一個meta鍵組合值。8成是對的  
  340. int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState));   //如果沒這套組合鍵,就返回0  
  341. //這又是在干什麼?猜測:每一個mMetaState值,對應著一個unicode值,這一步就是為了得到它,此猜測正確  
  342. mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);  
  343. //重置這個元狀態。當取得了C值之後,完全可以重置元狀態了,後面的語句不會出現任何問題。  
  344. //上面這三行有點疑問  
  345.  
  346.  
  347. InputConnection ic = getCurrentInputConnection();  
  348. //後邊這函數是inputmethodservice自己的,獲得當前的鏈接  
  349. if (c == 0 || ic == null) {  
  350. return false;  
  351. }  
  352.  
  353. boolean dead = false;  
  354. //一個dead=true意味著是一個有定義的組合鍵  
  355. if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {  
  356. //看看c所昭示的這個鍵能不能被允許組合鍵  
  357. dead = true;                                 //定義下來看能否使用這個組合鍵  
  358. c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;  
  359. //這樣就得到了真正的碼值  
  360. }  
  361.  
  362. if (mComposing.length() > 0) {       //這是處理“編輯中最後字符越變”的情況   
  363. char accent = mComposing.charAt(mComposing.length() -1 );  //返回正在編輯的字串的最後一個字符  
  364. int composed = KeyEvent.getDeadChar(accent, c);   //這種情況下最後是返回了新的阿斯課碼。composed最終還是要還給c.作為onKey的參數。  
  365.  
  366. if (composed != 0) {  
  367. c = composed;                   
  368. mComposing.setLength(mComposing.length()-1); // 要把最後一個字符去掉,才能夠在下一步中越變成為新的字符  
  369. }  
  370. }  
  371.  
  372. onKey(c, null); //強制輸入C,這樣就實現了組合鍵的功效  
  373.  
  374. return true;  
  375. }  
  376.  
  377. /**  
  378. * Use this to monitor key events being delivered to the application.  
  379. * We get first crack at them, and can either resume them or let them  
  380. * continue to the app.  
  381. */ 
  382. @Override public boolean onKeyDown(int keyCode, KeyEvent event) {  
  383. //這是重載了基類的,經測試確定,只有在硬件盤被敲擊時候才調用,除了那個鍵本身的功效,還有這裡定義的這些  
  384. //是對輸入法的影響  
  385. switch (keyCode) {  
  386. case KeyEvent.KEYCODE_BACK:   //這就是那個破箭頭,扭曲的  
  387.  
  388.  
  389. // The InputMethodService already takes care of the back  
  390. // key for us, to dismiss the input method if it is shown.  
  391. // However, our keyboard could be showing a pop-up window  
  392. // that back should dismiss, so we first allow it to do that.  
  393. if (event.getRepeatCount() == 0 && mInputView != null) {  
  394. //mInputView類是自己定義的keyBoardView類  
  395.  
  396. if (mInputView.handleBack()) {            //通過彎鉤鍵來關閉鍵盤的元凶在這裡  
  397. //這函數干嗎呢?猜測:如果成功地蕩掉了鍵盤,就返回真  
  398.  
  399. return true;      
  400. }  
  401. }  
  402. break;  
  403.  
  404. case KeyEvent.KEYCODE_DEL:  
  405.  
  406. // Special handling of the delete key: if we currently are  
  407. // composing text for the user, we want to modify that instead  
  408. // of let the application to the delete itself.  
  409. if (mComposing.length() > 0) {  
  410. onKey(Keyboard.KEYCODE_DELETE, null);     //所以,onkey定義中的事情才是軟鍵盤的事件  
  411. return true;  
  412. }  
  413. break;  
  414.  
  415. case KeyEvent.KEYCODE_ENTER:  
  416. // Let the underlying text editor always handle these.  
  417. return false;  
  418.  
  419. case KeyEvent.KEYCODE_A:                             //當然了,這裡定義的是A鍵在本輸入法中的作用,他的本來的輸入作用並沒有受到影響  
  420.  
  421. break;  
  422. default:  
  423. // For all other keys, if we want to do transformations on  
  424. // text being entered with a hard keyboard, we need to process  
  425. // it and do the appropriate action.  
  426. if (PROCESS_HARD_KEYS) {              //這個是個廢柴變量,因為在前面賦值了,永遠是true  
  427. if (keyCode == KeyEvent.KEYCODE_SPACE && (event.getMetaState()&KeyEvent.META_ALT_ON) != 0) {  
  428. //為什麼有這個按位與?因為這個META_ALT_ON就是用來按位與來判斷是否按下alt  
  429. //條件:alt+空格  
  430. // A silly example: in our input method, Alt+Space  
  431. // is a shortcut for 'android' in lower case.  
  432. InputConnection ic = getCurrentInputConnection();  
  433. if (ic != null) {  
  434. // First, tell the editor that it is no longer in the  
  435. // shift state, since we are consuming this.  
  436. ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);  // 清除組合鍵狀態,如果不清除,出來的字符就不是Android  
  437. keyDownUp(KeyEvent.KEYCODE_A);  
  438. //由此可知,這些函數才是控制顯示字符的,但貌似沒那麼簡單  
  439. keyDownUp(KeyEvent.KEYCODE_N);  
  440. keyDownUp(KeyEvent.KEYCODE_D);  
  441. keyDownUp(KeyEvent.KEYCODE_R);  
  442. keyDownUp(KeyEvent.KEYCODE_O);  
  443. keyDownUp(KeyEvent.KEYCODE_I);  
  444. keyDownUp(KeyEvent.KEYCODE_D);  
  445.  
  446. // And we consume this event.  
  447. return true;  
  448. }  
  449. }  
  450. if (mPredictionOn && translateKeyDown(keyCode, event)) {  
  451. return true;  
  452. }  
  453. }  
  454. }  
  455.  
  456. return super.onKeyDown(keyCode, event);  
  457. }  
  458.  
  459. /**  
  460. * Use this to monitor key events being delivered to the application.  
  461. * We get first crack at them, and can either resume them or let them  
  462. * continue to the app.  
  463. */ 
  464. @Override public boolean onKeyUp(int keyCode, KeyEvent event) {  
  465. // If we want to do transformations on text being entered with a hard  
  466. // keyboard, we need to process the up events to update the meta key  
  467. // state we are tracking.  
  468. if (PROCESS_HARD_KEYS) {    //哈哈,判斷是不在使用硬件輸入  
  469. //要懂得,mete keys意味著shift和alt這類的鍵  
  470. if (mPredictionOn) {  
  471. mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,keyCode, event);  
  472. //處理matakey的釋放  
  473.  
  474. }  
  475. }  
  476.  
  477. return super.onKeyUp(keyCode, event);  
  478. //      return true;  
  479. //只有在一個鍵被放起時候執行,但經過測試,他不是執行輸入的,僅僅是再輸入之前做些事務,  
  480. }  
  481.  
  482. /**  
  483. * Helper function to commit any text being composed in to the editor.  
  484. */ 
  485. private void commitTyped(InputConnection inputConnection) {  
  486. if (mComposing.length() > 0) {  
  487. inputConnection.commitText(mComposing, mComposing.length());  //後邊的參數決定了光標的應有位置  
  488. mComposing.setLength(0);  
  489. updateCandidates();            //這兩行聯手,一般能造成候選欄置空與候選詞條串置空的效果  
  490. }  
  491. }  
  492.  
  493. /**  
  494. * Helper to update the shift state of our keyboard based on the initial  
  495. * editor state.  
  496. */ 
  497. private void updateShiftKeyState(EditorInfo attr) {   //但是,這個函數每次輸入一個字母都要執行  
  498. //用於在開始輸入前切換大寫  
  499. //它首先是判斷是否輸入視圖存在,並且輸入框要求有輸入法,然後根據輸入框的輸入類型來獲得是否需要大小寫,最後定義在輸入視圖上。  
  500. //經測試,每當鍵盤剛出來的時候會有,每輸入一個字符都會有這個函數的作用  
  501. if (attr != null&& mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {   //getKeyboard又是個可得私有變量的公有函數  
  502. //條件的含義是:當有字母鍵盤存在的時候  
  503. int caps = 0;  
  504. EditorInfo ei = getCurrentInputEditorInfo();     //獲得當前輸入框的信息?本.java中,大多數的attr參數於這個東西等同  
  505. if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) {  //這個破inputtype類型是全0,一般不會有這種破類型  
  506. caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);  //返回的東西不是光標位置,得到的是  
  507. //是否需要大寫的判斷,但是返回值是怎麼弄的??  
  508. }  
  509. mInputView.setShifted(mCapsLock || caps != 0);  //參數boolean  
  510. }  
  511. // keyDownUp(KeyEvent.KEYCODE_N);  
  512. // keyDownUp(KeyEvent.KEYCODE_B);  
  513. }  
  514.  
  515. /**  
  516. * Helper to determine if a given character code is alphabetic.  
  517. */ 
  518. private boolean isAlphabet(int code) {    //看看是不是字母  
  519. if (Character.isLetter(code)) {  
  520. return true;  
  521. } else {  
  522. return false;  
  523. }  
  524. }  
  525.  
  526. /**  
  527. * Helper to send a key down / key up pair to the current editor.  
  528. */ 
  529. private void keyDownUp(int keyEventCode) {  
  530. getCurrentInputConnection().sendKeyEvent(  
  531. new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));   //參見文檔中KeyEvent  
  532. getCurrentInputConnection().sendKeyEvent(  
  533. new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));  
  534.  
  535. //明白了,這個函數是用來特殊輸出的,就好像前面定義的“android”輸出,但如果簡單地從鍵盤輸入字符,是不會經過這一步的     
  536. //一點都沒錯,強制輸出,特殊輸出,就這裡  
  537. //  keyDownUp(KeyEvent.KEYCODE_N);  
  538. //  keyDownUp(KeyEvent.KEYCODE_B);  
  539. }  
  540.  
  541. /**  
  542. * Helper to send a character to the editor as raw key events.  
  543. */ 
  544. private void sendKey(int keyCode) {    //傳入的參數是阿斯課碼  
  545. //處理中斷符的時候使用到了  
  546. switch (keyCode) {  
  547. case '\n':  
  548. keyDownUp(KeyEvent.KEYCODE_ENTER);  
  549. //又是“特別輸入”或稱為“強制輸入”  
  550. break;  
  551. default:  
  552. if (keyCode >= '0' && keyCode <= '9') {  
  553. keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);  
  554. } else {  
  555. getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);  
  556. }  
  557. break;  
  558. }  
  559. }  
  560.  
  561. // Implementation of KeyboardViewListener  
  562. //你難道沒看見這個類定義時候的接口嗎?那個接口定義的監聽函數就是為了監聽這種On事件的,這就是軟鍵盤按壓事件  
  563. public void onKey(int primaryCode, int[] keyCodes) {  
  564. if (isWordSeparator(primaryCode)) {  //後面定義的函數  
  565. //當輸入被中斷符號中斷  
  566. // Handle separator  
  567. if (mComposing.length() > 0) {  
  568. commitTyped(getCurrentInputConnection());  
  569. }  
  570. sendKey(primaryCode);     //提交完了輸出之後,還必須要把這個特殊字符寫上  
  571. updateShiftKeyState(getCurrentInputEditorInfo());   //看看是否到了特殊的位置,需要改變大小寫狀態  
  572. } else if (primaryCode == Keyboard.KEYCODE_DELETE) {  
  573. handleBackspace();  
  574. } else if (primaryCode == Keyboard.KEYCODE_SHIFT) {   //但是硬鍵盤上面的這個好像沒用,待考證  
  575. //大小寫轉換  
  576. handleShift();  
  577. } else if (primaryCode == Keyboard.KEYCODE_CANCEL) {  //左下角那個鍵,關閉  
  578. handleClose();  
  579. return;  
  580. } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) {  //這個鍵,是這樣的,前面的LatinKeyboardView這個類裡面定義了KEYCODE_OPTIONS  
  581. //用來描述長按左下角關閉鍵的代替。經測試,千真萬確  
  582. // Show a menu or something'  
  583. } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE  //就是顯示著“abc”或者"123"的那個鍵  
  584. && mInputView != null) {  
  585. Keyboard current = mInputView.getKeyboard();  
  586. if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {  
  587. current = mQwertyKeyboard;  
  588. } else {  
  589. current = mSymbolsKeyboard;  
  590. }  
  591. mInputView.setKeyboard(current);   //改變鍵盤的根本操作,但是對於具體輸入的是大寫字母這件事情,還要等按下了之後在做定論  
  592. if (current == mSymbolsKeyboard) {  
  593. current.setShifted(false);     //測試,這裡要是設置為true,打開之後只是shift鍵的綠點變亮,但是並沒有變成另一個符號鍵盤  
  594. }  
  595. } else {  
  596. handleCharacter(primaryCode, keyCodes);     //這就是處理真正的字符處理函數,不是那些其他的控制鍵  
  597. }  
  598. }  
  599.  
  600. public void onText(CharSequence text) {   //這也是接口類的觸發的函數。什麼時候響應,有待考證  
  601.  
  602. InputConnection ic = getCurrentInputConnection();  
  603. if (ic == null) return;  
  604. ic.beginBatchEdit();  
  605. if (mComposing.length() > 0) {  
  606. commitTyped(ic);  
  607. }  
  608. ic.commitText(text, 0);  
  609. ic.endBatchEdit();  
  610. updateShiftKeyState(getCurrentInputEditorInfo());  //看是否需要切換大小寫  
  611. }  
  612.  
  613. /**  
  614. * Update the list of available candidates from the current composing  
  615. * text.  This will need to be filled in by however you are determining  
  616. * candidates.  
  617. */ 
  618. private void updateCandidates() {  
  619. //此函數處理的是不允許從auto獲取的情況,應該是大多數情況  
  620. if (!mCompletionOn) {                       
  621. if (mComposing.length() > 0) {             //mComposing記錄著候選字符串之串,待考證  
  622. ArrayList<String> list = new ArrayList<String>();  //字符串之串  
  623. list.add(mComposing.toString());  
  624. setSuggestions(list, true, true);  
  625. } else {  
  626. setSuggestions(null, false, false);  
  627. }  
  628. }  
  629. }  
  630.  
  631. public void setSuggestions(List<String> suggestions, boolean completions,boolean typedWordValid) {  
  632. //這第三個參數是前面函數調用的時候人為給的,沒什麼玄妙  
  633. if (suggestions != null && suggestions.size() > 0)   
  634. {  
  635. setCandidatesViewShown(true);           //讓候選欄可視  
  636. }   
  637. else if (isExtractViewShown())        //疑問?  
  638. {  
  639. setCandidatesViewShown(true);     //不止這個,很多地方都表明,當需要輸入的程序處在全屏的時候,需要候選欄顯示  
  640. }  
  641. if (mCandidateView != null)   //只有當有候選條的時候才顯示  
  642. {  
  643. mCandidateView.setSuggestions(suggestions, completions, typedWordValid);  //就是改變了一下suggestion,在candidateView裡面真正靠的是onDraw  
  644. }  
  645. }  
  646.  
  647. private void handleBackspace() {  
  648. //刪除一個字,用的就是他  
  649. final int length = mComposing.length();  
  650. if (length > 1) {  
  651. mComposing.delete(length - 1, length);  
  652. getCurrentInputConnection().setComposingText(mComposing, 1);  
  653. updateCandidates();  
  654. } else if (length > 0) {  
  655. //就是在說等於1的時候  
  656. mComposing.setLength(0);  
  657. getCurrentInputConnection().commitText("", 0);  
  658. updateCandidates();  
  659. } else {  
  660. keyDownUp(KeyEvent.KEYCODE_DEL);  
  661. }  
  662. updateShiftKeyState(getCurrentInputEditorInfo());  //看看是否需要重歸大寫狀態(例如又到達了行首)  
  663.  
  664. }  
  665.  
  666. private void handleShift() {  
  667. //這才是大小寫的切換,是正常切換(通過轉換鍵)  
  668. if (mInputView == null) {  
  669. return;  
  670. }  
  671.  
  672. Keyboard currentKeyboard = mInputView.getKeyboard();  
  673. if (mQwertyKeyboard == currentKeyboard) {  
  674. // Alphabet keyboard  
  675. checkToggleCapsLock();        //只有當鍵盤是字母鍵盤的時候,需要檢驗鎖(控制變幻頻率,不能過快)  
  676. mInputView.setShifted(mCapsLock || !mInputView.isShifted());  //關鍵語句  
  677. } else if (currentKeyboard == mSymbolsKeyboard) {  
  678. mSymbolsKeyboard.setShifted(true);  
  679. mInputView.setKeyboard(mSymbolsShiftedKeyboard);  
  680. mSymbolsShiftedKeyboard.setShifted(true);  
  681. } else if (currentKeyboard == mSymbolsShiftedKeyboard) {  
  682. mSymbolsShiftedKeyboard.setShifted(false);        //所謂的setShift,僅僅指的是那個鍵盤的大小寫鍵變化,經測試,只要android:code=-1就有這種綠點效果  
  683. //不用setShift()都行  
  684. mInputView.setKeyboard(mSymbolsKeyboard);         //這才是真正的shift工作(換成另外一個鍵盤)  
  685. mSymbolsKeyboard.setShifted(false);  
  686. }  
  687. }  
  688.  
  689. private void handleCharacter(int primaryCode, int[] keyCodes) {     //primayCode是鍵的阿斯課碼值  
  690. if (isInputViewShown()) {  
  691. if (mInputView.isShifted()) {  
  692. primaryCode = Character.toUpperCase(primaryCode);   //這才真正把這個字符變成了大寫的效果,經測試,沒有就不行  
  693. //把鍵盤換成大寫的了還不夠,那只是從View上解決了問題,一定要這樣一句才行  
  694. }  
  695. }  
  696. if (isAlphabet(primaryCode) && mPredictionOn) {       //輸入的是個字母,而且允許候選欄顯示  
  697. mComposing.append((char) primaryCode);            //append(添加)就是把當前的輸入的一個字符放到mComposing裡面來  
  698. getCurrentInputConnection().setComposingText(mComposing, 1);    //在輸入目標中也顯示最新得到的mComposing.  
  699. updateShiftKeyState(getCurrentInputEditorInfo());          //每當輸入完結,都要檢驗是否需要變到大寫  
  700. updateCandidates();           
  701. } else {  
  702. getCurrentInputConnection().commitText(String.valueOf((char) primaryCode), 1); //比如說當輸入的是“‘”這個符號的時候,就會掉用這個  
  703. //結果就是remove掉所有編輯中的字符,第二個參數的正負,決定著  
  704. //光標位置的不同  
  705. }  
  706. }  
  707.  
  708. private void handleClose() {  
  709. //關閉鍵盤件的作用就在這裡,左下角那個.,記住!!!!!左下角那個,不是彎鉤鍵!!!!  
  710. commitTyped(getCurrentInputConnection());  
  711. requestHideSelf(0);           //關掉輸入法的區域,這才是關閉的王道.似乎這句包含了上面那句的作用(測試結果)  
  712. mInputView.closing();        //這個函數不懂什麼意思待問?? 哪裡都測試,哪裡都沒有用處??  
  713. }  
  714.  
  715. private void checkToggleCapsLock() {  
  716. //記錄上次變幻的時間  
  717. long now = System.currentTimeMillis();  
  718. if (mLastShiftTime + 800 > now) {    
  719. //不允許頻繁地換大小寫?  
  720. mCapsLock = !mCapsLock;         
  721. mLastShiftTime = 0;  
  722. } else {  
  723. mLastShiftTime = now;  
  724. }  
  725. }  
  726.  
  727. private String getWordSeparators() {  
  728. return mWordSeparators;  
  729. }  
  730.  
  731. public boolean isWordSeparator(int code) {  
  732. String separators = getWordSeparators();  
  733. return separators.contains(String.valueOf((char)code));//檢查所屬入的字符有沒有在這些字符裡面  
  734. }  
  735.  
  736.  
  737. //下面這些函數是用來繼承的吧?  
  738.  
  739. public void pickDefaultCandidate() {  
  740. pickSuggestionManually(0);  
  741. }  
  742.  
  743. public void pickSuggestionManually(int index) {  
  744. if (mCompletionOn && mCompletions != null && index >= 0&& index < mCompletions.length) {  
  745. CompletionInfo ci = mCompletions[index];  
  746. getCurrentInputConnection().commitCompletion(ci);  
  747. if (mCandidateView != null) {  
  748. mCandidateView.clear();  
  749. }  
  750. updateShiftKeyState(getCurrentInputEditorInfo());  
  751. } else if (mComposing.length() > 0) {  
  752. // If we were generating candidate suggestions for the current  
  753. // text, we would commit one of them here.  But for this sample,  
  754. // we will just commit the current text.  
  755. commitTyped(getCurrentInputConnection());  
  756. }  
  757. }  
  758.  
  759. //著下面6個函數,完全是因為聲明了那個接口類,所以必須要包含這幾個函數,還有上面的幾個函數,但是實際上這些函數可以沒有意義  
  760.  
  761. public void swipeRight() {              //迅速從左向右搓所得到的結果  
  762. if (mCompletionOn) {                //如果候選欄允許顯示,將顯示第0個候選詞  
  763. pickDefaultCandidate();  
  764. }  
  765. }  
  766.  
  767. public void swipeLeft() {  //搓!  
  768. handleBackspace();  
  769. }  
  770.  
  771. public void swipeDown() {  
  772. handleClose();  
  773. }  
  774.  
  775. public void swipeUp() {  
  776. }  
  777.  
  778. public void onPress(int primaryCode) {  
  779. }  
  780.  
  781. public void onRelease(int primaryCode) {  
  782. }  
  783. }  

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved