【android 9】【input】【11.发送普通motion事件1——touch设备的加载——MultiTouchInputMapper】

news2024/9/22 19:45:10

系列文章目录

 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm=1001.2014.3001.5501


目录

系列文章目录

1.简介

1.1流程介绍

1.2 时序图

2.touch设备的加载和配置流程分析

2.1 InputReader::loopOnce

2.2 EventHub::getEvents

2.3 scanDevicesLocked

2.4 scanDirLocked

2.5 openDeviceLocked

2.6 EventHub::loadConfigurationLocked

 2.7 getInputDeviceConfigurationFilePathByDeviceIdentifier

 2.8 getInputDeviceConfigurationFilePathByName

 2.9 appendInputDeviceConfigurationFileRelativePath

 2.10 PropertyMap::load

2.11 loadVirtualKeyMapLocked

2.12 registerDeviceForEpollLocked

2.13 processEventsLocked

2.14 addDeviceLocked

2.15 createDeviceLocked

2.16 MultiTouchInputMapper

 2.17 InputDevice::configure

2.18 TouchInputMapper::configure

2.19 TouchInputMapper::configureParameters

2.20 CursorScrollAccumulator::configure

2.21 TouchButtonAccumulator::configure

2.22 MultiTouchInputMapper::configureRawPointerAxes

2.23 InputMapper::getAbsoluteAxisInfo

2.24 EventHub::getAbsoluteAxisInfo

2.25 MultiTouchMotionAccumulator::configure

2.26 TouchInputMapper::parseCalibration

2.27 TouchInputMapper::resolveCalibration

2.28 TouchInputMapper::configureSurface

2.29 InputReaderConfiguration::getDisplayViewport

2.30 TouchInputMapper::configureVirtualKeys

3.重要的类型

3.1 Parameters

3.2 Calibration

3.3 RawPointerAxes

3.4 RawAbsoluteAxisInfo

3.5 InputReaderConfiguration


1.简介

     从之前的篇幅我们知道了,事件分为设备增删事件和原始输入事件,而原始输入事件主要有两种,一种是key按键事件的派发,一种是触摸事件的派发。Key事件的派发我们已经分析过了,本篇主要针对motion事件的派发。想要了解motion事件的派发,首先需要了解到touch设备的是如何加载的,本篇和前文的input设备流程相同,只是对于触摸屏的配置进行了更详细的描述。如MultiTouchInputMapper的创建过程。

1.1流程介绍

第一步:经过前面几篇文章我们知道,在开机启动后,input系统也在systemserver进程中被拉起,InputReader线程中的loopOnce会执行,loopOnce会执行getEvents函数,此函数在设备刚启动时,会调用scanDevicesLocked函数扫描/dev/input下的所有输入设备。
 
第二步:当扫描到/dev/input/xxx的设备时,会调用openDeviceLocked函数打开设备节点,并从中读取设备的厂商信息,如触摸屏配置文件路径等。

第三步:然后会调用loadConfigurationLocked去加载指定路径的配置文件将里面的内容加载到对应的map中,如触摸屏的Vendor_xxxx_Product_xxxx.idc文件。

第四步:会此设备注册到epoll中监听设备的原始输入事件。

第五步:生成设备添加事件。

第六步:processEventsLocked处理设备添加事件。此时会根据设备创建多个mapper对象,以触摸屏为例子,则会创建MultiTouchInputMapper对象。

第七步:然后便是对MultiTouchInputMapper进行配置,会调用configure函数。
              此函数有以下几个作用:
              1.对触摸屏判断多触摸还是单触摸,触摸设备是触摸屏还是触摸平板等
              2.读取屏幕的信息,构建物理坐标系,如x和y的范围等信息。
              3.准备输入设备的校准,即mConfiguration中读取大小,方向,压力等值。
              4. 配置device source、Surface尺寸、方向和缩放比例。完成物理坐标系到屏幕坐标系的转化。

第八步:等待触摸事件的到来。

1.2 时序图

 (为了完整的画出时序图,较为模糊,可保存到本地放大查看)

2.touch设备的加载和配置流程分析

首先我们从前文知道当input系统第一次启动时,会扫描/dev/input下的所有设备节点,然后读取所有设备节点的信息,并生成对应的mapper对象,那么本篇便来分析常用的触摸屏的加载具体会做些什么。

首先从启动篇我们知道,启动后,inputreader线程会执行loopOnce函数。前面的内容在启动篇已经介绍过了,所以本篇我们便从此处开始分析。

2.1 InputReader::loopOnce

主要作用为:

1. 通过EventHub的getEvents函数获取add设备事件。

2. processEventsLocked处理设备事件。

3.发布事件,通知inputdispatcher线程去处理消息。

//第一次启动时,执行的代码块
void InputReader::loopOnce() {

 
    size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);//通过EventHub的getEvents函数获取事件,
	//并存放在mEventBuffer中。此时可以知道刚启动时,会生成所有已经扫描的设备的add类型的事件
	//参数分析:timeoutMillis=-1,如果数字为0代表立即执行 -1为一直阻塞
	//mEventBuffer是一个存放从eventhub中读取的rawevent结构体类型的数组,源代码是:RawEvent mEventBuffer[EVENT_BUFFER_SIZE];
	//EVENT_BUFFER_SIZE值是256,代表最大可以读取256个原始事件,RawEvent结构体如下
	从EventHub检索到的原始事件
	//struct RawEvent {
    //nsecs_t when;//时间
    //int32_t deviceId;//事件发生的设备id
    //int32_t type;//类型,例如按键事件等
    //int32_t code;//扫描码,按键对应的扫描码
    //int32_t value;//值,表示按键按下,或者抬起等
	//};
 

 
        if (count)
		{//返回的事件数量大于,则调用processEventsLocked处理事件
            processEventsLocked(mEventBuffer, count);
		}
		
 
        if (oldGeneration != mGeneration) 
		{//此处是不等于的,因为当有add设备事件时processEventsLocked函数中调用addDeviceLocked,addDeviceLocked在完成设备配置后
		//会调用bumpGenerationLocked函数,使得mGeneration+1,从而不相等
            inputDevicesChanged = true;
            getInputDevicesLocked(inputDevices);//获取所有的新的设备信息到inputDevices容器中
        }
 
 

    //发布事件。 一般此处只会处理加工后的原始输入事件,而此时开机启动只有触摸屏幕add设备事件
    mQueuedListener->flush();
}

2.2 EventHub::getEvents

主要作用为:
1.设备刚启动,调用scanDevicesLocked函数扫描/dev/input下的所有输入设备,用Device类保存其信息,并生成DEVICE_ADDED类型的事件(设备增加类型事件)放入消息数组中
2.返回存在设备增加事件的数组,让inputreader进行处理。

size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
 
 
    for (;;) {//死循环
        nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);//获取当前时间
 
 
 
        if (mNeedToScanDevices) {//默认值为true,即第一次调用getevent时,会扫描/dev/input下的设备
            mNeedToScanDevices = false;//设置为false,避免重复扫描设备
            scanDevicesLocked();//执行扫描设备的函数。扫描/dev/input下的设备
            mNeedToSendFinishedDeviceScan = true;//mNeedToSendFinishedDeviceScan值为true,用于生成FINISHED_DEVICE_SCAN事件
        }
 
        while (mOpeningDevices != NULL) {
            Device* device = mOpeningDevices;//此时mOpeningDevices值是刚打开过的device
            mOpeningDevices = device->next;//device->next值为0,指向下一个设备
			//生成DEVICE_ADDED类型的事件,并通过event指针存放于buffer数组中
            event->when = now;
            event->deviceId = device->id == mBuiltInKeyboardId ? 0 : device->id;//如果是内置键盘,则其id为0,如果不是则是device->id
            event->type = DEVICE_ADDED;//类型
            event += 1;//event的定义是RawEvent* event = buffer,event指针指向传入的buffer数组的首地址,即第0个元素,
			//每存入一个事件,event指针向后移动一个元素
            mNeedToSendFinishedDeviceScan = true;
            if (--capacity == 0) {//buffer数组可容量-1
                break;
            }
        }
 
        if (mNeedToSendFinishedDeviceScan) {
            mNeedToSendFinishedDeviceScan = false;
			//生成FINISHED_DEVICE_SCAN类型的事件,并通过event指针存放于buffer数组中
            event->when = now;
            event->type = FINISHED_DEVICE_SCAN;
            event += 1;
            if (--capacity == 0) {
                break;
            }
        }
 
        
        bool deviceChanged = false;
		
 
 
        // 当event的指针不再指向buffer的首地址时,代表里面有数据,或者被唤醒时,立即退出循环
        if (event != buffer || awoken) {//此时生成了两种事件,一个是扫描的所有打开设备的事件,还有一个是完成设备扫描报告的事件,故退出循环
            break;
        }
    }
    // 全部完成后,返回我们读取的事件数。
    return event - buffer;
}

2.3 scanDevicesLocked

void EventHub::scanDevicesLocked() {
    status_t res = scanDirLocked(DEVICE_PATH);//调用scanDirLocked方法,DEVICE_PATH=/dev/input,返回0代表成功
 
    if (mDevices.indexOfKey(VIRTUAL_KEYBOARD_ID) < 0) {//
	//mDevices的定义是一个map容器,KeyedVector<int32_t, Device*> mDevices;mDevices中存放的是已经扫描完成的设备,即
	//已经完成设备厂商信息的获取和注册进epoll监听的设备。VIRTUAL_KEYBOARD_ID的值等于-1
	//此处如果从mDevice中没有找到虚拟键盘,则调用createVirtualKeyboardLocked方法创建虚拟键盘。
        createVirtualKeyboardLocked();
    }
}

2.4 scanDirLocked

1.循环打开/dev/input下的所有设备节点。

status_t EventHub::scanDirLocked(const char *dirname)
{
    char devname[PATH_MAX];
    char *filename;
    DIR *dir;
    struct dirent *de;
    dir = opendir(dirname);
    if(dir == NULL)
        return -1;
    strcpy(devname, dirname);
    filename = devname + strlen(devname);
    *filename++ = '/';
    while((de = readdir(dir))) {//循环打开目录下的所有设备
        if(de->d_name[0] == '.' &&
           (de->d_name[1] == '\0' ||
            (de->d_name[1] == '.' && de->d_name[2] == '\0')))
            continue;
        strcpy(filename, de->d_name);
        openDeviceLocked(devname);//打开设备
    }
    closedir(dir);//关闭目录
    return 0;
}

2.5 openDeviceLocked

针对触摸屏的主要作用为:

主要作用为:

1.打开/dev/input/xxxx的设备,然后获取设备的驱动版本,设备产品,设备供应商,设备物理地址,设备标识符将信息保存到InputDeviceIdentifier类的identifier对象中,此对象主要用于存储设备厂商的所有信息。

2.假设此时有一个设备/dev/input/event0,根据其dentifier对象生成对应的Device类对象。然后加载设备的配置文件到device类对象的PropertyMap中。

      配置文件主要有三类。

       一.idc文件,主要用于触摸屏配置。

       二.kl文件,主要用于键盘的扫描码和keycode的转化。

       三.kcm文件,主要作用是将 Android按键代码与修饰符的组合映射到 Unicode。

3.从设备的fd中读取数据判断其设备类型为EV_KEY、EV_ABS、EV_REL、EV_SW、EV_LED、EV_FF类型。

            一:EV_KEY,按键类型的事件。能够上报这类事件的设备有键盘、鼠标、手柄、手写板
            等一切拥有按钮的设备(包括手机上的实体按键)。在Device结构体中,对应的事件
            位掩码keyBitmask描述了设备可以产生的按键事件的集合。按键事件的全集包括字
            符按键、方向键、控制键、鼠标键、游戏按键等。


            二:EV_ABS,绝对坐标类型的事件。这类事件描述了在空间中的一个点,触控板、触
            摸屏等使用绝对坐标的输入设备可以上报这类事件。事件位掩码absBitmask描述了
            设备可以上报的事件的维度信息(ABS_X、ABS_Y、ABS_Z),以及是否支持多点
            事件。


            三:EV_REL,相对坐标类型的事件。这类事件描述了事件在空间中相对于上次事件
            的偏移量。鼠标、轨迹球等基于游标指针的设备可以上报此类事件。事件位掩码
            relBitmask描述了设备可以上报的事件的维度信息(REL_X、REL_Y、REL_Z)。


            四:EV_SW,开关类型的事件。这类事件描述了若干固定状态之间的切换。手机上的静
            音模式开关按钮、模式切换拨盘等设备可以上报此类事件。事件位掩码swBitmask表
            示了设备可切换的状态列表。

            五:EV_LED,光反馈类型事件。ledBitmask描述了设备是否支持光
            六:EV_FF,力反馈类型,ffBitmask则描述了设备是否支持力反馈。

4.根据上诉大类型,生成更细分的类型——INPUT_DEVICE_CLASS_xxx类型。如L按键事件可再通过有无X,y比特位,区分是键盘还是蓝牙手柄。

            一:INPUT_DEVICE_CLASS_KEYBOARD,可以上报鼠标按键以外的EV_KEY类型事件的设备都属于此类。如键盘、机身按钮(音量键、电源键等)。


            二:INPUT_DEVICE_CLASS_ALPHAKEY,可以上报字符按键的设备,例如键盘。此类   型的设备必定同时属于KEYBOARD。


           三:INPUT_DEVICE_CLASS_DPAD,可以上报方向键的设备。例如键盘、手机导航键

等。这类设备同时也属于KEYBOARD。


            四:INPUT_DEVICE_CLASS_GAMEPAD,可以上报游戏按键的设备,如游戏手柄。这类设备同时也属于KEYBOARD。


            五:INPUT_DEVICE_CLASS_TOUCH,可以上报EV_ABS类型事件的设备都属于此类,如触摸屏和触控板。


            六:INPUT_DEVICE_CLASS_TOUCH_MT,可以上报EV_ABS类型事件,并且其事件位掩码指示其支持多点事件的设备属于此类。例如多点触摸屏。这类设备同时也属于TOUCH类型。
            七:INPUT_DEVICE_CLASS_CURSOR,可以上报EV_REL类型的事件,并且可以上报BTN_MOUSE子类的EV_KEY事件的设备属于此类,例如鼠标和轨迹球。


            八:INPUT_DEVICE_CLASS_SWITCH,可以上报EV_SW类型事件的设备。


            九:INPUT_DEVICE_CLASS_JOYSTICK,属于GAMEPAD类型,并且属于TOUCH类型的设备。


            十:INPUT_DEVICE_CLASS_VIBRATOR,支持力反馈的设备。


            十一:INPUT_DEVICE_CLASS_VIRTUAL,虚拟设备。


            十二:INPUT_DEVICE_CLASS_EXTERNAL,外部设备,即非内建设备。如外接鼠标、键盘、游戏手柄等。

5.然后注册设备节点到epoll中,开始监听各个设备节点下是否有可读事件,即监听此设备的原始输入事件。

status_t EventHub::openDeviceLocked(const char *devicePath) {
    char buffer[80];
 
    int fd = open(devicePath, O_RDWR | O_CLOEXEC | O_NONBLOCK);//以读写,非阻塞,原子方式打开设备
	//打开设备节点的文件描述符,用于获取设备信息以及读取原始输入事件
	
	
 
    InputDeviceIdentifier identifier;//存储厂商的信息
	//接下来的代码通过ioctl()函数从设备节点中获取输入设备的厂商信息
	
    if(ioctl(fd, EVIOCGNAME(sizeof(buffer) - 1), &buffer) < 1) {//通过设备的fd,向驱动发送EVIOCGNAME指令,
	//获取设备名称,写入buffer中
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.name.setTo(buffer);//从buffer中取出名称信息,赋值给identifier的name属性
    }
 
    // 检查获取的设备名称是否在排除列表中下
    for (size_t i = 0; i < mExcludedDevices.size(); i++) {// 检查获取的设备名称是否在排除列表中下,
	//如果在mExcludedDevices列表中,则关闭此设备,并返回,mExcludedDevices列表在setExcludedDevices方法中赋值的,
	//而setExcludedDevices方法是在inputreader构造函数中的refreshConfigurationLocked方法中调用的,
	//同时mExcludedDevices最后是调用到java层ims中获取的。
        const String8& item = mExcludedDevices.itemAt(i);
        if (identifier.name == item) {
            ALOGI("ignoring event id %s driver %s\n", devicePath, item.string());
            close(fd);
            return -1;
        }
    }
 
    //获取设备驱动版本
    int driverVersion;
    if(ioctl(fd, EVIOCGVERSION, &driverVersion)) {//从驱动中获取的信息赋值给driverVersion
        ALOGE("could not get driver version for %s, %s\n", devicePath, strerror(errno));
        close(fd);
        return -1;
    }
 
    //获取设备标识符
    struct input_id inputId;
    if(ioctl(fd, EVIOCGID, &inputId)) {//赋值给inputId
        ALOGE("could not get device input id for %s, %s\n", devicePath, strerror(errno));
        close(fd);
        return -1;
    }
    identifier.bus = inputId.bustype;
    identifier.product = inputId.product;//设备产品
    identifier.vendor = inputId.vendor;//供应商
    identifier.version = inputId.version;//版本
 
    // 获取设备物理地址
    if(ioctl(fd, EVIOCGPHYS(sizeof(buffer) - 1), &buffer) < 1) {//放于buffer中
        //fprintf(stderr, "could not get location for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.location.setTo(buffer);//赋值给location
    }
 
    //获取设备唯一的id
    if(ioctl(fd, EVIOCGUNIQ(sizeof(buffer) - 1), &buffer) < 1) {
        //fprintf(stderr, "could not get idstring for %s, %s\n", devicePath, strerror(errno));
    } else {
        buffer[sizeof(buffer) - 1] = '\0';
        identifier.uniqueId.setTo(buffer);//赋值给uniqueId
    }
 
    
    assignDescriptorLocked(identifier);//将identifier信息填充到fd,分配唯一标识设备的设备描述符,主要作用是填写identifier.nonce字段。
 
    // 分配device,device对象获取fd的所有权
    int32_t deviceId = mNextDeviceId++;//mNextDeviceId初始值为1,故deviceId=1
    Device* device = new Device(fd, deviceId, String8(devicePath), identifier);
	//参数分析:
	//此处结合是getevent工具分析的
	//fd是dev/input/event0的设备的描述符
	//deviceid=1
	//devicePath=dev/input/event0
	//identifier存储了此设备所有的厂商信息
	
 
    
    loadConfigurationLocked(device);//加载device的配置文件。主要是例如:device.type和device.internal等信息
 
    // 详细事件报告的类型,从fd对应的device中读取各种信息,并保存到device的keyBitmask或absBitmask中,
	//例如:如果是键盘设备,则device->keyBitmask有数据,而device->absBitmask无数据
    ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(device->keyBitmask)), device->keyBitmask);//按键类型
    ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(device->absBitmask)), device->absBitmask);//绝对坐标类型
    ioctl(fd, EVIOCGBIT(EV_REL, sizeof(device->relBitmask)), device->relBitmask);//相对坐标类型,只要用于motion
    ioctl(fd, EVIOCGBIT(EV_SW, sizeof(device->swBitmask)), device->swBitmask);//开关类型
    ioctl(fd, EVIOCGBIT(EV_LED, sizeof(device->ledBitmask)), device->ledBitmask);//led等类型
    ioctl(fd, EVIOCGBIT(EV_FF, sizeof(device->ffBitmask)), device->ffBitmask);//力反馈类型
    ioctl(fd, EVIOCGPROP(sizeof(device->propBitmask)), device->propBitmask);
	//Device结构体的事件位掩码描述了6种类型的输入事件: 
    //EV_KEY,按键类型的事件。能够上报这类事件的设备有键盘、鼠标、手柄、手写板 
            //等一切拥有按钮的设备(包括手机上的实体按键)。在Device结构体中,对应的事件 
            //位掩码keyBitmask描述了设备可以产生的按键事件的集合。按键事件的全集包括字 
            //符按键、方向键、控制键、鼠标键、游戏按键等。 
    //EV_ABS,绝对坐标类型的事件。这类事件描述了在空间中的一个点,触控板、触 
            //摸屏等使用绝对坐标的输入设备可以上报这类事件。事件位掩码absBitmask描述了 
            //设备可以上报的事件的维度信息(ABS_X、ABS_Y、ABS_Z),以及是否支持多点 
            //事件。 
    //EV_REL,相对坐标类型的事件。这类事件描述了事件在空间中相对于上次事件 
            //的偏移量。鼠标、轨迹球等基于游标指针的设备可以上报此类事件。事件位掩码 
            //relBitmask描述了设备可以上报的事件的维度信息(REL_X、REL_Y、REL_Z)。 
    //EV_SW,开关类型的事件。这类事件描述了若干固定状态之间的切换。手机上的静 
            //音模式开关按钮、模式切换拨盘等设备可以上报此类事件。事件位掩码swBitmask表 
            //示了设备可切换的状态列表。
	//EV_LED,光反馈类型事件。ledBitmask描述了设备是否支持光 
	//EV_FF,力反馈类型,ffBitmask则描述了设备是否支持力反馈。
	
	
	
	//INPUT_DEVICE_CLASS_KEYBOARD,可以上报鼠标按键以外的EV_KEY类型事件的设备都属于此类。如键 
            //盘、机身按钮(音量键、电源键等)。 
    //INPUT_DEVICE_CLASS_ALPHAKEY,可以上报字符按键的设备,例如键盘。此类型的设备必定同时属于KEYBOARD。 
    //INPUT_DEVICE_CLASS_DPAD,可以上报方向键的设备。例如键盘、手机导航键等。这类设备同时也属于KEYBOARD。 
    //INPUT_DEVICE_CLASS_GAMEPAD,可以上报游戏按键的设备,如游戏手柄。这类设备同时也属于KEYBOARD。 
    //INPUT_DEVICE_CLASS_TOUCH,可以上报EV_ABS类型事件的设备都属于此类,如触摸屏和触控板。 
    //INPUT_DEVICE_CLASS_TOUCH_MT,可以上报EV_ABS类型事件,并且其事件位掩码指示其支持多点事件 
            //的设备属于此类。例如多点触摸屏。这类设备同时也属于TOUCH类型。 
    //INPUT_DEVICE_CLASS_CURSOR,可以上报EV_REL类型的事件,并且可以上报BTN_MOUSE子类的 
            //EV_KEY事件的设备属于此类,例如鼠标和轨迹球。 
    //INPUT_DEVICE_CLASS_SWITCH,可以上报EV_SW类型事件的设备。 
    //INPUT_DEVICE_CLASS_JOYSTICK,属于GAMEPAD类型,并且属于TOUCH类型的设备。 
    //INPUT_DEVICE_CLASS_VIBRATOR,支持力反馈的设备。 
    //INPUT_DEVICE_CLASS_VIRTUAL,虚拟设备。 
    //INPUT_DEVICE_CLASS_EXTERNAL,外部设备,即非内建设备。如外接鼠标、键盘、游戏手柄等。
 
 



 
    //通过查看device->absBitmask,查看这是不是触摸板。
    if (test_bit(ABS_MT_POSITION_X, device->absBitmask)
            && test_bit(ABS_MT_POSITION_Y, device->absBitmask)) {
        if (test_bit(BTN_TOUCH, device->keyBitmask) || !haveGamepadButtons) {//尝试确认设备确实触摸屏。
            device->classes |= INPUT_DEVICE_CLASS_TOUCH | INPUT_DEVICE_CLASS_TOUCH_MT;
        }
    // 查看这是不是旧式的单触的驱动
    } else if (test_bit(BTN_TOUCH, device->keyBitmask)
            && test_bit(ABS_X, device->absBitmask)
            && test_bit(ABS_Y, device->absBitmask)) {
        device->classes |= INPUT_DEVICE_CLASS_TOUCH;
    } 
 

    // 如果是触摸屏,则为其配置虚拟键盘
    if ((device->classes & INPUT_DEVICE_CLASS_TOUCH)) {
        //加载触摸屏的虚拟键(如果有)。
        status_t status = loadVirtualKeyMapLocked(device);//loadVirtualKeyMapLocked函数的作用大致为
		//加载系统提供的虚拟键盘的文件,然后将其键值对保存到virtualKeyMap中
        if (!status) {
            device->classes |= INPUT_DEVICE_CLASS_KEYBOARD;
        }
    }
 

 
    // 配置键盘、游戏板或虚拟键盘。
    if (device->classes & INPUT_DEVICE_CLASS_KEYBOARD) {
        
        if (!keyMapStatus
                && mBuiltInKeyboardId == NO_BUILT_IN_KEYBOARD//表示此时并未任何内置键盘配置过
                && isEligibleBuiltInKeyboard(device->identifier,
                        device->configuration, &device->keyMap)) //如果符合条件,会将键盘注册为内置键盘,
		//然后device->keyMap保存着键盘映射表信息
		{
            mBuiltInKeyboardId = device->id;//mBuiltInKeyboardId内置键盘id,如果是第一次打开设备,则此时id为1
        }
    }
 


 
 
    if (registerDeviceForEpollLocked(device) != OK) {//将设备节点描述符的可读事件添加到Epoll中,
	//当此设备的输入事件到来时,Epoll会在getEvents()函数的调用中产生一条epoll事件
        delete device;
        return -1;
    }
 
    configureFd(device);//给device对应的设备,通过ioctl设置重复设置为禁用
 
 
    addDeviceLocked(device);//将设备添加到Device容器中
    return OK;
}

2.6 EventHub::loadConfigurationLocked

1.通过getInputDeviceConfigurationFilePathByDeviceIdentifier拼接字符串找到对应的/vendor/usr/idc/Vendor_xxxx_Product_xxxx.idc文件
2.从指定的/vendor/usr/idc/Vendor_xxxx_Product_xxxx.id路径下加载信息到PropertyMap中。

void EventHub::loadConfigurationLocked(Device* device) {
    device->configurationFile = getInputDeviceConfigurationFilePathByDeviceIdentifier(//从供应商信息中获取此设备的device配置文件
            device->identifier, INPUT_DEVICE_CONFIGURATION_FILE_TYPE_CONFIGURATION);
			//此时configurationFile的值是/vendor/usr/idc/Vendor_xxxx_Product_xxxx.idc
    if (device->configurationFile.isEmpty()) {//如果供应商信息的文件为空
        ALOGD("No input device configuration file found for device '%s'.",
                device->identifier.name.string());
    } else {
        status_t status = PropertyMap::load(device->configurationFile,
                &device->configuration);//源文件路径为device->configurationFile=/vendor/usr/idc/Vendor_xxxx_Product_xxxx.idc,
				//读取属性并输出到device->configuration这个PropertyMap下
        if (status) {
            ALOGE("Error loading input device configuration file for device '%s'.  "
                    "Using default configuration.",
                    device->identifier.name.string());
        }
    }
}

 2.7 getInputDeviceConfigurationFilePathByDeviceIdentifier

1.先查找Vendor_xxx_Product_xxx_Version_xxx.idc格式的idc,再查找Vendor_xxx_Product_xxx.idc格式的idc,最后根据deice名称获取配置文件路径.

