安卓纯native层模拟手指触摸
前言: 写此项目主要是因为市面上好像并没有一个像样的模拟触摸工具(不与手指触摸冲突.有人维护并且开源)
其实这个项目去年就写完了,但是还是突然想记录一下…
思路
本来想的很简单,用uinput模块创建驱动并提交事件,但是写完了才发现并没有这么简单,一但手指触摸和虚拟触摸同时存在就会冲突
然后又想着可否把真实的触摸给屏蔽掉,与虚拟触摸进行融合,然后在虚拟设备中统一提交?
说干就淦!
实现
初始化屏幕信息
void touch::InitScreenInfo() { std::string window_size = exec("wm size"); sscanf(window_size.c_str(), "Physical size: %dx%d", &this->screenInfo.width, &this->screenInfo.height); }
|
初始化触摸屏信息
void touch::InitTouchScreenInfo() { bool isFound{false}; for (const auto &entry: std::filesystem::directory_iterator("/dev/input/")) { int fd = open(entry.path().c_str(), O_RDWR); if(fd < 0) { std::cout<<"打开"<<entry.path()<<"失败"<<std::endl; } input_absinfo absinfo{}; ioctl(fd, EVIOCGABS(ABS_MT_SLOT), &absinfo); if (absinfo.maximum == 9) { if(!isFound) { isFound = true; this->touchScreenInfo.fd = open(entry.path().c_str(), O_RDWR); close(fd); if(touchScreenInfo.width == 0||touchScreenInfo.height == 0) { input_absinfo absX{}, absY{}; ioctl(touchScreenInfo.fd, EVIOCGABS(ABS_MT_POSITION_X), &absX); ioctl(touchScreenInfo.fd, EVIOCGABS(ABS_MT_POSITION_Y), &absY); if(absX.maximum!=0&&absY.maximum!=0) { this->touchScreenInfo.width = absX.maximum; this->touchScreenInfo.height = absY.maximum; } } } else { if(touchScreenInfo.width == 0||touchScreenInfo.height == 0) { input_absinfo absX{}, absY{}; ioctl(fd, EVIOCGABS(ABS_MT_POSITION_X), &absX); ioctl(fd, EVIOCGABS(ABS_MT_POSITION_Y), &absY); if(absX.maximum!=0 && absY.maximum!=0) { this->touchScreenInfo.width = absX.maximum; this->touchScreenInfo.height = absY.maximum; } } ioctl(fd, EVIOCGRAB, 0x1); threads.emplace_back(&touch::PTScreenEventToFingerByFd,this,fd); } } } }
|
这样写是因为ABS_MT_SLOT为9的设备在部分设备上好像不止一个……
转换
把物理触摸信息转换为touchOBJ
void touch::PTScreenEventToFinger() { input_event ie{}; int latestSlot{}; while (true) { read(touchScreenInfo.fd, &ie, sizeof(ie)); { if (ie.type == EV_ABS) { if (ie.code == ABS_MT_SLOT) { latestSlot = ie.value; Fingers[0][latestSlot].TRACKING_ID = 114514 + latestSlot; continue; } if (ie.code == ABS_MT_TRACKING_ID) { if (ie.value == -1) { Fingers[0][latestSlot].isDown = false; Fingers[0][latestSlot].isUse = false; } else { Fingers[0][latestSlot].isUse = true; Fingers[0][latestSlot].isDown = true; } continue; } if (ie.code == ABS_MT_POSITION_X) { Fingers[0][latestSlot].x = ie.value; continue; } if (ie.code == ABS_MT_POSITION_Y) { Fingers[0][latestSlot].y = ie.value; continue; } } if (ie.type == EV_SYN) { if (ie.code == SYN_REPORT) { upLoad(); continue; } continue; } } } }
|
把touchOBJ转为触摸信息并提交
void touch::upLoad() { std::vector<input_event> events{}; for (auto &fingers: Fingers) { for (auto &finger: fingers) { if (finger.isDown) { input_event down_events[] { {.type = EV_ABS, .code = ABS_MT_TRACKING_ID, .value = finger.TRACKING_ID}, {.type = EV_ABS, .code = ABS_MT_POSITION_X, .value = finger.x}, {.type = EV_ABS, .code = ABS_MT_POSITION_Y, .value = finger.y}, {.type = EV_SYN, .code = SYN_MT_REPORT, .value = 0}, }; int arrCount = sizeof(down_events) / sizeof(down_events[0]); events.insert(events.end(), down_events, down_events + arrCount); } } } input_event touchEnd{}; touchEnd.type = EV_SYN; touchEnd.code = SYN_MT_REPORT; touchEnd.value = 0; events.push_back(touchEnd); input_event end{}; end.type = EV_SYN; end.code = SYN_REPORT; end.value = 0; events.push_back(end); for (const auto &event: events) { write(uinputFd, &event, sizeof(event)); } events.clear(); }
|
BY
有几点可能要说一下
1.最后提交的时候是使用的多点触控a协议,因为b协议我写出来有bug,没找出哪里的原因,发现linux内核同时支持ab,索性就用a了
2.效率略低,有很大优化空间
3.开源地址