Android Input子系统-含实例源码

版权声明:欢迎关注微信公众号:嵌入式linux https://blog.csdn.net/weiqifa0/article/details/82419313

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子系统发上来的键值做对应的操作。

![这里写图片描述](https://img-blog.csdn.net/20180905111900628?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXFpZmEw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)
![这里写图片描述](https://img-blog.csdn.net/20180905164519678?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXFpZmEw/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70)

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 87cf351..45a33ab 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 <linux/input.h>
    /*声明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[0] = 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 0;

发送键值的位置

 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 63fa997..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 19135aa..956ea3e 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 056f2c9..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..366790c 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 93743df..094e6c2 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1861,6 +1861,7 @@ i
         <enum name="KEYCODE_MICMUTE" value="312" />
         <enum name="KEYCODE_WLAN" value="313" />
         <enum name="KEYCODE_AUDIO" value="314" />
+        <enum name="KEYCODE_WEIQIFA" value="315" />
     </attr>

     <!-- ***************************************************************** -->



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..1cd69a2 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..3a622fc 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 2dff4e0..977aa22 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(), 0);
            }

            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 = 0 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       00f9                 DOWN
/dev/input/event0: EV_SYN       SYN_REPORT           00000000
/dev/input/event0: EV_KEY       00f9                 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
大部分支持的键值如下

0 -->  "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"

这里写图片描述

猜你喜欢

转载自blog.csdn.net/weiqifa0/article/details/82419313