native层实现touch事件转key事件_touchinputmapper::dispatchmotion-程序员宅基地

技术标签: Android framework 开发 工作记录  android framework  

需求

    最近公司来了一个需求,需要将touch事件转成key事件,只针对滑动事件与触摸事件。


需求分析

    首先这个需求是可以在kernel里面做的,由于我们没有kernel代码,因此这个方案就被pass掉了。第二个想到的是在java层做,想找一个拦截touch事件的方法,类似PhoneWindowMananger中拦截key事件的方法,可是没找到,找到的地方都已经到app层了,这样就可能有点晚了(也可能java层有,只是我还没找到合适的地方)。最后没办法将android事件分发机制重新看了一遍,决定直接在native层做,也就是读取event的地方----InputReader.cpp中。


具体实现

    这个需求里面最重要的就是找到合适的地方拦截touch然后转成key。

touch事件分发的函数:

void TouchInputMapper::dispatchMotion(nsecs_t when, uint32_t policyFlags, uint32_t source,
        int32_t action, int32_t actionButton, int32_t flags,
        int32_t metaState, int32_t buttonState, int32_t edgeFlags,
        const PointerProperties* properties, const PointerCoords* coords,
        const uint32_t* idToIndex, BitSet32 idBits, int32_t changedId,
        float xPrecision, float yPrecision, nsecs_t downTime) {
    PointerCoords pointerCoords[MAX_POINTERS];
    PointerProperties pointerProperties[MAX_POINTERS];
    uint32_t pointerCount = 0;
    while (!idBits.isEmpty()) {
        uint32_t id = idBits.clearFirstMarkedBit();
        uint32_t index = idToIndex[id];
        pointerProperties[pointerCount].copyFrom(properties[index]);
        pointerCoords[pointerCount].copyFrom(coords[index]);

        if (changedId >= 0 && id == uint32_t(changedId)) {
            action |= pointerCount << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
        }

        pointerCount += 1;
    }

    ALOG_ASSERT(pointerCount != 0);

    if (changedId >= 0 && pointerCount == 1) {
        // Replace initial down and final up action.
        // We can compare the action without masking off the changed pointer index
        // because we know the index is 0.
        if (action == AMOTION_EVENT_ACTION_POINTER_DOWN) {
            action = AMOTION_EVENT_ACTION_DOWN;
        } else if (action == AMOTION_EVENT_ACTION_POINTER_UP) {
            action = AMOTION_EVENT_ACTION_UP;
        } else {
            // Can't happen.
            ALOG_ASSERT(false);
        }
    }

    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
            action, actionButton, flags, metaState, buttonState, edgeFlags,
            mViewport.displayId, pointerCount, pointerProperties, pointerCoords,
            xPrecision, yPrecision, downTime);
    getListener()->notifyMotion(&args);
}

可以看到dispatchMotion这个函数的最后,构建了一个NotifyMotionArgs,然后通过getListener()->notifyMotion(&args)函数分发,NotifyMotionArgs这个类构造函数中的参数就是touch事件的参数,比如eventTime(也就是when)、action、xy坐标等等都是后面我们要用的。


InputReader.cpp中也有key事件的分发函数,我们可以利用这个函数来转key事件:

