Implementation of detection of external keyboard in Android

Today came a problem: the soft keyboard can't pop up. After analysis, because the system judges that there is an external hard keyboard, the soft keyboard will be hidden. However, the actual situation is not so simple. This problem occurs occasionally only under specific conditions, and the specific analysis process is not mentioned. It is the logic problem of soft and hard keyboard support. Take this opportunity to sort out the process of keyboard detection.

Configuration

Android system judges whether there is an external keyboard by reading the value of keyboard in configuration. The definition of keyboard type in configuration is as follows,

  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键小键盘

In the most common case, when the external keyboard is not connected, the value of keyboard is keyboard_ Nokeys: when the keyboard connection is detected, the value of keyboard will be updated to keyboard_ QWERTY 。 The application can judge whether there is an external keyboard according to the value of the keyboard. There is a similar judgment code in inputmethodservice.java.

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

The question now turns to how the configuration keyboard is updated. In windowmanagerservice.java, the configuration will be updated when the application starts. The relevant codes are as follows.

  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;
      }
      ......
    }

The values that affect the keyboard in the configuration are,

inputflinger

Next, you need to pay attention to when keyboard is set when inputting the device_ TYPE_ Alphabetic. You can see from the search code that this flag is actually set in the native code, and the code is in inputlinker / inputreader.cpp. Native and Java use the same definition value. If you modify the definition, you need to pay attention to modifying it at the same time. The name in native is 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;
}

When inputreader adds devices, it sets the keyboard type according to the flag of classes. This flag is set in eventhub.cpp.

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;
    }
  ......
}

It is clear here that when the eventhub loads the device, if the input device is a keyboard with 'Q' key, it is considered to be a standard external keyboard. But why to judge the 'Q' key is not very clear.

keylayout

As mentioned above, the 'Q' key is used to determine whether it is an external keyboard. This' Q 'key is the key value of Android. Whether the key value exists is determined by a keylayout file. KL files are stored in / system / usr / keylayout / of the target system. The system can have multiple KL files named according to the device ID. When the system loads the keyboard device, it will find the KL file under / system / usr / keylayout / according to the vendor ID and product ID of the device. For example, a KL file named vendor_ 0c45_ Product_ 1109. KL "indicates that the vendor ID of the equipment is 0c45 and the product ID is 1109. An example of the contents of a KL is as follows,

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

The key value mapping needs to be declared with the key "key", followed by the number for the key value definition in the linux driver, and then the string is the name of the key in Android. The existence of the 'Q' key depends entirely on whether there is a mapping in the KL file, not the actual physical key. There is also a rule for searching the KL file, and the search order is as follows,

/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

Both soft and hard keyboards are supported

With the above knowledge, we can give a scheme to support both soft and hard keyboards.

There are two ways to modify the third scheme. One is to modify the default setting value and add it in the file frameworks / base / packages / settingsprovider / RES / values / defaults.xml,

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

Another way is to set it in the code through the interface when the system starts.

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

The above is the whole content of this article. I hope it will help you in your study, and I hope you will support us a lot.

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>