Android6.0 按键流程 KeyboardInputMapper扫描码转成键盘码 (二)

我们详细分析了InputReader中读取设备事件,到processEventsLocked函数处理事件(包括设备事件,设备添加、删除等),再到ProcessEventsForDeviceLocked处理设备事件,最后到InputDevice的process函数,去遍历各个InputMapper执行process函数。

今天我们继续从这里开始分析,Input设备有很多种类,其消息格式各不相同,因此就有很多InputMapper对各个不同的RawEvent进行处理。

我们今天主要从按键的KeyboardInputMapper来讲解。


一、KeyboardInputMapper

下面我们主要从按键,比如音量键、power键的这个InputMapper说起:

  1. void KeyboardInputMapper::process(const RawEvent* rawEvent) {  
  2.     switch (rawEvent->type) {  
  3.           
  4.     case EV_KEY: {  
  5.         int32_t scanCode = rawEvent->code;  
  6.         int32_t usageCode = mCurrentHidUsage;  
  7.         mCurrentHidUsage = 0;  
  8.   
  9.         if (isKeyboardOrGamepadKey(scanCode)) {  
  10.             int32_t keyCode;  
  11.             uint32_t flags;  
  12.             if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {//扫描码对应成按键码  
  13.                 keyCode = AKEYCODE_UNKNOWN;  
  14.                 flags = 0;  
  15.             }  
  16.             processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);  
  17.         }  
  18.         break;  
  19.     }  
  20.     case EV_MSC: {  
  21.         if (rawEvent->code == MSC_SCAN) {  
  22.             mCurrentHidUsage = rawEvent->value;  
  23.         }  
  24.         break;  
  25.     }  
  26.     case EV_SYN: {  
  27.         if (rawEvent->code == SYN_REPORT) {  
  28.             mCurrentHidUsage = 0;  
  29.         }  
  30.     }  
  31.     }  
  32. }  


1.1 EventHub的mapKey函数

我们先来看下EventHub的mapKey函数,这个函数中outKeycode是入参,但是传的是指针,会往里面写值。

  1. status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,  
  2.         int32_t* outKeycode, uint32_t* outFlags) const {  
  3.     AutoMutex _l(mLock);  
  4.     Device* device = getDeviceLocked(deviceId);  
  5.   
  6.     if (device) {  
  7.         // Check the key character map first.  
  8.         sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();  
  9.         if (kcm != NULL) {  
  10.             if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {  
  11.                     scanCode, *outKeycode);  
  12.                 *outFlags = 0;  
  13.                 return NO_ERROR;  
  14.             }  
  15.         }  
  16.   
  17.         // Check the key layout next.  
  18.         if (device->keyMap.haveKeyLayout()) {  
  19.             if (!device->keyMap.keyLayoutMap->mapKey(  
  20.                     scanCode, usageCode, outKeycode, outFlags)) {  
  21.                 return NO_ERROR;  
  22.             }  
  23.         }  
  24.     }  
  25.   
  26.     *outKeycode = 0;  
  27.     *outFlags = 0;  
  28.     return NAME_NOT_FOUND;  
  29. }  
我们看到还是通过device中的成员变量,由此可知肯定是在EventHub的openDeviceLocked函数中,
  1. status_t keyMapStatus = NAME_NOT_FOUND;  
  2. if (device->classes & (INPUT_DEVICE_CLASS_KEYBOARD | INPUT_DEVICE_CLASS_JOYSTICK)) {  
  3.     // Load the keymap for the device.  
  4.     keyMapStatus = loadKeyMapLocked(device);  
  5. }  

果然在openDeviceLocked中有上面这段代码。

  1. status_t EventHub::loadKeyMapLocked(Device* device) {  
  2.     return device->keyMap.load(device->identifier, device->configuration);  
  3. }  

