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

背景:

前面blog文章已经分享过如何实现这种大厂里面一键连招,触摸宏的功能,原理本身是对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版本上也可以方案?

更多framework技术干货,请关注下面“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值