如何基于scrcpy改造实现大厂一键连招/触摸宏功能(带java源码)-千里马安卓framework实战

news2024/11/15 21:56:07

背景:

前面公众号文章已经分享过如何实现这种大厂里面一键连招,触摸宏的功能,原理本身是对dev/input下面的节点进行读取保存文件,然后在读取文件进行写入dev/input下面的节点,从而实现了触摸事件的读取和写入,不过这个一定要root的手机版本。
在这里插入图片描述
上面文章一发布后,就有好些学员联系我,他们在学习了投屏专题后,也对scrcpy有了深入的研究和理解了。很多同学就提出是否可以考虑参考scrcpy的事件注入,即已经实现了触摸注入了,只需要再额外补充一个事件的录制保存文件既可以。

方案设计

如果使用scrcpy方案则设计模块图如下:
在这里插入图片描述
可以看的出这里重点的方案就是scrcpy如何获取用户的触摸事件,即要监听到全局的触摸事件。

这个监听全局事件,学过framework专题课程的都应该知道可以考虑使用InputManager下面的monitor全局事件监听。
这样搞定了触摸事件监听后,整体上就没啥技术难点了,下面来开始进行用scrcpy实战实现该功能。

主程序部分代码

主程序需要实现2个核心逻辑:

1.实现对触摸事件的录制操作

2.实现对触摸事件的注入操作

