Android tp的虚拟按键处理
现在在越来越多的Android的手机都是虚拟按键来操作,但是对于开发者来说可能会关心Android对虚拟按键如何处理的。对Linux熟悉的人可能会说,it's easy, 调用input_report_key()。OK,你说的没有错误,但是在android中,google让你对策略和驱动有了更加深入的了解。
APP------->
Framework------->
Kernel------->
Hardware
上面就是整个Android的Virtual key的整个的框图。
由于是搞驱动的,所以这里先从驱动开始说起。
其实说起对virtual key的处理对于驱动来说没有任何的难处,实现了Touch panel驱动,你也就将virtual key的底层驱动实现了。这里你试验了吗?你可能会说,“不行,这里实现不了”。是的,这个时候还不行,还有关键的步骤得操作。
在这里,你需要如下代码加入才可以。
1. static unsigned int tpd_keycnt = 0;
2. static int tpd_keys[TPD_VIRTUAL_KEY_MAX]={0};
3. static int tpd_keys_dim[TPD_VIRTUAL_KEY_MAX][4];// = {0};
4. static ssize_t cust_virtual_keys_show(struct kobject *kobj,
5. struct kobj_attribute *attr, char *buf) {
6. int i, j;
7. for(i=0, j=0;i<tpd_keycnt;i++)
8. "%s%s:%d:%d:%d:%d:%d%s",buf,
9. __stringify(EV_KEY),tpd_keys[i],
10. tpd_keys_dim[i][0],tpd_keys_dim[i][1],
11. tpd_keys_dim[i][2],tpd_keys_dim[i][3],
12. "\n":":"));
13. return j;
14. }
15.
16.
17. static struct kobj_attribute cust_virtual_keys_attr = {
18. .attr = {
19. "virtualkeys.cust-tpd",
20. .mode = S_IRUGO,
21. },
22. .show = &cust_virtual_keys_show,
23. };
24.
25.
26. static struct attribute *cust_properties_attrs[] = {
27. &cust_virtual_keys_attr.attr,
28. NULL
29. };
30.
31.
32. static struct attribute_group cust_properties_attr_group = {
33. .attrs = cust_properties_attrs,
34. };
35.
36.
37. struct kobject *properties_kobj;
38.
39.
40. void tpd_button_init(void) {
41. int ret = 0, i = 0, j=0;
42.
43.
44. tpd->kpd=input_allocate_device();
45. /* struct input_dev kpd initialization and registration */
46. "-kpd";
47. set_bit(EV_KEY, tpd->kpd->evbit);
48. for(i=0;i<tpd_keycnt;i++)
49. __set_bit(tpd_keys[i], tpd->kpd->keybit);
50. tpd->kpd->id.bustype = BUS_HOST;
51. tpd->kpd->id.vendor = 0x0001;
52. tpd->kpd->id.product = 0x0001;
53. tpd->kpd->id.version = 0x0100;
54. if(input_register_device(tpd->kpd))
55. "input_register_device failed.(kpd)\n");
56. set_bit(EV_KEY, tpd->dev->evbit);
57. for(i=0;i<tpd_keycnt;i++)
58. __set_bit(tpd_keys[i], tpd->dev->keybit);
59. "board_properties", NULL);
60. if(properties_kobj)
61. ret = sysfs_create_group(properties_kobj,&cust_properties_attr_group);
62. if(!properties_kobj || ret)
63. "failed to create board_properties\n");
64. }
65.
66.
67. void tpd_button_setting(int keycnt, void *keys, void *keys_dim)
68. {
69. tpd_keycnt = keycnt;
70. memcpy(tpd_keys, keys, keycnt*4);
71. memcpy(tpd_keys_dim, keys_dim, keycnt*4*4);
72. }
有了上面的代码,我们的virtual key才可以使用,这里主要是需要注册/sys/board_properties/virtualkeys.cust-tpd。这个是framework需要的文件节点。他的出现可以使我们的虚拟按键畅通无阻了。
当然,在这里tpd_keys这个定义key的数组和定义区域的tpd_keys_dim要准确的填充才可以的。具体的填充的规则如下:
每一个虚拟按键有六个参数:
1. 0x01: A version code. Must always be 0x01.
2. <Linux key code>: The Linux key code of the virtual key.
3. <centerX>: The X pixel coordinate of the center of the virtual key.
4. <centerY>: The Y pixel coordinate of the center of the virtual key.
5. <width>: The width of the virtual key in pixels.
6. <height>: The height of the virtual key in pixels.
7. 对比我的milestone来看看:
8. 0x01:158:32:906:63:57:
9. 0x01:139:162:906:89:57:
10. 0x01:102:292:906:89:57:
11. 0x01:217:439:906:63:57
则可以看出定义了有back,menu,home,search,具体的区域也一清二楚了。
下面就是framework中的处理了,文件在framework/base/services/java/com/android/server/InputManager.java。
在其中通过调用getVirtualKeyDefinitions来获得定义的虚拟按键。
1. public VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
2. new ArrayList<VirtualKeyDefinition>();
3.
4. try {
5. new FileInputStream(
6. "/sys/board_properties/virtualkeys." + deviceName);
7. new InputStreamReader(fis);
8. new BufferedReader(isr, 2048);
9. String str = br.readLine();
10. if (str != null) {
11. ":");
12. if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "***** VIRTUAL KEYS: " + it);
13. final int N = it.length-6;
14. for (int i=0; i<=N; i+=6) {
15. if (!"0x01".equals(it[i])) {
16. "Unknown virtual key type at elem #"
17. ": " + it[i] + " for device " + deviceName);
18. continue;
19. }
20. try {
21. new VirtualKeyDefinition();
22. 1]);
23. 2]);
24. 3]);
25. 4]);
26. 5]);
27. if (DEBUG_VIRTUAL_KEYS) Slog.v(TAG, "Virtual key "
28. ": center=" + key.centerX + ","
29. " size=" + key.width + "x"
30. + key.height);
31. keys.add(key);
32. catch (NumberFormatException e) {
33. "Bad number in virtual key definition at region "
34. " in: " + str + " for device " + deviceName, e);
35. }
36. }
37. }
38. br.close();
39. catch (FileNotFoundException e) {
40. "No virtual keys found for device " + deviceName + ".");
41. catch (IOException e) {
42. "Error reading virtual keys for device " + deviceName + ".", e);
43. }
44.
45. return keys.toArray(new VirtualKeyDefinition[keys.size()]);
46. }
其实找这个函数的调用的话,其实是发现通过JNI com_android_server_InputManager.cpp,InputReader.cpp来调用的。
最终通过notifyKey()来将key事件上报给app来处理。
在这其中还需要配置:
Key layout file: /system/usr/keylayout/touchyfeely.kl.
key 158 BACK
key 139 MENU
key 102 HOME
key 217 SEARCH
Key character map file: /system/usr/keychars/touchyfeely.kcm.
type SPECIAL_FUNCTION
其实这个例子给我的最大的感受是让我更加的了解了什么是策略,什么是机制,一定要区分清楚。读源码可以让自己的想法也会有些转变的。
Have Fun!
补充资料: