1.框架
设备驱动获取按键值,然后通过input子系统上报,native层有一个进程inputflinger,会一直监控内核上传的event事件并按键值上报,上层跟底层的按键值是通过kl文件来映射的,主要的作用就是通过键值对把上层(上层的键值定义在keyEvent当中)跟底层(input.h中定义)分开解耦,框架层phonewindosmanager框架服务会拦截keyEvent的按键值就可以了,然后处理或者分发给应用。
2.修改
一:驱动部分:
(1)定义新的按键值
./kenerl-3.18/include/uapi/linux/input.h
./kernel-3.18/arch/arm64/boot/dts/include/dt-bindings/input(修改一个编译后会全部生效)、
#define KEY_SCREEN_CTR 249 /* turn on/off the screen*/
(2)驱动做逻辑,例如在触摸屏驱动中根据坐标上报一个按键值,
//在探测probe函数中添加
input_set_capability(tpd->dev, EV_KEY, KEY_SCREEN_CTR);
//在触摸中断判断是否为虚拟键位置
if(有虚拟按钮触摸值按下){
if ((input_y > 83)&&(input_y < 120)){
key_pressed = 1;
input_report_key(tpd->dev, KEY_SCREEN_CTR, 1);
input_sync(tpd->dev);
}
}else{
//松开虚拟按钮
if(keypressed){
key_pressed = 0;
input_report_key(tpd->dev, KEY_SCREEN_CTR, 0);
input_sync(tpd->dev);
}
}
二:映射部分
在./frameworks/native/libs/input/Keyboard.cpp 中 KeyMap::load 方法获取.kl。
通过 dumpsys 命令决定要修改那个文件,KeyLayoutFile 则为要修改的 kl 文件。
通过 dumpsys input 得到下面信息:INPUT MANAGER (dumpsys input)
Input Manager State:
Interactive: true
System UI Visibility: 0x400
Pointer Speed: 0
Pointer Gestures Enabled: true
Show Touches: false
Event Hub State:
BuiltInKeyboardId: -2
Devices:
-1: Virtual
Classes: 0x40000023
Path: <virtual>
Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd
Location:
ControllerNumber: 0
UniqueId: <virtual>
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
1: mtk-tpd
Classes: 0x00000015
Path: /dev/input/event2
Descriptor: 73fe932b1bfd0f08a6467ab0f7c50a74e0a54543
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0911, version=0x1060
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
3: mtk-kpd
Classes: 0x00000001
Path: /dev/input/event0
Descriptor: f0d2e427e7a05eb6d316f5e14800c5ac7b6aee79
Location:
ControllerNumber: 0
UniqueId:Identifier: bus=0x0019, vendor=0x2454, product=0x6500, version=0x0010
KeyLayoutFile: /system/usr/keylayout/mtk-kpd.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
信息中有三个 input,但是本次的触摸屏是 /dev/input/event2,因为利用在 getevent
/dev/input/event2 的命令调试中,按下触摸 TP 只有/dev/input/event2 有数据打印出来。
/dev/input/event2 对应的 KeyLayoutFile 属性为:/system/usr/keylayout/Generic.kl,因此上面第
三步我们修改的是 Generic.kl 文件,一般来kl文件路径:./frameworks/base/data/keyboards/Generic.kl
key 249 SCREEN_CTR
三:framework层
(1)/frameworks/native/include/android/keycodes.h
中添加安卓对应kl文件中文件的名字,一般以AKEYCODE开头
/** key turn off/on screen **/
AKEYCODE_SCREEN_CTR = 285
(2)./frameworks/native/include/input/InputEventLabels.h中添加按键的定义
DEFINE_KEYCODE(SCREEN),
(3)./frameworks/base/core/java/android/view/KeyEvent.java
注意:
修改完后要记得使用make update-api命令更新,具体的说明参考:
https://blog.csdn.net/u010229714/article/details/73840014
因为KeyEvent.java是系统共用接口,所以要make update-api更新.
如果不用make-update-api更新接口,就在注释的时候加上@hide识别符
/** added by flyaudioos
*private static final int LAST_KEYCODE = KEYCODE_ALL_APPS;
* @hide*/
public static final int KEYCODE_SCREEN_CTR = 285;
private static final int LAST_KEYCODE = KEYCODE_SCREEN_CTR;
(4)添加自定义属性keycode,关于attr.xml
./frameworks/base/core/res/res/value/attr.xml
<enum name="KEYCODE_SCREEN_CTR" value="285" />
(5)在services/core/java/com/android/server/policy/PhoneWindowManager.java添加测试
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
switch (keyCode) {
...
case KeyEvent.KEYCODE_SCREEN_CTR:{
Log.d(TAG,"key screen pressed = 1");
break;
}
...
}
...
}