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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
static
unsigned
int
tpd_keycnt = 0;
static
int
tpd_keys[TPD_VIRTUAL_KEY_MAX]={0};
static
int
tpd_keys_dim[TPD_VIRTUAL_KEY_MAX][4];
// = {0};
static
ssize_t cust_virtual_keys_show(
struct
kobject *kobj,
struct
kobj_attribute *attr,
char
*buf) {
int
i, j;
for
(i=0, j=0;i<tpd_keycnt;i++)
j+=
sprintf
(buf,
"%s%s:%d:%d:%d:%d:%d%s"
,buf,
__stringify(EV_KEY),tpd_keys[i],
tpd_keys_dim[i][0],tpd_keys_dim[i][1],
tpd_keys_dim[i][2],tpd_keys_dim[i][3],
(i==tpd_keycnt-1?
"\n"
:
":"
));
return
j;
}
static
struct
kobj_attribute cust_virtual_keys_attr = {
.attr = {
.name =
"virtualkeys.cust-tpd"
,
.mode = S_IRUGO,
},
.show = &cust_virtual_keys_show,
};
static
struct
attribute *cust_properties_attrs[] = {
&cust_virtual_keys_attr.attr,
NULL
};
static
struct
attribute_group cust_properties_attr_group = {
.attrs = cust_properties_attrs,
};
struct
kobject *properties_kobj;
void
tpd_button_init(
void
) {
int
ret = 0, i = 0, j=0;
tpd->kpd=input_allocate_device();
/* struct input_dev kpd initialization and registration */
tpd->kpd->name = TPD_DEVICE
"-kpd"
;
set_bit(EV_KEY, tpd->kpd->evbit);
for
(i=0;i<tpd_keycnt;i++)
__set_bit(tpd_keys[i], tpd->kpd->keybit);
tpd->kpd->id.bustype = BUS_HOST;
tpd->kpd->id.vendor = 0x0001;
tpd->kpd->id.product = 0x0001;
tpd->kpd->id.version = 0x0100;
if
(input_register_device(tpd->kpd))
TPD_DMESG(
"input_register_device failed.(kpd)\n"
);
set_bit(EV_KEY, tpd->dev->evbit);
for
(i=0;i<tpd_keycnt;i++)
__set_bit(tpd_keys[i], tpd->dev->keybit);
properties_kobj = kobject_create_and_add(
"board_properties"
, NULL);
if
(properties_kobj)
ret = sysfs_create_group(properties_kobj,&cust_properties_attr_group);
if
(!properties_kobj || ret)
printk(
"failed to create board_properties\n"
);
}
void
tpd_button_setting(
int
keycnt,
void
*keys,
void
*keys_dim)
{
tpd_keycnt = keycnt;
memcpy
(tpd_keys, keys, keycnt*4);
memcpy
(tpd_keys_dim, keys_dim, keycnt*4*4);
}
|
有了上面的代码,我们的virtual key才可以使用,这里主要是需要注册/sys/board_properties/virtualkeys.cust-tpd。这个是framework需要的文件节点。他的出现可以使我们的虚拟按键畅通无阻了。
当然,在这里tpd_keys这个定义key的数组和定义区域的tpd_keys_dim要准确的填充才可以的。具体的填充的规则如下:
0x01: A version code. Must always be 0x01.
<Linux key code>: The Linux key code of the virtual key.
<centerX>: The X pixel coordinate of the center of the virtual key.
<centerY>: The Y pixel coordinate of the center of the virtual key.
<width>: The width of the virtual key in pixels.
<height>: The height of the virtual key in pixels.
对比我的milestone来看看:
0x01:158:32:906:63:57:
0x01:139:162:906:89:57:
0x01:102:292:906:89:57:
0x01:217:439:906:63:57
则可以看出定义了有back,menu,home,search,具体的区域也一清二楚了。
下面就是framework中的处理了,文件在framework/base/services/java/com/android/server/InputManager.java。
在其中通过调用getVirtualKeyDefinitions来获得定义的虚拟按键。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public
VirtualKeyDefinition[] getVirtualKeyDefinitions(String deviceName) {
ArrayList<VirtualKeyDefinition> keys =
new
ArrayList<VirtualKeyDefinition>();
try
{
FileInputStream fis =
new
FileInputStream(
"/sys/board_properties/virtualkeys."
+ deviceName);
InputStreamReader isr =
new
InputStreamReader(fis);
BufferedReader br =
new
BufferedReader(isr, 2048);
String str = br.readLine();
if
(str != null) {
String[] it = str.split(
":"
);
if
(DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
"***** VIRTUAL KEYS: "
+ it);
final
int
N = it.length-6;
for
(
int
i=0; i<=N; i+=6) {
if
(!
"0x01"
.equals(it[i])) {
Slog.w(TAG,
"Unknown virtual key type at elem #"
+ i +
": "
+ it[i] +
" for device "
+ deviceName);
continue
;
}
try
{
VirtualKeyDefinition key =
new
VirtualKeyDefinition();
key.scanCode = Integer.parseInt(it[i+1]);
key.centerX = Integer.parseInt(it[i+2]);
key.centerY = Integer.parseInt(it[i+3]);
key.width = Integer.parseInt(it[i+4]);
key.height = Integer.parseInt(it[i+5]);
if
(DEBUG_VIRTUAL_KEYS) Slog.v(TAG,
"Virtual key "
+ key.scanCode +
": center="
+ key.centerX +
","
+ key.centerY +
" size="
+ key.width +
"x"
+ key.height);
keys.add(key);
}
catch
(NumberFormatException e) {
Slog.w(TAG,
"Bad number in virtual key definition at region "
+ i +
" in: "
+ str +
" for device "
+ deviceName, e);
}
}
}
br.close();
}
catch
(FileNotFoundException e) {
Slog.i(TAG,
"No virtual keys found for device "
+ deviceName +
"."
);
}
catch
(IOException e) {
Slog.w(TAG,
"Error reading virtual keys for device "
+ deviceName +
"."
, e);
}
return
keys.toArray(
new
VirtualKeyDefinition[keys.size()]);
}
|
其实找这个函数的调用的话,其实是发现通过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!
转自:http://www.2cto.com/kf/201307/230972.html