parsec 使用遇到软件问题

背景

自己已经使用parsec远程办公一段时间,写代码非常流畅,基本和本地写代码差不多,国产的远程软件达不到,向日葵,todesk都达不到这么流畅,不过使用遇到过黑屏的问题。

问题

黑屏

  1. 向日葵远程开启黑屏,偶尔启动电脑会导致parsec连接上黑屏,重启几次可能恢复,后面我直接关闭了默认连接开启黑屏功能,这个问题就解决了。
  2. 笔记本盖子没有打开,导致连接黑屏,必须笔记本盖子开启,向日葵也会显示不正常,但能用。

卡住

  1. 点击nvdia geforce 软件 就会卡住,我只能用向日葵远程点击这个弹窗就恢复正常

parsec与其他远程一起用

  1. 向日葵配合他开机棒,用远程开机【向日葵开机启动】
  2. 开机后,向日葵远程控制登陆账号然后启动parsec软件
  3. 文件传送用向日葵或者一些临时文件发送的网站,比喻奶牛快传【现在要注册才能发送】
  4. 如果卡住了,用向日葵点击一下

补充

如果没有实体显示器,可以用网上虚拟显示器方法,具体可以看之前的文章。。。

其实我没有明白,parsec能够低延迟,应该主要还是显卡编码加成,网络协议应该没有那么重要。

scrcpy 实现全选功能ctrl+a 输入法

背景

之前实现输入法功能,然后去android keyevent文档上找是否这样子,结果毛都没有,然后看scrcpy上面也没有看到单独一个函数是实现全选,后面想了好久是不是就是实现ctrl+a 这个按键呢?后面果然发现确实是这样子

知识点

在scrcpy 他实现按键时候传递metaState 这个属性值,我自己没有实现,然后看了一个关键词 AMETA_CTRL_LEFT_ON,然后搜索到这个对应值,所以只要模拟A时候设置一下metaState

PC代码

bool WindowsUI::HandleSelectAll(const SDL_KeyboardEvent& ev)
{
    if (ev.keysym.sym == SDLK_a && (ev.keysym.mod & KMOD_LCTRL) == KMOD_LCTRL) {
        //a + ctrl
        //AMETA_CTRL_LEFT_ON 0x2000
        m_contronl_net->SendKeyEvent(29, 0x2000);        //全选
        return true;
    }
    return false;
}

android 代码

    private void handleKeyCodeMessage(JSONObject data) throws JSONException{
        int key_code = data.getInt("key_code");
        int meta_state = data.getInt("mode");
        actionImplement.keyEvent(key_code, meta_state, false);
    }

        private void sendKeyEvent(int inputSource, int keyCode, int meteState, boolean longpress) {
        long now = SystemClock.uptimeMillis();

        EventFactory.injectKeyEventSelf(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, meteState,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
        if (longpress) {
            EventFactory.injectKeyEventSelf(new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 1, meteState,
                    KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_LONG_PRESS,
                    inputSource));
        }

        EventFactory.injectKeyEventSelf(new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode, 0, meteState,
                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, inputSource));
    }

我模拟按键跟scrcpy不一样,感觉简单一些,因为我抄的是adb 实现模拟,看一眼就特别清晰。。
现在自己用协同工具非常舒服了,我现在就缺少文件传送了,这个东西还是非常方便。主要平时自己还不到图片发送,主要看手机上APP的东西。

scrcpy 类似软件实现思路与探索(初版)

背景

当初看到这个scrcpy工具觉得非常神奇,不知道怎么实现,我对某种业务具体实现特别感兴趣,但我对编程语言没有太多兴趣,对一些用不到算法也特别不感兴趣。后面自己研究一段时间,然后结合scrcpy源代码和其他产品大概实现思路,总结scrcpy 通过app_process实现技术。