//先查找Vendor_xxx_Product_xxx_Version_xxx.idc
//然后查找Vendor_xxx_Product_xxx.idc
//此函数的返回值是/vendor/usr/idc/Vendor_xxxx_Product_xxxx.idc
String8 getInputDeviceConfigurationFilePathByDeviceIdentifier(const InputDeviceIdentifier& deviceIdentifier,InputDeviceConfigurationFileType type) {
    if (deviceIdentifier.vendor !=0 && deviceIdentifier.product != 0) {
        if (deviceIdentifier.version != 0) {//根据vendor,product,version获取配置文件路径
            // Try vendor product version.
            String8 versionPath(getInputDeviceConfigurationFilePathByName(
                    String8::format("Vendor_%04x_Product_%04x_Version_%04x",//拼接字符串为此格式,一般为此类名字为
                            deviceIdentifier.vendor, deviceIdentifier.product,
                            deviceIdentifier.version),
                    type));
            if (!versionPath.isEmpty()) {
                return versionPath;
            }
        }

        // Try vendor product.
        String8 productPath(getInputDeviceConfigurationFilePathByName(//根据vendor和product获取配置文件路径
                String8::format("Vendor_%04x_Product_%04x",
                        deviceIdentifier.vendor, deviceIdentifier.product),
                type));
        if (!productPath.isEmpty()) {
            return productPath;
        }
    }

    // Try device name.
    return getInputDeviceConfigurationFilePathByName(deviceIdentifier.name, type);//根据deice名称获取配置文件路径
}

 2.8 getInputDeviceConfigurationFilePathByName

1.组装文件的完整路径和名称。

//大部分时候vendor和odm下是没有的,一般是在system下指定idc,名称为Vendor_054c_Product_09cc.idc
String8 getInputDeviceConfigurationFilePathByName(const String8& name, InputDeviceConfigurationFileType type) {
    // Search system repository.
	//搜索系统存储库
    String8 path;

    // Treblized input device config files will be located /odm/usr or /vendor/usr.
	//input设备的配置文件将会坐落于/odm/usr或者/vendor/usr
    const char *rootsForPartition[] {"/odm", "/vendor", getenv("ANDROID_ROOT")};//ANDROID_ROOT的值是system
    for (size_t i = 0; i < size(rootsForPartition); i++) {//从odm和vendor和system路径下查找文件,但大部分时候是在system下,文件名称为Vendor_xxxx_Product_xxxx.idc
        path.setTo(rootsForPartition[i]);
        path.append("/usr/");
        appendInputDeviceConfigurationFileRelativePath(path, name, type);//传入的path是/system/usr/,name是Vendor_xxxx_Product_xxxx_Version_xxxx.idc,type是0
            return path;
        }
    }

    // Search user repository.
	//搜索用户存储库
    // TODO Should only look here if not in safe mode.
    path.setTo(getenv("ANDROID_DATA"));
    path.append("/system/devices/");
    appendInputDeviceConfigurationFileRelativePath(path, name, type);

        return path;
    }


    return String8();
}

 2.9 appendInputDeviceConfigurationFileRelativePath

//根据传入的文件路径和文件名称,组成完整的文件名
static void appendInputDeviceConfigurationFileRelativePath(String8& path,const String8& name, InputDeviceConfigurationFileType type) {
    path.append(CONFIGURATION_FILE_DIR[type]);//此时type是0,所以path是/system/usr/idc/
    for (size_t i = 0; i < name.length(); i++) {
        char ch = name[i];
        if (!isValidNameChar(ch)) {
            ch = '_';
        }
        path.append(&ch, 1);
    }
    path.append(CONFIGURATION_FILE_EXTENSION[type]);//此时path等于/vendor/usr/idc/Vendor_xxxx_Product_xxxx.idc
}

static const char* CONFIGURATION_FILE_DIR[] = {
        "idc/",
        "keylayout/",
        "keychars/",
};
static const char* CONFIGURATION_FILE_EXTENSION[] = {
        ".idc",
        ".kl",
        ".kcm",
};

 2.10 PropertyMap::load

1.Tokenizer::open将对应的configurationFile的fd使用mmap函数和madvise函数映射到一段内存buffer中,并将数据传递给Tokenizer类对象。

2.Parser是一个解析类,负责解析configurationFile的内容,将Key-Value对保存到outMap对应的PropertyMap中去。

status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
    *outMap = nullptr;

    Tokenizer* tokenizer;
    status_t status = Tokenizer::open(filename, &tokenizer);
    if (status) {
        ALOGE("Error %d opening property file %s.", status, filename.string());
    } else {
        PropertyMap* map = new PropertyMap();
        if (!map) {
            ALOGE("Error allocating property map.");
            status = NO_MEMORY;
        } else {
            Parser parser(map, tokenizer);
            status = parser.parse();

            if (status) {
                delete map;
            } else {
                *outMap = map;
            }
        }
        delete tokenizer;
    }
    return status;
}

2.11 loadVirtualKeyMapLocked

加载虚拟键盘映射表到virtualKeyMap中。

status_t EventHub::loadVirtualKeyMapLocked(Device* device) {
    //virtualKeyMap,虚拟键盘映射表由内核作为主板属性文件提供
    String8 path;
    path.append("/sys/board_properties/virtualkeys.");//路径
    path.append(device->identifier.name);//路径+文件名
    if (access(path.string(), R_OK)) {
        return NAME_NOT_FOUND;
    }
    return VirtualKeyMap::load(path, &device->virtualKeyMap);//加载path的键值对到virtualKeyMap中,
	//注意返回值,0代表真,1代表假,大致返回0
}

2.12 registerDeviceForEpollLocked

上面完成了/dev/input/xxxx设备节点到Device类的生成,Device类包含各个设备节点的厂商信息、设备类别、上报的事件种类、设备的映射表等诸多信息,然后注册设备节点到epoll中,开始监听各个设备节点下是否有可读事件,即监听设备的原始输入事件。

input事件主要分为两种:

   一:原始输入事件,就是当触摸屏幕等操作时,产生的事件。

   二:设备的增删事件。

status_t EventHub::registerDeviceForEpollLocked(Device* device) {
    struct epoll_event eventItem;
    memset(&eventItem, 0, sizeof(eventItem));
    eventItem.events = EPOLLIN;//监听的文件描述符是否有可读事件
    if (mUsingEpollWakeup) {//EPOLLWAKEUP标志就能保证事件在挂起或处理时,系统不会挂起或休眠。
        eventItem.events |= EPOLLWAKEUP;
    }
    eventItem.data.u32 = device->id;//事件触发时会返回eventItem.data数据
    if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, device->fd, &eventItem)) {//监听device->fd对应的设备是否有可读事件。
	//如果有事件可读,则返回eventItem.data
        ALOGE("Could not add device fd to epoll instance.  errno=%d", errno);
        return -errno;
    }
    return OK;
}
void EventHub::addDeviceLocked(Device* device) {
    mDevices.add(device->id, device);//mDevices的定义是一个容器,KeyedVector<int32_t, Device*> mDevices;
    device->next = mOpeningDevices;//Device结构体是一个单链表,其next指向下一个设备,但此时mOpeningDevices在初始化时值为0,0代表最近无设备打开
    mOpeningDevices = device;//mOpeningDevices也是一个Device*指针,指向此device,代表最近打开的设备。
}

2.13 processEventsLocked

 经过前面分析我们知道,input系统启动时候,会先扫描/dev/input下的所有设备,并对所有设备进行信息的读取和配置文件的加载,并生成对应的Device类对象。然后会生成设备添加的事件,当完成所有设备的扫描后,会生成一个设备扫描完成事件。

RawEvent事件含义如下:

    struct RawEvent {
            nsecs_t when;//时间
            int32_t deviceId;//事件发生的设备id
            int32_t type;//类型,例如按键事件等
            int32_t code;//扫描码,按键对应的扫描码
            int32_t value;//值,表示按键按下,或者抬起等
    };

void InputReader::processEventsLocked(const RawEvent* rawEvents, size_t count) {//用rawEvents指针接收传入的从传入的mEventBuffer数组的首地址
    for (const RawEvent* rawEvent = rawEvents; count;) {//for循环遍历数组
        int32_t type = rawEvent->type;//取出数组中第0号的元素rawEvent的type.
        size_t batchSize = 1;
		//事件信息有两种,一种是设备节点的增加和删除事件,统称为设备事件,另一种是原始输入事件。
		//此处满足条件,则是对设备事件进行处理
        if (type < EventHubInterface::FIRST_SYNTHETIC_EVENT) {
        } else {
            switch (rawEvent->type) {//处理设备添加事件
            case EventHubInterface::DEVICE_ADDED://设备添加事件。同时为其创建对应的mapper
                addDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::DEVICE_REMOVED://设备删除事件
                removeDeviceLocked(rawEvent->when, rawEvent->deviceId);
                break;
            case EventHubInterface::FINISHED_DEVICE_SCAN://扫描完成事件
                handleConfigurationChangedLocked(rawEvent->when);//生成一个通知的事件塞进队列
                break;
            default:
                ALOG_ASSERT(false);
                break;
            }
        }
        count -= batchSize;
        rawEvent += batchSize;
    }
}

2.14 addDeviceLocked

根据Device对象的一些信息生成InputDevice对象。InputDevice对象中会根据其设备是开关设备、键盘设备、还是滚轮式设备生成诸多对应的mapper对象。

Device类和InputDevice类非常相似,其主要区别是InputDevice相对于Device结构体多了一个
InputMapper列表。

InputMapper有一系列的子类,分别用于加工不同类型的原始输入事件。

void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) {
    ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
 
 
    InputDeviceIdentifier identifier = mEventHub->getDeviceIdentifier(deviceId);//mEventHub是在inputreader初始化时赋值的,
	//是EventHub类对象,此处只是将device->identifier取出来
    uint32_t classes = mEventHub->getDeviceClasses(deviceId);//取出device->classes
    int32_t controllerNumber = mEventHub->getDeviceControllerNumber(deviceId);
 
    InputDevice* device = createDeviceLocked(deviceId, controllerNumber, identifier, classes);//创建InputDevice
    device->configure(when, &mConfig, 0);//对设备一些厂商信息进行配置,对按键等布局信息进行加载到map中,并对生成的mapper进行配置。配置坐标系映射等
    device->reset(when);//重置所有mapper,比如按键mapper是将保存所有按键按下的vector清空。
 
    if (device->isIgnored()) {//isIgnored()函数返回的是mMapper容器是否为空,一般不为空,除非出错
        ALOGI("Device added: id=%d, name='%s' (ignored non-input device)", deviceId,
                identifier.name.string());
    } else {
        ALOGI("Device added: id=%d, name='%s', sources=0x%08x", deviceId,
                identifier.name.string(), device->getSources());
    }
 
    mDevices.add(deviceId, device);
    bumpGenerationLocked();
 
    if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) {
        notifyExternalStylusPresenceChanged();
    }
}

2.15 createDeviceLocked

1.生成了InputDevice类对象。

2.根据设备的class类型生成了多个对应的inputMapper对象。并将inputMapper对象存储在InputDevice类的一个容器中。我们此处着重看MultiTouchInputMapper

InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controllerNumber,
        const InputDeviceIdentifier& identifier, uint32_t classes) {
    InputDevice* device = new InputDevice(&mContext, deviceId, bumpGenerationLocked(),controllerNumber, identifier, classes);
	//此处本质是通过Device结构体,生成InputReader类的InputDevice对象,InputDevice表示的是单个设备的状态。单个很重要
    //根据Device结构体指针的class属性,为InputReader类赋值
	//参数分析:
	//mContext是inputreader对象
	//bumpGenerationLocked函数会将Generation值加1.故此时是2
    if (classes & INPUT_DEVICE_CLASS_EXTERNAL) {
        device->setExternal(true);//源码为inline void setExternal(bool external) { mIsExternal = external; }
    }
 
    if (classes & INPUT_DEVICE_CLASS_TERTIARY1) {
        device->setTertiary(1);//源码为inline void setTertiary(int tertiary) { mIsTertiary = tertiary; }
    }
 
    if (classes & INPUT_DEVICE_CLASS_TERTIARY2) {
        device->setTertiary(2);//源码为inline void setTertiary(int tertiary) { mIsTertiary = tertiary; }
    }
 
	.......
 
    // 触摸屏或者触摸平板设备
    if (classes & INPUT_DEVICE_CLASS_TOUCH_MT) {
        device->addMapper(new MultiTouchInputMapper(device));//new了一个多点触摸的Mapper
    } else if (classes & INPUT_DEVICE_CLASS_TOUCH) {
        device->addMapper(new SingleTouchInputMapper(device));//new了一个单点触摸的Mapper
    }
	
	......
 
    return device;
}

2.16 MultiTouchInputMapper

MultiTouchInputMapper::MultiTouchInputMapper(InputDevice* device) : 
TouchInputMapper(device) 
{}
TouchInputMapper::TouchInputMapper(InputDevice* device) :
        InputMapper(device),
        mSource(0), mDeviceMode(DEVICE_MODE_DISABLED),//初始化时,设备是被禁用的
        mSurfaceWidth(-1), mSurfaceHeight(-1), mSurfaceLeft(0), mSurfaceTop(0),
        mPhysicalWidth(-1), mPhysicalHeight(-1), mPhysicalLeft(0), mPhysicalTop(0),
        mSurfaceOrientation(DISPLAY_ORIENTATION_0) 
		{
			//mSurfaceWidth代表为屏幕坐标系
			//mPhysicalWidth是物理坐标系
		}
InputMapper::InputMapper(InputDevice* device) :
        mDevice(device), mContext(device->getContext()) 
{
}

 2.17 InputDevice::configure

主要作用为:
1.循环调用此设备的所有mapper进行相关配置。

void InputDevice::configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes) {
    mSources = 0;

    if (!isIgnored()) {//isIgnored()函数返回的是mMapper容器是否为空,一般不为空,除非出错
        if (!changes) { // 仅设备第一次添加时,此处执行
            mContext->getEventHub()->getConfiguration(mId, &mConfiguration);//从Device类的对象中获取configuration,
		//赋值给传入的inputDevice类对象的mConfiguration,mConfiguration只是一个PropertyMap,相当于从Device类中将map转移到了inputDevice类中
		//mId是deviceid
        }


        size_t numMappers = mMappers.size();
        for (size_t i = 0; i < numMappers; i++) {//循环对具体的mapper进行配置
            InputMapper* mapper = mMappers[i];
            mapper->configure(when, config, changes);
            mSources |= mapper->getSources();
        }
    }
}

