今天來了一個(gè)問題:軟鍵盤無法彈出。分析后是因?yàn)橄到y(tǒng)判斷當(dāng)前有外接硬鍵盤,就會(huì)隱藏軟鍵盤。但實(shí)際情況并不是這么簡單,該問題只有在特定條件下偶現(xiàn),具體分析過程就不說了,就是軟硬鍵盤支持上的邏輯問題。借著這個(gè)機(jī)會(huì)整理一下鍵盤檢測(cè)的過程。

創(chuàng)新互聯(lián)專注于白銀區(qū)網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠為您提供白銀區(qū)營銷型網(wǎng)站建設(shè),白銀區(qū)網(wǎng)站制作、白銀區(qū)網(wǎng)頁設(shè)計(jì)、白銀區(qū)網(wǎng)站官網(wǎng)定制、小程序開發(fā)服務(wù),打造白銀區(qū)網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供白銀區(qū)網(wǎng)站排名全網(wǎng)營銷落地服務(wù)。
Configuration
Android系統(tǒng)中通過讀取Configuration中keyboard的值來判斷是否存在外接鍵盤。Configuration中關(guān)于鍵盤類型的定義如下,
public static final int KEYBOARD_UNDEFINED = 0; // 未定義的鍵盤 public static final int KEYBOARD_NOKEYS = 1; // 無鍵鍵盤,沒有外接鍵盤時(shí)為該類型 public static final int KEYBOARD_QWERTY = 2; // 標(biāo)準(zhǔn)外接鍵盤 public static final int KEYBOARD_12KEY = 3; // 12鍵小鍵盤
在最常見的情況下,外接鍵盤未連接時(shí)keyboard的值為KEYBOARD_NOKEYS,當(dāng)檢測(cè)到鍵盤連接后會(huì)將keyboard的值更新為KEYBOARD_QWERTY 。應(yīng)用就可以根據(jù)keyboard的值來判斷是否存在外接鍵盤,InputMethodService.java中有類似的判斷代碼。
  // 軟件盤是否可以顯示
  public boolean onEvaluateInputViewShown() {
    Configuration config = getResources().getConfiguration();
    return config.keyboard == Configuration.KEYBOARD_NOKEYS
        || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
  }  
現(xiàn)在的問題就轉(zhuǎn)向Configuration的keyboard是如何更新的。在WindowManagerService.java中,應(yīng)用啟動(dòng)時(shí)會(huì)更新Configuration,相關(guān)代碼如下。
  boolean computeScreenConfigurationLocked(Configuration config) {
    ......
    if (config != null) {
      // Update the configuration based on available input devices, lid switch,
      // and platform configuration.
      config.touchscreen = Configuration.TOUCHSCREEN_NOTOUCH;
      // 默認(rèn)值為KEYBOARD_NOKEYS
      config.keyboard = Configuration.KEYBOARD_NOKEYS;
      config.navigation = Configuration.NAVIGATION_NONAV;
      
      int keyboardPresence = 0;
      int navigationPresence = 0;
      final InputDevice[] devices = mInputManager.getInputDevices();
      final int len = devices.length;
      // 遍歷輸入設(shè)備
      for (int i = 0; i < len; i++) {
        InputDevice device = devices[i];
        // 如果不是虛擬輸入設(shè)備,會(huì)根據(jù)輸入設(shè)備的flags來更新Configuration
        if (!device.isVirtual()) {
          ......
          // 如果輸入設(shè)備的鍵盤類型為KEYBOARD_TYPE_ALPHABETIC,則將keyboard設(shè)置為KEYBOARD_QWERTY
          if (device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
            config.keyboard = Configuration.KEYBOARD_QWERTY;
            keyboardPresence |= presenceFlag;
          }
        }
      }
      ......
      // Determine whether a hard keyboard is available and enabled.
      boolean hardKeyboardAvailable = config.keyboard != Configuration.KEYBOARD_NOKEYS;
      // 更新硬件鍵盤狀態(tài)
      if (hardKeyboardAvailable != mHardKeyboardAvailable) {
        mHardKeyboardAvailable = hardKeyboardAvailable;
        mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
        mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE);
      }
      // 如果Setting中SHOW_IME_WITH_HARD_KEYBOARD被設(shè)置,將keyboard設(shè)置為KEYBOARD_NOKEYS,讓軟件盤可以顯示
      if (mShowImeWithHardKeyboard) {
        config.keyboard = Configuration.KEYBOARD_NOKEYS;
      }
      ......
    }
