背景

前文说到需求,需要在系统应用里模拟手柄摇杆和按键。之前已经通过模拟KeyEvent实现按键,模拟MotionEvent实现摇杆大致实现了这个功能,但是遇到新的问题,有些游戏不识别按键,尤其是多人云游戏。

解决方案

大致了解之后, KeyEvent和MotionEvent里有个deviceId字段,这个字段是用来表示不同的设备的。比如多人游戏,a手柄和b手柄的deviceId是不同的,游戏根据这个来区分不同的人做的操作,游戏可能是根据这个deviceId是否存在并且可以匹配,如果不存在则可能不处理这个事件。

  1. 第一想法是虚构一个deviceId,游戏都是通过InputDevice.getDeviceIds 来获取全部的,于是我反射了这个类的mInputDevices,但最后效果还是不可以,游戏还是无法识别。

  2. 搜索到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模拟手柄设备相关推荐

  1. Android 使用 sendevent 模拟鼠标和键盘事件

    Android 使用 sendevent 模拟鼠标和键盘事件 模拟原理是对驱动发送消息,就是linux里面的input子系统. 命令格式: sendevent /dev/input/eventX [t ...

  2. 大学android移动开发笔记,基于Android的移动模拟练习系统的设计与实现

    李思莉 聂芝献 摘要:该文主要论述基于Android的移动模拟练习系统的功能设计及数据设计.数据实现.该系统客户端使用基于Android的移动应用开发技术,服务器端采用JAVA WEB+MySQL技术 ...

  3. android x86还是arm,Android x86是否模拟ARM?(Does Android x86 emulate ARM?)

    Android x86是否模拟ARM?(Does Android x86 emulate ARM?) 试图找出应用程序在为ARM编译时如何在VMWare上的Android x86上工作. GUI是否在 ...

  4. 如何在android模拟器中模拟sd卡,如何在Android模拟器中模拟SD卡

    如何在Android模拟器中模拟SD卡 简介 Android允许开发者创建一个SD卡镜像并在启动模拟器加载它, 用于模拟物理设备中的SD卡. 下面将介绍: 1. 如何创建一个SD卡镜像? 2. 如何拷 ...

  5. 关于HCE——Android手机NFC模拟刷卡成果和心得(上)

    关于HCE--Android手机NFC模拟刷卡成果和心得 一.前言 在最近,开始研究了手机模拟NFC刷卡的一些内容,想是自己实现一次手机模拟刷卡. NFC大家应该都了解,这两年的安卓手机基本都是支持了 ...

  6. Android使用NFC模拟M卡实现 (一)

    Android使用NFC模拟M卡实现 (一) Android使用NFC模拟M卡实现 (二) Android使用NFC模拟M卡实现 (三) 在百度找一遍,没有一篇,讲的比较通俗易懂的文件.讲解Andro ...

  7. 记一次尝试用脚本模拟手柄打游戏(一)

    最近打游戏累了 想自动化打游戏 最开始是打算模拟键鼠方案的,但是吧,很快就遇到了问题. 对于常规的窗口来讲,ctypes库足以模拟键鼠输入了 但是进到第三人称视角的游戏里面吧,键盘模拟还好说,鼠标移动 ...

  8. appcompat v21: 让 Android 5.0 前的设备支持 Material Design

    1. 十大Material Design开源项目 2. appcompat v21: 让 Android 5.0 前的设备支持 Material Design 主题 AppCompat已经支持最新的调 ...

  9. uinput模拟触摸屏双指放大与缩小

    uinput模拟触摸屏双指放大与缩小 前言 创建虚拟设备并配置属性 写入单个事件 创建事件序列 程序运行过程 前言 有时为了获取某种事件,需要使用uinput来创建一个虚拟的设备,通过先配置好设备属性 ...

最新文章

  1. python opencv 官方文档里LaTeX公式不能正常显示怎么办?
  2. 如何查看软连接,以及相关注意事项
  3. 视频测试序列的下载地址
  4. Python02期预科课程笔记索引
  5. Symantec(赛门铁克)非受管检测
  6. get,post网络请求
  7. LUT查表法乘法器所犯下错误。。。。
  8. 2021年最新的Java面试题,精选100题,大厂必备
  9. 欠拟合与过拟合概念和局部加权回归
  10. Liunx树莓派(ARM)开发篇—第六章、树莓派wiringPi库外设开发
  11. Yoshua Bengio:深度学习的未来需要“探索高级认知的归纳偏置”
  12. LDPC — 信道编码
  13. zblog微信小程序模板-青春主题小程序免费开源模板
  14. ab并发测试-Linux
  15. 无线路由器的设置方法
  16. 北航计算机组成实验project4,北航fpga实验的报告.docx
  17. 基于Python的毕业论文怎么写?
  18. 机器视觉工程师前景如何,计算机视觉工程师薪资
  19. 计算机学院学生工作办公室,上海交通大学-电子信息与电气工程学院-学生工作办公室...
  20. 在JSP页面中获取JavaScript中var变量的值

热门文章

  1. 【Python·问题解决】IndexError: too many indices for array: array is 2-dimensional, but 3 were indexed
  2. linux的gtk无法显示中文,GTK中文显示出现乱码解决方案
  3. 行业软件下载整理(全)
  4. Sysdiagnose在iOS能耗测试中的应用
  5. 用asp.net开发的网站的运行环境
  6. magento两个比较好的运费插件
  7. 什么是Kubernetes? 一文了解K8s是什么_红帽
  8. DS18B20温度转化
  9. 22.10.25补卡 一堆cf水题
  10. SQL创建表之数据类型;