最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android中外接鍵盤的檢測的實現(xiàn)

 更新時間:2019年11月22日 11:40:54   作者:戈壁老王  
這篇文章主要介紹了Android中外接鍵盤的檢測的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧

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

Configuration

Android系統(tǒng)中通過讀取Configuration中keyboard的值來判斷是否存在外接鍵盤。Configuration中關(guān)于鍵盤類型的定義如下,

  public static final int KEYBOARD_UNDEFINED = 0; // 未定義的鍵盤
  public static final int KEYBOARD_NOKEYS = 1; // 無鍵鍵盤,沒有外接鍵盤時為該類型
  public static final int KEYBOARD_QWERTY = 2; // 標準外接鍵盤
  public static final int KEYBOARD_12KEY = 3; // 12鍵小鍵盤

在最常見的情況下,外接鍵盤未連接時keyboard的值為KEYBOARD_NOKEYS,當檢測到鍵盤連接后會將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)用啟動時會更新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;
      // 默認值為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è)備,會根據(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的值有,

  • 默認值為KEYBOARD_NOKEYS,表示沒有外接鍵盤。
  • 當輸入設(shè)備為KEYBOARD_TYPE_ALPHABETIC時,更新為KEYBOARD_QWERTY,一個標準鍵盤。
  • 當Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD為1時,設(shè)置為KEYBOARD_NOKEYS,目的是讓軟鍵盤可以顯示。

inputflinger

接下來需要關(guān)注輸入設(shè)備時何時被設(shè)置KEYBOARD_TYPE_ALPHABETIC的。搜索代碼可以看到,這個flag實在native代碼中設(shè)置的,代碼在inputflinger/InputReader.cpp中。native和java使用了同一定義值,如果修改定義時需要注意同時修改。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è)備時,根據(jù)classes的flag來設(shè)置鍵盤類型。這個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è)備為鍵盤,并且?guī)в?Q'鍵,就認為這是一個標準的外接鍵盤。但為何判斷'Q'鍵還不是很清楚。

keylayout

上面說道通過'Q'鍵來判斷是否為外接鍵盤,這個'Q'鍵是Android的鍵值,鍵值是否存在是通過一個keylayout文件決定的。kl文件存儲在目標系統(tǒng)的/system/usr/keylayout/下,系統(tǒng)可以有多個kl文件,根據(jù)設(shè)備的ID來命名。當系統(tǒng)加載鍵盤設(shè)備時,就會根據(jù)設(shè)備的Vendor ID和Product ID在/system/usr/keylayout/下尋找kl文件。例如一個kl文件名為”Vendor_0c45_Product_1109.kl“,表明設(shè)備的Vendor ID為0c45,Product ID為1109。一個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“進行聲明,之后跟著的數(shù)字為Linux驅(qū)動中的鍵值定義,再后面的字符串是Android中按鍵的名稱。'Q'鍵是否存在完全取決于kl文件中是否有映射,而不是實際物理鍵是否存在。kl文件的查找也是有一個規(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è)置Configuration中keyboard的值為KEYBOARD_NOKEYS。這種Hack其實不好,破壞原生邏輯,缺乏移植性。非要這樣改的話,可以增加對設(shè)備的判斷,只有特定的鍵盤設(shè)備設(shè)置為KEYBOARD_NOKEYS,減少副作用。
  • 修改keylayout,去掉'Q'鍵映射。有時kl文件寫的不標準,為了通用把所有鍵的映射都寫上了,實際硬件鍵卻很少,我們就是這種情況。應(yīng)該按照真實硬件來編寫kl文件。
  • 設(shè)置Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD為1。我認為這是最標準的修改方式,也非常方便。

關(guān)于第三個方案的修改方式有兩種,一種是修改缺省的setting值,在文件frameworks/base/packages/SettingsProvider/res/values/defaults.xml中增加,

<integer name="def_show_ime_with_hard_keyboard">1</integer>

另一種方式是在系統(tǒng)啟動時在代碼中通過接口進行設(shè)置。

Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);

