android輸入法01:SoftKeyboard源碼解析03

4、SoftKeyboard

[java] view plaincopy
  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.         Log.i("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.         Log.i("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.         mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);  
  82.         mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);  
  83.         mSymbolsShiftedKeyboard = 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.         Log.i("mytest""SoftKeyboard_onCreateInputView");  
  94.         mInputView = (KeyboardView) getLayoutInflater().inflate(  
  95.                 R.layout.input, null);  
  96.       //上邊的函數findViewById對於keyboardView是不能用的  
  97.       //只對TextView等可以用  
  98.         mInputView.setOnKeyboardActionListener(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.         Log.i("mytest""SoftKeyboard_onCreateCandidatesView");  
  110.         mCandidateView = new CandidateView(this);  
  111.         //爲什麼參數是this??因爲activity,inputmethodservice,這都是context的派生類  
  112.         mCandidateView.setService(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.         Log.i("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.         mComposing.setLength(0);  
  129.         updateCandidates();//可知此處的candidateview註定還不顯示  
  130.           
  131.         if (!restarting) {  
  132.             // Clear shift states.  
  133.             mMetaState = 0;  
  134.         }  
  135.           
  136.         mPredictionOn = false//猜測:是否需要顯示候選詞條,證實確實如此  
  137.         mCompletionOn = false//允許auto的內容顯示在後選欄中  
  138.         mCompletions = 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.                 mPredictionOn = 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.                     mPredictionOn = 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.                     mPredictionOn = 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.                     mPredictionOn = 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.                 updateShiftKeyState(attribute);//決定是否需要初始大寫狀態  
  213.         }  
  214.           
  215.         // Update the label on the enter key, depending on what the application  
  216.         // says it will do.  
  217.         mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions);//根據輸入目標設置回車鍵  
  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.         Log.i("mytest""SoftKeyboard_onFinishInput");  
  227.         //經測試,終於發現,start與finish,在輸入框切換的時候,平時這倆結束函數並不調用,或許輸入框只是隱藏。  
  228.   
  229.       //測試語句      mInputView=null;  
  230.         // Clear current composing text and candidates.  
  231.         mComposing.setLength(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.         setCandidatesViewShown(false);//默認的就是不可見的  
  239.           
  240.         mCurKeyboard = mQwertyKeyboard;  
  241.         if (mInputView != null) {  
  242.             mInputView.closing(); //據分析,關閉輸入界面和收起輸入界面還不是一回事?  
  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.         Log.i("mytest""SoftKeyboard_onStartInputView");  
  252.         mInputView.setKeyboard(mCurKeyboard);  
  253.         //這個是轉換鍵盤的關鍵  
  254.       //mInputView是自己定義的一個鍵盤  
  255.         mInputView.closing(); //這個語句能讓整個需要輸入的目標關閉?到底是幹什麼用的??疑問?  
  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.         Log.i("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.             mComposing.setLength(0);//這纔是候選欄置空的精義所在  
  276.             updateCandidates();//候選欄置空  
  277.             InputConnection ic = getCurrentInputConnection(); //這個語句和下面if裏面那個,決定了結束輸入的全過程  
  278.             if (ic != null) {  
  279.                 ic.finishComposingText();//這個語句的作用是,讓輸入目標內的下劃線去掉,完成一次編輯  
  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.         Log.i("mytest""SoftKeyboard_onDisplayCompletions");  
  294.         if (mCompletionOn) { //必須這個變量允許  
  295.             mCompletions = completions; //賦值給本來裏面專門記錄候選值的變量  
  296.             if (completions == null) {  
  297.                 setSuggestions(nullfalsefalse); //如果沒有候選詞,就這樣處置  
  298.                 return;  
  299.             }  
  300.               
  301.             List<String> stringList = 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.             setSuggestions(stringList, truetrue);  
  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.         Log.i("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.             dead = 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.                 mComposing.setLength(mComposing.length()-1); // 要把最後一個字符去掉,才能夠在下一步中越變成爲新的字符  
  354.             }  
  355.         }  
  356.           
  357.         onKey(c, 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.         Log.i("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.                     onKey(Keyboard.KEYCODE_DELETE, 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.                             && (event.getMetaState()&KeyEvent.META_ALT_ON) != 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.                             ic.clearMetaKeyStates(KeyEvent.META_ALT_ON);// 清除組合鍵狀態,如果不清除,出來的字符就不是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.         Log.i("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.         Log.i("mytest""SoftKeyboard_commitTyped");  
  465.         if (mComposing.length() > 0) {  
  466.             inputConnection.commitText(mComposing, mComposing.length()); //後邊的參數決定了光標的應有位置  
  467.             mComposing.setLength(0);  
  468.             updateCandidates();//這兩行聯手,一般能造成候選欄置空與候選詞條串置空的效果  
  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.         Log.i("mytest""SoftKeyboard_updateShiftKeyState");  
  482.         //getKeyboard又是個可得私有變量的公有函數  
  483.         //條件的含義是:當有字母鍵盤存在的時候  
  484.         if (attr != null   
  485.                 && mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) {  
  486.             int caps = 0;  
  487.             EditorInfo ei = getCurrentInputEditorInfo(); //獲得當前輸入框的信息?本.java中,大多數的attr參數於這個東西等同  
  488.           //這個破inputtype類型是全0,一般不會有這種破類型  
  489.             if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) {  
  490.                 caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType);//返回的東西不是光標位置,得到的是  
  491.               //是否需要大寫的判斷,但是返回值是怎麼弄的??  
  492.             }  
  493.             mInputView.setShifted(mCapsLock || caps != 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.         Log.i("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.         Log.i("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.         Log.i("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.                     keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);  
  539.                 } else {  
  540.                     getCurrentInputConnection().commitText(String.valueOf((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.         Log.i("mytest""SoftKeyboard_onKey");  
  551.          //後面定義的函數  
  552.         //當輸入被中斷符號中斷  
  553.         if (isWordSeparator(primaryCode)) {  
  554.             // Handle separator  
  555.             if (mComposing.length() > 0) {  
  556.                 commitTyped(getCurrentInputConnection());  
  557.             }  
  558.             sendKey(primaryCode); //提交完了輸出之後,還必須要把這個特殊字符寫上  
  559.             updateShiftKeyState(getCurrentInputEditorInfo());//看看是否到了特殊的位置,需要改變大小寫狀態  
  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.                 && mInputView != 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.                 current.setShifted(false); //測試,這裏要是設置爲true,打開之後只是shift鍵的綠點變亮,但是並沒有變成另一個符號鍵盤  
  583.             }  
  584.         } else {  
  585.             handleCharacter(primaryCode, keyCodes); //這就是處理真正的字符處理函數,不是那些其他的控制鍵  
  586.         }  
  587.     }  
  588.   
  589.     public void onText(CharSequence text) { //這也是接口類的觸發的函數。什麼時候響應,有待考證  
  590.         Log.i("mytest""SoftKeyboard_onText");  
  591.         InputConnection ic = getCurrentInputConnection();  
  592.         if (ic == nullreturn;  
  593.         ic.beginBatchEdit();  
  594.         if (mComposing.length() > 0) {  
  595.             commitTyped(ic);  
  596.         }  
  597.         ic.commitText(text, 0);  
  598.         ic.endBatchEdit();  
  599.         updateShiftKeyState(getCurrentInputEditorInfo());//看是否需要切換大小寫  
  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.         Log.i("mytest""SoftKeyboard_updateCandidates");  
  609.         if (!mCompletionOn) {  
  610.             if (mComposing.length() > 0) { //mComposing記錄着候選字符串之串,待考證  
  611.                 ArrayList<String> list = new ArrayList<String>();  
  612.                 list.add(mComposing.toString());  
  613.                 setSuggestions(list, truetrue);  
  614.             } else {  
  615.                 setSuggestions(nullfalsefalse);  
  616.             }  
  617.         }  
  618.     }  
  619.       
  620.     public void setSuggestions(List<String> suggestions, boolean completions,  
  621.             boolean typedWordValid) {  
  622.         //這第三個參數是前面函數調用的時候人爲給的,沒什麼玄妙  
  623.         Log.i("mytest""SoftKeyboard_setSuggestions");  
  624.         if (suggestions != null && suggestions.size() > 0) {  
  625.             setCandidatesViewShown(true);  
  626.         } else if (isExtractViewShown()) {  
  627.             setCandidatesViewShown(true);  
  628.         }  
  629.         if (mCandidateView != null) {  
  630.             mCandidateView.setSuggestions(suggestions, completions, typedWordValid);  
  631.             //就是改變了一下suggestion,在candidateView裏面真正靠的是onDraw  
  632.         }  
  633.     }  
  634.   //刪除一個字,用的就是他  
  635.     private void handleBackspace() {  
  636.         Log.i("mytest""SoftKeyboard_handleBackspace");  
  637.         final int length = mComposing.length();  
  638.         if (length > 1) {//就是在說等於1的時候  
  639.             mComposing.delete(length - 1, length);  
  640.             getCurrentInputConnection().setComposingText(mComposing, 1);  
  641.             updateCandidates();  
  642.         } else if (length > 0) {  
  643.             mComposing.setLength(0);  
  644.             getCurrentInputConnection().commitText(""0);  
  645.             updateCandidates();  
  646.         } else {  
  647.             keyDownUp(KeyEvent.KEYCODE_DEL);  
  648.         }  
  649.         updateShiftKeyState(getCurrentInputEditorInfo());  
  650.     }  
  651.   
  652.     private void handleShift() {//這纔是大小寫的切換,是正常切換(通過轉換鍵)  
  653.         Log.i("mytest""SoftKeyboard_handleShift");  
  654.         if (mInputView == null) {  
  655.             return;  
  656.         }  
  657.           
  658.         Keyboard currentKeyboard = mInputView.getKeyboard();  
  659.         if (mQwertyKeyboard == currentKeyboard) {  
  660.             // Alphabet keyboard  
  661.             checkToggleCapsLock();  //只有當鍵盤是字母鍵盤的時候,需要檢驗鎖(控制變幻頻率,不能過快)  
  662.             mInputView.setShifted(mCapsLock || !mInputView.isShifted());  
  663.         } else if (currentKeyboard == mSymbolsKeyboard) {  
  664.             mSymbolsKeyboard.setShifted(true);   
  665.             //所謂的setShift,僅僅指的是那個鍵盤的大小寫鍵變化,經測試,只要android:code=-1就有這種綠點效果  
  666.             mInputView.setKeyboard(mSymbolsShiftedKeyboard);  
  667.             mSymbolsShiftedKeyboard.setShifted(true);  
  668.         } else if (currentKeyboard == mSymbolsShiftedKeyboard) {  
  669.             mSymbolsShiftedKeyboard.setShifted(false);  
  670.             mInputView.setKeyboard(mSymbolsKeyboard);  
  671.             mSymbolsKeyboard.setShifted(false);  
  672.         }  
  673.     }  
  674.       
  675.     private void handleCharacter(int primaryCode, int[] keyCodes) {  //primayCode是鍵的阿斯課碼值  
  676.         Log.i("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.             mComposing.append((char) primaryCode); //append(添加)就是把當前的輸入的一個字符放到mComposing裏面來  
  686.             getCurrentInputConnection().setComposingText(mComposing, 1);//在輸入目標中也顯示最新得到的mComposing.  
  687.             updateShiftKeyState(getCurrentInputEditorInfo()); //每當輸入完結,都要檢驗是否需要變到大寫        
  688.             updateCandidates();  
  689.         } else {  
  690.              //比如說當輸入的是“‘”這個符號的時候,就會掉用這個  
  691.             //結果就是remove掉所有編輯中的字符,第二個參數的正負,決定着  
  692.             //光標位置的不同  
  693.             getCurrentInputConnection().commitText(  
  694.                     String.valueOf((char) primaryCode), 1);  
  695.         }  
  696.     }  
  697.   
  698.     private void handleClose() {  
  699.         Log.i("mytest""SoftKeyboard_handleClose");  
  700.         //關閉鍵盤件的作用就在這裏,左下角那個.,記住!!!!!左下角那個,不是彎鉤鍵!!!!  
  701.         commitTyped(getCurrentInputConnection());  
  702.         requestHideSelf(0); //關掉輸入法的區域,這纔是關閉的王道.似乎這句包含了上面那句的作用(測試結果)  
  703.         mInputView.closing(); //這個函數不懂什麼意思待問?? 哪裏都測試,哪裏都沒有用處??  
  704.     }  
  705.   
  706.     private void checkToggleCapsLock() {  
  707.         Log.i("mytest""SoftKeyboard_checkToggleCapsLock");  
  708.         long now = System.currentTimeMillis();//記錄上次變幻的時間  
  709.         if (mLastShiftTime + 800 > now) {//不允許頻繁地換大小寫?  
  710.             mCapsLock = !mCapsLock;  
  711.             mLastShiftTime = 0;  
  712.         } else {  
  713.             mLastShiftTime = now;  
  714.         }  
  715.     }  
  716.       
  717.     private String getWordSeparators() {  
  718.         Log.i("mytest""SoftKeyboard_getWordSeparators");  
  719.         return mWordSeparators;  
  720.     }  
  721.       
  722.     public boolean isWordSeparator(int code) {  
  723.         Log.i("mytest""SoftKeyboard_isWordSeparator");  
  724.         String separators = getWordSeparators();//檢查所屬入的字符有沒有在這些字符裏面  
  725.         return separators.contains(String.valueOf((char)code));  
  726.     }  
  727.   
  728.     public void pickDefaultCandidate() {  
  729.         Log.i("mytest""SoftKeyboard_pickDefaultCandidate");  
  730.         pickSuggestionManually(0);  
  731.     }  
  732.       
  733.     public void pickSuggestionManually(int index) {  
  734.         Log.i("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.         Log.i("mytest""SoftKeyboard_swipeRight");  
  754.         if (mCompletionOn) {  
  755.             pickDefaultCandidate();  
  756.         }  
  757.     }  
  758.       
  759.     public void swipeLeft() {  
  760.         Log.i("mytest""SoftKeyboard_swipeLeft");  
  761.         handleBackspace();  
  762.     }  
  763.   
  764.     public void swipeDown() {  
  765.         Log.i("mytest""SoftKeyboard_swipeDown");  
  766.         handleClose();  
  767.     }  
  768.   
  769.     public void swipeUp() {  
  770.         Log.i("mytest""SoftKeyboard_swipeUp");  
  771.     }  
  772.       
  773.     public void onPress(int primaryCode) {  
  774.         Log.i("mytest""SoftKeyboard_onPress");  
  775.     }  
  776.       
  777.     public void onRelease(int primaryCode) {  
  778.         Log.i("mytest""SoftKeyboard_onRelease");  
  779.     }  
  780. }  

參考文獻:

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

發佈了14 篇原創文章 · 獲贊 15 · 訪問量 54萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章