再来看下load函数,先通过deviceConfiguration获取keyLayoutName,deviceConfiguration肯定也是前面openDeviceLocked的时候创建的,这里就不分析了。

  1. status_t KeyMap::load(const InputDeviceIdentifier& deviceIdenfifier,  
  2.         const PropertyMap* deviceConfiguration) {  
  3.     // Use the configured key layout if available.  
  4.     if (deviceConfiguration) {  
  5.         String8 keyLayoutName;  
  6.         if (deviceConfiguration->tryGetProperty(String8("keyboard.layout"),  
  7.                 keyLayoutName)) {//通过deviceConfiguration获取keyLayoutName  
  8.             status_t status = loadKeyLayout(deviceIdenfifier, keyLayoutName);  
  9.             if (status == NAME_NOT_FOUND) {  
  10.                 ALOGE("Configuration for keyboard device '%s' requested keyboard layout '%s' but "  
  11.                         "it was not found.",  
  12.                         deviceIdenfifier.name.string(), keyLayoutName.string());  
  13.             }  
  14.         }  
  15.   
  16.         String8 keyCharacterMapName;  
  17.         if (deviceConfiguration->tryGetProperty(String8("keyboard.characterMap"),  
  18.                 keyCharacterMapName)) {  
  19.             status_t status = loadKeyCharacterMap(deviceIdenfifier, keyCharacterMapName);  
  20.             if (status == NAME_NOT_FOUND) {  
  21.                 ALOGE("Configuration for keyboard device '%s' requested keyboard character "  
  22.                         "map '%s' but it was not found.",  
  23.                         deviceIdenfifier.name.string(), keyLayoutName.string());  
  24.             }  
  25.         }  
  26.   
  27.         if (isComplete()) {  
  28.             return OK;  
  29.         }  
  30.     }  
  31.   
  32.     // Try searching by device identifier.  
  33.     if (probeKeyMap(deviceIdenfifier, String8::empty())) {  
  34.         return OK;  
  35.     }  
  36.   
  37.     // Fall back on the Generic key map.  
  38.     // TODO Apply some additional heuristics here to figure out what kind of  
  39.     //      generic key map to use (US English, etc.) for typical external keyboards.  
  40.     if (probeKeyMap(deviceIdenfifier, String8("Generic"))) {  
  41.         return OK;  
  42.     }  
  43.   
  44.     // Try the Virtual key map as a last resort.  
  45.     if (probeKeyMap(deviceIdenfifier, String8("Virtual"))) {  
  46.         return OK;  
  47.     }  
  48.   
  49.     // Give up!  
  50.     ALOGE("Could not determine key map for device '%s' and no default key maps were found!",  
  51.             deviceIdenfifier.name.string());  
  52.     return NAME_NOT_FOUND;  
  53. }  
我们再来看loadKeyLayout函数
  1. status_t KeyMap::loadKeyLayout(const InputDeviceIdentifier& deviceIdentifier,  
  2.         const String8& name) {  
  3.     String8 path(getPath(deviceIdentifier, name,  
  4.             INPUT_DEVICE_CONFIGURATION_FILE_TYPE_KEY_LAYOUT));  
  5.     if (path.isEmpty()) {  
  6.         return NAME_NOT_FOUND;  
  7.     }  
  8.   
  9.     status_t status = KeyLayoutMap::load(path, &keyLayoutMap);  
  10.     if (status) {  
  11.         return status;  
  12.     }  
  13.   
  14.     keyLayoutFile.setTo(path);  
  15.     return OK;  
  16. }  

我们先来分析下getPath函数,看它是如何获取path的

  1. String8 KeyMap::getPath(const InputDeviceIdentifier& deviceIdentifier,  
  2.         const String8& name, InputDeviceConfigurationFileType type) {  
  3.     return name.isEmpty()  
  4.             ? getInputDeviceConfigurationFilePathByDeviceIdentifier(deviceIdentifier, type)  
  5.             : getInputDeviceConfigurationFilePathByName(name, type);  
  6. }  