代码设计如下:

 public static void main(String... args) {
        System.out.println("Hello World OneKeyLink demo!!!! ");
        if (args.length > 0) {
            HandlerThread  handlerThread = new HandlerThread("test motion");
            handlerThread.start();
            Handler handler = new Handler(handlerThread.getLooper());
            if (args[0].equals("record")) {//识别如果当前是录制情况

                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        InputManager inputManager = InputManager.create();
                        inputManager.monitorAllTouch();
                    }
                });
            }else if (args[0].equals("play")) {//识别如果当前是播放情况
                File file = new File(InputManager.SAVE_MOTION_PATH);
                if (file.exists() && file.length() > 0) {
                    try {
                        InputManager inputManager = InputManager.create();
                        inputManager.injectEventFromFile(InputManager.SAVE_MOTION_PATH,handler);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }


如果要进行录制,传递record

adb shell CLASSPATH=/data/local/tmp/onekeylink.jar app_process / com.genymobile.scrcpy.Server record

如果要进行播放,传递play

adb shell CLASSPATH=/data/local/tmp/onekeylink.jar app_process / com.genymobile.scrcpy.Server play

scrcpy触摸事件全局监听

使用InputManager相关接口如下:
frameworks/base/core/java/android/hardware/input/InputManager.java

/**
 * Monitor input on the specified display for gestures.
 *
 * @hide
 */
public InputMonitor monitorGestureInput(String name, int displayId) {
    return mGlobal.monitorGestureInput(name, displayId);
}

现在InputManager就只有这一个monitorGestureInput接口来监听全局触摸事件了,而且还是个hide,不过这个对于scrcpy来说反射都不是事。

    private Method getMonitorGestureInput() {
        try {
            return manager.getClass().getMethod("monitorGestureInput", String.class,int.class);
        }catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    public void monitorAllTouch() {
        new File(SAVE_MOTION_PATH).delete();
        try {
            InputMonitor mInputMonitor = (InputMonitor) getMonitorGestureInput().invoke(manager, "clipboard overlay", 0);//采用反射方法进行监听获取mInputMonitor
            new InputEventReceiver(
                    mInputMonitor.getInputChannel(), Looper.myLooper()) {
                    //采用反射方法进行监听获取后使用mInputMonitorgetInputChannel
                @Override
                public void onInputEvent(InputEvent event) {
                    System.out.println(" onInputEvent "+event);
                    if (event instanceof MotionEvent ) {

											//识别触摸事件然后,进行事件转换成text
                        String motionText = covertMotionEventToSmall((MotionEvent) event).toSaveString();
                        try {
                            saveTouchFile = new FileWriter(SAVE_MOTION_PATH,true);
                            saveTouchFile.write(motionText + "\n");//保存写入触摸事件文本
                            saveTouchFile.close();
                        }catch (Exception e){
                            e.printStackTrace();
                        }
                    }
                    finishInputEvent(event, true /* handled */);
                }
            };
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

上面就有2个核心代码部分:

1、反射调用InputManager的monitorGestureInput获取InputMonitor
2、根据InputMonitor的getInputChannel创建对应InputEventReceiver
3、接受触摸事件转换成文本,保存到文件

通过上面几步骤就完成了监听触摸事件保存到文件的操作。

读取文件进行注入

这部分其实不要怎么讲解,就是读取文件然后进行注入

 if (file.exists() && file.length() > 0) {
                try {
                    InputManager inputManager = InputManager.create();
                    inputManager.injectEventFromFile(InputManager.SAVE_MOTION_PATH,handler);//传递文件路径
                }catch (Exception e) {
                    e.printStackTrace();
                }

            }

 public void injectEventFromFile(String path, Handler handler) {
        if (!TextUtils.isEmpty(path)) {
            try (BufferedReader br = new BufferedReader(new FileReader(path))) {//读取解析文件
                String line;
                while ((line = br.readLine()) != null) {
                    // 处理每行数据
                   // System.out.println(line);
                    SmallMotionEvent smallMotionEvent = constructFromStrLine(line);
                    System.out.println("smallMotionEvent : " + smallMotionEvent.toSaveString());
                    MotionEvent event = convertSmallEventToNormal(smallMotionEvent);//文件转换成MotionEvent
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            injectInputEvent(event,0);//进行事件注入
                            System.out.println("injectInputEvent event " +event);
                        }
                    },event.getDownTime() - initEventTime);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

测试结果如下

操作:
先使用./test_server.sh record 进行一个录制操作
录制完成后再使用 ./test_server.sh play
test_server.sh 内容

adb push /home/test/demos/scrcpy2.4/onekeylink/server/build/outputs/apk/debug/server-debug.apk /data/local/tmp/onekeylink.jar
adb shell CLASSPATH=/data/local/tmp/onekeylink.jar app_process / com.genymobile.scrcpy.Server $@


在这里插入图片描述

该方案因为需要MONITOR_INPUT权限,但是shell不自带该权限,所以也需要root权限,否则报错如下:
Caused by: java.lang.SecurityException: Requires MONITOR_INPUT permission
在这里插入图片描述
留给各位学员思考的问题:
是否可以实现一个完全user版本上也可以方案?

(完整代码需要联系马哥获取,限vip学员)

更多framework详细代码和资料参考如下链接
投屏专题部分:
https://mp.weixin.qq.com/s/IGm6VHMiAOPejC_H3N_SNg
hal+perfetto+surfaceflinger

https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
其他课程七件套专题:在这里插入图片描述
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw

视频试看:
https://www.bilibili.com/video/BV1wc41117L4/

参考相关链接:
https://blog.csdn.net/zhimokf/article/details/137958615

更多framework假威风耗:androidframework007

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2157768.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenMVG试用

1 OpenMVG 简介 全称 Open Multiple View Geometry,是法国人 Pierre Moulon 读博期间开源的一个 C 库 最早版本 OpenMVG 0.1 是 2013年 2月 发布的,目前最新版本是 2021年 10月 发布的 OpenMVG 2.0 LinkedIn 显示,此前一直在…

docker存储

docker分层结构 如图所示,容器是由最上面可读可写的容器层,以及若干个只读镜像层组成,创建容器时,容器中的 数据都来自镜像层。这样的分层机构最大的特点是写时复制: 1、容器中新生成的数据会直接存放在容器层&#xf…

8. 防火墙

8. 防火墙 (1) 防火墙的类型和结构 防火墙的类型和结构可以根据其在网络协议栈中的过滤层次和实现方式进行分类。常见的防火墙类型包括: 包过滤防火墙:工作在网络层(OSI模型的第3层),主要检查IP包头的信息,如源地址、目的地址、端口号等。电路级网关防火墙:工作在会话层…

初始MYSQL数据库(6)—— 事务

找往期文章包括但不限于本期文章中不懂的知识点: 个人主页:我要学编程(ಥ_ಥ)-CSDN博客 所属专栏: MYSQL 目录 事务的概念 事务的ACID特性 使用事务 查看支持事务的存储引擎 事务的语法 保存点 自动/手动提交事务 事务的隔离性和…

NLP 文本分类任务核心梳理

解决思路 分解为多个独立二分类任务将多标签分类转化为多分类问题更换 loss 直接由模型进行多标签分类 数据稀疏问题 标注更多数据,核心解决方案: 自己构造训练样本 数据增强,如使用 chatGPT 来构造数据更换模型 减少数据需求增加规则弥补…

MySQL --基本查询(下)

文章目录 3.Update3.1将孙悟空同学的数学成绩变更为 80 分3.2将曹孟德同学的数学成绩变更为 60 分,语文成绩变更为 70 分3.3将总成绩倒数前三的 3 位同学的数学成绩加上 30 分3.4将所有同学的语文成绩更新为原来的 2 倍 4.Delete4.1删除数据4.1.1删除孙悟空同学的考…

learn C++ NO.19——二叉搜索树

简单介绍一下二叉搜索树 二叉搜索树也称为二叉排序树。它是一种具有特殊性质的二叉树。它有如下性质。 1、当前节点的左子树的值一定小于当前节点,当前节点的右子树的值一锭大于当前节点。这也就意味着,在接近完全二叉树的情况下(高度较为合…

开源实时多模态AI聊天机器人Moshi,语音对话延迟低至200毫秒!

开源实时多模态AI聊天机器人Moshi,语音对话延迟低至200毫秒! 最近AI圈真是热闹非凡,继Meta发布Llama 3之后,各种开源大模型也是层出不穷。这不,法国一个非盈利AI研究实验室Kyutai,又搞了个大新闻&#xff0…

从零到一:如何用Ollama和OpenUI构建强大的AI模型库

搭建开源大模型平台的步骤与模型介绍 在这篇文章中,我将分享如何在Windows上使用Ollama和OpenUI搭建开源大模型平台的步骤,并介绍我所部署的几个模型及其擅长的领域。 目录 搭建开源大模型平台的步骤与模型介绍一、搭建平台步骤1. 安装Ollama2. 安装Ope…

C++自动驾驶面试核心问题整理

应用开发 概述:比较基础,没啥壁垒,主要有linux开发经验即可 问题:基础八股,如计算机网络、操作系统、c11等基础三件套;中等难度算法题1-2道。 中间件开发(性能优化) 概述&am…

FutureTask源码分析

Thread类的run方法返回值类型是void,因此我们无法直接通过Thread类获取线程执行结果。如果要获取线程执行结果就需要使用FutureTask。用法如下: class CallableImpl implements Callable{Overridepublic Object call() throws Exception {//do somethin…

信息安全工程师(12)网络攻击概述

前言 网络攻击(Cyber Attacks,也称赛博攻击)是指针对计算机信息系统、基础设施、计算机网络或个人计算机设备的任何类型的进攻动作。这些攻击旨在破坏、揭露、修改、使软件或服务失去功能,或在未经授权的情况下偷取或访问计算机数…

超详细超实用!!!AI编程之cursor编写一个官网(二)

云风网 云风笔记 云风知识库 一、新建html文件 选中添加index.html,输入编写官网要求&#xff0c;自动生成代码&#xff0c;先来个简单的。 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"…

WPS2019 数据透视表多列数据如何显示同一行

在excel表格中&#xff0c;只有行筛选&#xff0c;没有列筛选功能&#xff0c;当我们需要只选取某些列的数据时&#xff0c;使用数据透视表是个可行的方法&#xff0c;但默认生成的数据透视表可观性较差。要如何才能使得数据透视表格式与原来数据格式一样美观易看呢&#xff1f…

Leetcode990.等式方程的可满足性

题目 原题链接 等式方程的可满足性 思路 定义一个长度为26&#xff08;变量为小写字母&#xff09;的数组充当并查集&#xff0c;并将数组中的元素初始化为 -1判断“”并合并元素&#xff0c;将相等的放在一个集合中判断“!”&#xff1b;不等的如果在一个集合中&#xff0c;则…

【Linux】指令和权限的这些细节,你确定都清楚吗?

&#x1f680;个人主页&#xff1a;奋斗的小羊 &#x1f680;所属专栏&#xff1a;Linux 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言&#x1f4a5;一、Linux基本指令&#x1f4a5;1.1 mv 指令&#x1f4a5;1.2 cat 指令&#x1f4a5;…

webLogic反序列化漏洞CVE-2017-3506

1.环境搭建 cd vulhub-master/weblogic/weak_password docker-compose up -d 2.判断wls-wsat组件是否存在 拼接/wls-wsat/CoordinatorPortType 查看页面是否有回显 有回显说明存在组件 3.在当前页面抓包 反弹shell 添加请求包内容 <soapenv:Envelope xmlns:soapenv&q…

hCaptcha 图像识别 API 对接说明

hCaptcha 图像识别 API 对接说明 本文将介绍一种 hCaptcha 图像识别 API 对接说明&#xff0c;它可以通过用户输入识别的内容和 hCaptcha验证码图像&#xff0c;最后返回需要点击的小图像的坐标&#xff0c;完成验证。 接下来介绍下 hCaptcha 图像识别 API 的对接说明。 注册…

线程的状态及join()插队方法

一、线程的状态 线程整个生命周期中有6种状态&#xff0c;分别为 NEW 新建状态 、RUNNABLE 可运行状态、TERMINATED 终止状态、TIMED_WAITING计时等待状态、WAITING 等待状态、BLOCKED 阻塞状态 线程各个状态之间的转换&#xff1a; 在 JAVA 程序中&#xff0c;一个线程对象通过…

一文搞懂offset、client、scroll系列及案例

目录 一、offset 1-1、offset系列属性 1-2、offset与style区别 1-3、案例 1-3-1、计算鼠标在盒子内的坐标 1-3-2、拖动模态框 二、client 2-1、client系列属性 三、scroll 3-1、scroll系列属性 3-2、案例 3-2-1、滚动页面一定距离后固定侧边栏 一、offset offset是…