今天我们继续从这里开始分析,Input设备有很多种类,其消息格式各不相同,因此就有很多InputMapper对各个不同的RawEvent进行处理。
我们今天主要从按键的KeyboardInputMapper来讲解。
一、KeyboardInputMapper
下面我们主要从按键,比如音量键、power键的这个InputMapper说起:
- void KeyboardInputMapper::process(const RawEvent* rawEvent) {
- switch (rawEvent->type) {
- case EV_KEY: {
- int32_t scanCode = rawEvent->code;
- int32_t usageCode = mCurrentHidUsage;
- mCurrentHidUsage = 0;
- if (isKeyboardOrGamepadKey(scanCode)) {
- int32_t keyCode;
- uint32_t flags;
- if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {//扫描码对应成按键码
- keyCode = AKEYCODE_UNKNOWN;
- flags = 0;
- }
- processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
- }
- break;
- }
- case EV_MSC: {
- if (rawEvent->code == MSC_SCAN) {
- mCurrentHidUsage = rawEvent->value;
- }
- break;
- }
- case EV_SYN: {
- if (rawEvent->code == SYN_REPORT) {
- mCurrentHidUsage = 0;
- }
- }
- }
- }
1.1 EventHub的mapKey函数
我们先来看下EventHub的mapKey函数,这个函数中outKeycode是入参,但是传的是指针,会往里面写值。
- status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const {
- AutoMutex _l(mLock);
- Device* device = getDeviceLocked(deviceId);
- if (device) {
- // Check the key character map first.
- sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
- if (kcm != NULL) {
- if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
- scanCode, *outKeycode);
- *outFlags = 0;
- return NO_ERROR;
- }
- }
- // Check the key layout next.
- if (device->keyMap.haveKeyLayout()) {
- if (!device->keyMap.keyLayoutMap->mapKey(
- scanCode, usageCode, outKeycode, outFlags)) {
- return NO_ERROR;
- }
- }
- }
- *outKeycode = 0;
- *outFlags = 0;
- return NAME_NOT_FOUND;
- }
- status_t keyMapStatus = NAME_NOT_FOUND;
- if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {
- // Load the keymap for the device.
- keyMapStatus = loadKeyMapLocked(device);
- }
果然在openDeviceLocked中有上面这段代码。
- status_t EventHub::loadKeyMapLocked(Device* device) {
- return device->keyMap.load(device->identifier, device->configuration);
- }
再来看下load函数,先通过deviceConfiguration获取keyLayoutName,deviceConfiguration肯定也是前面openDeviceLocked的时候创建的,这里就不分析了。
- status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,
- const PropertyMap* deviceConfiguration) {
- // Use the configured key layout if available.
- if (deviceConfiguration) {
- String8 keyLayoutName;
- if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),
- keyLayoutName)) {//通过deviceConfiguration获取keyLayoutName
- status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);
- if (status == NAME_NOT_FOUND) {
- ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "
- "it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
- }
- }
- String8 keyCharacterMapName;
- if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),
- keyCharacterMapName)) {
- status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);
- if (status == NAME_NOT_FOUND) {
- ALOGE("Configuration for keyboard device '%s' requested keyboard character "
- "map '%s' but it was not found.",
- deviceIdenfifier.name.string(), keyLayoutName.string());
- }
- }
- if (isComplete()) {
- return OK;
- }
- }
- // Try searching by device identifier.
- if (probeKeyMap(deviceIdenfifier, String8::empty())) {
- return OK;
- }
- // Fall back on the Generic key map.
- // TODO Apply some additional heuristics here to figure out what kind of
- // generic key map to use (US English, etc.) for typical external keyboards.
- if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {
- return OK;
- }
- // Try the Virtual key map as a last resort.
- if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {
- return OK;
- }
- // Give up!
- ALOGE("Could not determine key map for device '%s' and no default key maps were found!",
- deviceIdenfifier.name.string());
- return NAME_NOT_FOUND;
- }
- status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name) {
- String8 path(getPath(deviceIdentifier, name,
- INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));
- if (path.isEmpty()) {
- return NAME_NOT_FOUND;
- }
- status_t status = KeyLayoutMap::load(path, &keyLayoutMap);
- if (status) {
- return status;
- }
- keyLayoutFile.setTo(path);
- return OK;
- }
我们先来分析下getPath函数,看它是如何获取path的
- String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,
- const String8& name, InputDeviceConfigurationFileType type) {
- return name.isEmpty()
- ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)
- : getInputDeviceConfigurationFilePathByName(name, type);
- }
我们再看getInputDeviceConfigurationFilePathByName函数,到system/usr目录下
- String8 getInputDeviceConfigurationFilePathByName(
- const String8& name, InputDeviceConfigurationFileType type) {
- // Search system repository.
- String8 path;
- path.setTo(getenv("ANDROID_ROOT"));
- path.append("/usr/");
- appendInputDeviceConfigurationFileRelativePath(path, name, type);
- #if DEBUG_PROBE
- ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());
- #endif
- if (!access(path.string(), R_OK)) {
- #if DEBUG_PROBE
- ALOGD("Found");
- #endif
- return path;
- }
- static void appendInputDeviceConfigurationFileRelativePath(String8& path,
- const String8& name, InputDeviceConfigurationFileType type) {
- path.append(CONFIGURATION_FILE_DIR[type]);
- for (size_t i = 0; i < name.length(); i++) {
- char ch = name[i];
- if (!isValidNameChar(ch)) {
- ch = '_';
- }
- path.append(&ch, 1);
- }
- path.append(CONFIGURATION_FILE_EXTENSION[type]);
- }
CONFIGURATION_FILE_DIR是各个 type对应的各个目录
- static const char* CONFIGURATION_FILE_DIR[] = {
- "idc/",
- "keylayout/",
- "keychars/",
- };
- static const char* CONFIGURATION_FILE_EXTENSION[] = {
- ".idc",
- ".kl",
- ".kcm",
- };
我们再结合手机里的文件看下:
- root@lte26007:/system/usr/keylayout # ls
- ls
- AVRCP.kl
- Generic.kl
- Vendor_0079_Product_0011.kl
- Vendor_045e_Product_028e.kl
- Vendor_046d_Product_b501.kl
- Vendor_046d_Product_c216.kl
- Vendor_046d_Product_c219.kl
- Vendor_046d_Product_c21d.kl
- Vendor_046d_Product_c21f.kl
- Vendor_046d_Product_c294.kl
- Vendor_046d_Product_c299.kl
- Vendor_046d_Product_c532.kl
- Vendor_054c_Product_0268.kl
- Vendor_0583_Product_2060.kl
- Vendor_05ac_Product_0239.kl
- Vendor_0b05_Product_4500.kl
- Vendor_1038_Product_1412.kl
- Vendor_12bd_Product_d015.kl
- Vendor_1532_Product_0900.kl
- Vendor_1689_Product_fd00.kl
- Vendor_1689_Product_fd01.kl
- Vendor_1689_Product_fe00.kl
- Vendor_18d1_Product_2c40.kl
- Vendor_1949_Product_0401.kl
- Vendor_1bad_Product_f016.kl
- Vendor_1bad_Product_f023.kl
- Vendor_1bad_Product_f027.kl
- Vendor_1bad_Product_f036.kl
- Vendor_1d79_Product_0009.kl
- Vendor_22b8_Product_093d.kl
- Vendor_2378_Product_1008.kl
- Vendor_2378_Product_100a.kl
- comip-gpio-keys.kl
- comip-keypad.kl
- ft5x06.kl
- h2w_headset.kl
- qwerty.kl
- sensor00fn11.kl
我们再来看下Generic.kl这个文件,截取部分如下:扫描码对应的键值。
- .....
- key 108 DPAD_DOWN
- key 109 PAGE_DOWN
- key 110 INSERT
- key 111 FORWARD_DEL
- # key 112 "KEY_MACRO"
- key 113 VOLUME_MUTE
- key 114 VOLUME_DOWN
- key 115 VOLUME_UP
- key 116 POWER
- key 117 NUMPAD_EQUALS
- # key 118 "KEY_KPPLUSMIN
- key 119 BREAK
- # key 120 (undefined)
- key 121 NUMPAD_COMMA
- key 122 KANA
- key 123 EISU
- key 124 YEN
- key 125 META_LEFT
- key 126 META_RIGHT
- key 127 MENU
- key 128 MEDIA_STOP
我们继续看下KeyLayoutMap::load这个函数,这个函数我们就不细说了。
- status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {
- outMap->clear();
- Tokenizer* tokenizer;
- status_t status = Tokenizer::open(filename, &tokenizer);//通过这个函数获取Tokenizer
- if (status) {
- ALOGE("Error %d opening key layout map file %s.", status, filename.string());
- } else {
- sp<KeyLayoutMap> map = new KeyLayoutMap();
- if (!map.get()) {
- ALOGE("Error allocating key layout map.");
- status = NO_MEMORY;
- } else {
- #if DEBUG_PARSER_PERFORMANCE
- nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
- #endif
- Parser parser(map.get(), tokenizer);//解析
- status = parser.parse();
- #if DEBUG_PARSER_PERFORMANCE
- nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
- ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",
- tokenizer->getFilename().string(), tokenizer->getLineNumber(),
- elapsedTime / 1000000.0);
- #endif
- if (!status) {
- *outMap = map;
- }
- }
- delete tokenizer;
- }
- return status;
- }
1.2 KeyboardInputMapper的processKey函数
下面我们再来看KeyboardInputMapper::process中的processKey函数
- void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
- int32_t scanCode, uint32_t policyFlags) {
- if (down) {
- // Rotate key codes according to orientation if needed.
- if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
- keyCode = rotateKeyCode(keyCode, mOrientation);
- }
- // Add key down.
- ssize_t keyDownIndex = findKeyDown(scanCode);
- if (keyDownIndex >= 0) {
- // key repeat, be sure to use same keycode as before in case of rotation
- keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
- } else {
- // key down
- if ((policyFlags & POLICY_FLAG_VIRTUAL)
- && mContext->shouldDropVirtualKey(when,
- getDevice(), keyCode, scanCode)) {
- return;
- }
- if (policyFlags & POLICY_FLAG_GESTURE) {
- mDevice->cancelTouch(when);
- }
- mKeyDowns.push();
- KeyDown& keyDown = mKeyDowns.editTop();
- keyDown.keyCode = keyCode;
- keyDown.scanCode = scanCode;
- }
- mDownTime = when;
- } else {
- // Remove key down.
- ssize_t keyDownIndex = findKeyDown(scanCode);
- if (keyDownIndex >= 0) {
- // key up, be sure to use same keycode as before in case of rotation
- keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
- mKeyDowns.removeAt(size_t(keyDownIndex));
- } else {
- // key was not actually down
- ALOGI("Dropping key up from device %s because the key was not down. "
- "keyCode=%d, scanCode=%d",
- getDeviceName().string(), keyCode, scanCode);
- return;
- }
- }
- int32_t oldMetaState = mMetaState;
- int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);
- bool metaStateChanged = oldMetaState != newMetaState;
- if (metaStateChanged) {
- mMetaState = newMetaState;
- updateLedState(false);
- }
- nsecs_t downTime = mDownTime;
- // Key down on external an keyboard should wake the device.
- // We don't do this for internal keyboards to prevent them from waking up in your pocket.
- // For internal keyboards, the key layout file should specify the policy flags for
- // each wake key individually.
- // TODO: Use the input device configuration to control this behavior more finely.
- if (down && getDevice()->isExternal()) {
- policyFlags |= POLICY_FLAG_WAKE;
- }
- if (mParameters.handlesKeyRepeat) {
- policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
- }
- if (metaStateChanged) {
- getContext()->updateGlobalMetaState();
- }
- if (down && !isMetaKey(keyCode)) {
- getContext()->fadePointer();
- }
- NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
- down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
- getListener()->notifyKey(&args);
- }
这个函数,一开始还是再把扫描码转成键盘码,后面主要调用了notifyKey函数。
getListener函数如下
- InputListenerInterface* InputReader::ContextImpl::getListener() {
- return mReader->mQueuedListener.get();
- }
而notifyKey函数如下,就是把对象放在一个变量中。
- void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {
- mArgsQueue.push(new NotifyKeyArgs(*args));
- }
二、InputReader的loopOnce函数
最后我们再回到InputReader的loopOnce函数,我们主要看最后mQueuedListener->flush函数。
- void InputReader::loopOnce() {
- int32_t oldGeneration;
- int32_t timeoutMillis;
- bool inputDevicesChanged = false;
- Vector<InputDeviceInfo> inputDevices;
- { // acquire lock
- AutoMutex _l(mLock);
- oldGeneration = mGeneration;
- timeoutMillis = -1;
- uint32_t changes = mConfigurationChangesToRefresh;
- if (changes) {
- mConfigurationChangesToRefresh = 0;
- timeoutMillis = 0;
- refreshConfigurationLocked(changes);
- } else if (mNextTimeout != LLONG_MAX) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);
- }
- } // release lock
- size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
- { // acquire lock
- AutoMutex _l(mLock);
- mReaderIsAliveCondition.broadcast();
- if (count) {
- processEventsLocked(mEventBuffer, count);
- }
- if (mNextTimeout != LLONG_MAX) {
- nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
- if (now >= mNextTimeout) {
- #if DEBUG_RAW_EVENTS
- ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);
- #endif
- mNextTimeout = LLONG_MAX;
- timeoutExpiredLocked(now);
- }
- }
- if (oldGeneration != mGeneration) {
- inputDevicesChanged = true;
- getInputDevicesLocked(inputDevices);
- }
- } // release lock
- // Send out a message that the describes the changed input devices.
- if (inputDevicesChanged) {
- mPolicy->notifyInputDevicesChanged(inputDevices);
- }
- // Flush queued events out to the listener.
- // This must happen outside of the lock because the listener could potentially call
- // back into the InputReader's methods, such as getScanCodeState, or become blocked
- // on another thread similarly waiting to acquire the InputReader lock thereby
- // resulting in a deadlock. This situation is actually quite plausible because the
- // listener is actually the input dispatcher, which calls into the window manager,
- // which occasionally calls into the input reader.
- mQueuedListener->flush();
- }
QueuedInputListener::flush函数在文件InputListener.cpp中。
- void QueuedInputListener::flush() {
- size_t count = mArgsQueue.size();
- for (size_t i = 0; i < count; i++) {
- NotifyArgs* args = mArgsQueue[i];
- args->notify(mInnerListener);
- delete args;
- }
- mArgsQueue.clear();
- }
这个函数中遍历之前我们在每个InputMapper存入的NotifyArgs对象,最后调用了NotifyArgs对象的notify函数
之前我们的NotifyArgs对象是NotifyKeyArgs对象,这个notify是个虚函数,就到NotifyKeyArgs::notify
- void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {
- listener->notifyKey(this);
- }
而这个listener,是新建QueuedInputListener的时候传进来的
- mQueuedListener = new QueuedInputListener(listener);
listener是InputReader里面传过来的,所以我们知道InputReader是在InputManager中创建的
- InputReader::InputReader(const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& policy,
- const sp<InputListenerInterface>& listener) :
我们看下InputManager的构造函数,传进来的InputDispatcher
- InputManager::InputManager(
- const sp<EventHubInterface>& eventHub,
- const sp<InputReaderPolicyInterface>& readerPolicy,
- const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
- mDispatcher = new InputDispatcher(dispatcherPolicy);
- mReader = new InputReader(eventHub, readerPolicy, mDispatcher);
- initialize();
- }