android 模拟触摸
来源:互联网 发布:虚拟机安装mac卡 编辑:程序博客网 时间:2024/06/06 05:40
package android.car.server.input;import android.car.utils.InputIoctl;import android.car.utils.touch.TouchWriter;import android.os.SystemClock;import android.util.Log;import android.view.InputDevice;import android.view.MotionEvent;import android.view.MotionEvent.PointerCoords;import java.util.ArrayList;import static android.car.define.MainConfig.MCU_DEBUG;import static android.view.MotionEvent.ACTION_DOWN;import static android.view.MotionEvent.ACTION_MOVE;import static android.view.MotionEvent.ACTION_POINTER_DOWN;import static android.view.MotionEvent.ACTION_POINTER_INDEX_MASK;import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;import static android.view.MotionEvent.ACTION_POINTER_UP;import static android.view.MotionEvent.ACTION_UP;public class MultiTouchInject { static final String TAG = "Car-MultiTouchInject"; private static final int MAX_TOUCH_COUNT = 10; public static boolean USE_TOUCH_WRITER = true; private int[] mPointerIds = new int[MAX_TOUCH_COUNT]; private PointerCoords[] mPointerCoords = new PointerCoords[MAX_TOUCH_COUNT]; private long mMultiTouchDownTime = 0; private TouchWriter mTouchWriter; static class PointerState { public boolean valid; public int id; public int action; public int x; public int y; public void clear() { valid = false; id = -1; action = -1; x = 0; y = 0; } } private PointerState[] mPointers = new PointerState[MAX_TOUCH_COUNT]; private ArrayList<PointerState> mActivePointers = new ArrayList<>(); public MultiTouchInject() { for (int i = 0; i < MAX_TOUCH_COUNT; ++i) { mPointerCoords[i] = new PointerCoords(); mPointers[i] = new PointerState(); } String touchInputDevice = InputIoctl.getTouchInputDevicePath(); Log.e(TAG, "touchInputDevice=" + touchInputDevice); mTouchWriter = new TouchWriter(touchInputDevice); mTouchWriter.init(); } /** * 生成多点action */ private int makeMtAction(int id, int action) { return ((id << ACTION_POINTER_INDEX_SHIFT) & ACTION_POINTER_INDEX_MASK) | action; } /** * 通过id和action生成多点时用的action * * @param id * @param action * @return */ private int getMultiAction(int id, int action) { // 如果是第一个点或MOVE事件, 则直接使用 switch (action) { case ACTION_MOVE: return ACTION_MOVE; case ACTION_DOWN: return makeMtAction(id, ACTION_POINTER_DOWN); case ACTION_UP: return makeMtAction(id, ACTION_POINTER_UP); } return -1; } private void stateToCoords(PointerState ps, PointerCoords pc) { pc.clear(); pc.x = ps.x; pc.y = ps.y; pc.pressure = 1.0f; pc.size = 1.0f; } // 使用TouchWrite方式写入, 注意和另一个函数不能同时使用 public void addTouchEventRaw(int id, int action, int x, int y, int w, int h) { if (id < 0 || id >= MAX_TOUCH_COUNT) { return; } final PointerState ps = mPointers[id]; if (ps.id == id && ACTION_MOVE == action && ps.x == x && ps.y == y) { return; } ps.valid = true; ps.id = id; ps.action = action; ps.x = x; ps.y = y; // 当第一次DOWN时, 产生DOWN事件 if (mActivePointers.size() == 0 && action == ACTION_DOWN) { mTouchWriter.writeDown(); } if (!mActivePointers.contains(ps)) { mActivePointers.add(ps); } int count = mActivePointers.size(); // 产生点事件 for (PointerState i : mActivePointers) { if (i.valid && i.id >= 0 && i.id < MAX_TOUCH_COUNT) { mTouchWriter.writePoint(i.id, i.x, i.y, w, h); } } mTouchWriter.writeSync(); if (count == 1 && action == ACTION_UP) { // 只有一个点并且为UP时, 产生UP事件 mTouchWriter.writeUp(); } if (action == ACTION_UP) { ps.clear(); if (mActivePointers.contains(ps)) { mActivePointers.remove(ps); } } } public MotionEvent addTouchEvent(int id, int action, int x, int y) { if (id < 0 || id >= MAX_TOUCH_COUNT) { return null; } long eventTime = SystemClock.uptimeMillis(); final PointerState ps = mPointers[id];// if (ps.id == id// && ps.action == action// && action == ACTION_MOVE// && ps.x == x// && ps.y == y) {// return null;// } ps.valid = true; ps.id = id; ps.action = action; ps.x = x; ps.y = y; long downTime = eventTime; // 当第一次DOWN时, 记录downTime if (mActivePointers.size() == 0 && action == ACTION_DOWN) { mMultiTouchDownTime = downTime; } else { downTime = mMultiTouchDownTime; } if (!mActivePointers.contains(ps)) { mActivePointers.add(ps); } int count = mActivePointers.size(); // 对Action做处理 // 1.单点时, 使用ACTION_DOWN/UP // 2.当多点时, 使用ACTION_POINTER_DOWN/UP // 3.最后一个点UP时, 使用ACTION_UP int mtAction = getMultiAction(id, action); int finalAction = mtAction; // 只有一个点并且id为0时, 使用原本的action if (count == 1 && id == 0) { finalAction = action; } else if (count == 1 && action == ACTION_UP) { // 只有一个点并且为UP时, 使用ACTION_UP finalAction = action; } if (MCU_DEBUG) Log.e(TAG, "addTouchEvent count=" + count + ", id=" + id + ", x=" + x + " y=" + y + ", action=" + MotionEvent.actionToString(action) + ", mtAction=" + MotionEvent.actionToString(mtAction) + ", finalAction=" + MotionEvent.actionToString(finalAction)); MotionEvent event = null; if (USE_TOUCH_WRITER) { } else { event = createMotionEvent(finalAction, downTime, eventTime); } // 当为UP事件时, 将此点清空 if (action == ACTION_UP) { ps.clear(); if (mActivePointers.contains(ps)) { mActivePointers.remove(ps); } } return event; } private MotionEvent createMotionEvent(int action, long downTime, long eventTime) { int pointerCount = mActivePointers.size(); // 找出有效的并配置 count, ids, coords for (int i = 0; i < pointerCount; ++i) { PointerState ps = mActivePointers.get(i); if (ps.valid && ps.id >= 0 && ps.id < MAX_TOUCH_COUNT) { mPointerIds[i] = ps.id; stateToCoords(ps, mPointerCoords[i]); } } MotionEvent event = MotionEvent.obtain(downTime, eventTime, action, pointerCount, mPointerIds, mPointerCoords, 1 /*metaState*/, 1.0f /* xPrecision*/, 1.0f /*yPrecision*/, 0 /*deviceId*/, 0 /*edgeFlags*/, InputDevice.SOURCE_TOUCHSCREEN /*source*/, 0 /*flags*/); return event; }}
package android.car.utils.touch;import android.car.utils.InputIoctl;import android.car.utils.IoctlHelper;import android.os.SystemClock;import android.os.SystemProperties;import android.text.TextUtils;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.nio.ByteOrder;import libcore.io.Memory;import static android.car.utils.InputIoctl.ABS_MT_POSITION_X;import static android.car.utils.InputIoctl.ABS_MT_POSITION_Y;import static android.car.utils.InputIoctl.ABS_MT_TOUCH_MAJOR;import static android.car.utils.InputIoctl.ABS_MT_TRACKING_ID;import static android.car.utils.InputIoctl.ABS_MT_WIDTH_MAJOR;import static android.car.utils.InputIoctl.BTN_TOUCH;import static android.car.utils.InputIoctl.EV_ABS;import static android.car.utils.InputIoctl.EV_KEY;import static android.car.utils.InputIoctl.EV_SYN;import static android.car.utils.InputIoctl.SYN_MT_REPORT;import static android.car.utils.InputIoctl.SYN_REPORT;import static android.car.utils.InputIoctl.TOUCH_DOWN;import static android.car.utils.InputIoctl.TOUCH_UP;/** * 读取输入设备原生数据 */public class TouchWriter { private static final String TAG = "Car-TouchInputReader"; private static final boolean DEBUG_RAWDATA = false; static final boolean IS_64BIT = !TextUtils.isEmpty(SystemProperties.get("ro.product.cpu.abilist64", null)); /* 数据大小定义 */ static final int RAW_EVENT_TIME_SIZE = IS_64BIT ? 16 : 8; static final int RAW_EVENT_SIZE = RAW_EVENT_TIME_SIZE + 8; private String mDevicePath; private int mAbsXMax; private int mAbsYMax; private OutputStream mDeviceStream; public TouchWriter(String devicePath) { mDevicePath = devicePath; } public void init() { int fd = -1; try { fd = IoctlHelper.open(mDevicePath, IoctlHelper.O_RDWR); InputIoctl.AbsInfo xInfo = InputIoctl.getAbsInfo(fd, ABS_MT_POSITION_X); if (xInfo != null) { mAbsXMax = xInfo.max; } InputIoctl.AbsInfo yInfo = InputIoctl.getAbsInfo(fd, ABS_MT_POSITION_Y); if (yInfo != null) { mAbsYMax = yInfo.max; } mDeviceStream = new FileOutputStream(mDevicePath); } catch (Exception e) { e.printStackTrace(); } finally { IoctlHelper.close(fd); } } public int getAbsXMax() { return mAbsXMax; } public int getAbsYMax() { return mAbsYMax; } // 原生数据格式 // struct input_event { // struct timeval time; // __u16 type; // __u16 code; // __s32 value; // }; // struct timeval { // long tv_sec; /* seconds */ // long tv_usec; /* and microseconds */ // }; private final byte[] mWriteBuff = new byte[RAW_EVENT_SIZE]; private void writeEvent(long sec, long microSec, int type, int code, int value) { // TODO 对64位系统做处理 synchronized (mWriteBuff) { int pos = 0; Memory.pokeLong(mWriteBuff, pos, sec, ByteOrder.nativeOrder()); pos += 4; Memory.pokeLong(mWriteBuff, pos, microSec, ByteOrder.nativeOrder()); pos += 4; Memory.pokeShort(mWriteBuff, pos, (short) type, ByteOrder.nativeOrder()); pos += 2; Memory.pokeShort(mWriteBuff, pos, (short) code, ByteOrder.nativeOrder()); pos += 2; Memory.pokeShort(mWriteBuff, pos, (short) value, ByteOrder.nativeOrder()); if (mDeviceStream != null) { try { mDeviceStream.write(mWriteBuff); } catch (Exception e) { e.printStackTrace(); } } } } private void writeEvent(int type, int code, int value) { long time = SystemClock.currentTimeMicro(); long sec = time / 1000; long microSec = time % 1000 * 1000; writeEvent(sec, microSec, type, code, value); } public void writeSync() { writeEvent(EV_SYN, SYN_REPORT, 0); } // 按下事件, 只有第一个点的按下需要发送这个 // EV_KEY BTN_TOUCH DOWN // 触摸点 public void writeDown() { writeEvent(EV_KEY, BTN_TOUCH, TOUCH_DOWN); } public void writePoint(int id, int x, int y, int w, int h) { int absX = x * mAbsXMax / w; int absY = y * mAbsYMax / h; writeEvent(EV_ABS, ABS_MT_POSITION_X, absX); writeEvent(EV_ABS, ABS_MT_POSITION_Y, absY); writeEvent(EV_ABS, ABS_MT_TOUCH_MAJOR, 0x20); writeEvent(EV_ABS, ABS_MT_WIDTH_MAJOR, 0x20); writeEvent(EV_ABS, ABS_MT_TRACKING_ID, id); writeEvent(EV_SYN, SYN_MT_REPORT, 0); } // 抬起事件, 只有最后一个抬起的点需要发送这个 // EV_KEY BTN_TOUCH UP public void writeUp() { writeEvent(EV_KEY, BTN_TOUCH, TOUCH_UP); writeSync(); }}
MultiTouchInject mMultiTouchInject = new MultiTouchInject(); /** * 模拟触摸事件 * @param id 触摸点的id(0为第一个) * @param type 事件类型 * @param x x坐标 * @param y y坐标 */ private void onMultiTouchEvent(int id, int type, int x, int y) { if (USE_TOUCH_WRITER) { //更底层的模拟触摸 mMultiTouchInject.addTouchEventRaw(id, type, x, y, SystemHelper.getScreenWidth(), SystemHelper.getScreenHeight()); } else { //调用系统接口 MotionEvent event = mMultiTouchInject.addTouchEvent(id, type, x, y); if (event != null) { doInjectInputEventAsync(event); } } }
代码如上。
参考资料:http://blog.csdn.net/liyi_cs_dn/article/details/7347832
阅读全文
0 0
- android 模拟触摸
- android 向模拟发送多点触摸事件~
- android 模拟发送多点触摸事件
- Android应用程序中模拟发送键盘触摸消息
- 【Android】技术调研:用代码模拟屏幕点击、触摸事件
- 【Android】技术调研:用代码模拟屏幕点击、触摸事件
- 多点触摸模拟成功
- cocos2d 模拟触摸
- 模拟按键和触摸
- Android-单点触摸-多点触摸
- iOS模拟器模拟多点触摸
- 模拟触摸方式滚动canvas
- Android基于Socket无线遥控(2)--模拟触摸按键篇
- Android基于Socket无线遥控(2)--模拟触摸按键篇
- Android基于Socket无线遥控(二)-模拟触摸按键篇
- Android基于Socket无线遥控(2)--模拟触摸按键篇
- android 模拟触摸板控制鼠标(解决小屏幕控制大屏幕)
- Android随笔之——用shell脚本模拟用户按键、触摸操作
- 提示插件
- cairo设置
- 图标不够大的时候添加背景,让每个图标看起来都一样大
- QPixmap之颜色摄取器
- RedHat上面部署iObjects C++
- android 模拟触摸
- 多个文件共享结构体变量
- 获取URL中的某个参数的方法
- Ubuntu16.04安装XGBoost简明教程
- sort
- 编辑器ueditor使用总结
- xiaoCMS中sqllite转成mysql
- 文本选中事件
- 广播接受者拦截电话