以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Android實現(xiàn)圖片瀏覽并改變透明度

    Android實現(xiàn)圖片瀏覽并改變透明度

    這篇文章主要為大家詳細介紹了Android實現(xiàn)圖片瀏覽并改變透明度,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • Android日期顯示和日期選擇庫

    Android日期顯示和日期選擇庫

    這篇文章主要為大家詳細介紹了Android日期顯示和日期選擇庫的相關(guān)資料,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-05-05
  • Android中利用動態(tài)加載實現(xiàn)手機淘寶的節(jié)日特效

    Android中利用動態(tài)加載實現(xiàn)手機淘寶的節(jié)日特效

    這篇文章主要介紹了Android中利用動態(tài)加載實現(xiàn)手機淘寶的節(jié)日特效,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Android實現(xiàn)簡易的柱狀圖和曲線圖表實例代碼

    Android實現(xiàn)簡易的柱狀圖和曲線圖表實例代碼

    柱狀圖是統(tǒng)計圖表中經(jīng)常用到的一種圖表,比如降雨量之類的統(tǒng)計展示。這篇文章主要給大家介紹了關(guān)于利用Android如何實現(xiàn)簡易的柱狀圖和曲線圖表的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2017-12-12
  • Kotlin server多線程編程詳細講解

    Kotlin server多線程編程詳細講解

    這篇文章主要介紹了Kotlin server多線程編程,Service是實現(xiàn)程序后臺運行的解決方案,適合執(zhí)行非交互,后臺預(yù)先的任務(wù),即使用戶打開其他應(yīng)用,Service也能夠正常運行
    2023-01-01
  • 深入理解Kotlin的泛型系統(tǒng)

    深入理解Kotlin的泛型系統(tǒng)

    Kotlin 泛型即 “參數(shù)化類型”,將類型參數(shù)化,可以用在類,接口,方法上。下面 這篇文章主要給大家介紹了關(guān)于Kotlin泛型系統(tǒng)的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下。
    2017-12-12
  • Flutter路由的跳轉(zhuǎn)、動畫和傳參詳解(最簡單)

    Flutter路由的跳轉(zhuǎn)、動畫和傳參詳解(最簡單)

    這篇文章主要給大家介紹了關(guān)于Flutter路由的跳轉(zhuǎn)、動畫和傳參的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-01-01
  • Android實現(xiàn)屏幕截圖并保存截圖到指定文件

    Android實現(xiàn)屏幕截圖并保存截圖到指定文件

    這篇文章主要為大家詳細介紹了Android實現(xiàn)屏幕截圖并保存截取圖片到指定文件,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-10-10
  • Android實現(xiàn)捕獲未知異常并提交給服務(wù)器的方法

    Android實現(xiàn)捕獲未知異常并提交給服務(wù)器的方法

    這篇文章主要介紹了Android實現(xiàn)捕獲未知異常并提交給服務(wù)器的方法,涉及Android的異常與錯誤處理機制相關(guān)操作技巧,需要的朋友可以參考下
    2016-08-08
  • Android實現(xiàn)朋友圈評論回復(fù)列表

    Android實現(xiàn)朋友圈評論回復(fù)列表

    這篇文章主要為大家詳細介紹了Android實現(xiàn)朋友圈評論回復(fù)列表,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-11-11

最新評論

涿鹿县| 淄博市| 贵定县| 加查县| 酒泉市| 布尔津县| 昌图县| 安国市| 屯留县| 洛浦县| 新河县| 陵川县| 炉霍县| 泰安市| 高安市| 积石山| 景宁| 乌拉特中旗| 长子县| 墨竹工卡县| 东丽区| 黔江区| 昭平县| 获嘉县| 延边| 宁陵县| 察隅县| 泰安市| 广南县| 乐亭县| 涡阳县| 台江县| 吉林省| 栾川县| 长治市| 金华市| 泗水县| 和平县| 河北区| 临江市| 漳平市|