技术

  1. app_process 技术
    这个是根本技术,自己实现adb命令功能代码,为什么我们不直接用adb 实现呢?以前一些云控技术用的adb 命令,因为adb 命令会创建进程,对于非常频繁的行为,性能太低。同时跨进程,没有直接源码实现。所以用app_process技术,因为可以通过反射实现adb 代码实现,那你会想我反射不一定要app_process,直接在android 代码反射也可以,反射代码可以写,但没有权限或者说权限不够,模拟点击调用会失败,通过源代码发现他需要系统的权限。如果不走app_process,可以root手机达到反射条件。
  2. 反射
    怎么反射,对于新手完全找不到方向,你看scrcpy代码,你也不知道为什么他们能找到,后面我想既然他们反射实现的adb命令,应该看了android 命令实现代码,果然我在 android 源代码找到有关代码,那么我们方向找到了,只要找命令源代码,那么基本就能反射出来。
  3. android 怎么编码或者怎么截图
    1. 反射截图命令
      我最开始也是这么想的,反射命令截图,FPS可以达到30帧样子,虽然达不到60fps基本作为协作工具完全可以了
    2. android h264 编码
      1. 这个通过编码成h264,获取一个buffer就投递给PC端【直播】
      2. 这里难点不熟悉android 编码代码,直接自己搜索一下这方便代码,完全写一个直播丢给PC,不用反射,编码直接申请权限,调用代码就可以了。
  4. 网络通信
    1. scrcpy用原生socket,然后协议用二进制自定义协议

      我觉得不是很有必要,如果真的为什么节约通信大小,直接用protobuf就好了,毕竟动态的varint还是比较节约内存,不过对于简单协议,用什么都可以,我只是提一嘴。

    2. 我自己用websocket+JSON 来通信

      不用自己切包,JSON解析扩展性高,对于命令来说,这一点协议没有消耗无所谓。

    3. 视频流,直接丢给单独接受视频端口,如果有服务接入,那么考虑东西会多一些。
  5. PC端
    1. 视频解码

      业界ffmepg 开发库,按照官方解码视频就好

    2. 渲染
      1. 网页

        感觉渲染速度达不到,貌似都是解决mp4 标签来做的,都会缓存,我没有试过,底层解码成图片,然后投递给网页,我最开始截图成PNG,然后给网页,貌似性能不错。

      2. SDL

        scrcpy就是这么写的,我网页慢,也用sdl,只是整个写法完全自己写的,没有借鉴scrcpy,因为他的跨平台而且用纯c,用大量函数指针来模拟面向对象写法,我直接用c++写的 windows代码,用原生win32 没有用任何其他的,mfc,或者 duilib或者其他的界面。

  6. 业务代码
    1. 点击实现
      1. android 反射实现代码
      2. PC 界面与 手机界面比例,然后计算在android 真实的坐标
    2. 按键实现
      1. androi 反射 input 命令代码
      2. SDL 处理按键操作
        1. 快捷键处理

          要判断什么时候快捷键,什么单独按键,所以这么设计一些业务代码蛮多,我自己重写几次才写好,所以没有相信那么简单。keyup keydown 什么时候处理,什么时候不处理。

        2. keydown可能够处理连续按键,keyup 不会触发,所以处理单独按键要响应keydown,而不是keyup触发,否则无法实现一个按键一直按着,触发多次逻辑,
  7. android旋转
    1. android 反射监听手机旋转,旋转就重新创建编码,PC端检测手机传过来的编码变化就要重新处理buffer,我开始不知道,所以旋转导致ffmepeg解码报错,我都不知道什么原因。

      总结

      上面基本是scrcpy基本逻辑需要技术点,下篇文章我会说怎么找到adb 命令对象实现代码。
      这篇文章只是从我大脑技术一下子写完,总结自己疑惑。

      写博客只是养成一个长期习惯,从而实现思考的复利,博客加广告只是看是不是有真人看我的博客,其实有没有都不是那么重要(有更好),现在总共靠广告赚了3美元了,100美元提现,感觉这辈子应该看不到了。。

如果我的博客对你真有帮助,那我也稍微欣慰一下。。。
突然想起来,我当初写博客只是想看一下,互联网从0到1链接,感受互联的感觉。目前已经感受到了,发现google搜索带过来量,自己基本没有放过外联。不知道他怎么跑过来的。

android app_process 反射实现广播

背景

因为Scrcpy 目前版本不支持输入法,自己的协同工具为了方便自己使用,增加直接在windows用输入法,而不是直接Keycode方式,这样子体验好很多。

使用输入法

我这里直接用了网上开源 ADBKeyBoard 解决 不能支持uncode编码问题(因为adb input 不支持unicode,如果直接反射也是不可以使用的【这样子中文就有很大问题】),但这个实现用广播,原来scrcpy没有反射广播,于是我看 adb shell am broadcast -a 对应在android cmd 里面目录代码,看他用了broadcastIntent 方法

反射 Android12 broadcastIntent

public void sendBroadcast(Intent intent){
        //IntentReceiver receiver = new IntentReceiver();

        try {
            Class cls = Class.forName("android.app.IApplicationThread");
            //   public int broadcastIntent(IApplicationThread caller,
            //2352            Intent intent, String resolvedType,  IIntentReceiver resultTo,
            //2353            int resultCode, String resultData, Bundle map,
            //2354            String requiredPermission, int appOp, boolean serialized,
            //2355            boolean sticky, int userId)
            Method method = manager.getClass().getMethod("broadcastIntent",cls, Intent.class, String.class, IIntentReceiver.class, int.class, String.class,
                    Bundle.class, String[].class, int.class, Bundle.class,boolean.class, boolean.class, int.class);

            Object objString = method.invoke(manager, null,intent, null, null, 0, null, null, null, -1, null, true, false, android.os.Process.myUid()/100000);
            Ln.i("调用完成:" + objString.toString() );
        } catch (ClassNotFoundException e) {
            Ln.e("notfound" + e.toString());
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            Ln.e("InvocationTargetException" + e.toString());
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            Ln.e("NoSuchMethodException" + e.toString());
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            Ln.e("IllegalAccessException" + e.toString());
            e.printStackTrace();
        }
        //manager.getClass().getMethod()
        /*this.broadcastIntent(null, intent, null, null, 0, null, null, null, true, false,
                Binder.getOrigCallingUser());*/
        //receiver.waitForFinish();
    }

这个参数挺多的,不能版本参数不一样,所以要看android的源代码,这样子我在windows 启动SDL 输入法
响应input

        if (event.type == SDL_TEXTINPUT) {
            HandleInput(event); //直接发送网络请求到android里面,然后调用反射发送广播
            continue;
        }

这样子就是简单实现app_process 反射广播

难点

  1. 一开始不不知道怎么弄,所以要看adb 里面发送广播的实现,scrcpy 实现本质也是看android adb源代码,所以协同工具本质就是自己实现一个adb在 app_process,同时app_process 启动进程使用shell权限,所以能反射一些高级命令,模拟点击就是具有adb权限,如果apk 具备这样子权限,那么也可以直接反射调用点击命令。
  2. 参数好多,如果不熟练很容易反射报错。今天我实现反射shellCommand 命令(高版本android 实现命令新代码),实例化带一个参数报错,结果我传入null,默认转换空参数数组,导致实例化失败。。
  3. 不同android版本反射参数有区别,我这里只是反射自己用的,所以要注意。

补充

后面可以说一下Scrcpy 开发思路,同时重点说一下服务怎么反射

scrcpy 为什么要在旋转停止发送视频流

问题

我自己写了电脑控制手机协同(借鉴Scrcpy),但是自己偶尔会出现花屏(屏幕会出现残影)

排查

1:通过错误我找到无效数据包,但不知道为什么会无效,我把pc c++代码看了一下与sdl官方代码对比一下修复几个地方可能导致丢包的逻辑。

2:我发现屏幕旋转后,然后回到桌面,很容易出现花屏,因为我看过scrcpy代码,我发现他旋转时候会停止发送数据包,而我是没有处理

while (!consumeRotationChange() && !eof) {
            //这里是一直等待,所以这里很容易出现卡住,然后buffeer
            //是之前的surface的,旋转就导致宽度和高度不一样,导致前后不对
            int outputBufferId = codec.dequeueOutputBuffer(bufferInfo, -1);
            eof = (bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
            try {
                if (consumeRotationChange()) {
                    // must restart encoding with new size
                    //这里跳出来,
                    break;
                }
                if (outputBufferId >= 0) {
                    ByteBuffer codecBuffer = codec.getOutputBuffer(outputBufferId);

                    if (sendFrameMeta) {
                        writeFrameMeta(fd, bufferInfo, codecBuffer.remaining());
                    }

                    IO.writeFully(fd, codecBuffer);
                    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
                        // If this is not a config packet, then it contains a frame
                        firstFrameSent = true;
                    }
                }
            } finally {
                if (outputBufferId >= 0) {
                    codec.releaseOutputBuffer(outputBufferId, false);
                }
            }
        }

旋转会重新创建surface,这样子采集的数据不一样,所以会出现数据包错误。。。

总结

很多时候有现成的产品作为参考,可以避免很多坑,但如果自己不写,为什么这么是不知道真正的原因的。

浏览器自动删除指定网址历史记录插件

背景

自己访问一些网址,关闭标签或者关闭浏览器不会出现历史记录里面。

 插件

DynamicHistory

在chrome商店可以找到。

https://chrome.google.com/webstore/detail/dynamichistory/ehkdegpnplleadlmjoaidmjiabocgpok

https://www.chajianxw.com/product-tool/42001.html
这个是国内访问,我没有下载,只是搜到了,你可以下载试试,具体安装方法都是通过开发者模式进行安装,这种扩展网站都有写怎么安装的,你按照图片就可以了。

使用


点击插件,然后在上面框输入网址,我用* ,代表任意google的网址都不会记录。

其他的样式,自己可以在插件选项设置,主要是在显示被历史删除的网址的样式,标题是不一样的。
我自己都去掉了,这个看自己喜好

notepad++ 替代产品 everedit

背景

自己笔记本软件一直都是用notepad++,我喜欢他的多标签和多个文件搜索功能,但由于这个作者一直都有政治倾向,所以想找一款可以替换notepad++的软件,因为vscode比较重,所以我直接排除了,找几个几款都不是很满意,要么没有我想要的功能,要么就是太重。【vscode 用在写nodejs 或者网页时候】

everedit

我在搜索找到了everedit,而且他是国产的软件,同时支持我多标签自动保存和文件搜索功能,同时还有其他的为开发装备的扩展,我自己已经用几周,感觉非常满意,暂时没有找到其他的问题。虽然他高级功能收费,但我基本用不到高级功能,同时他应该是纯c开发,然后界面win32开发,因为我用vs 打开资源,可以看到他的对话框资源,同时没有引用mfc的dll,也没有用c++ 运行库,那么它可能纯c写的。而且文件大小都很小。

有时候真觉得纯c开发的软件真的小而美,用高级语言开发东西反而只是大了

everedit介绍

标签临时缓存

他默认多个标签不会缓存,必须自己在设置里面进行设置。

搜索

这个基本和nopted++ 支持多个

它高级查找还支持匹配行和非匹配行,统计行数,这个非常适合开发用,我感觉作者产品理解能力还是很强的。他文件路径搜索可以自己去在查找菜单里面,界面开发还是非常清晰,我感觉比notepad++还更加清晰。

base64使用