2.18 TouchInputMapper::configure

主要作用为:
1. configureParameters为配置基本参数,主要是判断其为单触摸还是多触摸并赋值,并判断触摸设备是touchScreen、touchPad、touchNavigation、pointer并赋值设备类型。

2.配置光标滚动累加器,一般用于轨迹球等触摸设备。

3.配置触摸按键累加器,一般用于手写笔等触摸设备。

4. 配置绝对轴的信息,如触摸椭圆的长轴,短轴,触摸x轴的范围,压力等信息。

5.输入设备的校准。

6. configureSurface函数会获取屏幕坐标系的信息,然后将物理坐标系的位置和屏幕坐标系对应起来,这样事件就可以从点击位置的传感器的物理坐标,转化为屏幕坐标系。

那么为什么要完成物理坐标系到屏幕坐标系的转化呢?

因为物理屏幕的分辨率各是不同的,不同的屏幕,即便物理大小相同,然后我们都按下中心位置,其由于物理屏幕的分辨率不同,从而会导致上报的x和y坐标不同,因此需要将不同的物理坐标系,通过计算转化为相同的屏幕坐标系。从软件端才能识别到正确的位置。

//MultiTouchInputMapper类继承自TouchInputMapper类,子类没有重写configure函数,故调用的是父类的configure函数
void TouchInputMapper::configure(nsecs_t when, const InputReaderConfiguration* config,uint32_t changes) {
//传入的when是时间,config此时还是空的,changes是0
    InputMapper::configure(when, config, changes);//父类的父类的configure啥都没干

    mConfig = *config;

    if (!changes) { // 仅第一次添加设备的时候执行
        // 配置基本参数,主要是判断其为单触摸还是多触摸并赋值,并判断触摸设备是touchScreen、touchPad、touchNavigation、pointer并赋值设备类型
        configureParameters();

        // 配置通用的累加器
        mCursorScrollAccumulator.configure(getDevice());//光标滚动累加器
        mTouchButtonAccumulator.configure(getDevice());//触摸按键累加器

        // 配置绝对轴.
        configureRawPointerAxes();//此处会调用MultiTouchInputMapper类的configureRawPointerAxes方法。

        
        parseCalibration();//准备输入设备的校准,从PropertyMap类型的mConfiguration中读取大小,方向,压力等值。
        resolveCalibration();//执行校准,判断读取的值是否有效,并设置其值
    }
	//第一次一定会执行,后续当发生变化时才执行
    if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) {//表示位置校准矩阵已更改
        //更新位置校准以反映当前设置
        updateAffineTransformation();
    }

    if (!changes || (changes & InputReaderConfiguration::CHANGE_POINTER_SPEED)) {//表示The pointer 速度改变
        // Update pointer speed.
		//pointer速度控制
        mPointerVelocityControl.setParameters(mConfig.pointerVelocityControlParameters);
		//滚轮X速度控制
        mWheelXVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
		//滚轮y速度控制
        mWheelYVelocityControl.setParameters(mConfig.wheelVelocityControlParameters);
    }

    bool resetNeeded = false;
    if (!changes ||
        (changes &
         (InputReaderConfiguration::CHANGE_DISPLAY_INFO |//显示大小或方向已改变
          InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT |//The pointer 手势控制已改变
          InputReaderConfiguration::CHANGE_SHOW_TOUCHES |//可见触摸选项已改变
          InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) {//外部手写笔的存在已更改
        // 配置device source、Surface尺寸、方向和缩放比例。
        configureSurface(when, &resetNeeded);
    }

    if (changes && resetNeeded) {
        // 发送重置,除非这是第一次配置设备,在这种情况下,reader将在所有mapper就绪后调用重置。
        getDevice()->notifyReset(when);
    }
}

2.19 TouchInputMapper::configureParameters

主要作用为:

1.判断设备类型是多指触摸还是单指触摸。

2.判断设备类型是触摸屏还是触摸板等设备。

void TouchInputMapper::configureParameters() {
    //对于不支持不同多点触摸的设备,请使用pointer显示模式。以点为基础的方式,依赖于能够在触摸板上准确定位两个或多个手指
    mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)//从驱动处判断此设备是单触还是多触
            ? Parameters::GESTURE_MODE_SINGLE_TOUCH
            : Parameters::GESTURE_MODE_MULTI_TOUCH;

    String8 gestureModeString;
	//从PropertyMap mConfiguration中,获取touch.gestureMode对应的值,然后赋值为手势是单触还是多触
    if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
                                                       gestureModeString)) {
        if (gestureModeString == "single-touch") {//如果是单触
            mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH;
        } else if (gestureModeString == "multi-touch") {//如果是多触
            mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH;
        } else if (gestureModeString != "default") {
            ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
        }
    }
	//获取input设备的类型
    if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_DIRECT)) {
        //该设备是触摸屏.
        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
    } else if (getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_POINTER)) {
        // 该设备是一个pointing device,像轨迹球一样
        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
    } else if (getEventHub()->hasRelativeAxis(getDeviceId(), REL_X) ||
               getEventHub()->hasRelativeAxis(getDeviceId(), REL_Y)) {//设备是否有相对坐标轴
        //该设备是带有触摸板的光标设备。
		//默认情况下,不要使用触摸板移动指针
        mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;//触摸板
    } else {
        //该设备是一个未知用途的touch pad
        mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
    }

    mParameters.hasButtonUnderPad =
            getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_BUTTONPAD);//从propBitmask数组中,查看是否有传入的INPUT_PROP_SEMI_MT值。如果有则,说明是单触摸,如果没有,则是多触

    String8 deviceTypeString;
    if (getDevice()->getConfiguration().tryGetProperty(String8("touch.deviceType"),
                                                       deviceTypeString)) {//从配置中读取设备类型
        if (deviceTypeString == "touchScreen") {//触摸屏
            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_SCREEN;
        } else if (deviceTypeString == "touchPad") {//触摸板
            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_PAD;
        } else if (deviceTypeString == "touchNavigation") {//触摸导航
            mParameters.deviceType = Parameters::DEVICE_TYPE_TOUCH_NAVIGATION;
        } else if (deviceTypeString == "pointer") {//指针,像轨迹球一样,可以理解为鼠标
            mParameters.deviceType = Parameters::DEVICE_TYPE_POINTER;
        } else if (deviceTypeString != "default") {
            ALOGW("Invalid value for touch.deviceType: '%s'", deviceTypeString.string());
        }
    }
	//如果是触摸屏,则方位感知默认是ture,否则默认为false
    mParameters.orientationAware = mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN;
	//从property中获取touch.orientationAware字符串对应的值,赋值给mParameters.orientationAware
    getDevice()->getConfiguration().tryGetProperty(String8("touch.orientationAware"),
                                                   mParameters.orientationAware);

    mParameters.hasAssociatedDisplay = false;
    mParameters.associatedDisplayIsExternal = false;
    mParameters.associatedDisplayIsTertiary = 0;
    if (mParameters.orientationAware ||
        mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN ||
        mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER) {//DEVICE_TYPE_POINTER代表是触摸屏,鼠标,触摸笔三种中一种
        mParameters.hasAssociatedDisplay = true;
        if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN) {//如果是触摸屏,则获取其displayid,赋值给mParameters.uniqueDisplayId
            mParameters.associatedDisplayIsExternal = getDevice()->isExternal();
            mParameters.associatedDisplayIsTertiary = getDevice()->isTertiary();
            getDevice()->getConfiguration().tryGetProperty(String8("touch.displayId"),
                                                           mParameters.uniqueDisplayId);
        }
    }
    //外部触摸设备上的初始按下应唤醒设备。
	//通常,我们不会对内部触摸屏这样做,以防止它们在口袋中醒来,但您可以使用输入设备配置启用它。
    mParameters.wake = getDevice()->isExternal();
    getDevice()->getConfiguration().tryGetProperty(String8("touch.wake"), mParameters.wake);
}
//从propBitmask数组中,查看是否有传入的INPUT_PROP_SEMI_MT值。如果有则,说明是单触摸,如果没有,则是多触
bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
    if (property >= 0 && property <= INPUT_PROP_MAX) {
        AutoMutex _l(mLock);

        Device* device = getDeviceLocked(deviceId);
        if (device) {
            return test_bit(property, device->propBitmask);
        }
    }
    return false;
}


//该宏用于判断“bit”是否设置在“array”中
#define test_bit(bit, array)    ((array)[(bit)/8] & (1<<((bit)%8)))

2.20 CursorScrollAccumulator::configure

配置光标滚动累加器,一般用于轨迹球等触摸设备。

//从device中获取RelativeAxis相对轴,赋值给mHaveRelWheel,和mHaveRelHWheel
void CursorScrollAccumulator::configure(InputDevice* device) {
	//CursorScrollAccumulator为光标滚动的配置
    mHaveRelWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_WHEEL);//相对坐标滚轮
    mHaveRelHWheel = device->getEventHub()->hasRelativeAxis(device->getId(), REL_HWHEEL);//高精度相对坐标滚轮
}

2.21 TouchButtonAccumulator::configure

主要作用为:
1.如果当前设备有触摸按键(如按钮工具笔),此类型则设置光标混动的信息,此类型主要针对手写笔设备。

void TouchButtonAccumulator::configure(InputDevice* device) {
    mHaveBtnTouch = device->hasKey(BTN_TOUCH);//设备是否有触摸按键
	//BTN_TOOL_PEN,按钮工具笔,
	//BTN_TOOL_RUBBER,按钮工具橡皮擦,
	//BTN_TOOL_BRUSH按钮工具刷子,
	//BTN_TOOL_PENCIL按钮工具铅笔,
	//BTN_TOOL_AIRBRUSH按钮_工具_空气刷
    mHaveStylus = device->hasKey(BTN_TOOL_PEN) || device->hasKey(BTN_TOOL_RUBBER) ||
            device->hasKey(BTN_TOOL_BRUSH) || device->hasKey(BTN_TOOL_PENCIL) ||
            device->hasKey(BTN_TOOL_AIRBRUSH);
}

2.22 MultiTouchInputMapper::configureRawPointerAxes

主要作用为:
1.根据相关标志如ABS_MT_POSITION_X,从指定的设备中,通过ioctl和驱动通信。取出其对应的最大值最小值等所有的信息,放入mRawPointerAxes.x。mRawPointerAxes,是个存储x,y,压力等各种信息的容器X坐标与Y坐标等等下面的这些技术指标构建了传感器的物理坐标系。

#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR	0x30	/*触摸椭圆的长轴 */
#define ABS_MT_TOUCH_MINOR	0x31	/* touching椭圆的短轴(如果是圆形,则省略) */
#define ABS_MT_WIDTH_MAJOR	0x32	/* approaching椭圆的长轴 */
#define ABS_MT_WIDTH_MINOR	0x33	/* approaching椭圆的短轴(如果是圆形,则省略) */
#define ABS_MT_ORIENTATION	0x34	/* 椭圆方向 */
#define ABS_MT_POSITION_X	0x35	/* 椭圆中心X位置 */
#define ABS_MT_POSITION_Y	0x36	/* 椭圆中心Y位置 */
#define ABS_MT_TOOL_TYPE	0x37	/* 触摸设备类型 */
#define ABS_MT_BLOB_ID		0x38	/* 将一组数据包 as a blob */
#define ABS_MT_TRACKING_ID	0x39	/* 最初触摸的唯一ID */
#define ABS_MT_PRESSURE		0x3a	/* 触摸区域的压力 */
#define ABS_MT_DISTANCE		0x3b	/* Contact hover distance,接触悬停距离 */
void MultiTouchInputMapper::configureRawPointerAxes() {
    TouchInputMapper::configureRawPointerAxes();//此函数内部会先清空mRawPointerAxes
	//主要作用是:根据相关标志如ABS_MT_POSITION_X,从指定的设备中,通过ioctl和驱动通信。取出其对应的最大值最小值等所有的信息,放入mRawPointerAxes.x中
	//mRawPointerAxes,是个存储x,y,压力等各种信息的容器,mRawPointerAxes.x的定义是RawAbsoluteAxisInfo x。
	//X坐标与Y坐标等等下面的这些技术指标构建了传感器的物理坐标系。
	//此处会调用父类InputMapper的getAbsoluteAxisInfo函数
    getAbsoluteAxisInfo(ABS_MT_POSITION_X, &mRawPointerAxes.x);//获取椭圆中心X位置的范围,精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_POSITION_Y, &mRawPointerAxes.y);//获取椭圆中心Y位置的范围、精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_TOUCH_MAJOR, &mRawPointerAxes.touchMajor);//获取触摸椭圆的长轴的范围,精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_TOUCH_MINOR, &mRawPointerAxes.touchMinor);//获取触摸椭圆的短轴的范围,精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_WIDTH_MAJOR, &mRawPointerAxes.toolMajor);//获取approaching椭圆的长轴的范围,精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_WIDTH_MINOR, &mRawPointerAxes.toolMinor);//获取approaching椭圆的短轴的范围,精度等各项信息
    getAbsoluteAxisInfo(ABS_MT_ORIENTATION, &mRawPointerAxes.orientation);//获取椭圆方向的范围和精度等信息
    getAbsoluteAxisInfo(ABS_MT_PRESSURE, &mRawPointerAxes.pressure);//获取触摸区域的压力的范围,精度等
    getAbsoluteAxisInfo(ABS_MT_DISTANCE, &mRawPointerAxes.distance);//获取距离的范围,精度等
    getAbsoluteAxisInfo(ABS_MT_TRACKING_ID, &mRawPointerAxes.trackingId);//最初触摸的唯一ID
    getAbsoluteAxisInfo(ABS_MT_SLOT, &mRawPointerAxes.slot);//使用的slot
	
	//如果设备各种信息的trackingId是有效的,且slot是有效的,设置slot的最大数量
    if (mRawPointerAxes.trackingId.valid && mRawPointerAxes.slot.valid &&
        mRawPointerAxes.slot.minValue == 0 && mRawPointerAxes.slot.maxValue > 0) {
        size_t slotCount = mRawPointerAxes.slot.maxValue + 1;
        if (slotCount > MAX_SLOTS) {
		//MultiTouch设备报告了多少slot,但该框架目前最多只支持多少slot
            ALOGW("MultiTouch Device %s reported %zu slots but the framework "
                  "only supports a maximum of %zu slots at this time.",
                  getDeviceName().string(), slotCount, MAX_SLOTS);
            slotCount = MAX_SLOTS;
        }
		//为设备配置最大的slotCount和usingSlotsProtocol为ture和是否有触摸工具笔
        mMultiTouchMotionAccumulator.configure(getDevice(), slotCount, true /*usingSlotsProtocol*/);
    } else {
        mMultiTouchMotionAccumulator.configure(getDevice(), MAX_POINTERS,
                                               false /*usingSlotsProtocol*/);
    }
}

