触摸事件常见类型为ACTION_DOWN/ACTION_UP/ACTION_MOVE等。而鼠标在触摸事件类型的基础上又多出ACTION_HOVER_MOVE等类型,同时鼠标左右按键在输入事件中的也对应有BUTTON_PRIMARY/BUTTON_SECONDARY等状态,鼠标的滚轮操作也对应着AXIS_VSCROLL的值。所以若在手机中把显示界面作为鼠标触摸板,把触摸事件转换为鼠标事件,则需要对触摸事件做多个判断,针对不同触摸手势做不同的处理。

Android系统对鼠标事件从驱动到framework的读取实在frameworks/native/services/inputflinger/reader/mapper/CursorInputMapper.cpp进行的,CursorInputMapper::sync(nsecs_t when)函数对鼠标事件做了所有的读取转换,而以下在java中实现触摸事件转换为鼠标事件的方法也大都是参考了其中的逻辑。

1.轻触点击对应鼠标的左键事件

手指轻触点击对应着click事件,所以当出现触摸短按点击事件后可以直接发送一个鼠标的左键按键事件。
        鼠标左键按键事件会依次发出4个MotionEvent,其类型分别为ACTION_DOWN ACTION_BUTTON_PRESS ACTION_BUTTON_RELEASE ACTION_UP,同时其MotionEvent的ButtonState属性也要变化,依次为MotionEvent.BUTTON_PRIMARY MotionEvent.BUTTON_PRIMARY 0 0。实现代码如下:

    private void sendLeftButton(MotionEvent lastMotionEvent){int buttonState = MotionEvent.BUTTON_PRIMARY;int buttonDownTime = SystemClock.uptimeMillis();MotionEvent.PointerProperties pp1 = new MotionEvent.PointerProperties();lastMotionEvent.getPointerProperties(0, pp1);MotionEvent.PointerCoords pc1 = new MotionEvent.PointerCoords();lastMotionEvent.getPointerCoords(0, pc1);properties[0] = pp1;pointerCoords[0] = pc1;//(1) downMotionEvent downMotionEvent = MotionEvent.obtain(buttonDownTime, buttonDownTime, MotionEvent.ACTION_DOWN, lastMotionEvent.getPointerCount(), properties, pointerCoords, lastMotionEvent.getMetaState(), buttonState, lastMotionEvent.getXPrecision(), lastMotionEvent.getYPrecision(), lastMotionEvent.getDeviceId(), lastMotionEvent.getEdgeFlags(), lastMotionEvent.getSource(), lastMotionEvent.getDisplayId(), lastMotionEvent.getFlags());//sendMotionEvent;//(2) pressMotionEvent pressedMotionEvent = MotionEvent.obtain(buttonDownTime, buttonDownTime, MotionEvent.ACTION_BUTTON_PRESS, lastMotionEvent.getPointerCount(), properties, pointerCoords, lastMotionEvent.getMetaState(), buttonState, lastMotionEvent.getXPrecision(), lastMotionEvent.getYPrecision(), lastMotionEvent.getDeviceId(), lastMotionEvent.getEdgeFlags(), lastMotionEvent.getSource(), lastMotionEvent.getDisplayId(), lastMotionEvent.getFlags());//sendMotionEvent;//(3) releasebuttonState = 0;MotionEvent releaseMotionEvent = MotionEvent.obtain(buttonDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_BUTTON_RELEASE, lastMotionEvent.getPointerCount(), properties, pointerCoords, lastMotionEvent.getMetaState(), buttonState, lastMotionEvent.getXPrecision(), lastMotionEvent.getYPrecision(), lastMotionEvent.getDeviceId(), lastMotionEvent.getEdgeFlags(), lastMotionEvent.getSource(), lastMotionEvent.getDisplayId(), lastMotionEvent.getFlags());//sendMotionEvent;//(4) upMotionEvent upMotionEvent = MotionEvent.obtain(buttonDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, lastMotionEvent.getPointerCount(), properties, pointerCoords, lastMotionEvent.getMetaState(), buttonState, lastMotionEvent.getXPrecision(), lastMotionEvent.getYPrecision(), lastMotionEvent.getDeviceId(), lastMotionEvent.getEdgeFlags(), lastMotionEvent.getSource(), lastMotionEvent.getDisplayId(), lastMotionEvent.getFlags());//sendMotionEvent;}

2.正常滑动对应鼠标的移动事件

手指在显示的界面滑动时,会一直有ACTION_MOVE事件,那么可以把此ACTION_MOVE事件(包括ACTION_DOWN/ACTION_UP事件)转换为ACTION_HOVER_MOVE事件。同时其鼠标位置的移动则需要修改MotionEvent.PointerProperties的值。实现代码如下:

    private MotionEvent.PointerCoords mTouchDownPointerCoords = null;private MotionEvent.PointerCoords mMouseDownPointerCoords = new MotionEvent.PointerCoords();private boolean handlerFingerTouchArea(MotionEvent ev,int pointerID){switch (ev.getActionMasked()){case MotionEvent.ACTION_DOWN:mTouchDownPointerCoords = new MotionEvent.PointerCoords();mTouchDownPointerCoords.x = ev.getX();mTouchDownPointerCoords.y = ev.getY();break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:mTouchDownPointerCoords = null;break;}float moveX = 0;float moveY = 0;if(mTouchDownPointerCoords != null){moveX = ev.getX() - mTouchDownPointerCoords.x;moveY = ev.getY() - mTouchDownPointerCoords.y;mTouchDownPointerCoords.x = ev.getX();mTouchDownPointerCoords.y = ev.getY();}//get (X,Y)MotionEvent.PointerProperties pp1 = new MotionEvent.PointerProperties();pp1.id = 0;pp1.toolType = MotionEvent.TOOL_TYPE_MOUSE;properties[0] = pp1;MotionEvent.PointerCoords pc1 = new MotionEvent.PointerCoords();pc1.x = Math.min(mMouseDownPointerCoords.x + moveX, 0);pc1.y = Math.min(mMouseDownPointerCoords.y + moveY, 0);mMouseDownPointerCoords.x = pc1.x;mMouseDownPointerCoords.y = pc1.y;pc1.pressure = 1;pc1.size = 1;pointerCoords[0] = pc1;// init Motion Eventlong eventTime = SystemClock.uptimeMillis();int action = MotionEvent.ACTION_HOVER_MOVE;MotionEvent customEvent = MotionEvent.obtain(0, eventTime,action, 1, properties, pointerCoords, 0, 0, 1, 1, 7, 0, InputDevice.SOURCE_MOUSE, displayID, 0);lastMotionEvent = MotionEvent.obtain(customEvent);//sendMotionEvent;return true;}

3.鼠标移动且鼠标按住左键时

鼠标移动加上鼠标按键实现很简单,就是在鼠标移动事件的过程中加入鼠标的左键事件,同时在鼠标左键未松开时所有的MotionEvent的ButtonState属性要一直为MotionEvent.BUTTON_PRIMARY。

4.鼠标的滚轮事件

鼠标的滚轮事件比较单一,就是修改MotionEvent.PointerProperties的AXIS_VSCROLL的值,其值为滚轮滚动的距离。实现代码如下:

    private boolean handlerMouseWheel(MotionEvent ev){MotionEvent clickMotionEvent = null;MotionEvent.PointerProperties pp1 = new MotionEvent.PointerProperties();MotionEvent.PointerCoords pc1 = new MotionEvent.PointerCoords();switch (ev.getActionMasked()){case MotionEvent.ACTION_DOWN:mVScrollDownY = ev.getY();break;case MotionEvent.ACTION_MOVE:float vscroll = ev.getY() - mVScrollDownY;if(Math.abs(vscroll) > 20){mVScrollDownY = ev.getY();ev.getPointerProperties(0, pp1);ev.getPointerCoords(0, pc1);pc1.setAxisValue(MotionEvent.AXIS_VSCROLL,vscroll > 0 ? 1 : -1);properties[0] = pp1;pointerCoords[0] = pc1;clickMotionEvent = MotionEvent.obtain(buttonDownTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_SCROLL, ev.getPointerCount(), properties, pointerCoords, ev.getMetaState(), 0, ev.getXPrecision(), ev.getYPrecision(), ev.getDeviceId(), ev.getEdgeFlags(), ev.getSource(), ev.getDisplayId(), ev.getFlags());}break;}if(clickMotionEvent != null){//sendMotionEvent;}return true;}

以下附上CursorInputMapper::sync(nsecs_t when)函数的Android 11平台的源码,对照的话还是要以此为主:

void CursorInputMapper::sync(nsecs_t when) {int32_t lastButtonState = mButtonState;int32_t currentButtonState = mCursorButtonAccumulator.getButtonState();mButtonState = currentButtonState;bool wasDown = isPointerDown(lastButtonState);bool down = isPointerDown(currentButtonState);bool downChanged;if (!wasDown && down) {mDownTime = when;downChanged = true;} else if (wasDown && !down) {downChanged = true;} else {downChanged = false;}nsecs_t downTime = mDownTime;bool buttonsChanged = currentButtonState != lastButtonState;int32_t buttonsPressed = currentButtonState & ~lastButtonState;int32_t buttonsReleased = lastButtonState & ~currentButtonState;float deltaX = mCursorMotionAccumulator.getRelativeX() * mXScale;float deltaY = mCursorMotionAccumulator.getRelativeY() * mYScale;bool moved = deltaX != 0 || deltaY != 0;// Rotate delta according to orientation if needed.if (mParameters.orientationAware && mParameters.hasAssociatedDisplay &&(deltaX != 0.0f || deltaY != 0.0f)) {rotateDelta(mOrientation, &deltaX, &deltaY);}// Move the pointer.PointerProperties pointerProperties;pointerProperties.clear();pointerProperties.id = 0;pointerProperties.toolType = AMOTION_EVENT_TOOL_TYPE_MOUSE;PointerCoords pointerCoords;pointerCoords.clear();float vscroll = mCursorScrollAccumulator.getRelativeVWheel();float hscroll = mCursorScrollAccumulator.getRelativeHWheel();bool scrolled = vscroll != 0 || hscroll != 0;mWheelYVelocityControl.move(when, nullptr, &vscroll);mWheelXVelocityControl.move(when, &hscroll, nullptr);mPointerVelocityControl.move(when, &deltaX, &deltaY);int32_t displayId;float xCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;float yCursorPosition = AMOTION_EVENT_INVALID_CURSOR_POSITION;if (mSource == AINPUT_SOURCE_MOUSE) {if (moved || scrolled || buttonsChanged) {mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);if (moved) {mPointerController->move(deltaX, deltaY);}if (buttonsChanged) {mPointerController->setButtonState(currentButtonState);}mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);}mPointerController->getPosition(&xCursorPosition, &yCursorPosition);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, xCursorPosition);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, yCursorPosition);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, deltaX);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, deltaY);displayId = mPointerController->getDisplayId();} else {pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, deltaX);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, deltaY);displayId = ADISPLAY_ID_NONE;}pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, down ? 1.0f : 0.0f);// Moving an external trackball or mouse should wake the device.// We don't do this for internal cursor devices to prevent them from waking up// the device in your pocket.// TODO: Use the input device configuration to control this behavior more finely.uint32_t policyFlags = 0;if ((buttonsPressed || moved || scrolled) && getDeviceContext().isExternal()) {policyFlags |= POLICY_FLAG_WAKE;}// Synthesize key down from buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,displayId, policyFlags, lastButtonState, currentButtonState);// Send motion event.if (downChanged || moved || scrolled || buttonsChanged) {int32_t metaState = getContext()->getGlobalMetaState();int32_t buttonState = lastButtonState;int32_t motionEventAction;if (downChanged) {motionEventAction = down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;} else if (down || (mSource != AINPUT_SOURCE_MOUSE)) {motionEventAction = AMOTION_EVENT_ACTION_MOVE;} else {motionEventAction = AMOTION_EVENT_ACTION_HOVER_MOVE;}if (buttonsReleased) {BitSet32 released(buttonsReleased);while (!released.isEmpty()) {int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());buttonState &= ~actionButton;NotifyMotionArgs releaseArgs(getContext()->getNextId(), when, getDeviceId(),mSource, displayId, policyFlags,AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,metaState, buttonState, MotionClassification::NONE,AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,&pointerCoords, mXPrecision, mYPrecision,xCursorPosition, yCursorPosition, downTime,/* videoFrames */ {});getListener()->notifyMotion(&releaseArgs);}}NotifyMotionArgs args(getContext()->getNextId(), when, getDeviceId(), mSource, displayId,policyFlags, motionEventAction, 0, 0, metaState, currentButtonState,MotionClassification::NONE, AMOTION_EVENT_EDGE_FLAG_NONE, 1,&pointerProperties, &pointerCoords, mXPrecision, mYPrecision,xCursorPosition, yCursorPosition, downTime,/* videoFrames */ {});getListener()->notifyMotion(&args);if (buttonsPressed) {BitSet32 pressed(buttonsPressed);while (!pressed.isEmpty()) {int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());buttonState |= actionButton;NotifyMotionArgs pressArgs(getContext()->getNextId(), when, getDeviceId(), mSource,displayId, policyFlags,AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,metaState, buttonState, MotionClassification::NONE,AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,&pointerCoords, mXPrecision, mYPrecision,xCursorPosition, yCursorPosition, downTime,/* videoFrames */ {});getListener()->notifyMotion(&pressArgs);}}ALOG_ASSERT(buttonState == currentButtonState);// Send hover move after UP to tell the application that the mouse is hovering now.if (motionEventAction == AMOTION_EVENT_ACTION_UP && (mSource == AINPUT_SOURCE_MOUSE)) {NotifyMotionArgs hoverArgs(getContext()->getNextId(), when, getDeviceId(), mSource,displayId, policyFlags, AMOTION_EVENT_ACTION_HOVER_MOVE, 0,0, metaState, currentButtonState, MotionClassification::NONE,AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,&pointerCoords, mXPrecision, mYPrecision, xCursorPosition,yCursorPosition, downTime, /* videoFrames */ {});getListener()->notifyMotion(&hoverArgs);}// Send scroll events.if (scrolled) {pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);NotifyMotionArgs scrollArgs(getContext()->getNextId(), when, getDeviceId(), mSource,displayId, policyFlags, AMOTION_EVENT_ACTION_SCROLL, 0, 0,metaState, currentButtonState, MotionClassification::NONE,AMOTION_EVENT_EDGE_FLAG_NONE, 1, &pointerProperties,&pointerCoords, mXPrecision, mYPrecision, xCursorPosition,yCursorPosition, downTime, /* videoFrames */ {});getListener()->notifyMotion(&scrollArgs);}}// Synthesize key up from buttons if needed.synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,displayId, policyFlags, lastButtonState, currentButtonState);mCursorMotionAccumulator.finishSync();mCursorScrollAccumulator.finishSync();
}

Android 触摸事件转换为鼠标事件相关推荐

  1. jQuery事件之鼠标事件

    jQuery事件之鼠标事件 鼠标事件是在用户移动鼠标光标或者使用任意鼠标键点击时触发的.    (1):click事件:click事件于用户在元素敲击鼠标左键,并在相同元素上松开左键时触发.      ...

  2. jQuery事件之鼠标事件(转)

    jQuery事件之鼠标事件 鼠标事件是在用户移动鼠标光标或者使用任意鼠标键点击时触发的.    (1):click事件:click事件于用户在元素敲击鼠标左键,并在相同元素上松开左键时触发.      ...

  3. java编写程序实现键盘钢琴,运用键盘事件、鼠标事件

    java编写程序实现键盘钢琴,运用键盘事件.鼠标事件 界面     实现 MouseListener,MouseMotionListener,KeyListener接口,当鼠标进入不同按钮时,会播放不 ...

  4. html 鼠标中键事件,Javascript事件模拟(鼠标事件、键盘事件)

    在javascript编程中,事件是用来描述网页中某一特定有趣时刻的,众所周知事件通常是在由用户和浏览器进行交互时触发,其实不然,通过Javascript可以在任何时间触发特定的事件,并且这些事件与浏 ...

  5. Js之事件类型-鼠标事件

    一.事件类型 鼠标事件 键盘事件 表单事件 其他事件 二.鼠标事件 click左键单击        dblclick左键双击 鼠标按下和抬起     mousedown / mouseup (左键, ...

  6. java程序 键盘事件_java编写程序实现键盘钢琴,运用键盘事件、鼠标事件

    java编写程序实现键盘钢琴,运用键盘事件.鼠标事件 界面     实现 MouseListener,MouseMotionListener,KeyListener接口,当鼠标进入不同按钮时,会播放不 ...

  7. JAVA之旅(三十一)——JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件

    JAVA之旅(三十一)--JAVA的图形化界面,GUI布局,Frame,GUI事件监听机制,Action事件,鼠标事件 有段时间没有更新JAVA了,我们今天来说一下JAVA中的图形化界面,也就是GUI ...

  8. QT 触控事件和鼠标事件的分离(问题已解决)

    问题:QT图形视图框架,QGraphicsScene中默认接收触控事件,会将第一个点当作鼠标事件处理. 在开发者开发的时候,可能会有这样的需求,希望自己的触控事件和鼠标事件能够分割开来. 找到的解决方 ...

  9. iPad 手指触摸与PC鼠标事件

    iPad上没有鼠标,所以手指在触发触摸事件(TouchEvent)的时候,系统也会产生出模拟的鼠标事件(MouseEvent). 这对于普通网页的浏览需求而言,基本可以做到与PC端浏览器无明显差异.但 ...

  10. Cesium常用事件,包括点击事件,鼠标事件,相机移动事件

    点击事件 let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);// 左键点击事件let leftclick = ...

最新文章

  1. Linux socket 网络编程 常用头文件
  2. 不吹不黑!让你搜遍GitHub都找不到这么吊炸天的网约车项目!
  3. Animator窗口视图Project视图PlayerIdleAnimation和PlayerWalkingAnimation
  4. TF-IDF与余弦相似性的应用(二):找出相似文章
  5. AcWing 499. 聪明的质监员
  6. 在Linux下编写C程序,怎么检查程序是否有内存泄漏?
  7. [导入]将Byte数组转化为String
  8. PHP苹果不给上架,苹果商城上架拒绝
  9. skypebridge.exe 损坏的映像 错误代码 0xc000012f
  10. iOS中控制器的实践和学习(2)-认识XCode4模版(A1,A3,B2简易图)
  11. Java从入门到精通 第5章 数据类型
  12. rocketmq在Kubernetes(k8s)中的集群配置,2m-2s-async:多Master多Slave模式,异步复制
  13. ssm毕设项目疫情防控管理系统02vsf(java+VUE+Mybatis+Maven+Mysql+sprnig)
  14. 电磁场计算的服务器性能指标,有限公式电磁场数值计算理论与性能
  15. 2020-09-22回忆一下高中物理的弹性碰撞速度公式推导
  16. 计算机课ppt插入图片,PPT中图片的巧妙切换 -电脑资料
  17. ios 内存深度优化_iPhone 6要用1GB内存 优化太好还是另有玄机?
  18. C primer plus 复习题答案(上)
  19. ubuntu20.04使用USB转串口进行串口调试
  20. Serialize的使用

热门文章

  1. iOS UISwitch控件
  2. Python植物大战僵尸源代码及素材
  3. Android入门教程 (零)付费专栏课程规划
  4. 超好用json转excel工具
  5. Linux快捷键的使用
  6. 实验 VoIP通信的配置
  7. 密码生成 算法编程题
  8. 广州科源980tc数控系统说明书_广州数控GSK980TC3车床数控系统 操作轴名
  9. node2vec 包安装
  10. MAC 重置 MySql密码步骤