編輯:Android開發實例
4.SoftKeyBoard.java
- /*
- * Copyright (C) 2008-2009 Google Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.example.android.softkeyboard;
- import android.inputmethodservice.InputMethodService;
- import android.inputmethodservice.Keyboard;
- import android.inputmethodservice.KeyboardView;
- import android.text.method.MetaKeyKeyListener;
- //加入了這個,你就能夠隨意使用metakey的listener
- import android.util.Log;
- import android.view.KeyCharacterMap;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.inputmethod.CompletionInfo;
- import android.view.inputmethod.EditorInfo;
- import android.view.inputmethod.InputConnection;
- import android.view.inputmethod.InputMethodManager;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * Example of writing an input method for a soft keyboard. This code is
- * focused on simplicity over completeness, so it should in no way be considered
- * to be a complete soft keyboard implementation. Its purpose is to provide
- * a basic example for how you would get started writing an input method, to
- * be fleshed out as appropriate.
- */
- public class SoftKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
- static final boolean DEBUG = false;
- /**
- * This boolean indicates the optional example code for performing
- * processing of hard keys in addition to regular text generation
- * from on-screen interaction. It would be used for input methods that
- * perform language translations (such as converting text entered on
- * a QWERTY keyboard to Chinese), but may not be used for input methods
- * that are primarily intended to be used for on-screen text entry.
- */
- static final boolean PROCESS_HARD_KEYS = true; //是否在用硬鍵盤,這裡默認的是總可以使用,費柴變量
- private KeyboardView mInputView; //鍵盤view對象,但不是自己定義的類latinkeyboardview....
- private CandidateView mCandidateView; //候選欄對象
- private CompletionInfo[] mCompletions; //候選串之串
- private StringBuilder mComposing = new StringBuilder(); //一個字符串
- private boolean mPredictionOn; //這東西是決定能不能有候選條
- private boolean mCompletionOn; //決定auto是否需要顯示在候選欄
- private int mLastDisplayWidth;
- private boolean mCapsLock;
- private long mLastShiftTime;
- private long mMetaState; //matakey的按下狀態,猜測是每種組合對應一個此值?
- private LatinKeyboard mSymbolsKeyboard;//符號鍵盤1
- private LatinKeyboard mSymbolsShiftedKeyboard;//符號鍵盤2
- private LatinKeyboard mQwertyKeyboard;//字母鍵盤
- private LatinKeyboard mCurKeyboard;//當前鍵盤
- private String mWordSeparators; //默認的使得輸入中斷的字符
- /**
- * Main initialization of the input method component. Be sure to call
- * to super class.
- */
- @Override public void onCreate() {
- super.onCreate();
- mWordSeparators = getResources().getString(R.string.word_separators);
- //對resource這個東西有了一些了解:getResources是contextWrapper類的函數,contextWrapper而是inputmethodservice
- //的間接基類
- }
- /**
- * This is the point where you can do all of your UI initialization. It
- * is called after creation and any configuration change.
- */
- @Override public void onInitializeInterface() {
- //這只加載鍵盤,類似於findViewById,離真正生成界面還早
- if (mQwertyKeyboard != null) { //什麼時候符合判斷條件??
- // Configuration changes can happen after the keyboard gets recreated,
- // so we need to be able to re-build the keyboards if the available
- // space has changed.
- int displayWidth = getMaxWidth();//可用的,最大屏幕寬度,好像也沒什麼用
- //就這個函數用了一下這個變量
- if (displayWidth == mLastDisplayWidth) return;
- mLastDisplayWidth = displayWidth; //難道就是為了記錄最大寬度於mLastDisplayWidth?
- }
- //如果是剛開始,那就執行下面的
- mQwertyKeyboard = new LatinKeyboard(this, R.xml.qwerty);
- mSymbolsKeyboard = new LatinKeyboard(this, R.xml.symbols);
- mSymbolsShiftedKeyboard = new LatinKeyboard(this, R.xml.symbols_shift);
- }
- /**
- * Called by the framework when your view for creating input needs to
- * be generated. This will be called the first time your input method
- * is displayed, and every time it needs to be re-created such as due to
- * a configuration change.
- */
- @Override public View onCreateInputView() {
- // mInputView = (KeyboardView)findViewById(R.layout.input);
- //上邊的函數findViewById對於keyboardView是不能用的
- //只對TextView等可以用
- mInputView = (KeyboardView) getLayoutInflater().inflate(R.layout.input, null);
- //這是inputmethodservice類特有的加載資源的過程?
- mInputView.setOnKeyboardActionListener(this); //加載監聽函數,建類的時候已經加載了監聽函數
- mInputView.setKeyboard(mQwertyKeyboard);
- return mInputView; //通過這個return,自己定義的keyboardview類對象就與這個類綁定了
- }
- /**
- * Called by the framework when your view for showing candidates needs to
- * be generated, like [email protected] #onCreateInputView}.
- */
- @Override public View onCreateCandidatesView() {
- mCandidateView = new CandidateView(this); //為什麼參數是this??因為activity,inputmethodservice,這都是context的派生類
- mCandidateView.setService(this); //在CandidateView類裡面對這個類的描述中,參數就是個SoftKeyboard
- // CandidateView mCandidateView1=new CandidateView(null);
- return mCandidateView; //這一步很重要,後面的setCandidatesViewShown(false);就是個返回的結果造成的?
- }
- /**
- * This is the main point where we do our initialization of the input method
- * to begin operating on an application. At this point we have been
- * bound to the client, and are now receiving all of the detailed information
- * about the target of our edits.
- */
- @Override public void onStartInput(EditorInfo attribute, boolean restarting) {
- super.onStartInput(attribute, restarting);
- // Reset our state. We want to do this even if restarting, because
- // the underlying state of the text editor could have changed in any way.
- mComposing.setLength(0);
- //一個StringBuilder,前面定義的
- updateCandidates();
- //可知此處的candidateview注定還不顯示
- if (!restarting) {
- // Clear shift states.
- mMetaState = 0;
- }
- mPredictionOn = false; //猜測:是否需要顯示候選詞條,證實確實如此
- mCompletionOn = false; //允許auto的內容顯示在後選欄中
- mCompletions = null; //候選串之串?
- // We are now going to initialize our state based on the type of
- // text being edited.
- //一個靠譜的猜測:inputtype的給定值裡面有那麼幾個掩碼,但是從參數傳來的具體inputtype值裡面包含了所有的信息,不同的掩碼能夠得出不同的信息
- //例如TYPE_MASK_CLASS就能得出下面四種,這四種屬於同一類期望信息,這個信息叫做CLASS,下面一個掩碼TYPE_MASK_VARIATION按位與出來的是一類
- //叫做VARIATION的信息
- switch (attribute.inputType&EditorInfo.TYPE_MASK_CLASS) {
- //按位與的兩者是同一類型的,attribute是EditorInfo類型的參數
- case EditorInfo.TYPE_CLASS_NUMBER:
- case EditorInfo.TYPE_CLASS_DATETIME:
- // Numbers and dates default to the symbols keyboard, with
- // no extra features.
- mCurKeyboard = mSymbolsKeyboard; //跟據不同的輸入框的類型改變當前的鍵盤類型
- break;
- case EditorInfo.TYPE_CLASS_PHONE:
- // Phones will also default to the symbols keyboard, though
- // often you will want to have a dedicated phone keyboard.
- mCurKeyboard = mSymbolsKeyboard;
- break;
- case EditorInfo.TYPE_CLASS_TEXT:
- // This is general text editing. We will default to the
- // normal alphabetic keyboard, and assume that we should
- // be doing predictive text (showing candidates as the
- // user types).
- mCurKeyboard = mQwertyKeyboard;
- mPredictionOn = true; //設置需要候選詞條
- // We now look for a few special variations of text that will
- // modify our behavior.
- int variation = attribute.inputType & EditorInfo.TYPE_MASK_VARIATION;
- if (variation == EditorInfo.TYPE_TEXT_VARIATION_PASSWORD ||variation == EditorInfo.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
- // Do not display predictions / what the user is typing
- // when they are entering a password.
- mPredictionOn = false; //密碼框的輸入是不需要候選詞條的
- }
- if (variation == EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
- || variation == EditorInfo.TYPE_TEXT_VARIATION_URI
- || variation == EditorInfo.TYPE_TEXT_VARIATION_FILTER) {
- // Our predictions are not useful for e-mail addresses
- // or URIs.
- mPredictionOn = false; //如果是網站或者是郵箱地址,不用候選詞條
- }
- if ((attribute.inputType&EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) { //開始界面的那個輸入框,就是自動生成的
- // If this is an auto-complete text view, then our predictions //是不是用TYPE_MASK_FLAGS 也可以?我的回答是肯定的
- // will not be shown and instead we will allow the editor
- // to supply their own. We only show the editor's
- // candidates when in fullscreen mode, otherwise relying
- // own it displaying its own UI.
- mPredictionOn = false; //不用候選詞條
- mCompletionOn = isFullscreenMode(); //經過測試,當輸入法處在全屏模式的時候,原本auto的候選詞會顯示在輸入法的候選欄中
- //這是mCompletiOn的作用,這個值初始化設為false.
- //如果把這裡的兩個值都設置為true則可以發現再輸入任意auto的時候都會在候選欄中顯示auto的詞語
- //所以,變量mCompletionOn的後續作用需要監視
- //這兩行做後續測試: 真值:false,isFullscreenMode()
- }
- // We also want to look at the current state of the editor
- // to decide whether our alphabetic keyboard should start out
- // shifted.
- updateShiftKeyState(attribute);
- break;
- default:
- // For all unknown input types, default to the alphabetic
- // keyboard with no special features.
- mCurKeyboard = mQwertyKeyboard;
- updateShiftKeyState(attribute); //決定是否需要初始大寫狀態
- }
- // Update the label on the enter key, depending on what the application
- // says it will do.
- mCurKeyboard.setImeOptions(getResources(), attribute.imeOptions); //根據輸入目標設置回車鍵
- }
- /**
- * This is called when the user is done editing a field. We can use
- * this to reset our state.
- */
- @Override public void onFinishInput() { //經測試,終於發現,start與finish,在輸入框切換的時候,平時這倆結束函數並不調用,或許輸入框只是隱藏。
- //測試語句 mInputView=null;
- // Clear current composing text and candidates.
- mComposing.setLength(0);
- updateCandidates();
- // We only hide the candidates window when finishing input on
- // a particular editor, to avoid popping the underlying application
- // up and down if the user is entering text into the bottom of
- // its window.
- setCandidatesViewShown(false); //默認的就是不可見的
- //inputmethodservice的函數,能設置候選此條的可見性
- mCurKeyboard = mQwertyKeyboard;
- if (mInputView != null) {
- mInputView.closing(); //據分析,關閉輸入界面和收起輸入界面還不是一回事?
- }
- }
- @Override public void onStartInputView(EditorInfo attribute, boolean restarting) {
- //如果沒有這個函數的作用,在切換輸入目標的時候不會發生鍵盤的變化
- //而且經過測試,這個函數執行的時間是開始輸入的時候
- super.onStartInputView(attribute, restarting);
- // Apply the selected keyboard to the input view.
- mInputView.setKeyboard(mCurKeyboard); //這個是轉換鍵盤的關鍵
- //mInputView是自己定義的一個鍵盤
- mInputView.closing(); //這個語句能讓整個需要輸入的目標關閉?到底是干什麼用的??疑問?
- }
- /**
- * Deal with the editor reporting movement of its cursor.
- */
- @Override
- public void onUpdateSelection(int oldSelStart, int oldSelEnd,int newSelStart, int newSelEnd,int candidatesStart, int candidatesEnd) {
- //光標!
- super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd,candidatesStart, candidatesEnd);
- //當輸入框向輸入法報告用戶移動了光標時調用。,當用戶移動輸入框中的光標的時候,它就默認的表示本次輸入完成了,
- //然後將候選詞以及正在輸入的文本復位,並且向編輯器報告輸入法已經完成了一個輸入。
- //四個整形都是坐標?
- // If the current selection in the text view changes, we should
- // clear whatever candidate text we have.
- if (mComposing.length() > 0 && (newSelStart != candidatesEnd|| newSelEnd != candidatesEnd)) {
- mComposing.setLength(0); //這才是候選欄置空的精義所在
- updateCandidates(); //候選欄置空
- InputConnection ic = getCurrentInputConnection(); //這個語句和下面if裡面那個,決定了結束輸入的全過程
- if (ic != null) {
- ic.finishComposingText(); //這個語句的作用是,讓輸入目標內的下劃線去掉,完成一次編輯
- }
- }
- // mCompletionOn=false;
- }
- /**
- * This tells us about completions that the editor has determined based
- * on the current text in it. We want to use this in fullscreen mode
- * to show the completions ourself, since the editor can not be seen
- * in that situation.
- */
- @Override public void onDisplayCompletions(CompletionInfo[] completions) { //當需要在候選欄裡面顯示auto的內容
- //此函數作用,猜測:當全屏幕模式的時候,mCompletionOn置true,可以通過候選欄來顯示auto
- if (mCompletionOn) { //必須這個變量允許
- mCompletions = completions; //賦值給本來裡面專門記錄候選值的變量
- if (completions == null) {
- setSuggestions(null, false, false); //如果沒有候選詞,就這樣處置
- return;
- }
- List<String> stringList = new ArrayList<String>();
- for (int i=0; i<(completions != null ? completions.length : 0); i++) {
- CompletionInfo ci = completions[i];
- if (ci != null) stringList.add(ci.getText().toString()); //由CompletionInfo向String轉變的過程
- }
- setSuggestions(stringList, true, true);
- }
- }
- /**
- * This translates incoming hard key events in to edit operations on an
- * InputConnection. It is only needed when using the
- * PROCESS_HARD_KEYS option.
- */
- private boolean translateKeyDown(int keyCode, KeyEvent event) {
- //這個函數在OnKeyDown中用到了
- //這個是當組合鍵時候用,shift+A或者別的Alt+A之類
- mMetaState = MetaKeyKeyListener.handleKeyDown(mMetaState,keyCode, event);
- //處理matakey的按下,猜測:每一個long型的mMetaState值都代表著一個meta鍵組合值。8成是對的
- int c = event.getUnicodeChar(MetaKeyKeyListener.getMetaState(mMetaState)); //如果沒這套組合鍵,就返回0
- //這又是在干什麼?猜測:每一個mMetaState值,對應著一個unicode值,這一步就是為了得到它,此猜測正確
- mMetaState = MetaKeyKeyListener.adjustMetaAfterKeypress(mMetaState);
- //重置這個元狀態。當取得了C值之後,完全可以重置元狀態了,後面的語句不會出現任何問題。
- //上面這三行有點疑問
- InputConnection ic = getCurrentInputConnection();
- //後邊這函數是inputmethodservice自己的,獲得當前的鏈接
- if (c == 0 || ic == null) {
- return false;
- }
- boolean dead = false;
- //一個dead=true意味著是一個有定義的組合鍵
- if ((c & KeyCharacterMap.COMBINING_ACCENT) != 0) {
- //看看c所昭示的這個鍵能不能被允許組合鍵
- dead = true; //定義下來看能否使用這個組合鍵
- c = c & KeyCharacterMap.COMBINING_ACCENT_MASK;
- //這樣就得到了真正的碼值
- }
- if (mComposing.length() > 0) { //這是處理“編輯中最後字符越變”的情況
- char accent = mComposing.charAt(mComposing.length() -1 ); //返回正在編輯的字串的最後一個字符
- int composed = KeyEvent.getDeadChar(accent, c); //這種情況下最後是返回了新的阿斯課碼。composed最終還是要還給c.作為onKey的參數。
- if (composed != 0) {
- c = composed;
- mComposing.setLength(mComposing.length()-1); // 要把最後一個字符去掉,才能夠在下一步中越變成為新的字符
- }
- }
- onKey(c, null); //強制輸入C,這樣就實現了組合鍵的功效
- return true;
- }
- /**
- * Use this to monitor key events being delivered to the application.
- * We get first crack at them, and can either resume them or let them
- * continue to the app.
- */
- @Override public boolean onKeyDown(int keyCode, KeyEvent event) {
- //這是重載了基類的,經測試確定,只有在硬件盤被敲擊時候才調用,除了那個鍵本身的功效,還有這裡定義的這些
- //是對輸入法的影響
- switch (keyCode) {
- case KeyEvent.KEYCODE_BACK: //這就是那個破箭頭,扭曲的
- // The InputMethodService already takes care of the back
- // key for us, to dismiss the input method if it is shown.
- // However, our keyboard could be showing a pop-up window
- // that back should dismiss, so we first allow it to do that.
- if (event.getRepeatCount() == 0 && mInputView != null) {
- //mInputView類是自己定義的keyBoardView類
- if (mInputView.handleBack()) { //通過彎鉤鍵來關閉鍵盤的元凶在這裡
- //這函數干嗎呢?猜測:如果成功地蕩掉了鍵盤,就返回真
- return true;
- }
- }
- break;
- case KeyEvent.KEYCODE_DEL:
- // Special handling of the delete key: if we currently are
- // composing text for the user, we want to modify that instead
- // of let the application to the delete itself.
- if (mComposing.length() > 0) {
- onKey(Keyboard.KEYCODE_DELETE, null); //所以,onkey定義中的事情才是軟鍵盤的事件
- return true;
- }
- break;
- case KeyEvent.KEYCODE_ENTER:
- // Let the underlying text editor always handle these.
- return false;
- case KeyEvent.KEYCODE_A: //當然了,這裡定義的是A鍵在本輸入法中的作用,他的本來的輸入作用並沒有受到影響
- break;
- default:
- // For all other keys, if we want to do transformations on
- // text being entered with a hard keyboard, we need to process
- // it and do the appropriate action.
- if (PROCESS_HARD_KEYS) { //這個是個廢柴變量,因為在前面賦值了,永遠是true
- if (keyCode == KeyEvent.KEYCODE_SPACE && (event.getMetaState()&KeyEvent.META_ALT_ON) != 0) {
- //為什麼有這個按位與?因為這個META_ALT_ON就是用來按位與來判斷是否按下alt
- //條件:alt+空格
- // A silly example: in our input method, Alt+Space
- // is a shortcut for 'android' in lower case.
- InputConnection ic = getCurrentInputConnection();
- if (ic != null) {
- // First, tell the editor that it is no longer in the
- // shift state, since we are consuming this.
- ic.clearMetaKeyStates(KeyEvent.META_ALT_ON); // 清除組合鍵狀態,如果不清除,出來的字符就不是Android
- keyDownUp(KeyEvent.KEYCODE_A);
- //由此可知,這些函數才是控制顯示字符的,但貌似沒那麼簡單
- keyDownUp(KeyEvent.KEYCODE_N);
- keyDownUp(KeyEvent.KEYCODE_D);
- keyDownUp(KeyEvent.KEYCODE_R);
- keyDownUp(KeyEvent.KEYCODE_O);
- keyDownUp(KeyEvent.KEYCODE_I);
- keyDownUp(KeyEvent.KEYCODE_D);
- // And we consume this event.
- return true;
- }
- }
- if (mPredictionOn && translateKeyDown(keyCode, event)) {
- return true;
- }
- }
- }
- return super.onKeyDown(keyCode, event);
- }
- /**
- * Use this to monitor key events being delivered to the application.
- * We get first crack at them, and can either resume them or let them
- * continue to the app.
- */
- @Override public boolean onKeyUp(int keyCode, KeyEvent event) {
- // If we want to do transformations on text being entered with a hard
- // keyboard, we need to process the up events to update the meta key
- // state we are tracking.
- if (PROCESS_HARD_KEYS) { //哈哈,判斷是不在使用硬件輸入
- //要懂得,mete keys意味著shift和alt這類的鍵
- if (mPredictionOn) {
- mMetaState = MetaKeyKeyListener.handleKeyUp(mMetaState,keyCode, event);
- //處理matakey的釋放
- }
- }
- return super.onKeyUp(keyCode, event);
- // return true;
- //只有在一個鍵被放起時候執行,但經過測試,他不是執行輸入的,僅僅是再輸入之前做些事務,
- }
- /**
- * Helper function to commit any text being composed in to the editor.
- */
- private void commitTyped(InputConnection inputConnection) {
- if (mComposing.length() > 0) {
- inputConnection.commitText(mComposing, mComposing.length()); //後邊的參數決定了光標的應有位置
- mComposing.setLength(0);
- updateCandidates(); //這兩行聯手,一般能造成候選欄置空與候選詞條串置空的效果
- }
- }
- /**
- * Helper to update the shift state of our keyboard based on the initial
- * editor state.
- */
- private void updateShiftKeyState(EditorInfo attr) { //但是,這個函數每次輸入一個字母都要執行
- //用於在開始輸入前切換大寫
- //它首先是判斷是否輸入視圖存在,並且輸入框要求有輸入法,然後根據輸入框的輸入類型來獲得是否需要大小寫,最後定義在輸入視圖上。
- //經測試,每當鍵盤剛出來的時候會有,每輸入一個字符都會有這個函數的作用
- if (attr != null&& mInputView != null && mQwertyKeyboard == mInputView.getKeyboard()) { //getKeyboard又是個可得私有變量的公有函數
- //條件的含義是:當有字母鍵盤存在的時候
- int caps = 0;
- EditorInfo ei = getCurrentInputEditorInfo(); //獲得當前輸入框的信息?本.java中,大多數的attr參數於這個東西等同
- if (ei != null && ei.inputType != EditorInfo.TYPE_NULL) { //這個破inputtype類型是全0,一般不會有這種破類型
- caps = getCurrentInputConnection().getCursorCapsMode(attr.inputType); //返回的東西不是光標位置,得到的是
- //是否需要大寫的判斷,但是返回值是怎麼弄的??
- }
- mInputView.setShifted(mCapsLock || caps != 0); //參數boolean
- }
- // keyDownUp(KeyEvent.KEYCODE_N);
- // keyDownUp(KeyEvent.KEYCODE_B);
- }
- /**
- * Helper to determine if a given character code is alphabetic.
- */
- private boolean isAlphabet(int code) { //看看是不是字母
- if (Character.isLetter(code)) {
- return true;
- } else {
- return false;
- }
- }
- /**
- * Helper to send a key down / key up pair to the current editor.
- */
- private void keyDownUp(int keyEventCode) {
- getCurrentInputConnection().sendKeyEvent(
- new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode)); //參見文檔中KeyEvent
- getCurrentInputConnection().sendKeyEvent(
- new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
- //明白了,這個函數是用來特殊輸出的,就好像前面定義的“android”輸出,但如果簡單地從鍵盤輸入字符,是不會經過這一步的
- //一點都沒錯,強制輸出,特殊輸出,就這裡
- // keyDownUp(KeyEvent.KEYCODE_N);
- // keyDownUp(KeyEvent.KEYCODE_B);
- }
- /**
- * Helper to send a character to the editor as raw key events.
- */
- private void sendKey(int keyCode) { //傳入的參數是阿斯課碼
- //處理中斷符的時候使用到了
- switch (keyCode) {
- case '\n':
- keyDownUp(KeyEvent.KEYCODE_ENTER);
- //又是“特別輸入”或稱為“強制輸入”
- break;
- default:
- if (keyCode >= '0' && keyCode <= '9') {
- keyDownUp(keyCode - '0' + KeyEvent.KEYCODE_0);
- } else {
- getCurrentInputConnection().commitText(String.valueOf((char) keyCode), 1);
- }
- break;
- }
- }
- // Implementation of KeyboardViewListener
- //你難道沒看見這個類定義時候的接口嗎?那個接口定義的監聽函數就是為了監聽這種On事件的,這就是軟鍵盤按壓事件
- public void onKey(int primaryCode, int[] keyCodes) {
- if (isWordSeparator(primaryCode)) { //後面定義的函數
- //當輸入被中斷符號中斷
- // Handle separator
- if (mComposing.length() > 0) {
- commitTyped(getCurrentInputConnection());
- }
- sendKey(primaryCode); //提交完了輸出之後,還必須要把這個特殊字符寫上
- updateShiftKeyState(getCurrentInputEditorInfo()); //看看是否到了特殊的位置,需要改變大小寫狀態
- } else if (primaryCode == Keyboard.KEYCODE_DELETE) {
- handleBackspace();
- } else if (primaryCode == Keyboard.KEYCODE_SHIFT) { //但是硬鍵盤上面的這個好像沒用,待考證
- //大小寫轉換
- handleShift();
- } else if (primaryCode == Keyboard.KEYCODE_CANCEL) { //左下角那個鍵,關閉
- handleClose();
- return;
- } else if (primaryCode == LatinKeyboardView.KEYCODE_OPTIONS) { //這個鍵,是這樣的,前面的LatinKeyboardView這個類裡面定義了KEYCODE_OPTIONS
- //用來描述長按左下角關閉鍵的代替。經測試,千真萬確
- // Show a menu or something'
- } else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE //就是顯示著“abc”或者"123"的那個鍵
- && mInputView != null) {
- Keyboard current = mInputView.getKeyboard();
- if (current == mSymbolsKeyboard || current == mSymbolsShiftedKeyboard) {
- current = mQwertyKeyboard;
- } else {
- current = mSymbolsKeyboard;
- }
- mInputView.setKeyboard(current); //改變鍵盤的根本操作,但是對於具體輸入的是大寫字母這件事情,還要等按下了之後在做定論
- if (current == mSymbolsKeyboard) {
- current.setShifted(false); //測試,這裡要是設置為true,打開之後只是shift鍵的綠點變亮,但是並沒有變成另一個符號鍵盤
- }
- } else {
- handleCharacter(primaryCode, keyCodes); //這就是處理真正的字符處理函數,不是那些其他的控制鍵
- }
- }
- public void onText(CharSequence text) { //這也是接口類的觸發的函數。什麼時候響應,有待考證
- InputConnection ic = getCurrentInputConnection();
- if (ic == null) return;
- ic.beginBatchEdit();
- if (mComposing.length() > 0) {
- commitTyped(ic);
- }
- ic.commitText(text, 0);
- ic.endBatchEdit();
- updateShiftKeyState(getCurrentInputEditorInfo()); //看是否需要切換大小寫
- }
- /**
- * Update the list of available candidates from the current composing
- * text. This will need to be filled in by however you are determining
- * candidates.
- */
- private void updateCandidates() {
- //此函數處理的是不允許從auto獲取的情況,應該是大多數情況
- if (!mCompletionOn) {
- if (mComposing.length() > 0) { //mComposing記錄著候選字符串之串,待考證
- ArrayList<String> list = new ArrayList<String>(); //字符串之串
- list.add(mComposing.toString());
- setSuggestions(list, true, true);
- } else {
- setSuggestions(null, false, false);
- }
- }
- }
- public void setSuggestions(List<String> suggestions, boolean completions,boolean typedWordValid) {
- //這第三個參數是前面函數調用的時候人為給的,沒什麼玄妙
- if (suggestions != null && suggestions.size() > 0)
- {
- setCandidatesViewShown(true); //讓候選欄可視
- }
- else if (isExtractViewShown()) //疑問?
- {
- setCandidatesViewShown(true); //不止這個,很多地方都表明,當需要輸入的程序處在全屏的時候,需要候選欄顯示
- }
- if (mCandidateView != null) //只有當有候選條的時候才顯示
- {
- mCandidateView.setSuggestions(suggestions, completions, typedWordValid); //就是改變了一下suggestion,在candidateView裡面真正靠的是onDraw
- }
- }
- private void handleBackspace() {
- //刪除一個字,用的就是他
- final int length = mComposing.length();
- if (length > 1) {
- mComposing.delete(length - 1, length);
- getCurrentInputConnection().setComposingText(mComposing, 1);
- updateCandidates();
- } else if (length > 0) {
- //就是在說等於1的時候
- mComposing.setLength(0);
- getCurrentInputConnection().commitText("", 0);
- updateCandidates();
- } else {
- keyDownUp(KeyEvent.KEYCODE_DEL);
- }
- updateShiftKeyState(getCurrentInputEditorInfo()); //看看是否需要重歸大寫狀態(例如又到達了行首)
- }
- private void handleShift() {
- //這才是大小寫的切換,是正常切換(通過轉換鍵)
- if (mInputView == null) {
- return;
- }
- Keyboard currentKeyboard = mInputView.getKeyboard();
- if (mQwertyKeyboard == currentKeyboard) {
- // Alphabet keyboard
- checkToggleCapsLock(); //只有當鍵盤是字母鍵盤的時候,需要檢驗鎖(控制變幻頻率,不能過快)
- mInputView.setShifted(mCapsLock || !mInputView.isShifted()); //關鍵語句
- } else if (currentKeyboard == mSymbolsKeyboard) {
- mSymbolsKeyboard.setShifted(true);
- mInputView.setKeyboard(mSymbolsShiftedKeyboard);
- mSymbolsShiftedKeyboard.setShifted(true);
- } else if (currentKeyboard == mSymbolsShiftedKeyboard) {
- mSymbolsShiftedKeyboard.setShifted(false); //所謂的setShift,僅僅指的是那個鍵盤的大小寫鍵變化,經測試,只要android:code=-1就有這種綠點效果
- //不用setShift()都行
- mInputView.setKeyboard(mSymbolsKeyboard); //這才是真正的shift工作(換成另外一個鍵盤)
- mSymbolsKeyboard.setShifted(false);
- }
- }
- private void handleCharacter(int primaryCode, int[] keyCodes) { //primayCode是鍵的阿斯課碼值
- if (isInputViewShown()) {
- if (mInputView.isShifted()) {
- primaryCode = Character.toUpperCase(primaryCode); //這才真正把這個字符變成了大寫的效果,經測試,沒有就不行
- //把鍵盤換成大寫的了還不夠,那只是從View上解決了問題,一定要這樣一句才行
- }
- }
- if (isAlphabet(primaryCode) && mPredictionOn) { //輸入的是個字母,而且允許候選欄顯示
- mComposing.append((char) primaryCode); //append(添加)就是把當前的輸入的一個字符放到mComposing裡面來
- getCurrentInputConnection().setComposingText(mComposing, 1); //在輸入目標中也顯示最新得到的mComposing.
- updateShiftKeyState(getCurrentInputEditorInfo()); //每當輸入完結,都要檢驗是否需要變到大寫
- updateCandidates();
- } else {
- getCurrentInputConnection().commitText(String.valueOf((char) primaryCode), 1); //比如說當輸入的是“‘”這個符號的時候,就會掉用這個
- //結果就是remove掉所有編輯中的字符,第二個參數的正負,決定著
- //光標位置的不同
- }
- }
- private void handleClose() {
- //關閉鍵盤件的作用就在這裡,左下角那個.,記住!!!!!左下角那個,不是彎鉤鍵!!!!
- commitTyped(getCurrentInputConnection());
- requestHideSelf(0); //關掉輸入法的區域,這才是關閉的王道.似乎這句包含了上面那句的作用(測試結果)
- mInputView.closing(); //這個函數不懂什麼意思待問?? 哪裡都測試,哪裡都沒有用處??
- }
- private void checkToggleCapsLock() {
- //記錄上次變幻的時間
- long now = System.currentTimeMillis();
- if (mLastShiftTime + 800 > now) {
- //不允許頻繁地換大小寫?
- mCapsLock = !mCapsLock;
- mLastShiftTime = 0;
- } else {
- mLastShiftTime = now;
- }
- }
- private String getWordSeparators() {
- return mWordSeparators;
- }
- public boolean isWordSeparator(int code) {
- String separators = getWordSeparators();
- return separators.contains(String.valueOf((char)code));//檢查所屬入的字符有沒有在這些字符裡面
- }
- //下面這些函數是用來繼承的吧?
- public void pickDefaultCandidate() {
- pickSuggestionManually(0);
- }
- public void pickSuggestionManually(int index) {
- if (mCompletionOn && mCompletions != null && index >= 0&& index < mCompletions.length) {
- CompletionInfo ci = mCompletions[index];
- getCurrentInputConnection().commitCompletion(ci);
- if (mCandidateView != null) {
- mCandidateView.clear();
- }
- updateShiftKeyState(getCurrentInputEditorInfo());
- } else if (mComposing.length() > 0) {
- // If we were generating candidate suggestions for the current
- // text, we would commit one of them here. But for this sample,
- // we will just commit the current text.
- commitTyped(getCurrentInputConnection());
- }
- }
- //著下面6個函數,完全是因為聲明了那個接口類,所以必須要包含這幾個函數,還有上面的幾個函數,但是實際上這些函數可以沒有意義
- public void swipeRight() { //迅速從左向右搓所得到的結果
- if (mCompletionOn) { //如果候選欄允許顯示,將顯示第0個候選詞
- pickDefaultCandidate();
- }
- }
- public void swipeLeft() { //搓!
- handleBackspace();
- }
- public void swipeDown() {
- handleClose();
- }
- public void swipeUp() {
- }
- public void onPress(int primaryCode) {
- }
- public void onRelease(int primaryCode) {
- }
- }
步驟:分兩步 一、usb連接: 在Ubuntu掛載使用MTP設備步驟如下: 1.將MTP設備連接至PC機 2.如果是第一次使用MTP設備需要安裝以下軟件,否則可以
Android提供了許多方法來控制播放的音頻/視頻文件和流。其中該方法是通過一類稱為MediaPlayer。Android是提供MediaPlayer類訪問內置的媒體播放
很多Android設備已經支持NFC(近距離無線通訊技術)了。本文就以實例的方
可以顯示在的Android任務,通過加載進度條的進展。進度條有兩種形狀。加載欄和加載微調(spinner)。在本章中,我們將討論微調(spinner)。Spinner 用