2.23 InputMapper::getAbsoluteAxisInfo

status_t InputMapper::getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo) 
{
    return getEventHub()->getAbsoluteAxisInfo(getDeviceId(), axis, axisInfo);
}

2.24 EventHub::getAbsoluteAxisInfo

status_t EventHub::getAbsoluteAxisInfo(int32_t deviceId, int axis,
        RawAbsoluteAxisInfo* outAxisInfo) const 
{
    outAxisInfo->clear();

    if (axis >= 0 && axis <= ABS_MAX) {
        AutoMutex _l(mLock);

        Device* device = getDeviceLocked(deviceId);
        if (device && device->hasValidFd() && test_bit(axis, device->absBitmask)) {//如果axis是有效的
            struct input_absinfo info;
            if(ioctl(device->fd, EVIOCGABS(axis), &info)) {//则从驱动中读取相关信息到input_absinfo中
                ALOGW("Error reading absolute controller %d for device %s fd %d, errno=%d",
                     axis, device->identifier.name.string(), device->fd, errno);
                return -errno;
            }

            if (info.minimum != info.maximum) {
                outAxisInfo->valid = true;//代表有效
                outAxisInfo->minValue = info.minimum;//保存从驱动获取到的最小值
                outAxisInfo->maxValue = info.maximum;//保存从驱动获取到的最大值
                outAxisInfo->flat = info.flat;
                outAxisInfo->fuzz = info.fuzz;//容错范围,表示因干扰所导致的最大偏移量
                outAxisInfo->resolution = info.resolution;//精度,表示在一毫米的范围内解析点的数量
            }
            return OK;
        }
    }
    return -1;
}
struct input_absinfo {
	__s32 value;//此轴的最新报告值
	__s32 minimum;//此项信息的最小值
	__s32 maximum;//此项信息的最大值
	__s32 fuzz;//容错范围,表示因干扰所导致的最大偏移量
	__s32 flat;//joydev接口将丢弃此值内的值,并将其报告为0。
	__s32 resolution;//精度,表示在一毫米的范围内解析点的数量
};

2.25 MultiTouchMotionAccumulator::configure

主要作用为:
1.为设备配置最大的slotCount,表示一次可以有多少个slot信息

//为设备配置最大的slotCount和usingSlotsProtocol为ture
void MultiTouchMotionAccumulator::configure(InputDevice* device, size_t slotCount,
                                            bool usingSlotsProtocol) {
    mSlotCount = slotCount;//值为数量
    mUsingSlotsProtocol = usingSlotsProtocol;//true
    mHaveStylus = device->hasAbsoluteAxis(ABS_MT_TOOL_TYPE);//是否有触控笔

    delete[] mSlots;
    mSlots = new Slot[slotCount];//配置多点触摸的slot槽
}

2.26 TouchInputMapper::parseCalibration

1.从PropertyMap类型的mConfiguration中读取大小,方向,压力等值,然后赋值Calibration类对象的各个属性,准备进行校准。

void TouchInputMapper::parseCalibration() {
    const PropertyMap& in = getDevice()->getConfiguration();
    Calibration& out = mCalibration;

    //大小
    out.sizeCalibration = Calibration::SIZE_CALIBRATION_DEFAULT;
    String8 sizeCalibrationString;
    if (in.tryGetProperty(String8("touch.size.calibration"), sizeCalibrationString)) {//解析校准的几个参数
        if (sizeCalibrationString == "none") {
            out.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
        } else if (sizeCalibrationString == "geometric") {
            out.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
        } else if (sizeCalibrationString == "diameter") {
            out.sizeCalibration = Calibration::SIZE_CALIBRATION_DIAMETER;
        } else if (sizeCalibrationString == "box") {
            out.sizeCalibration = Calibration::SIZE_CALIBRATION_BOX;
        } else if (sizeCalibrationString == "area") {
            out.sizeCalibration = Calibration::SIZE_CALIBRATION_AREA;
        } else if (sizeCalibrationString != "default") {
            ALOGW("Invalid value for touch.size.calibration: '%s'", sizeCalibrationString.string());
        }
    }

    out.haveSizeScale = in.tryGetProperty(String8("touch.size.scale"), out.sizeScale);
    out.haveSizeBias = in.tryGetProperty(String8("touch.size.bias"), out.sizeBias);
    out.haveSizeIsSummed = in.tryGetProperty(String8("touch.size.isSummed"), out.sizeIsSummed);

    //压力
    out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_DEFAULT;
    String8 pressureCalibrationString;
    if (in.tryGetProperty(String8("touch.pressure.calibration"), pressureCalibrationString)) {
        if (pressureCalibrationString == "none") {
            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
        } else if (pressureCalibrationString == "physical") {//物理的压力
            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;
        } else if (pressureCalibrationString == "amplitude") {//振幅
            out.pressureCalibration = Calibration::PRESSURE_CALIBRATION_AMPLITUDE;
        } else if (pressureCalibrationString != "default") {
            ALOGW("Invalid value for touch.pressure.calibration: '%s'",
                  pressureCalibrationString.string());
        }
    }

    out.havePressureScale = in.tryGetProperty(String8("touch.pressure.scale"), out.pressureScale);

    //方向
    out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_DEFAULT;
    String8 orientationCalibrationString;
    if (in.tryGetProperty(String8("touch.orientation.calibration"), orientationCalibrationString)) {
        if (orientationCalibrationString == "none") {
            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
        } else if (orientationCalibrationString == "interpolated") {
            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
        } else if (orientationCalibrationString == "vector") {
            out.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_VECTOR;
        } else if (orientationCalibrationString != "default") {
            ALOGW("Invalid value for touch.orientation.calibration: '%s'",
                  orientationCalibrationString.string());
        }
    }

    //距离
    out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_DEFAULT;
    String8 distanceCalibrationString;
    if (in.tryGetProperty(String8("touch.distance.calibration"), distanceCalibrationString)) {
        if (distanceCalibrationString == "none") {
            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
        } else if (distanceCalibrationString == "scaled") {
            out.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
        } else if (distanceCalibrationString != "default") {
            ALOGW("Invalid value for touch.distance.calibration: '%s'",
                  distanceCalibrationString.string());
        }
    }

    out.haveDistanceScale = in.tryGetProperty(String8("touch.distance.scale"), out.distanceScale);

    out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_DEFAULT;
    String8 coverageCalibrationString;
    if (in.tryGetProperty(String8("touch.coverage.calibration"), coverageCalibrationString)) {
        if (coverageCalibrationString == "none") {
            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
        } else if (coverageCalibrationString == "box") {
            out.coverageCalibration = Calibration::COVERAGE_CALIBRATION_BOX;
        } else if (coverageCalibrationString != "default") {
            ALOGW("Invalid value for touch.coverage.calibration: '%s'",
                  coverageCalibrationString.string());
        }
    }
}

2.27 TouchInputMapper::resolveCalibration

主要作用为:
1.执行校准,判断读取的值是否有效,并设置标志值。

void TouchInputMapper::resolveCalibration() {
    // 大小
	//如果椭圆的长轴是有效的或者toolMajor是有效的,并且sizeCalibration值为默认值,则设置其为几何的大小
    if (mRawPointerAxes.touchMajor.valid || mRawPointerAxes.toolMajor.valid) {
        if (mCalibration.sizeCalibration == Calibration::SIZE_CALIBRATION_DEFAULT) {
            mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_GEOMETRIC;
        }
    } else {//如果椭圆的长轴和toolMajor都是无效的,则设置为空
        mCalibration.sizeCalibration = Calibration::SIZE_CALIBRATION_NONE;
    }

    // 压力
    if (mRawPointerAxes.pressure.valid) {//如果压力有效则
        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_DEFAULT) {
            mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_PHYSICAL;//物理的压力
        }
    } else {//否则为空
        mCalibration.pressureCalibration = Calibration::PRESSURE_CALIBRATION_NONE;
    }

    // 方向
    if (mRawPointerAxes.orientation.valid) {
        if (mCalibration.orientationCalibration == Calibration::ORIENTATION_CALIBRATION_DEFAULT) {
            mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_INTERPOLATED;
        }
    } else {
        mCalibration.orientationCalibration = Calibration::ORIENTATION_CALIBRATION_NONE;
    }

    // 距离
    if (mRawPointerAxes.distance.valid) {
        if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_DEFAULT) {
            mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_SCALED;
        }
    } else {
        mCalibration.distanceCalibration = Calibration::DISTANCE_CALIBRATION_NONE;
    }

    // Coverage
    if (mCalibration.coverageCalibration == Calibration::COVERAGE_CALIBRATION_DEFAULT) {
        mCalibration.coverageCalibration = Calibration::COVERAGE_CALIBRATION_NONE;
    }
}
//从nativeManager获取,Surface方向是否有变化
void TouchInputMapper::updateAffineTransformation() {
    mAffineTransform = getPolicy()->getTouchAffineTransformation(mDevice->getDescriptor(),
                                                                 mSurfaceOrientation);
}

2.28 TouchInputMapper::configureSurface

主要作用为:
1.根据差异将物理屏幕坐标系转化为屏幕的坐标系。使得在事件到来时可以将点击位置从传感器的物理坐标系位置转化为屏幕坐标系的位置。

ViewPort表示物理屏和逻辑屏之间的对应关系,Input模块中,用ViewPort来将物理屏的touch事件坐标转换为逻辑屏的坐标。所以,每次进行逻辑屏和物理屏配置时,都会重新对view port进行填充,并发送给IMS模块。对显示屏幕的描述分为物理显示屏(physical display)和逻辑显示屏(logical display),物理屏主要从SurfaceFlinger中读取参数创建,代表实实在在的物理屏,描述其物理特性,不同物理屏有不同的属性。
逻辑屏则是相对于对物理屏,侧重于同一个物理屏的不同逻辑设置,受应用和WMS模块影响,如显示区域、显示位置坐标、显示方向等。
每一个物理屏幕都对应一个逻辑屏幕,可以修改逻辑屏幕参数,做到同一个物理屏的不同显示方式。

