Android 按键流程

一、驱动层流程

主要流程涉及以下文件

kernel/msm-4.19/drivers/input/keyboard/gpio_keys.c

kernel/msm-4.19/drivers/input/input.c

kernel/msm-4.19/drivers/input/evdev.c

kernel/msm-4.19/drivers/input/input-compat.c

有按键动作时,根据 dtsi 中配置 code 上报事件。在 gpio_keys.c 中进行处理,最终在 gpio_keys_gpio_report_event 函数中调用 input.c 上报事件。大概流程分为两步。

第一步:获取event事件保存到队列中

input.c:input_event -> input_handle_event -> input_pass_values -> input_to_handler(此函数中调用 handler->events ,handler 定义在 evdev.c 中,events 对应函数 evdev_events)

evdev.c:evdev_events -> evdev_pass_values -> __pass_event (将event事件添加到缓存队列 client->buffer)

第二步:通过循环读取队列中event事件保存到用户内存

evdev.c:evdev_read -> input_event_to_user

input-compat.c:input_event_to_user -> copy_to_user

 二、上层流程

主要流程涉及以下文件

frameworks/native/services/inputflinger/reader/EventHub.cpp

frameworks/native/services/inputflinger/reader/InputReader.cpp

frameworks/native/services/inputflinger/reader/InputDevice.cpp

frameworks/native/services/inputflinger/reader/mapper/KeyboardInputMapper.cpp

frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cpp

frameworks/native/libs/input/KeyLayoutMap.cpp

frameworks/native/libs/input/Keyboard.cpp

上层获取按键事件流程大致如下:

InputReader.cpp:loopOnce -> processEventsLocked -> processEventsForDeviceLocked (调用 device->process)

InputDevice.cpp:process (调用 mapper.process)

KeyboardInputMapper.cpp:process -> processKey(调用 getListener()->notifyKey)

InputDispatcher.cpp:notifyKey(调用 mPolicy->interceptKeyBeforeQueueing 传递到java层)

三、键值转换

按键键值有两个,底层驱动键值和上层应用使用键值,这个对应关系定义在 kl 文件中,kl 文件可以有多个,例如 Generic.kl fts_ts.kl 等,默认系统中路径在 /system/usr/keylayout/ 目录下。

#kl 文件内容格式
#key 驱动键值 上层键值
key 113   VOLUME_MUTE
key 114   VOLUME_DOWN
key 115   VOLUME_UP
key 116   POWER

系统开机时,会根据 frameworks/native/libs/input/InputDevice.cpp 规则加载 kl 文件。加载 kl 文件函数在 KeyLayoutMap.cpp 中,将所有文件按照 kl 名称类型加到 KeyedVector<int32_t, Key> 中缓存。

KeyLayoutMap.cpp:load -> parse -> parseKey

//parseKey 代码段
KeyedVector<int32_t, Key>& map = mapUsage ? mMap->mKeysByUsageCode : mMap->mKeysByScanCode;

... ...

#if DEBUG_PARSER
    ALOGD("Parsed key %s: code=%d, keyCode=%d, flags=0x%08x.",
            mapUsage ? "usage" : "scan code", code, keyCode, flags);
#endif
    Key key;
    key.keyCode = keyCode;
    key.flags = flags;
    map.add(code, key);
    return NO_ERROR;

 parseKey 函数 KeyedVector<int32_t, Key> map 中按照 code-key 格式保存,code就是 kl 中驱动键值,key里面保存了 kl 中上层键值。当驱动按键事件上来后,根据驱动键值查询上层键,整合再上传到java层供应用使用。查询动作在 KeyboardInputMapper.cpp processKey 函数中。函数调用关系如下:

[KeyboardInputMapper.cpp]processKey(getDeviceContext().mapKey) -> [InputDevice.h]mapKey -> [EventHub.cpp]mapKey -> [KeyLayoutMap.cpp]mapKey -> getKey

const KeyLayoutMap::Key* KeyLayoutMap::getKey(int32_t scanCode, int32_t usageCode) const {
    if (usageCode) {
        ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
        if (index >= 0) {
            return &mKeysByUsageCode.valueAt(index);
        }
    }
    if (scanCode) {
        ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
        if (index >= 0) {
            return &mKeysByScanCode.valueAt(index);
        }
    }
    return nullptr;
}

这里面的 mKeysByScanCode 就是上面解析 kl 保存的键值map,通过 scanCode(驱动键值)获取下标,通过下标获取 Key(上面说过的,保存上层键值的)。最后 KeyboardInputMapper.cpp processKey 后续流程把包含 Key 上报到 java 层使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中的按键派发流程如下: 1. 当用户按下按键时,系统会将该按键事件派发给当前活动的Window。 2. Window会将该事件派发给其最顶层的View(即根View),如果该View没有消费该事件,则该事件会继续向下传递给其子View。 3. 如果子View消费了该事件,则该事件的传递就结束了,不会再传递给其他View。 4. 如果所有的View都没有消费该事件,则该事件会传递给Window,如果Window也没有消费该事件,则该事件会传递给Activity。 5. 如果Activity也没有消费该事件,则该事件会传递给系统默认的处理器进行处理。 6. 在事件传递的过中,如果某个View或Window消费了该事件,则该事件的传递就会立即结束,不会再继续向下传递。 在事件传递的过中,可以通过重写View的onKeyDown()、onKeyUp()等方法,来处理按键事件。在这些方法中,可以根据keyCode等属性,来判断当前按下的是哪个按键,并进行相应的处理逻辑。 需要注意的是,对于一些特殊的按键事件,如Back键、Menu键等,Android系统会在View中自动处理这些事件,因此不需要在onKeyDown()、onKeyUp()等方法中进行处理。如果需要对这些事件进行特殊处理,可以重写onBackPressed()、onCreateOptionsMenu()等方法。 总之,按键派发流程Android中一个非常重要且基础的概念,在开发中应用广泛,理解这个流程可以帮助开发者更好地处理按键事件,提升应用序的交互性和用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值