Android 使用uInput模拟手柄设备
背景
前文说到需求,需要在系统应用里模拟手柄摇杆和按键。之前已经通过模拟KeyEvent实现按键,模拟MotionEvent实现摇杆大致实现了这个功能,但是遇到新的问题,有些游戏不识别按键,尤其是多人云游戏。
解决方案
大致了解之后, KeyEvent和MotionEvent里有个deviceId字段,这个字段是用来表示不同的设备的。比如多人游戏,a手柄和b手柄的deviceId是不同的,游戏根据这个来区分不同的人做的操作,游戏可能是根据这个deviceId是否存在并且可以匹配,如果不存在则可能不处理这个事件。
第一想法是虚构一个deviceId,游戏都是通过InputDevice.getDeviceIds 来获取全部的,于是我反射了这个类的mInputDevices,但最后效果还是不可以,游戏还是无法识别。
搜索到Linux提供了/dev/uinput 可以用来虚拟外接设备。从底层虚拟输入设备。声明这个设备支持了摇杆和一些按键,操控实际的手柄。
#include "com_test_CommandDispatcher.h"#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <linux/uinput.h>
#include <linux/input.h>#include "android/log.h"
static const char *TAG="uinput";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)#define KEY_CUSTOM_UP 0x20
#define KEY_CUSTOM_DOWN 0x30static struct uinput_user_dev uinput_dev;
static int uinput_fd;extern "C"
JNIEXPORT jint JNICALLJava_com_test_CommandDispatcher_createUinput(JNIEnv* env,
jobject /* this */,jstring name) {int i;int ret = 0;const char *strContent = env->GetStringUTFChars(name, JNI_FALSE);uinput_fd = open("/dev/uinput", O_RDWR | O_NDELAY);if(uinput_fd < 0){LOGE("%s:%d\n", __func__, __LINE__);return -1;//error process.}//to set uinput devmemset(&uinput_dev, 0, sizeof(struct uinput_user_dev));strcpy(uinput_dev.name,strContent);env->ReleaseStringUTFChars(name, strContent);uinput_dev.id.version = 1;//BUS_VIRTUAL BUS_USB时对于游戏来说这个设备是真实存在通过usb连接的uinput_dev.id.bustype = BUS_USB;uinput_dev.id.vendor = 0x1;uinput_dev.id.product = 0x1;//min 和 max必须不同uinput_dev.absmin[ABS_X] = -1;uinput_dev.absmax[ABS_X] = 1;uinput_dev.absmin[ABS_Y] = -1;uinput_dev.absmax[ABS_Y] = 1;uinput_dev.absmin[ABS_Z] = -1;uinput_dev.absmax[ABS_Z] = 1;uinput_dev.absmin[ABS_RZ] = -1;uinput_dev.absmax[ABS_RZ] = 1;uinput_dev.absmin[ABS_THROTTLE] = -1;uinput_dev.absmax[ABS_THROTTLE] = 1;uinput_dev.absmin[ABS_BRAKE] = -1;uinput_dev.absmax[ABS_BRAKE] = 1;uinput_dev.absmin[ABS_HAT0X] = -1;uinput_dev.absmax[ABS_HAT0X] = 1;uinput_dev.absmin[ABS_HAT0Y] = -1;uinput_dev.absmax[ABS_HAT0Y] = 1;ioctl(uinput_fd, UI_SET_EVBIT, EV_SYN);ioctl(uinput_fd, UI_SET_EVBIT, EV_KEY);ioctl(uinput_fd, UI_SET_EVBIT, EV_MSC);for(i = 0; i < 256; i++){ioctl(uinput_fd, UI_SET_KEYBIT, i);}ioctl(uinput_fd, UI_SET_KEYBIT, BTN_THUMBL);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_THUMBR);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_X);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_A);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_Y);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_B);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_RIGHT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_LEFT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_SELECT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_START);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_DPAD_LEFT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_DPAD_RIGHT);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_DPAD_UP);ioctl(uinput_fd, UI_SET_KEYBIT, BTN_DPAD_DOWN);ioctl(uinput_fd, UI_SET_EVBIT, EV_ABS);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_HAT0X);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_HAT0Y);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_X);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_Y);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_Z);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_RZ);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_THROTTLE);ioctl(uinput_fd, UI_SET_ABSBIT, ABS_BRAKE);ioctl(uinput_fd, UI_SET_MSCBIT, KEY_CUSTOM_UP);ioctl(uinput_fd, UI_SET_MSCBIT, KEY_CUSTOM_DOWN);ret = write(uinput_fd, &uinput_dev, sizeof(struct uinput_user_dev));if(ret < 0){LOGE("%s:%d\n", __func__, __LINE__);return ret;//error process.}ret = ioctl(uinput_fd, UI_DEV_CREATE);if(ret < 0){LOGE("%s:%d\n", __func__, __LINE__);close(uinput_fd);return ret;//error process.}return 1;
}JNIEXPORT void JNICALL Java_com_test_CommandDispatcher_closeUinput(JNIEnv *, jobject) {close(uinput_fd);
}
createUinput 传入的参数就是设备名,调用方法后,
通过InputDevice.getDeviceIds()拿到所有的deviceId,
通过InputDevice.getDevice(deviceId) 拿到device,
判断device.getName和设备名一致时,device.getId()就是deviceId.
后续模拟事件都使用该id即可。
其他
这种在native层通过写/dev/uinput虚拟出设备, 然后在Android层模拟各种事件实现其实是比较取巧的办法,虚拟出设备后,其实是可以往这个设备节点写数据,达到模拟输入的效果的。参考下面第二个文档。
参考文档
使用UInput模拟系统输入设备–键盘,鼠标,触摸屏
android 使用uinput模拟输入设备
Android 使用uInput模拟手柄设备相关推荐
- Android 使用 sendevent 模拟鼠标和键盘事件
Android 使用 sendevent 模拟鼠标和键盘事件 模拟原理是对驱动发送消息,就是linux里面的input子系统. 命令格式: sendevent /dev/input/eventX [t ...
- 大学android移动开发笔记,基于Android的移动模拟练习系统的设计与实现
李思莉 聂芝献 摘要:该文主要论述基于Android的移动模拟练习系统的功能设计及数据设计.数据实现.该系统客户端使用基于Android的移动应用开发技术,服务器端采用JAVA WEB+MySQL技术 ...
- android x86还是arm,Android x86是否模拟ARM?(Does Android x86 emulate ARM?)
Android x86是否模拟ARM?(Does Android x86 emulate ARM?) 试图找出应用程序在为ARM编译时如何在VMWare上的Android x86上工作. GUI是否在 ...
- 如何在android模拟器中模拟sd卡,如何在Android模拟器中模拟SD卡
如何在Android模拟器中模拟SD卡 简介 Android允许开发者创建一个SD卡镜像并在启动模拟器加载它, 用于模拟物理设备中的SD卡. 下面将介绍: 1. 如何创建一个SD卡镜像? 2. 如何拷 ...
- 关于HCE——Android手机NFC模拟刷卡成果和心得(上)
关于HCE--Android手机NFC模拟刷卡成果和心得 一.前言 在最近,开始研究了手机模拟NFC刷卡的一些内容,想是自己实现一次手机模拟刷卡. NFC大家应该都了解,这两年的安卓手机基本都是支持了 ...
- Android使用NFC模拟M卡实现 (一)
Android使用NFC模拟M卡实现 (一) Android使用NFC模拟M卡实现 (二) Android使用NFC模拟M卡实现 (三) 在百度找一遍,没有一篇,讲的比较通俗易懂的文件.讲解Andro ...
- 记一次尝试用脚本模拟手柄打游戏(一)
最近打游戏累了 想自动化打游戏 最开始是打算模拟键鼠方案的,但是吧,很快就遇到了问题. 对于常规的窗口来讲,ctypes库足以模拟键鼠输入了 但是进到第三人称视角的游戏里面吧,键盘模拟还好说,鼠标移动 ...
- appcompat v21: 让 Android 5.0 前的设备支持 Material Design
1. 十大Material Design开源项目 2. appcompat v21: 让 Android 5.0 前的设备支持 Material Design 主题 AppCompat已经支持最新的调 ...
- uinput模拟触摸屏双指放大与缩小
uinput模拟触摸屏双指放大与缩小 前言 创建虚拟设备并配置属性 写入单个事件 创建事件序列 程序运行过程 前言 有时为了获取某种事件,需要使用uinput来创建一个虚拟的设备,通过先配置好设备属性 ...
最新文章
- python opencv 官方文档里LaTeX公式不能正常显示怎么办?
- 如何查看软连接,以及相关注意事项
- 视频测试序列的下载地址
- Python02期预科课程笔记索引
- Symantec(赛门铁克)非受管检测
- get,post网络请求
- LUT查表法乘法器所犯下错误。。。。
- 2021年最新的Java面试题,精选100题,大厂必备
- 欠拟合与过拟合概念和局部加权回归
- Liunx树莓派(ARM)开发篇—第六章、树莓派wiringPi库外设开发
- Yoshua Bengio:深度学习的未来需要“探索高级认知的归纳偏置”
- LDPC — 信道编码
- zblog微信小程序模板-青春主题小程序免费开源模板
- ab并发测试-Linux
- 无线路由器的设置方法
- 北航计算机组成实验project4,北航fpga实验的报告.docx
- 基于Python的毕业论文怎么写?
- 机器视觉工程师前景如何,计算机视觉工程师薪资
- 计算机学院学生工作办公室,上海交通大学-电子信息与电气工程学院-学生工作办公室...
- 在JSP页面中获取JavaScript中var变量的值
热门文章
- 【Python·问题解决】IndexError: too many indices for array: array is 2-dimensional, but 3 were indexed
- linux的gtk无法显示中文,GTK中文显示出现乱码解决方案
- 行业软件下载整理(全)
- Sysdiagnose在iOS能耗测试中的应用
- 用asp.net开发的网站的运行环境
- magento两个比较好的运费插件
- 什么是Kubernetes? 一文了解K8s是什么_红帽
- DS18B20温度转化
- 22.10.25补卡 一堆cf水题
- SQL创建表之数据类型;