MTK 驱动(65)---Android 多点触摸协议(Multi-touch Protocol)


Android 多点触摸协议(Multi-touch Protocol)

关于Linux多点触摸协议大家可以参考kernel中的文档:https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt

多点触摸协议有两种:包括A协议和B协议(基于硬件能力区分);

A协议

A协议:处理无关联的接触:用于直接发送原始数据;

/*
两点触摸数据上报如下:
系统以SYN_MT_REPORT为一个点信息的结尾,以SYN_REPORT为一个事件的结束,
系统受到一个点之后并不会立即处理,而是一个事件完成后才会处理;
*/
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_REPOR


/*
手抬起的时候,只有SYNC,没有其他任何信息,系统就会认为此次事件为UP;
*/
SYN_MT_REPORT 
SYN_REPORT  
  • A协议比较简单,我们也可以发现在上面的序列中根本就没有轨迹跟踪的信息,有的只是点坐标等信息,

报上去的信息简单粗暴不需要什么顺序,系统根本无法识别报上的点是属于哪一条线的,事件过滤和手指跟踪的工作留给用户空间来实现。

B协议

B协议:处理跟踪识别类的接触:通过事件slot把每个接触点的单独更新发给接受者;

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

手抬起的时候如下样子: 
ABS_MT_SLOT 0 
ABS_MT_TRACKING_ID -1 
SYN_REPORT 
ABS_MT_SLOT 1 
ABS_MT_TRACKING_ID -1 
SYN_REPORT
  • 对于协议B,内核驱动应该把每一个识别出的触控和一个slot相关联,并使用该 slot来传播触摸状态的改变,

通过修改关联slot的ABS_MT_TRACKING_ID来达到对触摸点的创建,替换和销毁。

上报 ABS_MT_TRACKING_ID -1系统会清除对应的ID和slot,再次按下手指时分配新ID值(ID值是每次+1的);

使用ABS_MT_TRACKING_ID,即当前序列中某点的ID值,用来跟踪当前点属于哪一条线;

如果与前一次序列中某点的ID值相等,那么他们就属于同一条线,应用层就不用在去劳心劳神的算那个点是那条线上的啦。

如果按下并一直按同一个点,那么input子系统会做个处理来屏蔽上下两次相同的点,减少IO的负担。

注:使用B协议的时候会产生一个问题,当使用QQ或微信<按住说话>说话功能的时候,当按住说话的时间大于灭屏时间的时候,会出现灭屏现象;

代码编写

Protocol A:


注册:

set_bit(EV_SYN, input_dev->evbit); 
set_bit(EV_KEY, input_dev->evbit); 
set_bit(EV_ABS, input_dev->evbit); 
set_bit(INPUT_PROP_DIRECT, input_dev->propbit); 
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); 
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); 
input_register_device(input_dev); 
  • 上报:
for (finger = 0; finger < num_of_fingers; finger++) { 
    //读取计算x、y坐标,id值,触摸的状态 
    if (finger_down) { 
        input_report_abs(input_dev, ABS_MT_POSITION_X, x); 
        input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 
        input_mt_sync(input_dev); 
    } else { 
        input_mt_sync(input_dev); 
} 

input_sync(input_dev); 


如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 
如果注册了BTN_TOUCH, 上报时就要上报BTN_TOUCH, 1:按下  0:抬起 
  • 上报log:
按下一个点抬起 
[     140.781791] EV_ABS       ABS_MT_POSITION_X    00000148 
[     140.781801] EV_ABS       ABS_MT_POSITION_Y    0000044f 
[     140.781805] EV_SYN       SYN_MT_REPORT        00000000 
[     140.781807] EV_SYN       SYN_REPORT           00000000 
[     140.796553] EV_SYN       SYN_MT_REPORT        00000000 
[     140.796563] EV_SYN       SYN_REPORT           00000000 

按下两个点抬起 
[     245.011718] EV_ABS       ABS_MT_POSITION_X    00000102 
[     245.011757] EV_ABS       ABS_MT_POSITION_Y    000003d0 
[     245.011771] EV_SYN       SYN_MT_REPORT        00000000 
[     245.011785] EV_ABS       ABS_MT_POSITION_X    00000220 
[     245.011798] EV_ABS       ABS_MT_POSITION_Y    00000419 
[     245.011810] EV_SYN       SYN_MT_REPORT        00000000 
[     245.011819] EV_SYN       SYN_REPORT           00000000 
[     245.025296] EV_SYN       SYN_MT_REPORT        00000000 
[     245.025311] EV_SYN       SYN_MT_REPORT        00000000 
[     245.025313] EV_SYN       SYN_REPORT           00000000 
  • Protocol B:

注册:

set_bit(EV_SYN, input_dev->evbit); 
set_bit(EV_KEY, input_dev->evbit); 
set_bit(EV_ABS, input_dev->evbit); 
set_bit(INPUT_PROP_DIRECT, input_dev->propbit); 
input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, sensor_max_x, 0, 0); 
input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, sensor_max_y, 0, 0); 
input_mt_init_slots(input_dev, num_of_fingers);   //和A相比多注册slot 
input_register_device(input_dev); 