//ViewPort表示物理屏和逻辑屏之间的对应关系,Input模块中,用ViewPort来将物理屏的touch事件坐标转换为逻辑屏的坐标。
//所以,每次进行逻辑屏和物理屏配置时,都会重新对view port进行填充,并发送给IMS模块。
//对显示屏幕的描述分为物理显示屏(physical display)和逻辑显示屏(logical display),物理屏主要从SurfaceFlinger中读取参数创建,
//代表实实在在的物理屏,描述其物理特性,不同物理屏有不同的属性。
//逻辑屏则是相对于对物理屏,侧重于同一个物理屏的不同逻辑设置,受应用和WMS模块影响,如显示区域、显示位置坐标、显示方向等。
//每一个物理屏幕都对应一个逻辑屏幕,可以修改逻辑屏幕参数,做到同一个物理屏的不同显示方式。
void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) {
    int32_t oldDeviceMode = mDeviceMode;

    resolveExternalStylusPresence();

    // 设置device mode.
	/*
    if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER &&mConfig.pointerGesturesEnabled) //如果触摸设备是带有光标的,可以理解为触摸板
		{
			mSource = AINPUT_SOURCE_MOUSE;//设置设备source是鼠标
			mDeviceMode = DEVICE_MODE_POINTER;//设置device模式是指针模式
			if (hasStylus()) {//是否有触控笔
				mSource |= AINPUT_SOURCE_STYLUS;
			}
		} */
	else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_SCREEN &&
               mParameters.hasAssociatedDisplay) {//如果是触摸屏幕,走这里
        mSource = AINPUT_SOURCE_TOUCHSCREEN;
        mDeviceMode = DEVICE_MODE_DIRECT;
        if (hasStylus()) {//判断是否还有触摸笔
            mSource |= AINPUT_SOURCE_STYLUS;
        }
        if (hasExternalStylus()) {//是否有外部触摸笔
            mSource |= AINPUT_SOURCE_BLUETOOTH_STYLUS;
        }
    } 
	/*else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) {
        mSource = AINPUT_SOURCE_TOUCH_NAVIGATION;
        mDeviceMode = DEVICE_MODE_NAVIGATION;
    } else {
        mSource = AINPUT_SOURCE_TOUCHPAD;
        mDeviceMode = DEVICE_MODE_UNSCALED;
    }*/

    // 确保我们有有效的X and Y 轴.
    if (!mRawPointerAxes.x.valid || !mRawPointerAxes.y.valid) {
        ALOGW(INDENT "Touch device '%s' did not report support for X or Y axis!  "
                     "The device will be inoperable.",
              getDeviceName().string());
        mDeviceMode = DEVICE_MODE_DISABLED;
        return;
    }

    // 原始方位的raw宽度和高度.
    int32_t rawWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
    int32_t rawHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;

    // 获取关联的display大小。
    DisplayViewport newViewport;
    if (mParameters.hasAssociatedDisplay) {//如果是触摸屏则hasAssociatedDisplay是ture
        const String8* uniqueDisplayId = NULL;
        ViewportType viewportTypeToUse;

        if (mParameters.associatedDisplayIsExternal) {//如果是外部设备,触摸屏不是
            viewportTypeToUse = ViewportType::VIEWPORT_EXTERNAL;
        } else if (mParameters.associatedDisplayIsTertiary == 1) {
            viewportTypeToUse = ViewportType::VIEWPORT_TERTIARY1;
        } else if (mParameters.associatedDisplayIsTertiary == 2) {
            viewportTypeToUse = ViewportType::VIEWPORT_TERTIARY2;
        } else if (!mParameters.uniqueDisplayId.isEmpty()) {
            // 如果IDC文件指定了唯一的显示器Id,那么它将链接到具有相同唯一Id的virtual display,虚拟display用于屏幕录制等不依赖物理设备的屏幕
            uniqueDisplayId = &mParameters.uniqueDisplayId;
            viewportTypeToUse = ViewportType::VIEWPORT_VIRTUAL;//虚拟显示
        } else {
            viewportTypeToUse = ViewportType::VIEWPORT_INTERNAL;//内部显示
        }

        if (!mConfig.getDisplayViewport(viewportTypeToUse, uniqueDisplayId, &newViewport)) {//获取最新的viewport
            ALOGI(INDENT "Touch device '%s' could not query the properties of its associated "
                         "display.  The device will be inoperable until the display size "
                         "becomes available.",
                  getDeviceName().string());
            mDeviceMode = DEVICE_MODE_DISABLED;
            return;
        }
    } 
	/*else {//无显示屏
        newViewport.setNonDisplayViewport(rawWidth, rawHeight);
    }*/
    bool viewportChanged = mViewport != newViewport;
    if (viewportChanged) {//如果viewport发生了变化
        mViewport = newViewport;

        if (mDeviceMode == DEVICE_MODE_DIRECT || mDeviceMode == DEVICE_MODE_POINTER) {//如果是触摸屏或者触摸设备有光标(触摸板)
            // 将旋转的viewport转化为曲面坐标。
            int32_t naturalLogicalWidth, naturalLogicalHeight;
            int32_t naturalPhysicalWidth, naturalPhysicalHeight;
            int32_t naturalPhysicalLeft, naturalPhysicalTop;
            int32_t naturalDeviceWidth, naturalDeviceHeight;
            switch (mViewport.orientation) {
                case DISPLAY_ORIENTATION_90://当方向是90度时,则宽高重新计算
                    naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;//
                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                    naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                    naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                    naturalPhysicalLeft = mViewport.deviceHeight - mViewport.physicalBottom;
                    naturalPhysicalTop = mViewport.physicalLeft;
                    naturalDeviceWidth = mViewport.deviceHeight;
                    naturalDeviceHeight = mViewport.deviceWidth;
                    break;
                case DISPLAY_ORIENTATION_180:
                    naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;
                    naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;
                    naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;
                    naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;
                    naturalPhysicalLeft = mViewport.deviceWidth - mViewport.physicalRight;
                    naturalPhysicalTop = mViewport.deviceHeight - mViewport.physicalBottom;
                    naturalDeviceWidth = mViewport.deviceWidth;
                    naturalDeviceHeight = mViewport.deviceHeight;
                    break;
                case DISPLAY_ORIENTATION_270:
                    naturalLogicalWidth = mViewport.logicalBottom - mViewport.logicalTop;
                    naturalLogicalHeight = mViewport.logicalRight - mViewport.logicalLeft;
                    naturalPhysicalWidth = mViewport.physicalBottom - mViewport.physicalTop;
                    naturalPhysicalHeight = mViewport.physicalRight - mViewport.physicalLeft;
                    naturalPhysicalLeft = mViewport.physicalTop;
                    naturalPhysicalTop = mViewport.deviceWidth - mViewport.physicalRight;
                    naturalDeviceWidth = mViewport.deviceHeight;
                    naturalDeviceHeight = mViewport.deviceWidth;
                    break;
                case DISPLAY_ORIENTATION_0://0度就是正常情况
                default:
                    naturalLogicalWidth = mViewport.logicalRight - mViewport.logicalLeft;//逻辑右-逻辑左就是逻辑屏的宽
                    naturalLogicalHeight = mViewport.logicalBottom - mViewport.logicalTop;//逻辑底-逻辑顶就是逻辑屏的高
                    naturalPhysicalWidth = mViewport.physicalRight - mViewport.physicalLeft;//物理右-物理左就是物理屏的宽
                    naturalPhysicalHeight = mViewport.physicalBottom - mViewport.physicalTop;//物理底-物理顶就是物理屏的高
                    naturalPhysicalLeft = mViewport.physicalLeft;
                    naturalPhysicalTop = mViewport.physicalTop;
                    naturalDeviceWidth = mViewport.deviceWidth;//设备的宽
                    naturalDeviceHeight = mViewport.deviceHeight;//设备的高
                    break;
            }

            mPhysicalWidth = naturalPhysicalWidth;//更新物理屏幕的宽
            mPhysicalHeight = naturalPhysicalHeight;//更新物理屏幕的高
            mPhysicalLeft = naturalPhysicalLeft;//更新物理屏幕的左
            mPhysicalTop = naturalPhysicalTop;//更新物理屏幕的顶

            mSurfaceWidth = naturalLogicalWidth * naturalDeviceWidth / naturalPhysicalWidth;
            mSurfaceHeight = naturalLogicalHeight * naturalDeviceHeight / naturalPhysicalHeight;
            mSurfaceLeft = naturalPhysicalLeft * naturalLogicalWidth / naturalPhysicalWidth;
            mSurfaceTop = naturalPhysicalTop * naturalLogicalHeight / naturalPhysicalHeight;

            mSurfaceOrientation =
                    mParameters.orientationAware ? mViewport.orientation : DISPLAY_ORIENTATION_0;
        } 
		else {
            mPhysicalWidth = rawWidth;
            mPhysicalHeight = rawHeight;
            mPhysicalLeft = 0;
            mPhysicalTop = 0;

            mSurfaceWidth = rawWidth;
            mSurfaceHeight = rawHeight;
            mSurfaceLeft = 0;
            mSurfaceTop = 0;
            mSurfaceOrientation = DISPLAY_ORIENTATION_0;
        }
    }

    // If moving between pointer modes, need to reset some state.
    bool deviceModeChanged = mDeviceMode != oldDeviceMode;//如果设备类型发生变化
    if (deviceModeChanged) {
        mOrientedRanges.clear();
    }

    //
    if (mDeviceMode == DEVICE_MODE_POINTER ||
        (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {//如果是指针模式(触摸板,显示是鼠标),则创建mPointerController
        if (mPointerController == NULL) {
            mPointerController = getPolicy()->obtainPointerController(getDeviceId());
        }
    } else {
        mPointerController.clear();
    }

    if (viewportChanged || deviceModeChanged) {//第一次配置此处为true
        ALOGI("Device reconfigured: id=%d, name='%s', size %dx%d, orientation %d, mode %d, "
              "display id %d",
              getDeviceId(), getDeviceName().string(), mSurfaceWidth, mSurfaceHeight,
              mSurfaceOrientation, mDeviceMode, mViewport.displayId);

        // 此处是为了换算物理屏和显示屏的缩放比例
        mXScale = float(mSurfaceWidth) / rawWidth;//计算x轴的缩放比例,mSurfaceWidth是相当于逻辑宽,rawWidth则是物理屏的x轴的宽
        mYScale = float(mSurfaceHeight) / rawHeight;//计算x轴的缩放比例
        mXTranslate = -mSurfaceLeft;
        mYTranslate = -mSurfaceTop;
        mXPrecision = 1.0f / mXScale;//精度
        mYPrecision = 1.0f / mYScale;//精度

        mOrientedRanges.x.axis = AMOTION_EVENT_AXIS_X;
        mOrientedRanges.x.source = mSource;
        mOrientedRanges.y.axis = AMOTION_EVENT_AXIS_Y;
        mOrientedRanges.y.source = mSource;

        configureVirtualKeys();//配置虚拟按键

        mGeometricScale = avg(mXScale, mYScale);//不在特定轴上定向的术语的比例因子。如果像素是正方形的,则xScale==yScale,否则我们通过选择平均值来伪造它。


        float diagonalSize = hypotf(mSurfaceWidth, mSurfaceHeight);//对角线轴的长度

        //大小的比例因子
        if (mCalibration.sizeCalibration != Calibration::SIZE_CALIBRATION_NONE) {
            if (mRawPointerAxes.touchMajor.valid && mRawPointerAxes.touchMajor.maxValue != 0) {//如果触摸长轴有效
                mSizeScale = 1.0f / mRawPointerAxes.touchMajor.maxValue;
            } else if (mRawPointerAxes.toolMajor.valid && mRawPointerAxes.toolMajor.maxValue != 0) {
                mSizeScale = 1.0f / mRawPointerAxes.toolMajor.maxValue;
            } else {
                mSizeScale = 0.0f;
            }

            mOrientedRanges.haveTouchSize = true;
            mOrientedRanges.haveToolSize = true;
            mOrientedRanges.haveSize = true;

            mOrientedRanges.touchMajor.axis = AMOTION_EVENT_AXIS_TOUCH_MAJOR;
            mOrientedRanges.touchMajor.source = mSource;
            mOrientedRanges.touchMajor.min = 0;
            mOrientedRanges.touchMajor.max = diagonalSize;
            mOrientedRanges.touchMajor.flat = 0;
            mOrientedRanges.touchMajor.fuzz = 0;
            mOrientedRanges.touchMajor.resolution = 0;

            mOrientedRanges.touchMinor = mOrientedRanges.touchMajor;
            mOrientedRanges.touchMinor.axis = AMOTION_EVENT_AXIS_TOUCH_MINOR;

            mOrientedRanges.toolMajor.axis = AMOTION_EVENT_AXIS_TOOL_MAJOR;
            mOrientedRanges.toolMajor.source = mSource;
            mOrientedRanges.toolMajor.min = 0;
            mOrientedRanges.toolMajor.max = diagonalSize;
            mOrientedRanges.toolMajor.flat = 0;
            mOrientedRanges.toolMajor.fuzz = 0;
            mOrientedRanges.toolMajor.resolution = 0;

            mOrientedRanges.toolMinor = mOrientedRanges.toolMajor;
            mOrientedRanges.toolMinor.axis = AMOTION_EVENT_AXIS_TOOL_MINOR;

            mOrientedRanges.size.axis = AMOTION_EVENT_AXIS_SIZE;
            mOrientedRanges.size.source = mSource;
            mOrientedRanges.size.min = 0;
            mOrientedRanges.size.max = 1.0;
            mOrientedRanges.size.flat = 0;
            mOrientedRanges.size.fuzz = 0;
            mOrientedRanges.size.resolution = 0;
        } else {
            mSizeScale = 0.0f;
        }

        //计算压力缩放因子
        mPressureScale = 0;
        float pressureMax = 1.0;
        if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL ||
            mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
            if (mCalibration.havePressureScale) {
                mPressureScale = mCalibration.pressureScale;
                pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
            } else if (mRawPointerAxes.pressure.valid && mRawPointerAxes.pressure.maxValue != 0) {
                mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
            }
        }

        mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
        mOrientedRanges.pressure.source = mSource;
        mOrientedRanges.pressure.min = 0;
        mOrientedRanges.pressure.max = pressureMax;
        mOrientedRanges.pressure.flat = 0;
        mOrientedRanges.pressure.fuzz = 0;
        mOrientedRanges.pressure.resolution = 0;

        // 倾斜角度
        mTiltXCenter = 0;
        mTiltXScale = 0;
        mTiltYCenter = 0;
        mTiltYScale = 0;
        mHaveTilt = mRawPointerAxes.tiltX.valid && mRawPointerAxes.tiltY.valid;
        if (mHaveTilt) {
            mTiltXCenter = avg(mRawPointerAxes.tiltX.minValue, mRawPointerAxes.tiltX.maxValue);
            mTiltYCenter = avg(mRawPointerAxes.tiltY.minValue, mRawPointerAxes.tiltY.maxValue);
            mTiltXScale = M_PI / 180;
            mTiltYScale = M_PI / 180;

            mOrientedRanges.haveTilt = true;

            mOrientedRanges.tilt.axis = AMOTION_EVENT_AXIS_TILT;
            mOrientedRanges.tilt.source = mSource;
            mOrientedRanges.tilt.min = 0;
            mOrientedRanges.tilt.max = M_PI_2;
            mOrientedRanges.tilt.flat = 0;
            mOrientedRanges.tilt.fuzz = 0;
            mOrientedRanges.tilt.resolution = 0;
        }

        // 方向
        mOrientationScale = 0;
        if (mHaveTilt) {
            mOrientedRanges.haveOrientation = true;

            mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
            mOrientedRanges.orientation.source = mSource;
            mOrientedRanges.orientation.min = -M_PI;
            mOrientedRanges.orientation.max = M_PI;
            mOrientedRanges.orientation.flat = 0;
            mOrientedRanges.orientation.fuzz = 0;
            mOrientedRanges.orientation.resolution = 0;
        } else if (mCalibration.orientationCalibration !=
                   Calibration::ORIENTATION_CALIBRATION_NONE) {
            if (mCalibration.orientationCalibration ==
                Calibration::ORIENTATION_CALIBRATION_INTERPOLATED) {
                if (mRawPointerAxes.orientation.valid) {
                    if (mRawPointerAxes.orientation.maxValue > 0) {
                        mOrientationScale = M_PI_2 / mRawPointerAxes.orientation.maxValue;
                    } else if (mRawPointerAxes.orientation.minValue < 0) {
                        mOrientationScale = -M_PI_2 / mRawPointerAxes.orientation.minValue;
                    } else {
                        mOrientationScale = 0;
                    }
                }
            }

            mOrientedRanges.haveOrientation = true;

            mOrientedRanges.orientation.axis = AMOTION_EVENT_AXIS_ORIENTATION;
            mOrientedRanges.orientation.source = mSource;
            mOrientedRanges.orientation.min = -M_PI_2;
            mOrientedRanges.orientation.max = M_PI_2;
            mOrientedRanges.orientation.flat = 0;
            mOrientedRanges.orientation.fuzz = 0;
            mOrientedRanges.orientation.resolution = 0;
        }

        // 触摸的距离
        mDistanceScale = 0;
        if (mCalibration.distanceCalibration != Calibration::DISTANCE_CALIBRATION_NONE) {
            if (mCalibration.distanceCalibration == Calibration::DISTANCE_CALIBRATION_SCALED) {
                if (mCalibration.haveDistanceScale) {
                    mDistanceScale = mCalibration.distanceScale;
                } else {
                    mDistanceScale = 1.0f;
                }
            }

            mOrientedRanges.haveDistance = true;

            mOrientedRanges.distance.axis = AMOTION_EVENT_AXIS_DISTANCE;
            mOrientedRanges.distance.source = mSource;
            mOrientedRanges.distance.min = mRawPointerAxes.distance.minValue * mDistanceScale;
            mOrientedRanges.distance.max = mRawPointerAxes.distance.maxValue * mDistanceScale;
            mOrientedRanges.distance.flat = 0;
            mOrientedRanges.distance.fuzz = mRawPointerAxes.distance.fuzz * mDistanceScale;
            mOrientedRanges.distance.resolution = 0;
        }

		//计算当前屏幕朝向的精度和范围
        switch (mSurfaceOrientation) {
            case DISPLAY_ORIENTATION_90:
            case DISPLAY_ORIENTATION_270:
                mOrientedXPrecision = mYPrecision;
                mOrientedYPrecision = mXPrecision;

                mOrientedRanges.x.min = mYTranslate;
                mOrientedRanges.x.max = mSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.x.flat = 0;
                mOrientedRanges.x.fuzz = 0;
                mOrientedRanges.x.resolution = mRawPointerAxes.y.resolution * mYScale;

                mOrientedRanges.y.min = mXTranslate;
                mOrientedRanges.y.max = mSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.y.flat = 0;
                mOrientedRanges.y.fuzz = 0;
                mOrientedRanges.y.resolution = mRawPointerAxes.x.resolution * mXScale;
                break;

            default:
                mOrientedXPrecision = mXPrecision;
                mOrientedYPrecision = mYPrecision;

                mOrientedRanges.x.min = mXTranslate;
                mOrientedRanges.x.max = mSurfaceWidth + mXTranslate - 1;
                mOrientedRanges.x.flat = 0;
                mOrientedRanges.x.fuzz = 0;
                mOrientedRanges.x.resolution = mRawPointerAxes.x.resolution * mXScale;

                mOrientedRanges.y.min = mYTranslate;
                mOrientedRanges.y.max = mSurfaceHeight + mYTranslate - 1;
                mOrientedRanges.y.flat = 0;
                mOrientedRanges.y.fuzz = 0;
                mOrientedRanges.y.resolution = mRawPointerAxes.y.resolution * mYScale;
                break;
        }

        // Location
        updateAffineTransformation();

        if (mDeviceMode == DEVICE_MODE_POINTER) {//如果是类似于鼠标,则计算手势的相关参数
            // Compute pointer gesture detection parameters.
            float rawDiagonal = hypotf(rawWidth, rawHeight);//触摸板的宽和高
            float displayDiagonal = hypotf(mSurfaceWidth, mSurfaceHeight);//图像的宽和高

			//缩放移动,以便在没有施加加速度的情况下,触摸板的一次完整滑动覆盖相对于显示器对角线尺寸的给定区域。
			//假设触摸板具有方形纵横比,使得相同数量的原始单元在X和Y方向上的移动覆盖相同的物理距离。
            mPointerXMovementScale =
                    mConfig.pointerGestureMovementSpeedRatio * displayDiagonal / rawDiagonal;
					//pointerGestureMovementSpeedRatio是触摸板相对于显示器大小的手势移动速度因子。此值用于当手指沿同一方向移动时,移动速度适用。
            mPointerYMovementScale = mPointerXMovementScale;

            mPointerXZoomScale =
                    mConfig.pointerGestureZoomSpeedRatio * displayDiagonal / rawDiagonal;
					//是触摸板相对于显示器大小的手势移动速度因子。此值用于当手指主要相对移动时,缩放速度适用。
            mPointerYZoomScale = mPointerXZoomScale;

			//检测滑动的指针之间的最大宽度,如果大于触摸板对角线轴的某个分数则会认为是一个手势,而不是指针滑动,例如截屏
            mPointerGestureMaxSwipeWidth = mConfig.pointerGestureSwipeMaxWidthRatio * rawDiagonal;

            //中止当前指针的使用,因为状态已更改。
            abortPointerUsage(when, 0 /*policyFlags*/);
        }

        // 通知dispathcer这些变化
        *outResetNeeded = true;
        bumpGeneration();//更新设备的次数加1
    }
}

