在上一篇博客中,我们详细分析了InputReader中读取设备事件,到processEventsLocked函数处理事件(包括设备事件,设备添加、删除等),再到ProcessEventsForDeviceLocked处理设备事件,最后到InputDevice的process函数,去遍历各个InputMapper执行process函数。
今天我们继续从这里开始分析,Input设备有很多种类,其消息格式各不相同,因此就有很多InputMapper对各个不同的RawEvent进行处理。
我们今天主要从按键的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; } } } }
我们先来看下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; }我们看到还是通过device中的成员变量,由此可知肯定是在EventHub的openDeviceLocked函数中,
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; }我们再来看loadKeyLayout函数
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; }再看appendInputDeviceConfigurationFileRelativePath函数
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/", };而CONFIGURATION_FILE_EXTENSION是各个type对应的文件后缀
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; }
下面我们再来看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函数,我们主要看最后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(); }
所以最后这个listener是InputDispatcher,因此最后就是调用的InputDispatcher的notifyKey函数。
而InputDispatcher的notifyKey函数,我们在下篇博客中分析。