11. 输入检测

本章介绍在Android中使用gpio-keys驱动将GPIO配置为按键并进行检测。

gpio-keys驱动是Linux内核为通过GPIO引脚连接的按键设备设计的通用驱动,属于输入子系统的一部分。 其核心作用是:监测GPIO引脚的电平变化(高/低电平切换),将其转换为输入子系统可识别的按键事件(如KEY_PRESS、KEY_RELEASE),并上报给用户空间,最终被应用程序捕获处理。

11.1. 配置引脚

参考“40pin引脚对照图”章节,查看需要使用的GPIO引脚, 修改设备树源码来进行配置,并重新编译镜像

如果对设备树不熟悉的用户,请学习野火配套的《嵌入式Linux驱动开发实战指南》的 Linux设备树 章节内容。

以使能LubanCat-4-V1的GPIO4_A0为例,修改SDK源码/kernel-5.10/arch/arm64/boot/dts/rockchip/rk3588s-lubancat-4-v1.dtsi (其他板卡修改板卡对应的设备树),在设备树中添加以下节点:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
gpio_keys: gpio-keys {
    compatible = "gpio-keys";
    pinctrl-names = "default";
    status = "okay";
    //autorepeat;

    Key0{
        label = "KEY_0";
        linux,code = <KEY_0>;
        gpios = <&gpio4 RK_PA0 GPIO_ACTIVE_LOW>;
        pinctrl-0 = <&button_key0_pin>;
        interrupt-parent = <&gpio4>;
        interrupts = <RK_PA0 IRQ_TYPE_EDGE_FALLING>;
    };
};

&pinctrl {
    keys {
        button_key0_pin: button-key0-pin {
            rockchip,pins = <4 RK_PA0 RK_FUNC_GPIO &pcfg_pull_up>;
        };
    };
};
  • linux,code 中的事件可从内核中的linux-event-codes.h或者rk-input.h中选择,需确认dtsi引用的是linux-event-codes.h还是rk-input.h。

  • 如果按键按下电平为高,可将gpios设置为GPIO_ACTIVE_HIGH,interrupts设置为IRQ_TYPE_EDGE_RISING,button_key0_pin设置为pcfg_pull_none或者pcfg_pull_down。

修改为如下图所示,如果与其他节点冲突需关闭冲突节点再添加:

button节点
button节点

参考 编译 Android 镜像 章节重新编译镜像并将编译出来的镜像烧录到板卡。

11.2. 检查事件注册

可以通过getevent命令查看系统事件注册情况。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#连接shell终端
adb shell

#检查系统event
getevent

#信息输出如下
add device 1: /dev/input/event4
name:     "adc-keys"
add device 2: /dev/input/event2
name:     "headset-keys"
add device 3: /dev/input/event5
name:     "gpio-keys"
add device 4: /dev/input/event0
name:     "febd0030.pwm"
add device 5: /dev/input/event1
name:     "rk805 pwrkey"
add device 6: /dev/input/event3
name:     "rockchip-es8388 Headset"

其中name为gpio-keys的event就是我们添加的GPIO按键,对应/dev/input/event5。

11.3. 使用shell命令检测按键

可以通过getevent命令检测系统事件上报,将选定的GPIO引脚接按键或者杜邦线 分别短接 到板卡40pin 3.3V和GND模拟按键按下松开。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#连接shell终端
adb shell

#检查系统event
getevent

#以上gpio-keys对应的event为5,所以输入5进行选择,然后按回车
5

#按下按键或者杜邦线分别短接40pin 3.3v和GND

#信息输出如下
130|rk3588s_lubancat_4_v1_mipi1080p:/ $ getevent
add device 1: /dev/input/event3
name:     "rockchip-es8388 Headset"
add device 2: /dev/input/event2
name:     "headset-keys"
add device 3: /dev/input/event5
name:     "gpio-keys"
add device 4: /dev/input/event1
name:     "rk805 pwrkey"
add device 5: /dev/input/event0
name:     "febd0030.pwm"
add device 6: /dev/input/event4
name:     "adc-keys"
5
/dev/input/event5: 0001 000b 00000001
/dev/input/event5: 0000 0000 00000000
/dev/input/event5: 0001 000b 00000000
/dev/input/event5: 0000 0000 00000000

11.4. 使用安卓应用检测按键

野火提供的安卓综合测试应用能很方便的检测按键。

11.4.1. 应用测试

可参考“野火安卓综合测试应用”章节的“按键测试”小节进行测试,如下图:

应用测试

11.4.2. 实现方式

参考野火应用源码ebf_android_app/app/src/main/java/com/example/ebf_android_app/ButtonDetectionActivity.java

1、视图初始化

在onCreate()中调用initViews(),获取布局中的按钮(开始检测/停止检测/清空日志)、日志文本框(eventLogTextView)和滚动视图(logScrollView)。

2、广播接收器注册

调用registerKeyEventReceiver()创建KeyEventReceiver广播接收器,并通过IntentFilter指定只接收ACTION_KEY_EVENT类型的广播。

3、按钮点击事件绑定

为 “开始检测”、“停止检测”、“清空日志” 按钮设置点击监听器,分别控制检测状态和日志显示。

4、按键事件处理

按键按下记录当前按键码(currentKeyCode)和按下时间(keyDownTime),通过KeyEvent.keyCodeToString()获取按键名称,调用appendLog()添加 “按键按下” 日志(含键码和名称)。

按键释放计算按键按下时长,调用sendKeyEventBroadcast()发送包含键码、名称和时长的广播。

5、广播通信阶段

发送广播创建ACTION_KEY_EVENT类型的Intent,通过setPackage(getPackageName())指定广播仅发送到当前应用。 向Intent中添加额外数据:键码(EXTRA_KEY_CODE)、键名(EXTRA_KEY_NAME)、按下时长(EXTRA_PRESS_DURATION)。 调用sendBroadcast()发送广播。

接收广播接收器通过onReceive()监听ACTION_KEY_EVENT广播,解析Intent中的键码、名称和时长。用appendLog()添加“接收到广播”日志,展示完整的按键事件信息。

6、资源释放

在onDestroy()中,重置isDetecting状态为false,并注销广播接收器,避免内存泄漏。

11.5. 自定义按键

以上测试是将按键绑定到KEY_0,按下按键等于按下键盘上的数字“0”按键,如果不希望按键影响系统,可以自定义按键在安卓hal进行绑定,可参考以下文章进行修改:

Android系统下基于Input子系统实现自定义按键驱动的完整指南