2.29 InputReaderConfiguration::getDisplayViewport

bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
        const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
    const DisplayViewport* viewport = NULL;
    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {//如果该屏幕的idc绑定了指定的displayid
        for (const DisplayViewport& currentViewport : mVirtualDisplays) {//mVirtualDisplays保存着多个DisplayViewport
            if (currentViewport.uniqueId == *uniqueDisplayId) {//找到虚拟窗口对应的Viewport
                viewport = &currentViewport;
                break;
            }
        }
    } else if (viewportType == ViewportType::VIEWPORT_EXTERNAL) {//外部设备
        viewport = &mExternalDisplay;
    } else if (viewportType == ViewportType::VIEWPORT_INTERNAL) {//内部设备,当触摸屏的idc中没有配置指定的displayid时,值是这个
        viewport = &mInternalDisplay;
    } else if (viewportType == ViewportType::VIEWPORT_TERTIARY1) {
        viewport = &mTertiaryDisplay1;
    } else if (viewportType == ViewportType::VIEWPORT_TERTIARY2) {
        viewport = &mTertiaryDisplay2;
    }

    if (viewport != NULL && viewport->displayId >= 0) {
        *outViewport = *viewport;
        return true;
    }
    return false;
}

2.30 TouchInputMapper::configureVirtualKeys

主要作用为:
1.配置每个虚拟按键,并计算每个虚拟按键的边界的位置。

void TouchInputMapper::configureVirtualKeys() {
    Vector<VirtualKeyDefinition> virtualKeyDefinitions;
    getEventHub()->getVirtualKeyDefinitions(getDeviceId(), virtualKeyDefinitions);//将virtualKeyMap中的map复制给virtualKeyDefinitions

    mVirtualKeys.clear();

    if (virtualKeyDefinitions.size() == 0) {
        return;
    }

    mVirtualKeys.setCapacity(virtualKeyDefinitions.size());

    int32_t touchScreenLeft = mRawPointerAxes.x.minValue;//获取触摸屏幕的最左端
    int32_t touchScreenTop = mRawPointerAxes.y.minValue;
    int32_t touchScreenWidth = mRawPointerAxes.x.maxValue - mRawPointerAxes.x.minValue + 1;
    int32_t touchScreenHeight = mRawPointerAxes.y.maxValue - mRawPointerAxes.y.minValue + 1;

    for (size_t i = 0; i < virtualKeyDefinitions.size(); i++) {
        const VirtualKeyDefinition& virtualKeyDefinition = virtualKeyDefinitions[i];

        mVirtualKeys.add();
        VirtualKey& virtualKey = mVirtualKeys.editTop();

        virtualKey.scanCode = virtualKeyDefinition.scanCode;//虚拟按键的扫描码等于Keymap中的扫描码
        int32_t keyCode;
        int32_t dummyKeyMetaState;
        uint32_t flags;
        if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0, &keyCode,
                                  &dummyKeyMetaState, &flags)) {
            ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring", virtualKey.scanCode);
            mVirtualKeys.pop(); // drop the key
            continue;
        }

        virtualKey.keyCode = keyCode;
        virtualKey.flags = flags;

        //将按键定义的显示坐标转换为点击框的触摸坐标
        int32_t halfWidth = virtualKeyDefinition.width / 2;
        int32_t halfHeight = virtualKeyDefinition.height / 2;

        virtualKey.hitLeft =
                (virtualKeyDefinition.centerX - halfWidth) * touchScreenWidth / mSurfaceWidth +
                touchScreenLeft;//获取每个虚拟按键的边界左
        virtualKey.hitRight =
                (virtualKeyDefinition.centerX + halfWidth) * touchScreenWidth / mSurfaceWidth +
                touchScreenLeft;//获取每个虚拟按键的边界右
        virtualKey.hitTop =
                (virtualKeyDefinition.centerY - halfHeight) * touchScreenHeight / mSurfaceHeight +
                touchScreenTop;
        virtualKey.hitBottom =
                (virtualKeyDefinition.centerY + halfHeight) * touchScreenHeight / mSurfaceHeight +
                touchScreenTop;
    }
}

至此,我们触摸屏的加载过程就全部了解完成了,那么好奇的读者在读到2.29节时,应该会想知道

viewport变量时在何处赋值的,值又代表什么含义,此处内容我们将放在下一篇进行详细的分析。

3.重要的类型

3.1 Parameters

//不可变的配置参数.
struct Parameters {
        enum DeviceType {//设备类型
            DEVICE_TYPE_TOUCH_SCREEN,//触摸屏幕
            DEVICE_TYPE_TOUCH_PAD,//触摸平板
            DEVICE_TYPE_TOUCH_NAVIGATION,//轨迹球导航设备
            DEVICE_TYPE_POINTER,//指针,感觉像是指鼠标
        };

        DeviceType deviceType;
        bool hasAssociatedDisplay;//具有关联的display
        bool associatedDisplayIsExternal;//关联的外部的display
        int associatedDisplayIsTertiary;//第三放的关联的display
        bool orientationAware;//方位感知
        bool hasButtonUnderPad;
        String8 uniqueDisplayId;//独一无二的displayid

        enum GestureMode {//手势模式
            GESTURE_MODE_SINGLE_TOUCH,//单触
            GESTURE_MODE_MULTI_TOUCH,//多点触摸
        };
        GestureMode gestureMode;

        bool wake;//是否唤醒
} mParameters;

3.2 Calibration

// 不可变的校准参数。
struct Calibration {
        // 大小
        enum SizeCalibration {
            SIZE_CALIBRATION_DEFAULT,//默认值大小
            SIZE_CALIBRATION_NONE,//大小为空
            SIZE_CALIBRATION_GEOMETRIC,
            SIZE_CALIBRATION_DIAMETER,
            SIZE_CALIBRATION_BOX,
            SIZE_CALIBRATION_AREA,
        };

        SizeCalibration sizeCalibration;

        bool haveSizeScale;
        float sizeScale;//大小缩放比例
        bool haveSizeBias;
        float sizeBias;//大小偏差
        bool haveSizeIsSummed;
        bool sizeIsSummed;

        //压力
        enum PressureCalibration {
            PRESSURE_CALIBRATION_DEFAULT,
            PRESSURE_CALIBRATION_NONE,
            PRESSURE_CALIBRATION_PHYSICAL,//压力校准_物理
            PRESSURE_CALIBRATION_AMPLITUDE,//压力校准_振幅
        };

        PressureCalibration pressureCalibration;
        bool havePressureScale;
        float pressureScale;

        // 方向
        enum OrientationCalibration {
            ORIENTATION_CALIBRATION_DEFAULT,
            ORIENTATION_CALIBRATION_NONE,
            ORIENTATION_CALIBRATION_INTERPOLATED,
            ORIENTATION_CALIBRATION_VECTOR,
        };

        OrientationCalibration orientationCalibration;

        // 距离
        enum DistanceCalibration {
            DISTANCE_CALIBRATION_DEFAULT,
            DISTANCE_CALIBRATION_NONE,
            DISTANCE_CALIBRATION_SCALED,
        };

        DistanceCalibration distanceCalibration;
        bool haveDistanceScale;
        float distanceScale;
		
		//范围
        enum CoverageCalibration {
            COVERAGE_CALIBRATION_DEFAULT,
            COVERAGE_CALIBRATION_NONE,
            COVERAGE_CALIBRATION_BOX,
        };

        CoverageCalibration coverageCalibration;

        inline void applySizeScaleAndBias(float* outSize) const {
            if (haveSizeScale) {
                *outSize *= sizeScale;
            }
            if (haveSizeBias) {
                *outSize += sizeBias;
            }
            if (*outSize < 0) {
                *outSize = 0;
            }
        }
} mCalibration;

3.3 RawPointerAxes

//来自驱动器的原始轴信息. 
stuct RawPointerAxes {
    RawAbsoluteAxisInfo x;
    RawAbsoluteAxisInfo y;
    RawAbsoluteAxisInfo pressure;//压力信息
    RawAbsoluteAxisInfo touchMajor;//触摸主要的轴
    RawAbsoluteAxisInfo touchMinor;//触摸次要
    RawAbsoluteAxisInfo toolMajor;//工具主要
    RawAbsoluteAxisInfo toolMinor;//工具次要
    RawAbsoluteAxisInfo orientation;//方向
    RawAbsoluteAxisInfo distance;//距离
    RawAbsoluteAxisInfo tiltX;//倾斜x
    RawAbsoluteAxisInfo tiltY;//倾斜y
    RawAbsoluteAxisInfo trackingId;//跟踪id
    RawAbsoluteAxisInfo slot;//slot

    RawPointerAxes();
    void clear();
};

