這期內(nèi)容當(dāng)中小編將會給大家?guī)碛嘘P(guān)Android中怎么檢測外接鍵盤,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
壺關(guān)網(wǎng)站建設(shè)公司創(chuàng)新互聯(lián),壺關(guān)網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗(yàn)。已為壺關(guān)近千家提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的壺關(guān)做網(wǎng)站的公司定做!
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; // 標(biāo)準(zhǔn)外接鍵盤 public static final int KEYBOARD_12KEY = 3; // 12鍵小鍵盤
在最常見的情況下,外接鍵盤未連接時keyboard的值為KEYBOARD_NOKEYS,當(dāng)檢測到鍵盤連接后會將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; // 默認(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è)備,會根據(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的值有,
默認(rèn)值為KEYBOARD_NOKEYS,表示沒有外接鍵盤。當(dāng)輸入設(shè)備為KEYBOARD_TYPE_ALPHABETIC時,更新為KEYBOARD_QWERTY,一個標(biāo)準(zhǔn)鍵盤。當(dāng)Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD為1時,設(shè)置為KEYBOARD_NOKEYS,目的是讓軟鍵盤可以顯示。
inputflinger
接下來需要關(guān)注輸入設(shè)備時何時被設(shè)置KEYBOARD_TYPE_ALPHABETIC的。搜索代碼可以看到,這個flag實(shí)在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ī)в?#39;Q'鍵,就認(rèn)為這是一個標(biāo)準(zhǔn)的外接鍵盤。但為何判斷'Q'鍵還不是很清楚。
keylayout
上面說道通過'Q'鍵來判斷是否為外接鍵盤,這個'Q'鍵是Android的鍵值,鍵值是否存在是通過一個keylayout文件決定的。kl文件存儲在目標(biāo)系統(tǒng)的/system/usr/keylayout/下,系統(tǒng)可以有多個kl文件,根據(jù)設(shè)備的ID來命名。當(dāng)系統(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 BACKkey 28 DPAD_CENTERkey 102 HOMEkey 103 DPAD_UPkey 105 DPAD_LEFTkey 106 DPAD_RIGHTkey 108 DPAD_DOWNkey 113 VOLUME_MUTEkey 114 VOLUME_DOWNkey 115 VOLUME_UPkey 142 POWER
鍵值映射需要使用關(guān)鍵之”key“進(jìn)行聲明,之后跟著的數(shù)字為Linux驅(qū)動中的鍵值定義,再后面的字符串是Android中按鍵的名稱。'Q'鍵是否存在完全取決于kl文件中是否有映射,而不是實(shí)際物理鍵是否存在。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è)備設(shè)置為KEYBOARD_NOKEYS,減少副作用。修改keylayout,去掉'Q'鍵映射。有時kl文件寫的不標(biāo)準(zhǔn),為了通用把所有鍵的映射都寫上了,實(shí)際硬件鍵卻很少,我們就是這種情況。應(yīng)該按照真實(shí)硬件來編寫kl文件。設(shè)置Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD為1。我認(rèn)為這是最標(biāo)準(zhǔn)的修改方式,也非常方便。
關(guān)于第三個方案的修改方式有兩種,一種是修改缺省的setting值,在文件frameworks/base/packages/SettingsProvider/res/values/defaults.xml中增加,
另一種方式是在系統(tǒng)啟動時在代碼中通過接口進(jìn)行設(shè)置。
Settings.Secure.putInt(context.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1);
上述就是小編為大家分享的Android中怎么檢測外接鍵盤了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。