Android2.3触摸屏功能详解

来源:互联网 发布:淘宝解id锁有人解过吗 编辑:程序博客网 时间:2024/05/15 23:26

1) 触摸设备驱动应当只需要注册轴、与轴对应的键值和真正支持的按钮。注册过多的轴或键值可能会迷惑设备分类算法或导致系统不能正确地检测设备的能力。

         比如:如果设备驱动报告了BTN_TOUCH键值, Android系统将认为BTN_TOUCH总是被用于指示触摸工具是否真正地接触触摸屏或仅仅在上方盘旋。

        2) 单点触摸(Single-touch)设备支持以下Linux输入事件:       

  • ABS_X: (必须) :报告工具的x坐标
  • ABS_Y: (必须) :报告工具的y坐标
  • ABS_PRESSURE: (可选): 报告触摸工具顶尖处的压力或触摸接触的信号强度。
  • ABS_TOOL_WIDTH: (可选): 报告接触部分区域,或接触宽度或工具本身的宽度。
  • ABS_DISTANCE: (可选):报告从触摸设备表面到工具的距离
  • ABS_TILT_X: (可选): 报告工具沿触摸设备表面X轴的倾斜
  • ABS_TILT_Y: (可选):  报告工具沿触摸设备表面Y轴的倾斜.
  • BTN_TOUCH: (必须) :指示工具是否接触触摸设备.
  • BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_BACK, BTN_SIDE, BTN_FORWARD, BTN_EXTRA, BTN_STYLUS, BTN_STYLUS2: (可选):  报告按钮状态.
  • BTN_TOOL_FINGER, BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_BRUSH, BTN_TOOL_PENCIL, BTN_TOOL_AIRBRUSH, BTN_TOOL_MOUSE, BTN_TOOL_LENS, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP: (可选): 报告工具类型.

      3) 多点触摸(Multi-touch)设备支持以下Linux输入事件:      

  • ABS_MT_POSITION_X: (必须): 报告工具的X坐标
  • ABS_MT_POSITION_Y: (必须): 报告工具的X坐标
  • ABS_MT_PRESSURE: (可选): 报告触摸工具顶尖处的压力或触摸接触的信号强度
  • ABS_MT_TOUCH_MAJOR: (可选): 报告接触面积或接触面的长轴
  • ABS_MT_TOUCH_MINOR: (可选): 报告接触面的短轴。如果ABS_MT_TOUCH_MAJOR 报告接触面积,且此参数不应该使用。
  • ABS_MT_WIDTH_MAJOR: (可选): 报告接触工具本身的面积,或接触工具本身的长轴。如果接触工具的尺寸未知,则不应该使用此参数。
  • ABS_MT_WIDTH_MINOR: (可选): 报告接触工具本身的短轴,如果ABS_MT_WIDTH_MAJOR报告了面积区域, 或接触工具的尺寸未知,则不应该使用此参数。
  • ABS_MT_ORIENTATION: (可选):报告工具的方向.
  • ABS_MT_DISTANCE: (可选):  报告从触摸设备表面到工具的距离.
  • ABS_MT_TOOL_TYPE: (可选): 报告工具类型为:MT_TOOL_FINGER 或 MT_TOOL_PEN.
  • ABS_MT_TRACKING_ID: (可选): 报告工具的跟踪.
  • ABS_MT_SLOT: (可选): 报告工具的slot id,当使用Linux多点协议B.参考其文档获取更多信息。 
  • BTN_TOUCH: (必须): 指示工具是否接触触摸设备.
  • BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_BACK, BTN_SIDE, BTN_FORWARD, BTN_EXTRA, BTN_STYLUS, BTN_STYLUS2: (可选): 报告按钮状态
  • BTN_TOOL_FINGER, BTN_TOOL_PEN, BTN_TOOL_RUBBER, BTN_TOOL_BRUSH, BTN_TOOL_PENCIL, BTN_TOOL_AIRBRUSH, BTN_TOOL_MOUSE, BTN_TOOL_LENS, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP, BTN_TOOL_QUADTAP: (可选): 报告工具类型

      4) 如果单点触摸和多点触摸的轴都定义了,则只有多点协议的轴被使用,单点触摸的轴则被忽略。

      5) ABS_X, ABS_Y, ABS_MT_POSITION_X andABS_MT_POSITION_Y 轴的最小值和最大值以设备表面具体的单位(如像素)定义了活动区域的边界。对于触摸屏,活动区域描述了触摸设备真正覆盖显示部分的区域。

      6) 在Android4.0中,触摸屏驱动需要修改以与Linux输入协议规范兼容。

     下列变化可能需要:

          1) 当一个工具变成不活动时(如手指抬起) ,在随后的multi-touch sync report它不应该出现;当所有的工具不活动时(如所有的手指抬起),驱动应该发送一个空的sync report包,如:SYN_MT_REPORT紧跟一个SYN_REPORT。

          以前的Android版本期望报告一个up事件(通过发送一个pressure值为0) 。旧的操作方式与Linux input协议规范不兼容,所以不再使用。             

     2) 物理压力或信号强度信息应该使用ABS_MT_PRESSURE报告。

            以前的Android版本从ABS_MT_TOUCH_MAJOR获取压力信息。旧的操作方式与Linux input协议规范不兼容,所以不再使用。

     3) 触摸尺寸信息通过ABS_MT_TOUCH_MAJOR报告。

      以前的Android版本从ABS_MT_TOOL_MAJOR获取触摸尺寸信息。旧的操作方式与Linux input协议规范不兼容,所以不再使用。

      触摸设备驱动不再需要Android定制化。通过标准的Linux input协议,Android可以支持大量的触摸设备,且不用修改驱动。

   