如果注册了ABS_MT_PRESSURE,上报时就要上报ABS_MT_PRESSURE。 
  • 上报:
for (finger = 0; finger < num_of_fingers; finger++) { 
    ...//读取计算x、y坐标和id,触摸的状态 
    input_mt_slot(input_dev, id); 
    if (finger_down) { 
        input_mt_report_slot_state(input_dev, MT_TOOL_FINGER, 1); 
        input_report_abs(input_dev, ABS_MT_POSITION_X, x); 
        input_report_abs(input_dev, ABS_MT_POSITION_Y, y); 
    } else {  //finger_up 
        input_mt_report_slot_state(ip_dev, MT_TOOL_FINGER, 0); 
    } 
} 

input_mt_report_pointer_emulation(input_dev, false); 
input_sync(input_dev); 
  • 上报log:
按下一个点抬起 
[      78.541863] EV_ABS       ABS_MT_TRACKING_ID   00000007 //按下分配ID 
[      78.541928] EV_ABS       ABS_MT_POSITION_X    0000021b 
[      78.541944] EV_ABS       ABS_MT_POSITION_Y    00000442 
[      78.541981] EV_SYN       SYN_REPORT           00000000 
[      78.605574] EV_ABS       ABS_MT_TRACKING_ID   ffffffff //抬起释放ID  ID=-1释放 
[      78.605595] EV_SYN       SYN_REPORT           00000000 

再次按下一个点抬起
[      98.324526] EV_ABS       ABS_MT_TRACKING_ID   00000008 //按下分配ID  上一次的ID +1 
[      98.324590] EV_ABS       ABS_MT_POSITION_X    000000c8 
[      98.324605] EV_ABS       ABS_MT_POSITION_Y    0000037a 
[      98.324641] EV_SYN       SYN_REPORT           00000000 
[      98.388583] EV_ABS       ABS_MT_TRACKING_ID   ffffffff //抬起释放ID  ID=-1释放 
[      98.388603] EV_SYN       SYN_REPORT           00000000 

两个点同时按下抬起 
[     208.775409] EV_ABS       ABS_MT_SLOT          00000000 //多点时标示 属于哪个slot 标示slot 0 
[     208.775462] EV_ABS       ABS_MT_TRACKING_ID   0000000e //分配ID 
[     208.775484] EV_ABS       ABS_MT_POSITION_X    00000215 
[     208.775498] EV_ABS       ABS_MT_POSITION_Y    0000037c 
[     208.775533] EV_SYN       SYN_REPORT           00000000 
[     208.859516] EV_ABS       ABS_MT_SLOT          00000001 //标示slot 1 
[     208.859534] EV_ABS       ABS_MT_TRACKING_ID   0000000f //分配ID 上一 次ID +1 
[     208.859538] EV_ABS       ABS_MT_POSITION_X    000000e6 
[     208.859541] EV_ABS       ABS_MT_POSITION_Y    0000031f 
[     208.859550] EV_SYN       SYN_REPORT           00000000 
[     208.873597] EV_ABS       ABS_MT_SLOT          00000000 
[     208.873637] EV_ABS       ABS_MT_TRACKING_ID   ffffffff //释放slot0 的ID 
[     208.873659] EV_ABS       ABS_MT_SLOT 00000001 
[     208.873667] EV_ABS       ABS_MT_TRACKING_ID   ffffffff //释放slot1 的ID 
[     208.873688] EV_SYN       SYN_REPORT           00000000 

代码分析:

input_mt_slot()根据ID注册一个slot; 
static inline void input_mt_slot(struct input_dev *dev, int slot) 
{ 
    input_event(dev, EV_ABS, ABS_MT_SLOT, slot); 
} 

input_mt_report_slot_state()分配ABS_MT_TRACKING_ID; 
void input_mt_report_slot_state(struct input_dev *dev, unsigned int tool_type, bool active) 
{ 
    struct input_mt_slot *mt; 
    int id; 

    //如果active 为0就上报 ABS_MT_TRACKING_ID = -1表示手指抬起 
    if (!dev->mt || !active) {
        input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); 
        return; 
    } 

    mt = &dev->mt[dev->slot]; 
    id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
    //如果是从新触摸的点即上一次ABS_MT_TRACKING_ID=-1  
    if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
        id = input_mt_new_trkid(dev); //就从新分配ABS_MT_TRACKING_ID, 新ID上在上一次的基础上+1 

    //如果手指没抬起,即ABS_MT_TRACKING_ID大于0,ABS_MT_TRACKING_ID本次并没有改变即还在一个轨迹上; 
    input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id); 
    input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type); 
} 

input_mt_report_pointer_emulation(input_dev, false); //文档中写函数是用来 检测驱动是否能报告比slot还多的触控点
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值