我们再看getInputDeviceConfigurationFilePathByName函数,到system/usr目录下

  1. String8 getInputDeviceConfigurationFilePathByName(  
  2.         const String8& name, InputDeviceConfigurationFileType type) {  
  3.     // Search system repository.  
  4.     String8 path;  
  5.     path.setTo(getenv("ANDROID_ROOT"));  
  6.     path.append("/usr/");  
  7.     appendInputDeviceConfigurationFileRelativePath(path, name, type);  
  8. #if DEBUG_PROBE  
  9.     ALOGD("Probing for system provided input device configuration file: path='%s'", path.string());  
  10. #endif  
  11.     if (!access(path.string(), R_OK)) {  
  12. #if DEBUG_PROBE  
  13.         ALOGD("Found");  
  14. #endif  
  15.         return path;  
  16.     }  
再看appendInputDeviceConfigurationFileRelativePath函数
  1. static void appendInputDeviceConfigurationFileRelativePath(String8& path,  
  2.         const String8& name, InputDeviceConfigurationFileType type) {  
  3.     path.append(CONFIGURATION_FILE_DIR[type]);  
  4.     for (size_t i = 0; i < name.length(); i++) {  
  5.         char ch = name[i];  
  6.         if (!isValidNameChar(ch)) {  
  7.             ch = '_';  
  8.         }  
  9.         path.append(&ch, 1);  
  10.     }  
  11.     path.append(CONFIGURATION_FILE_EXTENSION[type]);  
  12. }  

CONFIGURATION_FILE_DIR是各个 type对应的各个目录

  1. static const char* CONFIGURATION_FILE_DIR[] = {  
  2.         "idc/",  
  3.         "keylayout/",  
  4.         "keychars/",  
  5. };  
而CONFIGURATION_FILE_EXTENSION是各个type对应的文件后缀
  1. static const char* CONFIGURATION_FILE_EXTENSION[] = {  
  2.         ".idc",  
  3.         ".kl",  
  4.         ".kcm",  
  5. };  

我们再结合手机里的文件看下:

  1. root@lte26007:/system/usr/keylayout # ls  
  2. ls  
  3. AVRCP.kl  
  4. Generic.kl  
  5. Vendor_0079_Product_0011.kl  
  6. Vendor_045e_Product_028e.kl  
  7. Vendor_046d_Product_b501.kl  
  8. Vendor_046d_Product_c216.kl  
  9. Vendor_046d_Product_c219.kl  
  10. Vendor_046d_Product_c21d.kl  
  11. Vendor_046d_Product_c21f.kl  
  12. Vendor_046d_Product_c294.kl  
  13. Vendor_046d_Product_c299.kl  
  14. Vendor_046d_Product_c532.kl  
  15. Vendor_054c_Product_0268.kl  
  16. Vendor_0583_Product_2060.kl  
  17. Vendor_05ac_Product_0239.kl  
  18. Vendor_0b05_Product_4500.kl  
  19. Vendor_1038_Product_1412.kl  
  20. Vendor_12bd_Product_d015.kl  
  21. Vendor_1532_Product_0900.kl  
  22. Vendor_1689_Product_fd00.kl  
  23. Vendor_1689_Product_fd01.kl  
  24. Vendor_1689_Product_fe00.kl  
  25. Vendor_18d1_Product_2c40.kl  
  26. Vendor_1949_Product_0401.kl  
  27. Vendor_1bad_Product_f016.kl  
  28. Vendor_1bad_Product_f023.kl  
  29. Vendor_1bad_Product_f027.kl  
  30. Vendor_1bad_Product_f036.kl  
  31. Vendor_1d79_Product_0009.kl  
  32. Vendor_22b8_Product_093d.kl  
  33. Vendor_2378_Product_1008.kl  
  34. Vendor_2378_Product_100a.kl  
  35. comip-gpio-keys.kl  
  36. comip-keypad.kl  
  37. ft5x06.kl  
  38. h2w_headset.kl  
  39. qwerty.kl  
  40. sensor00fn11.kl  

我们再来看下Generic.kl这个文件,截取部分如下:扫描码对应的键值。

  1. .....  
  2. key 108   DPAD_DOWN  
  3. key 109   PAGE_DOWN  
  4. key 110   INSERT  
  5. key 111   FORWARD_DEL  
  6. # key 112 "KEY_MACRO"  
  7. key 113   VOLUME_MUTE  
  8. key 114   VOLUME_DOWN  
  9. key 115   VOLUME_UP  
  10. key 116   POWER  
  11. key 117   NUMPAD_EQUALS  
  12. # key 118 "KEY_KPPLUSMIN  
  13. key 119   BREAK  
  14. # key 120 (undefined)  
  15. key 121   NUMPAD_COMMA  
  16. key 122   KANA  
  17. key 123   EISU  
  18. key 124   YEN  
  19. key 125   META_LEFT  
  20. key 126   META_RIGHT  
  21. key 127   MENU  
  22. key 128   MEDIA_STOP  

我们继续看下KeyLayoutMap::load这个函数,这个函数我们就不细说了。

  1. status_t KeyLayoutMap::load(const String8& filename, sp<KeyLayoutMap>* outMap) {  
  2.     outMap->clear();  
  3.   
  4.     Tokenizer* tokenizer;  
  5.     status_t status = Tokenizer::open(filename, &tokenizer);//通过这个函数获取Tokenizer  
  6.     if (status) {  
  7.         ALOGE("Error %d opening key layout map file %s.", status, filename.string());  
  8.     } else {  
  9.         sp<KeyLayoutMap> map = new KeyLayoutMap();  
  10.         if (!map.get()) {  
  11.             ALOGE("Error allocating key layout map.");  
  12.             status = NO_MEMORY;  
  13.         } else {  
  14. #if DEBUG_PARSER_PERFORMANCE  
  15.             nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);  
  16. #endif  
  17.             Parser parser(map.get(), tokenizer);//解析  
  18.             status = parser.parse();  
  19. #if DEBUG_PARSER_PERFORMANCE  
  20.             nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;  
  21.             ALOGD("Parsed key layout map file '%s' %d lines in %0.3fms.",  
  22.                     tokenizer->getFilename().string(), tokenizer->getLineNumber(),  
  23.                     elapsedTime / 1000000.0);  
  24. #endif  
  25.             if (!status) {  
  26.                 *outMap = map;  
  27.             }  
  28.         }  
  29.         delete tokenizer;  
  30.     }  
  31.     return status;  
  32. }  