3.4 RawAbsoluteAxisInfo

struct RawAbsoluteAxisInfo {
    bool valid; // 此项信息是否受到输入设备的支持,如果信息有效,则为true,否则为false

    int32_t minValue;  // 此项信息的最小值
    int32_t maxValue;  // 此项信息的最大值
    int32_t flat;      // 中心平面位置,例如flat==8表示中心在-8和8之间
    int32_t fuzz;      // 容错范围。表示因干扰所导致的最大偏移量,例如fuzz==4意味着干扰信息导致的值为+/-4
    int32_t resolution; // 精度,表示在1毫米的范围中的解析点的数量 
	//例如:
	//对设备的X坐标这项信息而言,RawAbsoluteAxisInfo的minValue和maxValue表示了事件上报的X坐标范围,
	//Resolution则表示传感器在每毫米距离中可以产生的X坐标点 的数量(ppm)。
	//X坐标与Y坐标的这些技术指标构建了传感器的物理坐标系。
	//而对压力值这项信息而言,如果其RawAbsoluteAxisInfo的valid值为false,则表示此设备不支持识别压力值。
	//当然,这些字段并不是对所有类型的信息都有效,例如对于传感器所支持的触控点数量这项信息,
	//仅有valid和maxValue两个字段有效,valid为true表示设备支持通过slot协议进行触控点索引的识别,
	//而maxValue则表示最大触控点的数量为maxValue+1。

    inline void clear() {
        valid = false;
        minValue = 0;
        maxValue = 0;
        flat = 0;
        fuzz = 0;
        resolution = 0;
    }
};
#define ABS_MT_SLOT		0x2f	/* MT slot being modified */
#define ABS_MT_TOUCH_MAJOR	0x30	/*触摸椭圆的长轴 */
#define ABS_MT_TOUCH_MINOR	0x31	/* touching椭圆的短轴(如果是圆形,则省略) */
#define ABS_MT_WIDTH_MAJOR	0x32	/* approaching椭圆的长轴 */
#define ABS_MT_WIDTH_MINOR	0x33	/* approaching椭圆的短轴(如果是圆形,则省略) */
#define ABS_MT_ORIENTATION	0x34	/* 椭圆方向 */
#define ABS_MT_POSITION_X	0x35	/* 椭圆中心X位置 */
#define ABS_MT_POSITION_Y	0x36	/* 椭圆中心Y位置 */
#define ABS_MT_TOOL_TYPE	0x37	/* 触摸设备类型 */
#define ABS_MT_BLOB_ID		0x38	/* 将一组数据包 as a blob */
#define ABS_MT_TRACKING_ID	0x39	/* 最初触摸的唯一ID */
#define ABS_MT_PRESSURE		0x3a	/* 触摸区域的压力 */
#define ABS_MT_DISTANCE		0x3b	/* 接触悬停距离 */

3.5 InputReaderConfiguration

struct InputReaderConfiguration {
    // 描述已发生的changes
    enum {
        // The pointer 速度改变
        CHANGE_POINTER_SPEED = 1 << 0,

        // The pointer手势控制已改变.
        CHANGE_POINTER_GESTURE_ENABLEMENT = 1 << 1,

        // 显示大小或方向已改变
        CHANGE_DISPLAY_INFO = 1 << 2,

        // 可见触摸选项已改变
        CHANGE_SHOW_TOUCHES = 1 << 3,

        // 键盘布局必须重新加载
        CHANGE_KEYBOARD_LAYOUTS = 1 << 4,

        // 对于某些设备,由提供的设备名称别名可能已更改。
        CHANGE_DEVICE_ALIAS = 1 << 5,

        //位置校准矩阵已更改
        CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6,

        // 外部手写笔的存在已更改
        CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7,

        // The pointer获取模式已更改
        CHANGE_POINTER_CAPTURE = 1 << 8,

        // 禁用的输入设备(disabledDevices)已更改。
        CHANGE_ENABLED_STATE = 1 << 9,

        // 所有设备必须重新打开
        CHANGE_MUST_REOPEN = 1 << 31,
    };
}
enum {
    /** unknown */
    AINPUT_SOURCE_UNKNOWN = 0x00000000,
    /** 键盘 */
    AINPUT_SOURCE_KEYBOARD = 0x00000100 | AINPUT_SOURCE_CLASS_BUTTON,
    /** 老式的方向按键的手机 */
    AINPUT_SOURCE_DPAD = 0x00000200 | AINPUT_SOURCE_CLASS_BUTTON,
    /** 游戏手柄*/
    AINPUT_SOURCE_GAMEPAD = 0x00000400 | AINPUT_SOURCE_CLASS_BUTTON,
    /** 触摸屏幕 */
    AINPUT_SOURCE_TOUCHSCREEN = 0x00001000 | AINPUT_SOURCE_CLASS_POINTER,
    /** 鼠标 */
    AINPUT_SOURCE_MOUSE = 0x00002000 | AINPUT_SOURCE_CLASS_POINTER,
    /** 手写笔 */
    AINPUT_SOURCE_STYLUS = 0x00004000 | AINPUT_SOURCE_CLASS_POINTER,
    /** 蓝牙手写笔 */
    AINPUT_SOURCE_BLUETOOTH_STYLUS = 0x00008000 | AINPUT_SOURCE_STYLUS,
    /** 光标轨迹球 */
    AINPUT_SOURCE_TRACKBALL = 0x00010000 | AINPUT_SOURCE_CLASS_NAVIGATION,
    /** mouse relative */
    AINPUT_SOURCE_MOUSE_RELATIVE = 0x00020000 | AINPUT_SOURCE_CLASS_NAVIGATION,
    /** 触摸板 */
    AINPUT_SOURCE_TOUCHPAD = 0x00100000 | AINPUT_SOURCE_CLASS_POSITION,
    /** 触摸导航*/
    AINPUT_SOURCE_TOUCH_NAVIGATION = 0x00200000 | AINPUT_SOURCE_CLASS_NONE,
    /** 游戏杆 */
    AINPUT_SOURCE_JOYSTICK = 0x01000000 | AINPUT_SOURCE_CLASS_JOYSTICK,
    /** rotary encoder */
    AINPUT_SOURCE_ROTARY_ENCODER = 0x00400000 | AINPUT_SOURCE_CLASS_NONE,
    /** any */
    AINPUT_SOURCE_ANY = 0xffffff00,
};	

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2043205.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

传知代码-CENet及多模态情感计算实战(论文复现)

代码以及视频讲解 本文所涉及所有资源均在传知代码平台可获取 一、概述 本文对 “Cross-Modal Enhancement Network for Multimodal Sentiment Analysis” 论文进行讲解和手把手复现教学&#xff0c;解决当下热门的多模态情感计算问题&#xff0c;并展示在MOSI和MOSEI两个数…

labview经验分享1-任意16进制字符类型匹配

系列文章目录 1、任意16进制字符类型匹配 文章目录 系列文章目录问题导入实现任意16进制字符类型匹配在这里插入图片描述 总结 问题导入 labveiw的字符串匹配&#xff0c;使用的是正则表达式&#xff0c;可以让我们很方便的对字符串进行字符处理操作。 但是某些情况下&#…

WEB渗透Bypass篇-常规操作

绕过lsa-protection https://github.com/RedCursorSecurityConsulting/PPLKillerLinux绕过disable_function LD_PRELOAD linux环境 putenv()、mail()可用 https://github.com/yangyangwithgnu/bypass_disablefunc_via_LD_PRELOAD http://192.168.0.107/bypass_disablefunc.p…

一篇文章教你搭建一个高深莫测的SQL优化器

❓在数据库操作中&#xff0c;SQL优化一直是一个让人头疼的问题。今天&#xff0c;我将教你一种无需编写任何代码&#xff0c;只需要两个组件&#xff0c;便能轻松搭建一个高深莫测的SQL优化器的方法。通过这个方法&#xff0c;它可以将巨慢无比的SQL&#xff0c;把速度优化到极…

重启人生计划-浮舟沧海

&#x1f973;&#x1f973;&#x1f973; 茫茫人海千千万万&#xff0c;感谢这一刻你看到了我的文章&#xff0c;感谢观赏&#xff0c;大家好呀&#xff0c;我是最爱吃鱼罐头&#xff0c;大家可以叫鱼罐头呦~&#x1f973;&#x1f973;&#x1f973; 如果你觉得这个【重启人生…

VIM复合命令

VIM提供了很多 复合命令&#xff0c;可以把两个动作合并为一次按键。极大提高了编辑效率。以下是一些具体的例子&#xff1a; 复合命令等效的长命令说明Cc$删除光标到行尾scl删除光标位置的字符S^C删除整行I^i光标移动到行首A$a光标移动到行尾oA 回车光标下方开启一行Oko光标…

一文掌握SOP搭建步骤方法

如果你正在阅读这篇文章&#xff0c;那么你很可能在寻找如何为你的企业编写标准操作程序&#xff08;SOP&#xff09;的指导&#xff0c;以确保更好的流程被传达给你的团队并且得到遵循。 为什么SOPs很重要 SOPs必须清晰地传达你的业务流程&#xff0c;以标准化操作并确保盈利性…

Vue2 消息订阅与发布

1.pubsub-js 第三方库实现 实现任何框架的消息订阅发布 npm i pubsub-js <template><div class"student"><h2>展示学生的名称:{{ name }}</h2><h2>展示学生的性别:{{ sex }}</h2></div> </template><script>…

浏览器插件利器--allWebPluginV2.0.0.16-Stable版发布

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品&#xff0c;致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器&#xff0c;实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

ollama使用llama3.1案例

ollama安装和运行llama3.1 8b conda create -n ollama python3.11 -y conda activate ollama curl -fsSL https://ollama.com/install.sh | sh ollama run songfy/llama3.1:8b 就这么简单就能运行起来了. 我们可以在命令行中与他交互. 当然我们也可以用接口访问: curl http:…

在IDEA中用自带的数据库 连接 redis 失败(JedisAccessControlException)

文章目录 1、问题出现的背景2、分析问题出现的原因3、解决办法不用输入用户名直接输入密码即可 1、问题出现的背景 redis.clients.jedis.exceptions.JedisAccessControlException: WRONGPASS invalid username-password pair or user is disabled.2、分析问题出现的原因 查看…

智慧水务项目(六)PyScada学习一,初步建立项目并测试

一、说明 Pyscada是scada的python实现&#xff0c;需要学习一下&#xff0c;以备不时之需&#xff0c;目前我的想法是用他来模拟opc数据&#xff0c;毕竟我准备做的项目需要系统与scada通过opc进行通信&#xff0c;正好做一个简单的scada系统 是一个开源的SCADA&#xff08;S…

记录|C#主界面设计【Web风格】

目录 前言一、页面效果二、布局设计2.1 左边菜单栏搭建框架Step1. panelMenu &#xff1a;Step2. panelLogoStep3. button模板Step4. 复制buttonStep5. 微调Button 2.2 界面颜色变换Step1. ThemeColor类Step2. From1.csStep3. 更换按钮点击颜色效果 2.3 按钮点击事件2.4 顶部ti…

十、Linux二进制安装ClickHouse集群(含rpm安装)

目录 十、Linux二进制安装ClickHouse集群(含rpm安装&#xff0c;单机版使用rpm&#xff0c;集群使用tar包安装方式)1 部署前服务器配置&#xff08;集群的话三台都要配置&#xff09;1.2 配置hosts文件1.3 打开文件数限制1.4 取消 SELINUX1.5 禁用透明大页 2 下载所需文件2.1 t…

24/8/14算法笔记 复习_支持向量机svc

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种强大的监督学习模型&#xff0c;用于分类、回归甚至异常检测。它基于统计学习理论&#xff0c;特别关注找到数据的最佳分隔超平面。 import numpy as np import matplotlib.pyplot as pltfrom sklearn.sv…

vue3 antdv a-datepicker 修改datepicker 的panel宽度,初始弹出一些正常,但再次弹出,宽度就再次变小的解决

1、展示页面的框架结构&#xff1a; 2、然后&#xff0c;我们上二张图对比一下&#xff1a; 图1-1 需要的效果图&#xff1a; 图1-2 对比一下图1-1与图1-2&#xff0c;我们就会发现图1-1中的农历&#xff0c;换行显示了&#xff0c;第二张是有效的。 3、我们修改样式&#x…

秋招突击——8/15——知识补充——垃圾回收机制

文章目录 引言正文指针引用可达性分析算法垃圾回收算法标记清除算法标记整理算法复制分代收集 垃圾收集器Serial收集器ParNew并行收集器Parallel Scavenge吞吐量优先收集器Serial Old老年代收集器Parallel old收集器CMS收集器G1收集器&#xff08;Garbage First垃圾优先&#x…

关于堆的介绍

1.堆的概念及结构 如果有一个关键码的集合&#xff0c;把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中&#xff0c;并满足&#xff1a;且则称为小堆&#xff08;或大堆&#xff09;。将根节点最大的堆叫做最大堆或者大根堆&#xff0c;根节点最小的堆叫做最小…

【Linux】:进程控制(创建、终止、等待、替换)

目录 1.进程创建 2.进程终止&#xff08;退出&#xff09; 2.1 什么是进程终止 2.2 进程退出的场景&#xff08;原因&#xff09; 2.3 进程退出码 2.4 错误码errno 2.5 进程常见的退出方法 正常终止 从main函数返回 调用库函数exit 系统接口_exit 3.进程等待 3.1 …

【Linux】简易线程池项目

线程池是一个可以巩固一些线程相关接口 && 加强理解的一个小项目。 注意&#xff1a;这里的线程池使用的线程并不是Linux原生接口&#xff0c;而是经过封装的&#xff0c;具体请看线程封装&#xff0c;为什么不使用原生接口&#xff1f; 因为原生接口一旦进行pthread…