多点触摸TP的touch异常事件

异常现象

android开启触摸白点模式后, 屏幕上出现白点不消失,存在一个长按down事件

分析

经过研究,发现多点触摸协议存在type A和type B。出现此异常的TP使用的是Type B的多点触摸协议,支持轨迹跟踪。

通过sendevent发送input event事件,发现该异常与ABS_MT_SLOT,ABS_MT_TRACKING_ID事件关系密切。先简单介绍下这2个事件。

多点触摸协议的事件

ABS_MT_SLOT这个事件的SLOT值由TP IC传递给主机.

ABS_MT_TRACKING_ID这个事件的值由Input Driver生成(也可以由TP Driver中hardCode)。在input driver中它的值分为2种情况正值(代表与之关联的SLOT的down事件),负值(-1代表与之关联的SLOT的UP事件);不同的SLOT匹配不同的ABS_MT_TRACKING_ID值,ABS_MT_TRACKING_ID值是一个递增的值。

本文之前提到的问题与ABS_MT_TRACKING_ID事件密切相关

异常的可能性

  1. TP Driver没有发送对应的ABS_MT_SLOT和ABS_MT_TRACKING_ID(-1)的事件

  1. TP Driver仅仅发送了ABS_MT_SLOT,没有发送ABS_MT_TRACKING_ID的正值;

第一类问题很好处理,仅仅需要在合适的时候增加一个UP的事件组合即可,第二类问题相对复杂。

第二类问题,可能是驱动本身遗漏了ABS_MT_TRACKING_ID的正值,相对容易排查;也可能是因为input event的异步发送导致的问题,这个问题相对复杂。经过调试input driver,我获取了一些信息。


对于常用的ABS_MT_SLOT常用通道(1~5)发生异常,很容易通过人为的多点触摸恢复,因为在新的多点触摸中驱动必然由down和up事件生成,那么此时异常旧恢复了,但是对于ABS_MT_SLOT通道值较大(10~15)的异常,旧很难通过人为的手动操作恢复了,没那么多手指去触摸呀。

我调试的是cyttsp的一款触摸板,通过手动触摸和sendevent命令同时操作很容易就触发这个bug。

经过调试我发现,cyttsp的驱动的sync_report插入了sendevent发送的事件中间,导致sendevent发送的事件添加了一个ABS_MT_SLOT为15的触摸事件集合,并且这个事件集合中没有ABS_MT_TRACKING_ID事件。最终这个点发送除去,并且被framework作为一个down事件处理。然而在最后释放的时候这个ABS_MT_SLOT为15对应的点确没有UP事件。

这个测试说明:缺少ABS_MT_TRACKING_ID的触摸down事件可以被framework处理,但是kernel没办法触发对应的

dev=8
function touch_point()
{
adb shell sendevent /dev/input/event${dev} 3 ABS_MT_SLOT $1
adb shell sendevent /dev/input/event${dev} 3 ABS_MT_TRACKING_ID $2            
adb shell sendevent /dev/input/event${dev} 3 53 $3
adb shell sendevent /dev/input/event${dev} 3 54 $4            
}

sendevent发送了ABS_MT_TRACKING_ID后,cyttsp发送了UP事件,完成了此次点击。后面2条命令继续发送,产生了以仅仅包含ABS_MT_SLOT的触摸事件。ABS_MT_SLOT的值为15是因为cyttsp驱动在每次事件处理后会遍历ABS_MT_SLOT并释放。


通过分析input模块代码,在tp driver或者user space空间向input driver发送input event时,

如果发送的事件ACTION_1包含(ABS_MT_SLOT,ABS_MT_POSITION_X,ABS_MT_POSITION_Y, ABS_MT_PRESSURE)且不含ABS_MT_TRACKING_ID时,

tp driver即使发送了ACTION_2(对应的ABS_MT_SLOT和ABS_MT_TRACKING_ID=-1),但是在input driver 模块处理event时,因为在input_handle_abs_event函数中逻辑如下:

static int input_handle_abs_event(struct input_dev *dev,
                  unsigned int code, int *pval)
{
    struct input_mt *mt = dev->mt;
    bool is_mt_event;
    int *pold;

    if (code == ABS_MT_SLOT) {
        //input_event函数发送ABS_MT_SLOT消息时,实际上并不将对应的事件添加到队列中
        //仅仅完成了赋值操作
        if (mt && *pval >= 0 && *pval < mt->num_slots)
            mt->slot = *pval;
        return INPUT_IGNORE_EVENT;
    }

    is_mt_event = input_is_mt_value(code);

    if (!is_mt_event) {
        pold = &dev->absinfo[code].value;
    } else if (mt) {
        //因为ACTION_1中没有ABS_MT_TRACKING_ID的值,因此这个值一直为-1
        //当发送ACTION_2事件时,这个pold的值为-1
        pold = &mt->slots[mt->slot].abs[code - ABS_MT_FIRST];
    } else {
        /*
         * Bypass filtering for multi-touch events when
         * not employing slots.
         */
        pold = NULL;
    }

    if (pold) {
        *pval = input_defuzz_abs_event(*pval, *pold,
                        dev->absinfo[code].fuzz);
        //pold和pval都为-1,因此不处理这个事件,丢失抬起事件
        if (*pold == *pval)
            return INPUT_IGNORE_EVENT;

        *pold = *pval;
    }

    /* Flush pending slot event */
    if (is_mt_event && mt && mt->slot != input_abs_get_val(dev, ABS_MT_SLOT)) {
        input_abs_set_val(dev, ABS_MT_SLOT, mt->slot);
        //input_event函数发送ABS_MT_SLOT消息时,实际上并不将对应的事件添加到队列中
        //在使用input_event发送其他消息时,根据需要在返回值中增加INPUT_SLOT,
        //然后在input_handle_event函数中把ABS_MT_SLOT数据添加发送队列中
        return INPUT_PASS_TO_HANDLERS | INPUT_SLOT;
    }

    return INPUT_PASS_TO_HANDLERS;
}

出现白点不消失后,需要再次给对应的ABS_MT_SLOT,发送一条包含ABS_MT_TRACKING_ID的值(需要为正值),然后再次发送释放point的input event(对应的ABS_MT_SLOT和ABS_MT_TRACKING_ID=-1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值