void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
        int32_t usageCode) {
    int32_t keyCode;
    int32_t keyMetaState;
    uint32_t policyFlags;

    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
                              &keyCode, &keyMetaState, &policyFlags)) {
        keyCode = AKEYCODE_UNKNOWN;
        keyMetaState = mMetaState;
        policyFlags = 0;
    }

    if (down) {
        // Rotate key codes according to orientation if needed.
        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
            keyCode = rotateKeyCode(keyCode, mOrientation);
        }

        // Add key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key repeat, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
        } else {
            // key down
            if ((policyFlags & POLICY_FLAG_VIRTUAL)
                    && mContext->shouldDropVirtualKey(when,
                            getDevice(), keyCode, scanCode)) {
                return;
            }
            if (policyFlags & POLICY_FLAG_GESTURE) {
                mDevice->cancelTouch(when);
            }

            mKeyDowns.push();
            KeyDown& keyDown = mKeyDowns.editTop();
            keyDown.keyCode = keyCode;
            keyDown.scanCode = scanCode;
        }

        mDownTime = when;
    } else {
        // Remove key down.
        ssize_t keyDownIndex = findKeyDown(scanCode);
        if (keyDownIndex >= 0) {
            // key up, be sure to use same keycode as before in case of rotation
            keyCode = mKeyDowns.itemAt(keyDownIndex).keyCode;
            mKeyDowns.removeAt(size_t(keyDownIndex));
        } else {
            // key was not actually down
            ALOGI("Dropping key up from device %s because the key was not down.  "
                    "keyCode=%d, scanCode=%d",
                    getDeviceName().string(), keyCode, scanCode);
            return;
        }
    }

    if (updateMetaStateIfNeeded(keyCode, down)) {
        // If global meta state changed send it along with the key.
        // If it has not changed then we'll use what keymap gave us,
        // since key replacement logic might temporarily reset a few
        // meta bits for given key.
        keyMetaState = mMetaState;
    }

    nsecs_t downTime = mDownTime;

    // Key down on external an keyboard should wake the device.
    // We don't do this for internal keyboards to prevent them from waking up in your pocket.
    // For internal keyboards, the key layout file should specify the policy flags for
    // each wake key individually.
    // TODO: Use the input device configuration to control this behavior more finely.
    if (down && getDevice()->isExternal()) {
        policyFlags |= POLICY_FLAG_WAKE;
    }

    if (mParameters.handlesKeyRepeat) {
        policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
    }

    if (down && !isMetaKey(keyCode)) {
        getContext()->fadePointer();
    }

    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
            down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
    getListener()->notifyKey(&args);
}

函数的最后我们可以看到一个与touch事件类似的分发调用,getListener()->notifyKey(&args)。

补充:其实这个getListener就是InputDispatcher对象。


总结

    找到这两个地方,转换的需求也就简单了,就是在TouchInputMapper::dispatchMotion中拦截touch事件,然后构建一个NotifyKeyArgs对象,通过调用getListener()->notifyKey(&args)来转发key事件。代码涉及到公司私密的逻辑我就不贴出来了,大概就是根据滑动的坐标转成相应的键值再转发key事件。


版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Johnsco/article/details/80562714

智能推荐

简单的安卓小项目 Android studio stopwatch 时间从小到大的秒表_android studio秒表-程序员宅基地

文章浏览阅读1k次,点赞6次,收藏15次。activity_stopwatch.xml<?xml version="1.0" encoding="utf-8"?><RelativeLayout ="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto..._android studio秒表

5GC 网元介绍(AMF、SMF、UPF、UDM、PCF)_5g smf-程序员宅基地

文章浏览阅读1.9w次,点赞9次,收藏89次。5GC 网元介绍(AMF、SMF、UPF、PCF、UDM)_5g smf

Ubuntu18.0.4仿Mac界面_linux仿苹果电脑窗口移动变形效果-程序员宅基地

文章浏览阅读1.6w次,点赞6次,收藏44次。安装完的效果: 参考:https://linuxhint.com/gnome-tweak-tool-ubuntu-17-10/————————————————————————————————————————————————————下面正式开始————————————————————————————————————————————————————要安装主题,首先要先安装相应的工具:TweakToo..._linux仿苹果电脑窗口移动变形效果

多线程编程?聊聊并发的背后知识_线程并行 锁总线-程序员宅基地

文章浏览阅读679次。一、现代计算机理论模型与工作方式现代计算机模型是基于-冯诺依曼计算机模型。计算机在运行时,先从内存中取出第一条指令,通过控制器的译码,按指令的要求,从存储器中取出数据进行指定的运算和逻辑操作等加工,然后再按地址把结果送到内存中去。接下来,再取出第二条指令,在控制器的指挥下完成规定操作。依此进行下去,直至遇到停止指令。程序与数据一样存储,按程序编排的顺序,一步一步地取出指令,自动地完成指令规定的操作是计算机最基本的工作模型。这一原理最初是由美籍匈牙利数学家冯.诺依曼于1945年提出来的,故称为冯.诺依_线程并行 锁总线

修改openwrt的Luci界面显示Helloworld_openwrt luci界面修改-程序员宅基地

文章浏览阅读3.9k次,点赞3次,收藏8次。这几天对openwrt的Luci界面很感兴趣,然而网上资料太少,而且许多资料又讲得太深,没有一个“helloworld”式的感性认识,故作此篇来帮助想要从头开始学Luci却无从下手的同学们。0、目标首先明确一下我们的目标:通过修改openwrt的内置web服务Luci(Lua Configuration Interface)里的文件来向web界面中增加我们想要的内容。具体分成两个步骤:修改controller层文件 增加view层的文件(即html页面)顺带一提,由于Luci默认使用缓存技_openwrt luci界面修改