1.2 KeyboardInputMapper的processKey函数

下面我们再来看KeyboardInputMapper::process中的processKey函数

  1. void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,  
  2.         int32_t scanCode, uint32_t policyFlags) {  
  3.   
  4.     if (down) {  
  5.         // Rotate key codes according to orientation if needed.  
  6.         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {  
  7.             keyCode = rotateKeyCode(keyCode, mOrientation);  
  8.         }  
  9.   
  10.         // Add key down.  
  11.         ssize_t keyDownIndex = findKeyDown(scanCode);  
  12.         if (keyDownIndex >= 0) {  
  13.             // key repeat, be sure to use same keycode as before in case of rotation  
  14.             keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;  
  15.         } else {  
  16.             // key down  
  17.             if ((policyFlags & POLICY_FLAG_VIRTUAL)  
  18.                     && mContext->shouldDropVirtualKey(when,  
  19.                             getDevice(), keyCode, scanCode)) {  
  20.                 return;  
  21.             }  
  22.             if (policyFlags & POLICY_FLAG_GESTURE) {  
  23.                 mDevice->cancelTouch(when);  
  24.             }  
  25.   
  26.             mKeyDowns.push();  
  27.             KeyDown& keyDown = mKeyDowns.editTop();  
  28.             keyDown.keyCode = keyCode;  
  29.             keyDown.scanCode = scanCode;  
  30.         }  
  31.   
  32.         mDownTime = when;  
  33.     } else {  
  34.         // Remove key down.  
  35.         ssize_t keyDownIndex = findKeyDown(scanCode);  
  36.         if (keyDownIndex >= 0) {  
  37.             // key up, be sure to use same keycode as before in case of rotation  
  38.             keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;  
  39.             mKeyDowns.removeAt(size_t(keyDownIndex));  
  40.         } else {  
  41.             // key was not actually down  
  42.             ALOGI("Dropping key up from device %s because the key was not down.  "  
  43.                     "keyCode=%d, scanCode=%d",  
  44.                     getDeviceName().string(), keyCode, scanCode);  
  45.             return;  
  46.         }  
  47.     }  
  48.   
  49.     int32_t oldMetaState = mMetaState;  
  50.     int32_t newMetaState = updateMetaState(keyCode, down, oldMetaState);  
  51.     bool metaStateChanged = oldMetaState != newMetaState;  
  52.     if (metaStateChanged) {  
  53.         mMetaState = newMetaState;  
  54.         updateLedState(false);  
  55.     }  
  56.   
  57.     nsecs_t downTime = mDownTime;  
  58.   
  59.     // Key down on external an keyboard should wake the device.  
  60.     // We don't do this for internal keyboards to prevent them from waking up in your pocket.  
  61.     // For internal keyboards, the key layout file should specify the policy flags for  
  62.     // each wake key individually.  
  63.     // TODO: Use the input device configuration to control this behavior more finely.  
  64.     if (down && getDevice()->isExternal()) {  
  65.         policyFlags |= POLICY_FLAG_WAKE;  
  66.     }  
  67.   
  68.     if (mParameters.handlesKeyRepeat) {  
  69.         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;  
  70.     }  
  71.   
  72.     if (metaStateChanged) {  
  73.         getContext()->updateGlobalMetaState();  
  74.     }  
  75.   
  76.     if (down && !isMetaKey(keyCode)) {  
  77.         getContext()->fadePointer();  
  78.     }  
  79.   
  80.     NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,  
  81.             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,  
  82.             AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);  
  83.     getListener()->notifyKey(&args);  
  84. }  

这个函数,一开始还是再把扫描码转成键盘码,后面主要调用了notifyKey函数。

getListener函数如下

  1. InputListenerInterface* InputReader::ContextImpl::getListener() {  
  2.     return mReader->mQueuedListener.get();  
  3. }  

而notifyKey函数如下,就是把对象放在一个变量中。

  1. void QueuedInputListener::notifyKey(const NotifyKeyArgs* args) {  
  2.     mArgsQueue.push(new NotifyKeyArgs(*args));  
  3. }  

二、InputReader的loopOnce函数

