当前位置 主页 > 网站技术 > 代码类 >

    Android中外接键盘的检测的实现

    栏目:代码类 时间:2019-11-22 12:08

    今天来了一个问题:软键盘无法弹出。分析后是因为系统判断当前有外接硬键盘,就会隐藏软键盘。但实际情况并不是这么简单,该问题只有在特定条件下偶现,具体分析过程就不说了,就是软硬键盘支持上的逻辑问题。借着这个机会整理一下键盘检测的过程。

    Configuration

    Android系统中通过读取Configuration中keyboard的值来判断是否存在外接键盘。Configuration中关于键盘类型的定义如下,

      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 。应用就可以根据keyboard的值来判断是否存在外接键盘,InputMethodService.java中有类似的判断代码。

      // 软件盘是否可以显示
      public boolean onEvaluateInputViewShown() {
        Configuration config = getResources().getConfiguration();
        return config.keyboard == Configuration.KEYBOARD_NOKEYS
            || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES;
      }  
    

    现在的问题就转向Configuration的keyboard是如何更新的。在WindowManagerService.java中,应用启动时会更新Configuration,相关代码如下。

      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;
          // 遍历输入设备
          for (int i = 0; i < len; i++) {
            InputDevice device = devices[i];
            // 如果不是虚拟输入设备,会根据输入设备的flags来更新Configuration
            if (!device.isVirtual()) {
              ......
              // 如果输入设备的键盘类型为KEYBOARD_TYPE_ALPHABETIC,则将keyboard设置为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;
          // 更新硬件键盘状态
          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被设置,将keyboard设置为KEYBOARD_NOKEYS,让软件盘可以显示
          if (mShowImeWithHardKeyboard) {
            config.keyboard = Configuration.KEYBOARD_NOKEYS;
          }
          ......
        }