python函数拟合不规则曲线_python 对于任意数据和曲线进行拟合并求出函数表达式的三种方案。...-程序员宅基地

文章浏览阅读988次。原博文2020-07-17 19:33 −本文链接:https://blog.csdn.net/changdejie/article/details/83089933第一种是进行多项式拟合,数学上可以证明,任意函数都可以表示为多项式形式。具体示例如下。###拟合年龄import numpy as npimport matplotl...相关推荐2019-12-15 10:09 −axios本身没有..._不规则曲线拟合

随便推点

netty源码分析(二十)NIO堆外内存与零拷贝深入讲解_堆外内存netty版本-程序员宅基地

文章浏览阅读6.6k次,点赞2次,收藏17次。ByteBuffer byteBuffer = ByteBuffer.allocateDirect(512); 直接内存:返回DirectByteBuffer对象,DirectByteBuffer的父类是MappedByteBuffer ,MappedByteBuffer 的父类是ByteBuffer , 在ByteBuffer的上边是Buffer,在 Buffer里边有一个_堆外内存netty版本

ElasticSearch分布式架构原理_es 分片 节点宕机-程序员宅基地

文章浏览阅读141次。ElasticSearch 分布式搜索引擎,在多台机器上启动多个ElasticSearch进程实例,组成一个 ElasticSearch集群。ES的基本单位:索引(index),相当于MySQL的一张表一个索引拆分成多个分片(shard)分片优点横向扩展:方便数据扩容,1T变2T提高性能:多个分片在不同服务器分布式执行,提高吞吐量和性能分片拥有多个备份,避免机器宕机,实现高可用ES集群拥有多个节点,负责切换主分片和副本分片的身份,主节点宕机自动选举一个新的主节点非主节点宕机时,此节点主分_es 分片 节点宕机

Android 让View 和 ViewGroup 同时响应点击或者长按事件_android viewgroup设置点击事件-程序员宅基地

文章浏览阅读2.7k次。面试的时候,被问到如何让View 和 其 父View 同时响应长按事件。我还记得当时自己的回答,子View 里面 处理了长按事件,但是返回了false, 没有处理,然后会继续调用到父View 的长按事件。其实这个回答是错误的,回头自己看了事件传递机制的源码之后,有了更好的方法:上布局: <LinearLayout android:layout_width=..._android viewgroup设置点击事件

QScrollArea垂直滚动条 水平滚动条隐藏_qtscrollarea取消滚动条-程序员宅基地

文章浏览阅读3.4k次,点赞3次,收藏9次。enum ScrollBarPolicy { ScrollBarAsNeeded, //需要的时候显示 ScrollBarAlwaysOff,//总是关闭 ScrollBarAlwaysOn//总是打开 };QScrollArea *scroll=new QScrollArea;scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);..._qtscrollarea取消滚动条

【matlab深度学习工具箱】convolution2dLayer参数详解-程序员宅基地

文章浏览阅读9.7k次,点赞10次,收藏80次。2-D 卷积层2-D 卷积层将滑动卷积滤波器应用于 2-D 输入。该层通过沿输入方向垂直和水平移动滤波器并计算权重和输入的点积,然后添加偏置项来卷积输入。描述 创建一个 2-D 卷积层,并设置 和 属性。名称-值对参数使用逗号分隔的名称-值对参数指定要沿图层输入边缘添加的填充的大小,或设置 参数和初始化、学习速率和正则化以及属性。将名称括在单引号中。示例:创建了一个2-D卷积层,其中包含16个大小的过滤器和的填充。在训练时,软件计算并设置填充的大小,以便图层输出具有与输入相同的大小。输入边填充,指定_convolution2dlayer

双目测距、重构(基于MATLAB和opencv-python)_matlab 基于双目视觉进行三维重构-程序员宅基地

文章浏览阅读3k次。双目测距、重构楼主之前用的SFM来进行重构,但是得到的是视差图,点云和实物存在比例关系,单目的还是不能解决scale这个问题的。所以今天用双目的来进行重构,期间遇到了很多坑,实属难受。双目测距过程大致可以分为,标定,图像校正,计算视差,测距,知道这个流程,目标就很明确了标定opencv和matlab都有标定的代码,但是老师说还是matlab的标定更加准确,自己试验下来也的确感受到matla..._matlab 基于双目视觉进行三维重构

推荐文章

热门文章

相关标签