最后我们再回到InputReader的loopOnce函数,我们主要看最后mQueuedListener->flush函数。

  1. void InputReader::loopOnce() {  
  2.     int32_t oldGeneration;  
  3.     int32_t timeoutMillis;  
  4.     bool inputDevicesChanged = false;  
  5.     Vector<InputDeviceInfo> inputDevices;  
  6.     { // acquire lock  
  7.         AutoMutex _l(mLock);  
  8.   
  9.         oldGeneration = mGeneration;  
  10.         timeoutMillis = -1;  
  11.   
  12.         uint32_t changes = mConfigurationChangesToRefresh;  
  13.         if (changes) {  
  14.             mConfigurationChangesToRefresh = 0;  
  15.             timeoutMillis = 0;  
  16.             refreshConfigurationLocked(changes);  
  17.         } else if (mNextTimeout != LLONG_MAX) {  
  18.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  19.             timeoutMillis = toMillisecondTimeoutDelay(now, mNextTimeout);  
  20.         }  
  21.     } // release lock  
  22.   
  23.     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);  
  24.   
  25.     { // acquire lock  
  26.         AutoMutex _l(mLock);  
  27.         mReaderIsAliveCondition.broadcast();  
  28.   
  29.         if (count) {  
  30.             processEventsLocked(mEventBuffer, count);  
  31.         }  
  32.   
  33.         if (mNextTimeout != LLONG_MAX) {  
  34.             nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);  
  35.             if (now >= mNextTimeout) {  
  36. #if DEBUG_RAW_EVENTS  
  37.                 ALOGD("Timeout expired, latency=%0.3fms", (now - mNextTimeout) * 0.000001f);  
  38. #endif  
  39.                 mNextTimeout = LLONG_MAX;  
  40.                 timeoutExpiredLocked(now);  
  41.             }  
  42.         }  
  43.   
  44.         if (oldGeneration != mGeneration) {  
  45.             inputDevicesChanged = true;  
  46.             getInputDevicesLocked(inputDevices);  
  47.         }  
  48.     } // release lock  
  49.   
  50.     // Send out a message that the describes the changed input devices.  
  51.     if (inputDevicesChanged) {  
  52.         mPolicy->notifyInputDevicesChanged(inputDevices);  
  53.     }  
  54.   
  55.     // Flush queued events out to the listener.  
  56.     // This must happen outside of the lock because the listener could potentially call  
  57.     // back into the InputReader's methods, such as getScanCodeState, or become blocked  
  58.     // on another thread similarly waiting to acquire the InputReader lock thereby  
  59.     // resulting in a deadlock.  This situation is actually quite plausible because the  
  60.     // listener is actually the input dispatcher, which calls into the window manager,  
  61.     // which occasionally calls into the input reader.  
  62.     mQueuedListener->flush();  
  63. }  

QueuedInputListener::flush函数在文件InputListener.cpp中。

  1. void QueuedInputListener::flush() {  
  2.     size_t count = mArgsQueue.size();  
  3.     for (size_t i = 0; i < count; i++) {  
  4.         NotifyArgs* args = mArgsQueue[i];  
  5.         args->notify(mInnerListener);  
  6.         delete args;  
  7.     }  
  8.     mArgsQueue.clear();  
  9. }  

这个函数中遍历之前我们在每个InputMapper存入的NotifyArgs对象,最后调用了NotifyArgs对象的notify函数

之前我们的NotifyArgs对象是NotifyKeyArgs对象,这个notify是个虚函数,就到NotifyKeyArgs::notify

  1. void NotifyKeyArgs::notify(const sp<InputListenerInterface>& listener) const {  
  2.     listener->notifyKey(this);  
  3. }  

而这个listener,是新建QueuedInputListener的时候传进来的

  1. mQueuedListener = new QueuedInputListener(listener);  

listener是InputReader里面传过来的,所以我们知道InputReader是在InputManager中创建的

  1. InputReader::InputReader(const sp<EventHubInterface>& eventHub,  
  2.         const sp<InputReaderPolicyInterface>& policy,  
  3.         const sp<InputListenerInterface>& listener) :  

我们看下InputManager的构造函数,传进来的InputDispatcher

  1. InputManager::InputManager(  
  2.         const sp<EventHubInterface>& eventHub,  
  3.         const sp<InputReaderPolicyInterface>& readerPolicy,  
  4.         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {  
  5.     mDispatcher = new InputDispatcher(dispatcherPolicy);  
  6.     mReader = new InputReader(eventHub, readerPolicy, mDispatcher);  
  7.     initialize();  
  8. }  
所以最后这个listener是InputDispatcher,因此最后就是调用的InputDispatcher的notifyKey函数。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值