影響Configuration中keyboard的值有,
inputflinger
接下來需要關(guān)注輸入設(shè)備時(shí)何時(shí)被設(shè)置KEYBOARD_TYPE_ALPHABETIC的。搜索代碼可以看到,這個(gè)flag實(shí)在native代碼中設(shè)置的,代碼在inputflinger/InputReader.cpp中。native和java使用了同一定義值,如果修改定義時(shí)需要注意同時(shí)修改。native中的名字為AINPUT_KEYBOARD_TYPE_ALPHABETIC。
InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
    const InputDeviceIdentifier& identifier, uint32_t classes) {
  InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),
      controllerNumber, identifier, classes);
  ......
  if (classes & INPUT_DEVICE_CLASS_ALPHAKEY) {
    keyboardType = AINPUT_KEYBOARD_TYPE_ALPHABETIC;
  }
  ......
  return device;
}
InputReader在增加設(shè)備時(shí),根據(jù)classes的flag來設(shè)置鍵盤類型。這個(gè)flag又是在EventHub.cpp中設(shè)置的。
status_t EventHub::openDeviceLocked(const char *devicePath) {
  ......
  // Configure the keyboard, gamepad or virtual keyboard.
  if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) { 
    // 'Q' key support = cheap test of whether this is an alpha-capable kbd
    if (hasKeycodeLocked(device, AKEYCODE_Q)) {
      device->classes |= INPUT_DEVICE_CLASS_ALPHAKEY;
    }
  ......
}
看到這里就比較明確了,在EventHub加載設(shè)備時(shí),如果輸入設(shè)備為鍵盤,并且?guī)в?Q'鍵,就認(rèn)為這是一個(gè)標(biāo)準(zhǔn)的外接鍵盤。但為何判斷'Q'鍵還不是很清楚。
keylayout
上面說道通過'Q'鍵來判斷是否為外接鍵盤,這個(gè)'Q'鍵是Android的鍵值,鍵值是否存在是通過一個(gè)keylayout文件決定的。kl文件存儲(chǔ)在目標(biāo)系統(tǒng)的/system/usr/keylayout/下,系統(tǒng)可以有多個(gè)kl文件,根據(jù)設(shè)備的ID來命名。當(dāng)系統(tǒng)加載鍵盤設(shè)備時(shí),就會(huì)根據(jù)設(shè)備的Vendor ID和Product ID在/system/usr/keylayout/下尋找kl文件。例如一個(gè)kl文件名為”Vendor_0c45_Product_1109.kl“,表明設(shè)備的Vendor ID為0c45,Product ID為1109。一個(gè)kl的內(nèi)容示例如下,
key 1 BACK key 28 DPAD_CENTER key 102 HOME key 103 DPAD_UP key 105 DPAD_LEFT key 106 DPAD_RIGHT key 108 DPAD_DOWN key 113 VOLUME_MUTE key 114 VOLUME_DOWN key 115 VOLUME_UP key 142 POWER
鍵值映射需要使用關(guān)鍵之”key“進(jìn)行聲明,之后跟著的數(shù)字為Linux驅(qū)動(dòng)中的鍵值定義,再后面的字符串是Android中按鍵的名稱。'Q'鍵是否存在完全取決于kl文件中是否有映射,而不是實(shí)際物理鍵是否存在。kl文件的查找也是有一個(gè)規(guī)則的,其查找順序如下,
/system/usr/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl /system/usr/keylayout/Vendor_XXXX_Product_XXXX.kl /system/usr/keylayout/DEVICE_NAME.kl /data/system/devices/keylayout/Vendor_XXXX_Product_XXXX_Version_XXXX.kl /data/system/devices/keylayout/Vendor_XXXX_Product_XXXX.kl /data/system/devices/keylayout/DEVICE_NAME.kl /system/usr/keylayout/Generic.kl /data/system/devices/keylayout/Generic.kl
同時(shí)支持軟硬鍵盤
有了上面的知識(shí),就可以給出同時(shí)支持軟硬鍵盤的方案。
關(guān)于第三個(gè)方案的修改方式有兩種,一種是修改缺省的setting值,在文件frameworks/base/packages/SettingsProvider/res/values/defaults.xml中增加,
<integer name="def_show_ime_with_hard_keyboard">1</integer>
另一種方式是在系統(tǒng)啟動(dòng)時(shí)在代碼中通過接口進(jìn)行設(shè)置。
Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
                網(wǎng)站題目:Android中外接鍵盤的檢測(cè)的實(shí)現(xiàn)
                
                標(biāo)題網(wǎng)址:http://chinadenli.net/article20/gghcco.html
            
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、App設(shè)計(jì)、手機(jī)網(wǎng)站建設(shè)、服務(wù)器托管、用戶體驗(yàn)、靜態(tài)網(wǎng)站
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)