手机设备上常用触摸屏进行用户操作,非常方便快捷,而且正好有个项目上用到这个设备,所以就花时间研究了一下。好了,还是老规则:大体了解概念先,细节线索找代码:

InputReader.cpp 中有针对单点触摸SingleTouchInputMapper及多点触摸MultiTouchInputMapper的处理代码,这两个类都继承自TouchInputMapper,由syncTouch处理最终的触摸屏动作的发送。

1、首先了解一下触摸屏中的几个参数概念:

“接触”一词用来描述一个物体直接碰到另一个物体的表面。

单点触摸的参数解析:

ABS_XABS_Y分别对应触摸屏的xy坐标

ABS_PRESSURE是压力值,一般触摸屏也只是分是否有按下去,按下去的话值会大于多少,没有按的话值小于多少

ABS_TOOL_WIDTH 触摸工具的宽度

多点触摸的参数解析:

ABS_MT_POSITION_X 接触面的形心的X坐标值 

ABS_MT_POSITION_Y 接触面的形心的Y坐标值 

 ABS_MT_TOUCH_MAJORABS_MT_WIDTH_MAJOR 分别被用来提供手指的大小和触摸面积大小 

TOUCH 和 WIDTH参数给出了个,想想如果一个手指按在玻璃上,透过玻璃你将看到两个区域,一个是手指与玻璃接触的区域,用 ABS_MT_TOUCH_MAJOR描述,一个是手指本身大小的区域,ABS_MT_WIDTH_MAJOR描述, 手指与玻璃接触的面积要小于手指本身的大小,通过这两个参数,可以换算出手指的压力。也可通过 ABS_MT_PRESSURE参数直接提供手指的压力。

除了 MAJOR这个参数,还可以提供一个 MINOR参数,手指可以被认为是一个椭圆,MAJOR和 MINOR可以认为是这个椭圆的长轴和短轴,椭圆的中心可以被 ORIENTATION这个参数描述。

ABS_MT_PRESSURE

接触工具对接触面的压力大小,可以用来代替上面的四个参数。

ABS_MT_ORIENTATION

描述随圆的转动趋势,这是一个抽相值,O值表示接触面在平行与触摸屏的Y轴,向左是负值,向右是正值,如果完全平行于X轴,则上向返回最大值。如果接触面是圆形,则可以忽略这个参数。如果内核不能获得这个参数有有效值,但可以区分接触面的长短轴,这个功能还是可以被部份支持,在一些设备中, ABS_MT_ORIENTATION 的值只能是 0和1。

ABS_MT_TOOL_TYPE描述接触工具类型(手指,触控笔等 ),很多内核驱动无法区分此参数如手指及笔,如果是这样,该参数可以不用,协议目前支持MT_TOOL_FINGERMT_TOOL_PEN两种类型。
ABS_MT_BLOB_ID形状集ID,集合几个点以描述一个形状,很多驱动没有形状属性,此参数可以不用。

ABS_MT_TRACKING_ID描述了从接触开始到释放的整个过程的集合,如果设备不支持,此参数可是不用。

计算方法:

一些设备将触摸面作为一个矩形上报,可以通过下面这些公式来计算出协议中所需要的信息。

