当前位置:操作系统 > 安卓/Android >>

Android tp的虚拟按键(virtual key)处理

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的底层驱动实现了。这里你试验了吗?你可能会说,“不行,这里实现不了”。是的,这个时候还不行,还有关键的步骤得操作。


在这里,你需要如下代码加入才可以。

 

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来获得定义的虚拟按键。
 

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 characte

补充:移动开发 , Android ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,