zoukankan      html  css  js  c++  java
  • android 多点

    引用:http://blog.163.com/fenglang_2006/blog/static/13366231820108205274325/

    第一章摘要

    Linux内核支持的基础上,Android在其2.0源码中加入多点触摸功能。由此触摸屏在Androidframeworks被完全分为2种实现途径:单点触摸屏的单点方式,多点触摸屏的单点和多点方式。

    第二章软件位

    Linuxinput.h中,多点触摸功能依赖于以下几个主要的软件位:

    ………………………..

    #define SYN_REPORT0

    #define SYN_CONFIG1

    #define SYN_MT_REPORT2

    ………………………...

    #define ABS_MT_TOUCH_MAJOR0x30/* Major axis of touching ellipse */

    #define ABS_MT_TOUCH_MINOR0x31/* Minor axis (omit if circular) */

    #define ABS_MT_WIDTH_MAJOR0x32/* Major axis of approaching ellipse */

    #define ABS_MT_WIDTH_MINOR0x33/* Minor axis (omit if circular) */

    #define ABS_MT_ORIENTATION0x34/* Ellipse orientation */

    #define ABS_MT_POSITION_X0x35/* Center X ellipse position */

    #define ABS_MT_POSITION_Y0x36/* Center Y ellipse position */

    #define ABS_MT_TOOL_TYPE0x37/* Type of touching device */

    #define ABS_MT_BLOB_ID0x38/* Group a set of packets as a blob */

    …………………………

    Android中对应的软件位定义在RawInputEvent.java:

    …………………..

    public class RawInputEvent {

    ……………….

      public static final int CLASS_TOUCHSCREEN_MT = 0x00000010;

    ………………..

      public static final int ABS_MT_TOUCH_MAJOR = 0x30;

      public static final int ABS_MT_TOUCH_MINOR = 0x31;

      public static final int ABS_MT_WIDTH_MAJOR = 0x32;

      public static final int ABS_MT_WIDTH_MINOR = 0x33;

      public static final int ABS_MT_ORIENTATION = 0x34;

      public static final int ABS_MT_POSITION_X = 0x35;

      public static final int ABS_MT_POSITION_Y = 0x36;

      public static final int ABS_MT_TOOL_TYPE = 0x37;

      public static final int ABS_MT_BLOB_ID = 0x38;

    ………………….

    public static final int SYN_REPORT = 0;

      public static final int SYN_CONFIG = 1;

    public static final int SYN_MT_REPORT = 2;

    ………………..

    Android中,多点触摸的实现方法在具体的代码实现中和单点是完全区分开的。在Android代码的EventHub.cpp中,单点屏和多点屏由如下代码段来判定:

    int EventHub::open_device(const char *deviceName)

    {

    ………………………

    if (test_bit(ABS_MT_TOUCH_MAJOR, abs_bitmask)

    && test_bit(ABS_MT_POSITION_X, abs_bitmask)

    && test_bit(ABS_MT_POSITION_Y, abs_bitmask)) {

    device->classes |= CLASS_TOUCHSCREEN | CLASS_TOUCHSCREEN_MT;

    //LOGI("It is a multi-touch screen!");

    //single-touch?

    else if (test_bit(BTN_TOUCH, key_bitmask)

    && test_bit(ABS_X, abs_bitmask) 

    && test_bit(ABS_Y, abs_bitmask)) {

    device->classes |= CLASS_TOUCHSCREEN;

    //LOGI("It is a single-touch screen!");

    }

    ………………..

    }

    我们知道,在触摸屏驱动中,通常在probe函数中会调用input_set_abs_params给设备的input_dev结构体初始化,这些input_dev的参数会在AndroidEventHub.cpp中被读取。如上可知,如果我们的触摸屏想被当成多点屏被处理,只需要在驱动中给input_dev额外增加以下几个参数即可:

    input_set_abs_params(mcs_data.input, ABS_MT_POSITION_X, pdata->abs_x_min,  pdata->abs_x_max, 0, 0);

    input_set_abs_params(mcs_data.input, ABS_MT_POSITION_Y, pdata->abs_y_min,  pdata->abs_y_max, 0, 0);

    input_set_abs_params(mcs_data.input, ABS_MT_TOUCH_MAJOR, 0, 15, 0, 0);

                    //相当于单点屏的ABX_PRESSURE

    input_set_abs_params(mcs_data.input, ABS_MT_WIDTH_MAJOR, 0, 15, 0, 0); 

    //相当于单点屏的ABS_TOOL_WIDTH

    注:

    为了让我们的驱动代码支持所有的Android版本,无论是多点屏还是单点屏,一般都会保留单点屏的事件,如ABS_TOUCH, ABS_PRESSURE, ABS_X, ABS_Y等。另外,由于在Android2.0前支持多点的frameworks大多是用HAT0X,HAT0Y来实现的,所以一般也会上报这2个事件。

    第三章同步方式

    由于多点触摸技术需要采集到多个点,然后再一起处理这些点,所以在软件实现中需要保证每一波点的准确性和完整性。因此,Linux内核提供了input_mt_sync(struct input_dev * input)函数。在每波的每个点上报后需要紧跟一句input_mt_sync(), 当这波所有点上报后再使用input_sync()进行同步。例如一波要上报3个点:

    /* 上报点1*/

    ……………..

    input_mt_sync(input);

    /* 上报点2*/

    ……………..

    input_mt_sync(input);

    /* 上报点3*/

    ……………..

    input_mt_sync(input);

    input_sync(input);

    注:即使是仅上报一个点的单点事件,也需要一次input_my_sync

    第四章触摸事件数组的处理

    上面我们曾说到generateAbsMotion这个方法,它们在InputDevice类的内部类MotionState中实现,该类被定义为InputDevice类的静态成员类(static class),调用它们可以直接使用:

    InputDeviceClass.MotionStateClass.generateAbsMotion()

    public class InputDevice {

     ……………………………

    static class MotionState {//下面是这个内部类的几个函数

     ……………………………….

    /* mLastNumPointers 为上一个动作在触屏上按键的个数 */

    int mLastNumPointers = 0;

    final int[] mLastData = new int[MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS];

    /* mNextNumPointers 为下一个动作在触屏上按键的个数 */

    /* 通过对这2个值大小的判断,可以确认新的动作方式 */

    int mNextNumPointers = 0;

    final int[] mNextData = new int[(MotionEvent.NUM_SAMPLE_DATA * MAX_POINTERS) 

    + MotionEvent.NUM_SAMPLE_DATA];

    ………………………………….

        int[] generateAveragedData(int upOrDownPointer, int lastNumPointers,

                    int nextNumPointers) { //平滑处理

        …………………………………….

        }

        private boolean assignPointer(int nextIndex, boolean allowOverlap) {//指派按键

        ……………………………………

        }

        private int updatePointerIdentifiers() {//更新按键ID

        ………………………………….

        }

        void removeOldPointer(int index) {

        ……………………………………

        }

        MotionEvent generateAbsMotion(InputDevice device, long curTime,

                    long curTimeNano, Display display, int orientation,

                    int metaState) {

        ……………………………………

    int upOrDownPointer = updatePointerIdentifiers();

        final int numPointers = mLastNumPointers;

        ………………………………………

        /* 对行为的判断 */

              if (nextNumPointers != lastNumPointers) { //前后在触屏上点个数不同,说明有手指updown

                    if (nextNumPointers > lastNumPointers) { 

                        if (lastNumPointers == 0) { //上次触屏上没有按键,新值又大,说明有按键按下

                            action = MotionEvent.ACTION_DOWN;

                            mDownTime = curTime;

                        } else {//有新点按下,分配给新点ID

                            action = MotionEvent.ACTION_POINTER_DOWN

                                    | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);

                        }

                    } else {//新动作比原来pointer数量少

                        if (numPointers == 1) { //原来只有1个点按下,所以现在的动作是全部按键up

                            action = MotionEvent.ACTION_UP;

                        } else { //原来有多点按下,现在是ACTION_POINTER_UP动作,

                            action = MotionEvent.ACTION_POINTER_UP

                                    | (upOrDownPointer << MotionEvent.ACTION_POINTER_ID_SHIFT);

                        }

                    }

                    currentMove = null;

               } else { //前后触屏pointer个数相同,所以是移动动作ACTION_MOVE

                    action = MotionEvent.ACTION_MOVE;

               }

       /* 后面则是根据屏幕的heightwidth以及屏幕方向orientation对这些点进行二次处理 */

        ……………………………………

        }

    MotionEvent generateRelMotion(InputDevice device, long curTime,

                    long curTimeNano, int orientation, int metaState) {

    /* 轨迹球等的处理方式 */

       …………………………………………..

       }

       void finish() {      //结束这轮动作

                mNextNumPointers = mAddingPointerOffset = 0;

                mNextData[MotionEvent.SAMPLE_PRESSURE] = 0;

       }

    …………………………………….

    }

    ……………………………….

    ……………………………………

    }

    第五章接口

    我们平时所看到的用2个手指对图片放大缩小、旋转等手势都是由应用程序编写浏览器实现的。这些应用程序大多会使用Android2.0以上的在MotionEvent.java中实现的新的接口。所以,我们还需要给MotionEvent类补充尽量全的接口。这里可以完全参照google新的android代码。

    第六章总结

    综上,在硬件支持基础上,Android1.6如果要实现多点触摸功能,主要工作可简述为以下几个方面:

    1、 驱动中,除了增加多点的事件上报方式,还要完全更改单点的事件上报方式。

    2、 AndroidFrameworks层需要修改的文件有:EventHub.cppRawInputEvent.javaKeyInputQueue.javaInputDevice.javaMotionEvent.java

    3、 编写新的支持多点触摸功能的多媒体浏览器。

    4、 为了代码简练,android2.0在轨迹球和单点屏事件方式中也全使用了新的变量名,以方便多点屏事件同样能使用这些变量,所以修改时还需要注意许多细节方面。

  • 相关阅读:
    一道编程面试题
    AtCoder Grand Contest 016 B
    AtCoder Regular Contest 076 D
    Codeforces Round #419 (Div. 2) B. Karen and Coffee
    2017 计蒜之道 复赛 Windows画图+百度地图导航
    Codeforces Round #418 (Div. 2) B. An express train to reveries
    棠梨煎雪
    Bits And Pieces
    Let Them Slide
    TeaTree
  • 原文地址:https://www.cnblogs.com/sode/p/3146134.html
Copyright © 2011-2022 走看看