论坛» 嵌入式开发» STM32

Android Input子系统-含实例源码

高工
2019-01-18 08:49 1楼

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

/*声明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

+

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"





高工
2019-01-18 09:30 2楼

谢谢楼主分享

菜鸟
2019-02-22 15:43 3楼

谢谢分享

共3条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]