前言
话说东哥
最近东哥应该是比较热门的,我每天吃饭前都会打开今天头条,跟同事交流一下我的大兄弟东哥事情的进展,我谋划着要去米国为东哥加油,东哥作为一个有道德心的企业家,从一个贫苦的农村出来,迎娶白富美,走上人生巅峰的励志故事一直是我等屌丝的楷模和榜样。
我认为诚信是一个人的基础,如果你去买鸡,老板给你说 10 块钱一斤,你准备拿手机扫码支付的时候,老板看见我用的是 IPhone X ,认为我是有钱人,然后坐地起价,变成 20 块钱一斤,这样的老板是非常不诚信,也是非常不道德的。
毕业季
最近是秋招季节,很多人都准备着找实习机会,想起来当时在校园招聘的时候面试了很多家企业,直到最后拿到 TCL 的 offer 才让我心满意足停止了找工作的步伐。我觉得作为应届生,一定要想清楚自己以后的路子。
1 、找准第一份工作,第一份工作决定你未来很多年,换行业需要很大的代价和努力。
2 、找准企业,很多人需要一个好的企业背景来托起自己职业生涯的起点
有同学问是应该往底层 Linux 内核发展还是做应用开发,往底层发展,会接触到比较少的业务逻辑,可以让你在某个方面越来越突出,成为业界的专家,往上层发展比如 APP ,后台,互联网方面,会让你接触越来越多的业务,接触的面也会越来越大。没有说哪个更好,一定先从自己的兴趣出发,没有兴趣很难坚持。
正文
现在说说 Android Input 子系统,因为发现在微信公众号上写文章有挺多不方便,我现在有些篇幅比较长,或者后期需要修改的文章,会写在 CSDN 上,大家可以点击阅读原文来阅读,这样也方便大家阅读和收藏。
1 Input 子系统作用
Android 很多外设都是用到输入输出设备,比如 touchscreen ,键盘,音量键等,输入
设备对应 Android 框架是 Android input 子系统,像我们定制类比较多的,很多
需要用到输入子系统,比如一键打开相机,一键唤醒,实体按键等。
2 Android input 子系统框架
Android Input 框架讲解最好的一篇文章
https://blog.csdn.net/mmmccc000/article/details/49756059
Android input 框架主要分为三个部分,一个是 kernel ,一个是 kl 文件, kl 也可
以划分为框架层, Framework 层主要做监听、过滤、分发的工作, Android App 部
分主要是接收 Input 子系统发上来的键值做对应的操作。
3 kernel input 框架
Kernel 主要是涉及 Input 设备节点的生成, proc 文件系统的生成
有一个文章写 Kernel 框架非常好的,我就不再讲了,给几个链接
https://blog.csdn.net/u013604527/article/details/53432623/
https://blog.csdn.net/jscese/article/details/42123673
https://blog.csdn.net/xubin341719/article/details/7881735
4 如何在 kernel 添加一个新的键值
4.1 先在头文件里面添加
找个共用的头文件添加要的 key 值,正常是在 include 下面的,我的代码是在这个位
置
diff --git a/include/uapi/linux/input- event -codes.h b/include/uapi/linux/input- event -codes.h
index 87 cf351. .45 a33ab 100644
--- a/include/uapi/linux/input- event -codes.h
+++ b/include/uapi/linux/input- event -codes.h
@@ -335 , 7 + 335 , 7 @@
#define KEY_RFKILL 247 /* Key that controls all radios */
#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
-
+ #define KEY_WEIQIFA_TEST 249
/* Code 255 is reserved for special needs of AT keyboard driver */
4.2 在 kernel 对应的位置注册和发送键值
注册的位置
/* 包含头文件 */
#include
/* 声明 input 设备 */
struct input_dev *button_dev;
/* 注册 input 子设备 */
printk(KERN_ERR " xxxx_wake_init\n" );
if (!(button_dev= input_allocate_device()))
{
printk(KERN_ERR "input_dev: not enough memory\n" );
return -ENOMEM;
}
button_dev->name = "xxxx" ;
button_dev->phys = "xxxx/event0" ;
button_dev->id.bustype = BUS_HOST;
button_dev->id.vendor = 0x0001 ;
button_dev->id.product = 0x0002 ;
button_dev->id.version = 0x0100 ;
button_dev->evbit[ ] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN);
set_bit(KEY_WEIQIFA_TEST,button_dev->keybit);
err = input_register_device(button_dev);
if (err) {
printk(KERN_ERR " fail to input_register_device\n" );
input_free_device(button_dev);
return err;
}
printk(KERN_ERR "xxxx_wake_init success!!!\n" );
return ;
发送键值的位置
input_report_key(button_dev, KEY_WEIQIFA_TEST, 1);
input_sync(button_dev);
input_report_key(button_dev, KEY_WEIQIFA_TEST, 0);
input_sync(button_dev);
4.3 写一个对应这个 kl 文件
kl 文件简单介绍
Kl 文件主要是起到了承上启下的作用, kernel 发过来的键值主要通过 kl 文件来映
射,我们来看看 kl 文件里面的内容把。左边的是对应 kernel 上报上来的键值,后
面是对应 Android Framework 上的键值。
22 key 399 GRAVE
23 key 2 1
...
49 key 103 DPAD_UP
50 key 102 HOME
51 key 105 DPAD_LEFT
52 key 106 DPAD_RIGHT
53 key 115 VOLUME_UP
kl 文件哪里来的呢
我们看项目配置下面,有很多 kl 文件,那么是每个 input 子系统对应一个 kl 文件,
还是所有的项目共用一个 kl 文件?
kl 源码位置在
./frameworks/ base /data/keyboards/AVRCP.kl
./frameworks/ base /data/keyboards/G
./frameworks/ base /data/keyboards/Vendor_0079_Product_0011.kl
./frameworks/ base /data/keyboards/Vendor_045e_Product_028e.kl...
在运行的设备里,它的位置如下
rk3399_mid:/ # busybox find / -iname *.kl
/ system /usr/keylayout/Generic.kl
/ system /usr/keylayout/Vendor_0079_Product_0011.kl
/ system /usr/keylayout/qwerty.kl
/ system /usr/keylayout/rk29-keypad.kl
/ system /usr/keylayout/rtkbt_virtual_hid.kl...
rk3399_mid:/ #
kl 是跟 input 设备如何对应起来的呢
我们可以用这个命令来看看 cat /proc/bus/input/devices
kl 文件里面的 vendor 和 product 分别对应下面的 vendor 和 product
rk3399_mid:/ # cat /proc/bus/input/devices
I: Bus=0019 Vendor=0001 Product=0002 Version=0100
N: Name="xxxx"
P: Phys=iflytek/event0
S: Sysfs=/devices/virtual/input/input0
U: Uniq=
H: Handlers=event0 cpufreq
B: PROP=0
B: EV=b
B: KEY=100000 0 0 0
B: ABS=0
添加我们对应的 kl 文件
文件命名跟你申请的 vendor 和 product 对应 上面的 input 设备对应的 kl 文件应该是: Vendor_0001_Product_0002.kl
里面的内容如下,当然如果你没有配置 kl 文件,默认会去 Generic.kl 找键值映
射,如果里面也没有,就会去其他 kl 文件继续找。
# OnLive, Inc. OnLive Wireless Controller
key 249 BUTTON_A
4.4 mtk 平台的一个 input 子系统驱动例子
上面写的是在 rockchip 平台做的例子,下面给出一个 mtk 平台的例子
[mkt 平台的 input 子系统例子 ]
(https://blog.csdn.net/weiqifa0/article/details/50387504)
5 Framework input 系统介绍
Framework 主要做的事情是监听底层的 input ,然后分发给上层
下面的两个链接框架说的非常好,可以看看,我下面给出步骤如何添加一个新的 key
到系统里面
https://blog.csdn.net/wangkaiblog/article/details/12085183
https://blog.csdn.net/mmmccc000/article/details/49756059
6 添加一个新的键值
主要涉及到几个文件位置
下面列出需要修改的文件还有修改的差异点
base/api/current.txt
base/api/system-current.txt
base/core/java/android/view/KeyEvent.java
base/core/res/res/values/attrs.xml
/ Generic.kl 这里也可以根据驱动添加 /
base/data/keyboards/Generic.kl
base/policy/src/com/android/internal/policy/impl/PhoneFallbackEventHandler.java
native/include/android/keycodes.h
native/include/input/InputEventLabels.h
diff --git a/api/current.txt b/api/current.txt
index 63 fa997..a7a4a2b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41599 , 6 + 41599 , 7 @@ package android.view {
field public static final int KEYCODE_ASSIST = 219 ; // 0xdb
field public static final int KEYCODE_AT = 77 ; // 0x4d
field public static final int KEYCODE_AUDIO = 314 ; // 0x13a
+ field public static final int KEYCODE_WEIQIFA = 315 ; // 0x13B
field public static final int KEYCODE_AVR_INPUT = 182 ; // 0xb6
field public static final int KEYCODE_AVR_POWER = 181 ; // 0xb5
field public static final int KEYCODE_B = 30 ; // 0x1e
diff --git a/api/system-current.txt b/api/system-current.txt
index 19135 aa. .956 ea3e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -44781 , 6 + 44781 , 7 @@ package android.view {
field public static final int KEYCODE_ASSIST = 219 ; // 0xdb
field public static final int KEYCODE_AT = 77 ; // 0x4d
field public static final int KEYCODE_AUDIO = 314 ; // 0x13a
+ field public static final int KEYCODE_WEIQIFA = 315 ; // 0x13b
field public static final int KEYCODE_AVR_INPUT = 182 ; // 0xb6
field public static final int KEYCODE_AVR_POWER = 181 ; // 0xb5
field public static final int KEYCODE_B = 30 ; // 0x1e
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 056 f2c9..f2d5235 100755
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -832 , 6 + 832 , 7 @@ public class KeyEvent extends InputEvent implements Parcelable {
public static final int KEYCODE_TV_MEDIA_PAUSE = 304 ;
public static final int KEYCODE_WLAN = 313 ;
public static final int KEYCODE_AUDIO = 314 ;
+ public static final int KEYCODE_WEIQIFA = 315 ;
//$_rbox_$_modify_$ end
private static final int LAST_KEYCODE = KEYCODE_TV_MEDIA_PAUSE;
diff --git a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
index e6635a1. .366790 c 100755
--- a/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
+++ b/core/java/com/android/internal/policy/PhoneFallbackEventHandler.java
@@ -141 , 7 + 141 , 12 @@ public class PhoneFallbackEventHandler implements FallbackEventHandler {
}
case KeyEvent.KEYCODE_AUDIO: {
Log.i(TAG, "---KEYCODE_AUDIO DOWN---" );
+
}
+ case KeyEvent.KEYCODE_WEIQIFA: {
+ Log.i(TAG, "KEYCODE_WEIQIFA" );
+ }
+
case KeyEvent.KEYCODE_CAMERA: {
if (getKeyguardManager().inKeyguardRestrictedInputMode() || dispatcher == null ) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 93743 df. .094e6 c2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1861 , 6 + 1861 , 7 @@ i
+
diff --git a/ include /android/keycodes.h b/ include /android/keycodes.h
index e3586b2..b657424 100755
--- a/ include /android/keycodes.h
+++ b/ include /android/keycodes.h
@@ -777 , 6 + 777 , 7 @@ enum {
AKEYCODE_MICMUTE = 312 ,
AKEYCODE_WLAN = 313 ,
AKEYCODE_AUDIO = 314
+ AKEYCODE_WEIQIFA = 315
// NOTE: If you add a new keycode here you must also add it to several other files.
// Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/ include /input/InputEventLabels.h b/ include /input/InputEventLabels.h
index fabf912. .1 cd69a2 100755
--- a/ include /input/InputEventLabels.h
+++ b/ include /input/InputEventLabels.h
@@ -68 , 6 + 68 , 7 @@ static const InputEventLabel KEYCODES[] = {
DEFINE_KEYCODE(POWER),
DEFINE_KEYCODE(WLAN),
DEFINE_KEYCODE(AUDIO),
+ DEFINE_KEYCODE(WEIQIFA),
DEFINE_KEYCODE(CAMERA),
DEFINE_KEYCODE(CLEAR),
DEFINE_KEYCODE(A),
如果出现以下编译错误
out/target/common/obj/PACKAGING/test-api.txt:41961: error 5: Added public field android.view.KeyEvent.KEYCODE_WEIQIFA
******************************
You have tried to change the API from what has been previously approved.
To make these errors go away, you have two choices:
1) You can add "@hide" javadoc comments to the methods, etc. listed in the
errors above.
2) You can update current.txt by executing the following command:
make update-api
To submit the revised current.txt to the main Android repository,
you will need approval.
******************************
提示你运行 make update-api ,但是要先回退 current.txt 和 system-current.txt ,因为这两个文件就是 make update-api 生成出来的
git checkout api/current.txt
git checkout api/system-current.txt
make update-api
关于 make update-api 详细看这个 https://blog.csdn.net/u010229714/article/details/73840014
如果需要调试,可以打开下面的调试文件
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -125 , 7 + 125 , 7 @@ import libcore.util.Objects;
public class InputManagerService extends IInputManager . Stub
implements Watchdog . Monitor {
static final String TAG = "InputManager" ;
- static final boolean DEBUG = false ;
+ static final boolean DEBUG = true ;
private static final String EXCLUDED_DEVICES_PATH = "etc/excluded-input-devices.xml" ;
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -172 , 7 + 172 , 7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
static final String TAG = "WindowManager" ;
static final boolean DEBUG = false ;
static final boolean localLOGV = false ;
- static final boolean DEBUG_INPUT = false ;
+ static final boolean DEBUG_INPUT = true ;
static final boolean DEBUG_KEYGUARD = false ;
static final boolean DEBUG_LAYOUT = false ;
static final boolean DEBUG_STARTING_WINDOW = false ;
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -17 , 31 + 17 , 31 @@
#define LOG_TAG "InputDispatcher"
#define ATRACE_TAG ATRACE_TAG_INPUT
- //#define LOG_NDEBUG 0
+ #define LOG_NDEBUG 1
// Log detailed debug messages about each inbound event notification to the dispatcher.
- #define DEBUG_INBOUND_EVENT_DETAILS 0
+ #define DEBUG_INBOUND_EVENT_DETAILS 1
// Log detailed debug messages about each outbound event processed by the dispatcher.
- #define DEBUG_OUTBOUND_EVENT_DETAILS 0
+ #define DEBUG_OUTBOUND_EVENT_DETAILS 1
// Log debug messages about the dispatch cycle.
- #define DEBUG_DISPATCH_CYCLE 0
+ #define DEBUG_DISPATCH_CYCLE 1
// Log debug messages about registrations.
- #define DEBUG_REGISTRATION 0
+ #define DEBUG_REGISTRATION 1
// Log debug messages about input event injection.
- #define DEBUG_INJECTION 0
+ #define DEBUG_INJECTION 1
// Log debug messages about input focus tracking.
- #define DEBUG_FOCUS 0
+ #define DEBUG_FOCUS 1
// Log debug messages about the app switch latency optimization.
- #define DEBUG_APP_SWITCH 0
+ #define DEBUG_APP_SWITCH 1
// Log debug messages about hover events.
- #define DEBUG_HOVER 0
+ #define DEBUG_HOVER 1
#include "InputDispatcher.h"
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index c8dc454. .3 a622fc 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -16 , 10 + 16 , 10 @@
#define LOG_TAG "InputReader"
- //#define LOG_NDEBUG 0
+ #define LOG_NDEBUG 1
// Log debug messages for each raw event received from the EventHub.
- #define DEBUG_RAW_EVENTS 0
+ #define DEBUG_RAW_EVENTS 1
// Log debug messages about touch screen filtering hacks.
#define DEBUG_HACKS 0
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 2 dff4e0. .977 aa22 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -5 , 19 + 5 , 19 @@
//
#define LOG_TAG "InputTransport"
- //#define LOG_NDEBUG 0
+ #define LOG_NDEBUG 1
// Log debug messages about channel messages (send message, receive message)
- #define DEBUG_CHANNEL_MESSAGES 0
+ #define DEBUG_CHANNEL_MESSAGES 1
// Log debug messages whenever InputChannel objects are created/destroyed
- #define DEBUG_CHANNEL_LIFECYCLE 0
+ #define DEBUG_CHANNEL_LIFECYCLE 1
// Log debug messages about transport actions
- #define DEBUG_TRANSPORT_ACTIONS 0
+ #define DEBUG_TRANSPORT_ACTIONS 1
// Log debug messages about touch event resampling
- #define DEBUG_RESAMPLING 0
+ #define DEBUG_RESAMPLING 1
7 App 接收键值
主要参照这个链接来写
https://www.cnblogs.com/zhujiabin/p/5915802.html
例程 Android studio 源码
链接: https://pan.baidu.com/s/1hzhQ-dLSRnAbg2Q8w5qKPw 密码: 944g
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_ENTER){
/* 隐藏软键盘 */
InputMethodManager inputMethodManager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager.isActive()){
inputMethodManager.hideSoftInputFromWindow(MainActivity. this .getCurrentFocus().getWindowToken(), );
}
edittext.setText( "success" );
webview.loadUrl(URL);
return true ;
}
return super .dispatchKeyEvent(event);
}
8 命令调试
8.1 测试上报时间
触发 Input 上报的时间点
rk3399_mid:/ $ logcat -s "CAE_LOG" |grep -E CAEIvwCb
09-06 14 : 10 : 13.502 327 436 D CAE_LOG : CAEIvwCb angle = 23 ,beam = CMScore = 1643
APK 接收到键值的时间点
09-06 14:10:13.518 5693-5693/com.hu.audiotest D/audiotest_MainActivity: KeyEvent.KEYCODE_ENTER KeyCode0
09-06 14:10:13.522 5693-5693/com.hu.audiotest D/audiotest_MainActivity: KeyEvent.KEYCODE_ENTER KeyCode0
消耗的时间大概需要 16MS ,但是触发是通过 HAL 层触发的,如果从 Kerne 触发事间会更短一些
8.2 设备文件调试
我们 kernel 下面正常用 getevent 来调试
getevent -l
cat /proc/bus/input/devices
rk3399_mid:/ # getevent -l
add device 1 : /dev/ input /event2
name: "rk29-keypad"
add device 2 : /dev/ input /event1
name: "as9102 Touchscreen"
add device 3 : /dev/ input /event0
name: "iflytek"
/dev/ input /event0: EV_KEY 00 f9 DOWN
/dev/ input /event0: EV_SYN SYN_REPORT 00000000
/dev/ input /event0: EV_KEY 00 f9 UP
/dev/ input /event0: EV_SYN SYN_REPORT 00000000
8.3 adb 上报键值调试
我们正常用 adb shell input keyevent xx xx 代表键值
可以用 input 来触发 touchscreen 也是可以的
有个比较好的文章
https://blog.csdn.net/jlminghui/article/details/39268419
大部分支持的键值如下
--> "KEYCODE_UNKNOWN"
1 --> "KEYCODE_MENU"
2 --> "KEYCODE_SOFT_RIGHT"
3 --> "KEYCODE_HOME"
4 --> "KEYCODE_BACK"
5 --> "KEYCODE_CALL"
6 --> "KEYCODE_ENDCALL"
7 --> "KEYCODE_0"
8 --> "KEYCODE_1"
9 --> "KEYCODE_2"
10 --> "KEYCODE_3"
11 --> "KEYCODE_4"
12 --> "KEYCODE_5"
13 --> "KEYCODE_6"
14 --> "KEYCODE_7"
15 --> "KEYCODE_8"
16 --> "KEYCODE_9"
17 --> "KEYCODE_STAR"
18 --> "KEYCODE_POUND"
19 --> "KEYCODE_DPAD_UP"
20 --> "KEYCODE_DPAD_DOWN"
21 --> "KEYCODE_DPAD_LEFT"
22 --> "KEYCODE_DPAD_RIGHT"
23 --> "KEYCODE_DPAD_CENTER"
24 --> "KEYCODE_VOLUME_UP"
25 --> "KEYCODE_VOLUME_DOWN"
26 --> "KEYCODE_POWER"
27 --> "KEYCODE_CAMERA"
28 --> "KEYCODE_CLEAR"
29 --> "KEYCODE_A"
30 --> "KEYCODE_B"
31 --> "KEYCODE_C"
32 --> "KEYCODE_D"
33 --> "KEYCODE_E"
34 --> "KEYCODE_F"
35 --> "KEYCODE_G"
36 --> "KEYCODE_H"
37 --> "KEYCODE_I"
38 --> "KEYCODE_J"
39 --> "KEYCODE_K"
40 --> "KEYCODE_L"
41 --> "KEYCODE_M"
42 --> "KEYCODE_N"
43 --> "KEYCODE_O"
44 --> "KEYCODE_P"
45 --> "KEYCODE_Q"
46 --> "KEYCODE_R"
47 --> "KEYCODE_S"
48 --> "KEYCODE_T"
49 --> "KEYCODE_U"
50 --> "KEYCODE_V"
51 --> "KEYCODE_W"
52 --> "KEYCODE_X"
53 --> "KEYCODE_Y"
54 --> "KEYCODE_Z"
55 --> "KEYCODE_COMMA"
56 --> "KEYCODE_PERIOD"
57 --> "KEYCODE_ALT_LEFT"
58 --> "KEYCODE_ALT_RIGHT"
59 --> "KEYCODE_SHIFT_LEFT"
60 --> "KEYCODE_SHIFT_RIGHT"
61 --> "KEYCODE_TAB"
62 --> "KEYCODE_SPACE"
63 --> "KEYCODE_SYM"
64 --> "KEYCODE_EXPLORER"
65 --> "KEYCODE_ENVELOPE"
66 --> "KEYCODE_ENTER"
67 --> "KEYCODE_DEL"
68 --> "KEYCODE_GRAVE"
69 --> "KEYCODE_MINUS"
70 --> "KEYCODE_EQUALS"
71 --> "KEYCODE_LEFT_BRACKET"
72 --> "KEYCODE_RIGHT_BRACKET"
73 --> "KEYCODE_BACKSLASH"
74 --> "KEYCODE_SEMICOLON"
75 --> "KEYCODE_APOSTROPHE"
76 --> "KEYCODE_SLASH"
77 --> "KEYCODE_AT"
78 --> "KEYCODE_NUM"
79 --> "KEYCODE_HEADSETHOOK"
80 --> "KEYCODE_FOCUS"
81 --> "KEYCODE_PLUS"
82 --> "KEYCODE_MENU"
83 --> "KEYCODE_NOTIFICATION"
84 --> "KEYCODE_SEARCH"
85 --> "TAG_LAST_KEYCODE"