选择要base64的文字,点击菜单工具的里面base64就可以进行编码与解码了,这个功能非常方便,如果某个文件要base64,那么直接权全选然后点击。

hex 二进制显示

这个自带二进制显示,然后右键可以直接复制16进制的字符串,这个对我非常方便,我以前用Hex专门工具,这样子就不需要了。

总结

我目前只用了上面这几个功能,其他功能暂时我没有用到,等我再用一段时间,如果我还觉得非常好友,去买一个永久激活码支持一下作者,虽然我用不到他的收费高级功能,算是支持国产软件。

貌似30天的试用期,试用期过期会弹出购买对话框,然后点击确定就可以正常使用,我目前还没有过30天,等后面看具体情况,没有高级高能收费这个说法。。。

官网

http://www.everedit.cn/

问题

我现在使用,发现新建标签会出现重复,比喻标签1,我关掉程序,然后再新建标签,还会创建标签1,看起来没有什么,但如果搜索第二个标签1时候,点击搜索内容会跳到第一个标签,导致错乱,感觉非常不爽,我不知道这个bug怎么会有,稍微用一下就应该重现。。

我暂时每次新建标签时候,如果重复直接关闭那个重复就不会出现这个问题,但感觉不爽,如果有时间直接给他打一个补丁,或者写一个插件解决这个问题,实在有点膈应自己,目前还没有过期,我还没有购买这个软件,我想想看看过期会不会弹出购买对话框

win32 button 可以设置icon大小

背景

记录一下win32编程,其实这种东西没有任何意义,只是回味一下win32编程,只是现在工具用的win32开发的,不想用第三方的界面库。

加载icon

方法一,这种无法设置icon的大小

    HICON folderico = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
    ::SendMessage(btn_control_home, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)folderico);

方法二,可以设置大小

    HANDLE new_image = LoadImage(NULL, L"res\\Power.ico", IMAGE_ICON, 28, 28, LR_LOADFROMFILE); 
    ::SendMessage(btn_control_power, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)new_image);

总结

win32 因为所有控件都是窗口,所以设置属性或者获取属性都是发送消息,但参数各式各样,这个谁记得住呢,所以才需要封装,点几个属性设置一下就可以了。。。所以win32界面开发的话,效率是过时的。如果不重要界面的话,那就无所谓。减少体积挺好的。

scrcpy 为什么不能常亮

scrcpy wifi连接无法常亮

我自己开发软件发现无法常亮,这样子用起来就非常不方便,然后我研究了scrcpy,他虽然有一个--stayway on 的命令,但我发现这个只有连接usb才会保持常亮。

过程

  1. 分析Scrcpy 只是设置setting 手机属性而已,电源管理设置而已,但如果用wifi没有效果了,因为我没有充电,但这样子如果我挂机软件或者游戏感觉用起来就不方便了。
  2. 我发现anlink可以做到。

分析anlink

我猜测他用什么adb命令,我懒的逆向分析,直接用火绒剑分析进程行为,我发现他使用了命令

adb shell input keyevent mouse

我找了半天mouse,也没有找到这个按键值,然后我看google input.java的 源代码也没有这个有关的知识,然后我猜测就是未知值,那么我直接adb shell input keyevent 0 不就可以了吗?于是我在代码构建按键,而不是用adb命令模式,每隔10秒发送一个未知按键,未知按键就是0,这个是android 代码里面定义的,这样子就实现屏幕常亮。。。这个操作不管什么类型的手机都能常亮,因为都一直在按键。

额外发现

我突然发现如果间隔50毫秒发送未知按键就导致我的手机无法锁屏,这个逻辑结合屏幕关闭,就可以导致用户无法操作手机。。。。。。 有点无敌啊。。。所以以后普通用户千万不要授权APP 具备ADB命令,现在手机可以直接wifi adb, 不需要连接,这样子就可能出现木马,强制控制手机行为了。。。。。
安全手机不要开启开发者模式,否则带来很大危险。