zoukankan      html  css  js  c++  java
  • Linux/Android多点触摸协议【转】

    本文转载自:

    链接点击打开链接

    关于Linux多点触摸协议大家可以参考kernel中的文档:https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt,而这里根据实际的例子来理解多点触摸协议。


    多点触摸协议有两种,A协议和B协议。

    首先来看A协议,协议上说了报点格式是这样的,以两点为例:

            ABS_MT_POSITION_X x[0]
            ABS_MT_POSITION_Y y[0]
            SYN_MT_REPORT
            ABS_MT_POSITION_X x[1]
            ABS_MT_POSITION_Y y[1]
            SYN_MT_REPORT
            SYN_REPORT


    如果第一个触点离开(抬起),这里的意思是说还有一个触点,需要继续上报这个触点。

            ABS_MT_POSITION_X x[1]
            ABS_MT_POSITION_Y y[1]
            SYN_MT_REPORT
            SYN_REPORT


    如果两个触点都离开了,那么只需要报告一个同步事件就可以了。

            SYN_MT_REPORT
            SYN_REPORT


    而代码示例如下:

    [cpp] view plain copy
     
    1. for (i = 0; i < count; i++) {  
    2.         input_report_abs(input_dev, ABS_MT_POSITION_X, finger[i].x);  
    3.         input_report_abs(input_dev, ABS_MT_POSITION_Y, finger[i].x);  
    4.         input_mt_sync(input_dev);  
    5. }  
    6.   
    7. if (!count)  
    8.         input_mt_sync(input_dev);  
    9.   
    10. input_sync(input_dev);  

    其中count值表示触点个数,如果是2个,那么这里值就为2,如果所有触点都离开了,那么count值就为0。

    上面可以说是最简单,也是最基本的A协议报点了。除了报点以外,我们也来关注一下input device注册时需要setting的一些东西。

    [cpp] view plain copy
     
    1. input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, MAX_X, 0, 0);  
    2. input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, MAX_Y, 0, 0);  
    3.   
    4. __set_bit(EV_SYN, input_dev->evbit);  
    5. __set_bit(EV_ABS, input_dev->evbit);  
    6.   
    7. __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);  

    可能你会看到有的代码会多下面这两句:

    [cpp] view plain copy
     
    1. __set_bit(ABS_MT_POSITION_X, input_dev->absbit);  
    2. __set_bit(ABS_MT_POSITION_X, input_dev->absbit);  

    其实这两句(包括上面的__set_bit(EV_ABS, input_dev->evbit);)是可有可无的,因为在input_set_abs_params函数中会做相应的设置。

    而这句__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);也是必须要有的,否则在Android中会出现一个白色小圆环,感觉像是缺少idc文件一样。最后通过getevent -p命令看一下触摸屏的setting。

    add device 1: /dev/input/event1
      name:     "ft6x36"
      events:
        ABS (0003): 0035  : value 0, min 0, max 540, fuzz 0, flat 0, resolution 0
                    0036  : value 0, min 0, max 960, fuzz 0, flat 0, resolution 0
      input props:
        INPUT_PROP_DIRECT

    对于B协议就稍微显得有点复杂。B协议需要硬件支持,和A协议主要区别在哪里呢?B协议可以使用一个ID来标识触点,可以减少上报到用户空间的数据量,这个ID(ABS_MT_TRACKING_ID)可以有硬件提供或者从原始数据计算而得。那>么下面我们就来看B协议怎么上报数据的。

            ABS_MT_SLOT 0
            ABS_MT_TRACKING_ID 45
            ABS_MT_POSITION_X x[0]
            ABS_MT_POSITION_Y y[0]
            ABS_MT_SLOT 1
            ABS_MT_TRACKING_ID 46
            ABS_MT_POSITION_X x[1]
            ABS_MT_POSITION_Y y[1]
            SYN_REPORT

    如果触点45只是在x方向做了移动,那么应该怎么报告这个事件呢?

            ABS_MT_SLOT 0
            ABS_MT_POSITION_X x[0]
            SYN_REPORT

    可以看到减少了很多数据的上报,这就是同A协议最大的区别。

    如果同slot 0相关的触点离开(抬起),只需要做下面的操作。
            ABS_MT_TRACKING_ID -1
            SYN_REPORT

    这里为什么没有发送ABS_MT_SLOT 0事件呢,因为之前slot已经被置成了0,再次发送ABS_MT_SLOT 0是会被忽略掉的。

    如果第二个触点被抬起,发送下面的事件序列。

            ABS_MT_SLOT 1
            ABS_MT_TRACKING_ID -1
            SYN_REPORT

    其他event
    ABS_MT_POSITION_X和ABS_MT_POSITION_Y是多点触摸协议的最小事件集,是最基本的事件,也是必须的事件。除此之外呢,还包括下面的一些时间集(需要设置支持):
    ABS_MT_TOUCH_MAJOR
    ABS_MT_TOUCH_MINOR
    ABS_MT_TOUCH*用来表示接触点区域大小(即手指与玻璃接触区域大小),通常接触区域是一个椭圆形状,那么MAJOR就表示椭圆的长轴,而MINOR就表示椭圆的短轴。如果接触区域是圆形的话,那么可以忽略MINOR,而MAJOR就表示圆形的直径大小。

    ABS_MT_WIDTH_MAJOR
    ABS_MT_WIDTH_MINOR
    上面的TOUCH表示接触区域的大小,而WIDTH则表示为接触工具的大小(例如手指,触控笔等)。

    ABS_MT_PRESSURE
    而PRESSURE表示压力值,这个压力值可以通过上面的4个参数计算而得,例如:ABS_MT_TOUCH_MAJOR/ABS_MT_WIDTH_MAJOR,可以看到接触面积越大,压力值也就越大。当然这个压力值也可以直接由设备提供。

    ABS_MT_DISTANCE
    触点与接触面的距离,0表示触点在接触面的表面(已经实实在在的接触到了),而正数表示在接触面的上方。

    ABS_MT_ORIENTATION
    触点的方向。

    ABS_MT_TOOL_X
    ABS_MT_TOOL_Y
    ABS_MT_TOOL_TYPE

    关于上报虚拟按键值
    通常触摸屏下方都有3个虚拟按键,而这3个按键同其它实体按键(例如:power按键、音量按键)又有所不同,它是触摸屏提供的一组虚拟按键,我们通过触摸屏会得到这一组按键的坐标值,可以通过这个坐标值上报相应的按键值来实
    现按键功能,那么怎么来上报这个按键值呢。首先需要对input设备做一些setting:

    [cpp] view plain copy
     
    1. __set_bit(KEY_MENU, input_dev->keybit);  
    2. __set_bit(KEY_HOMEPAGE, input_dev->keybit);  
    3. __set_bit(KEY_BACK, input_dev->keybit);  
    4.   
    5. __set_bit(EV_KEY, input_dev->evbit);  
    6. __set_bit(EV_SYN, input_dev->evbit);  

    OK,这些键值呢在kernel中是定义在uapi/linux/input.h中的,而通常我们的driver只需要包含linux/input.h就可以了,这个文件中include了的uapi/linux/input.h。

    好的,再来看怎么上报键值。
    按键按下:

    [cpp] view plain copy
     
    1. input_report_key(input_dev, key_value, 1);  
    2. input_sync(input_dev);  

    按键抬起:

    [cpp] view plain copy
     
    1. input_report_key(input_dev, key_value, 0);  
    2. input_sync(input_dev);  

    如果是按键一直被按下,重复上报按键被按下那部分就可以了。

    有的地方可能会看到直接使用input_event函数,例如:

    [cpp] view plain copy
     
    1. input_event(input_dev, EV_KEY, key_value, 1);  

    大家也可以去看看input_report_key函数,它其实是对input_event函数做了封装,不管是input_report_abs也好,还是input_sync,最终都是调用的input_event函数,所以真正上报event的函数其实是input_event函数。

    最后一点在setting时除了__set_bit之外,可能还会看到另外一个函数input_set_capability,这个函数实现在drivers/input/input.c中,而它最终还是调用了__set_bit函数,所以最后效果都是一样的。

  • 相关阅读:
    坚持的力量 第一篇
    有声似无声
    坚持的力量
    新浪技术面试题
    单词的个数
    我的研究生规划
    go to the train station
    百度面试题求绝对值最小的数
    关于CIW认证考试CIW 常见问题解答
    [恢]hdu 2087
  • 原文地址:https://www.cnblogs.com/zzb-Dream-90Time/p/7739309.html
Copyright © 2011-2022 走看看