ABS_MT_TOUCH_MAJOR := max(X, Y)

ABS_MT_TOUCH_MINOR := min(X, Y)

ABS_MT_ORIENTATION  := bool(X > Y)

ABS_MT_ORIENTATION的取值范围为0至1,用来标识矩形接触面偏向X轴或Y轴的程度。

触摸轨迹

仅有少数设备可以明触的标识真实的 trackingID,多数情况下 trackingID只能来标识一次触摸动作的过程。

手势

多点触摸指定的应用是创建手势动作, TOUCH和 WIDTH参数经常用来区别手指的压力和手指间的距离,另外 MINOR类的参数可以用来区别设备的接触面的大小(点接触还是面接触),ORIENTATION可以产生旋转事件。

以上的含义从http://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt 翻译而来,可以自行下载

2、代码入手

第一部分:直接写/dev/input/eventX接点实现

单点触摸事件发送序列:

EV_KEY (BTN_TOUCH) 发送是否在按下或弹出(0或者1

ABS_X 

ABS_Y

ABS_PRESSURE

ABS_TOOL_WIDTH

代码演示:

event.type  = EV_KEY;

event.code  = BTN_TOUCH;

mDown = (istEvent->pointers[0].abs_pressure > 0)?1:0 ;

Event.value  = mDown;

write(fd,&event,sizeof(event)) ;

/* 触摸屏键按下坐标定位  */

event.type  = EV_ABS;

    event.code  = ABS_X;

    event.value = istEvent->pointers[0].abs_x;

    write(fd,&event,sizeof(event)) ;

event.type  = EV_ABS;

    event.code  = ABS_Y;

    event.value = istEvent->pointers[0].abs_y;

    write(fd,&event,sizeof(event)) ;

    /* 触摸屏接触面的压力大小 */

event.type  = EV_ABS;

    event.code  = ABS_PRESSURE;

    event.value = istEvent->pointers[0].abs_pressure;

    write(fd,&event,sizeof(event)) ;

event.type   = EV_ABS;

event.code   = ABS_TOOL_WIDTH;

event.value  = istEvent->pointers[0].abs_touch_major;

/* 结束完整帧数据,发送同步信号 */

    event.type  = EV_SYN; 

    event.code  = SYN_REPORT;

    event.value = 0;

    write(fd, &event, sizeof(event));

    

    Ok,非常简单,对比inputreader.cpp中的代码,注意process代码:

void SingleTouchInputMapper::process(const RawEvent* rawEvent) {

    switch (rawEvent->type) {

    case EV_KEY:  //一定要注意发送这个event,否则触摸事件不会发送出去,直接丢弃

        switch (rawEvent->scanCode) {

        case BTN_TOUCH:

            mAccumulator.fields |= Accumulator::FIELD_BTN_TOUCH;

            mAccumulator.btnTouch = rawEvent->value != 0;

            // Don't sync immediately.  Wait until the next SYN_REPORT since we might

            // not have received valid position information yet.  This logic assumes that

            // BTN_TOUCH is always followed by SYN_REPORT as part of a complete 

            // packet.

            break;

        }

        break;

...

}

void SingleTouchInputMapper::sync(nsecs_t when) {

...

    if (mDown) {  // 这就是上面为何要发送的原因

        mCurrentTouch.pointerCount = 1;

        mCurrentTouch.pointers[0].id = 0;

        mCurrentTouch.pointers[0].x = mX;

        mCurrentTouch.pointers[0].y = mY;

        mCurrentTouch.pointers[0].pressure = mPressure;

        mCurrentTouch.pointers[0].touchMajor = 0;

        mCurrentTouch.pointers[0].touchMinor = 0;

        mCurrentTouch.pointers[0].toolMajor = mToolWidth;

        mCurrentTouch.pointers[0].toolMinor = mToolWidth;

        mCurrentTouch.pointers[0].orientation = 0;

        mCurrentTouch.idToIndex[0] = 0;

        mCurrentTouch.idBits.markBit(0);

}

...

}

多点触摸事件发送序列:

ABS_MT_TOUCH_MAJOR

ABS_MT_PRESSURE

ABS_MT_POSITION_X

ABS_MT_POSITION_Y

SYN_MT_REPORT      //上报第一个点

ABS_MT_TOUCH_MAJOR

ABS_MT_PRESSURE

ABS_MT_POSITION_X

ABS_MT_POSITION_Y

SYN_MT_REPORT      //上报第二个点

... //以上顺序组织多点touch event即可

SYN_REPORT         //最后发送的完整包动作

代码演示:

for(pointIndex=0;pointIndex<imtEvent->pointnums;pointIndex++)

{

/* 触摸屏键按下坐标定位  */

event.type  = EV_ABS;

event.code  = ABS_MT_POSITION_X;

event.value = imtEvent->pointers[pointIndex].abs_x;

write(fd,&event,sizeof(event)) ;

event.type  = EV_ABS;

event.code  = ABS_MT_POSITION_Y;

event.value = imtEvent->pointers[pointIndex].abs_y;

write(fd,&event,sizeof(event)) ;

    /* 触摸屏接触面的压力大小 */

event.type  = EV_ABS;

    event.code  = ABS_MT_PRESSURE;

    event.value = imtEvent->pointers[pointIndex].abs_pressure;

    write(fd,&event,sizeof(event)) ;

/* 触摸屏接触面积大小 */

event.type   = EV_ABS;

event.code   = ABS_MT_TOUCH_MAJOR;

event.value  = imtEvent->pointers[pointIndex].abs_touch_major;

event.type  = EV_SYN;

event.code  = SYN_MT_REPORT;

event.value = 0;

write(fd,&event,sizeof(event)) ;

}

/* 结束完整帧数据,发送同步信号 */

event.type  = EV_SYN;

event.code  = SYN_REPORT;

event.value = 0;

write(fd,&event,sizeof(event)) ;

Ok,只要深入研究下inputreader.cpp的代码即可轻松解决这些问题,更扩展的功能扩大及缩小,以及旋转的功能都可以搞定。

对于多点触摸的功能,首先在linux内核的input输入模型需要支持,这个在linux/input.h可以见到,多点触摸功能依赖于以下几个主要的软件位:

#define ABS_MT_TOUCH_MAJOR 0x30/* Major axis of touching ellipse */ 

#define ABS_MT_TOUCH_MINOR 0x31/* Minor axis (omit if circular) */ 

#define ABS_MT_WIDTH_MAJOR 0x32/* Major axis of approaching ellipse */ 

#define ABS_MT_WIDTH_MINOR 0x33/* Minor axis (omit if circular) */ 

#define ABS_MT_ORIENTATION 0x34/* Ellipse orientation */ 

#define ABS_MT_POSITION_X 0x35/* Center X ellipse position */ 

#define ABS_MT_POSITION_Y 0x36/* Center Y ellipse position */ 

#define ABS_MT_TOOL_TYPE 0x37/* Type of touching device */ 

#define ABS_MT_BLOB_ID 0x38/* Group a set of packets as a blob */

第二部分:利用linux input输入模型发送

主要函数介绍:

static inline void input_report_abs(struct input_dev *dev, unsigned int code, int value)

{

input_event(dev, EV_ABS, code, value);

}

static inline void input_mt_sync(struct input_dev *dev)

{

input_event(dev, EV_SYN, SYN_MT_REPORT, 0);

}

static inline void input_sync(struct input_dev *dev)

{

input_event(dev, EV_SYN, SYN_REPORT, 0);

}

代码示例:

设定初始参数(支持单点触摸及多点触摸):

    set_bit(EV_SYN, ts->input_dev->evbit);

    set_bit(EV_KEY, ts->input_dev->evbit);

    set_bit(EV_ABS, ts->input_dev->evbit);

    set_bit(BTN_TOUCH,ts->input_dev->keybit);

    

    max_x = 1280;

    max_y = 720;

    

    input_set_abs_params(ts->input_dev, ABS_X, 0, max_x, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_Y, 0, max_y, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_PRESSURE, 0, 255, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_TOOL_WIDTH, 0, 15, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X, 0, max_x, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y, 0, max_y, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0);

    input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0); 

    input_register_device(ts->input_dev);    

按下时:

for(i=0;i<finger;i++){

    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 1);

    input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 100);

    input_report_abs(ts->input_dev, ABS_MT_POSITION_X, ts->x[i]);

    input_report_abs(ts->input_dev, ABS_MT_POSITION_Y, ts->y[i]);

    input_mt_sync(ts->input_dev);

    ts->upsend=0;

}

input_sync(ts->input_dev);

弹起时:

    input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);

    input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);

    input_mt_sync(ts->input_dev);

    input_sync(ts->input_dev);


from:http://www.open-open.com/lib/view/open1328192180734.html

原创粉丝点击