Android autojs随时翻译剪贴板单词实现示例

来自:网络
时间:2022-12-26
阅读:
目录

使用场景

在看英文的时候, 我们会遇到不懂得单词, 就需要查阅单词的意思,

一般步骤是长按出现菜单, 选中单词, 菜单里有的有翻译选项, 点击之后跳转搜索单词的页面,

有的菜单里面没有翻译选项, 复制以后, 需要自行打开百度, 或者其他翻译软件, 再搜索翻译

这里面有很多非常干扰我们阅读的操作, 在app之间跳来跳去, 不爽;

目标

我们今天就做一个, 当长按之后, 选中单词, 点击复制, 直接出翻译的功能

主要功能

监听剪贴板

这个监听剪贴板的功能在高版本安卓是可以实现的, 只是相比于安卓9之前的版本, 步骤复杂一点点,

Google 在近年来一直在打击第三方应用程序对剪切板的访问,目的是增强用户的个人资料安全。 在发布 Android 10 时就已经禁止后台应用读取剪贴板数据。

我的手机是安卓12, 如果我阅读文章的app在前台, autojs在后台肯定 是读取不到剪贴板内容的

在autojs的菜单中, 有一个前台服务, 打开之后, 回到手机桌面, 测试读取剪贴板, 内容为空, 读取不到

Android autojs随时翻译剪贴板单词实现示例

悬浮窗算前台吗?

前台服务不行的话, 我们用悬浮窗试试, 悬浮窗算前台吗?

试试就知道了

let w = floaty.window(
    <vertical>
        <button id="readClipboard" text="读取剪贴板" w="auto" />
    </vertical>
);
w.readClipboard.click(() => {
    let content = getClip();
    toastLog(content);
});
setInterval(() => {}, 1000);

经过测试, toast气泡内容为空, 证明悬浮窗不算安卓所说的前台,

焦点

查阅了一番教程之后, 说安卓10获取剪贴板要获取焦点,

那么我们就给按钮申请焦点试试

w.readClipboard.click(() => {
    // 申请焦点
    w.requestFocus();
    setTimeout(() => {
        let content = getClip();
        toastLog(content);
    }, 500);
});

焦点申请了, 第一次点击没有获取到剪贴板内容, 之后的点击都获取到了剪贴板内容

时差

再次查阅资料, 说申请焦点以后, 还要等一下再获取剪贴板, 那我们就等一下

w.readClipboard.click((view) => {
    log(view.text());
    // 申请焦点
    w.requestFocus();
    setTimeout(() => {
        let content = getClip();
        toastLog(content);
    }, 500);
});

这下测试就正常了, 第一次点击也可以获取到剪贴板内容,

这里有个问题, 我们申请了焦点, 用完之后应该去除焦点

w.readClipboard.click((view) => {
    w.requestFocus();
    setTimeout(() => {
        let content = getClip();
        toastLog(content);
        w.disableFocus();
    }, 500);
});

监听剪贴板

获取剪贴板内容解决了, 怎么监听呢?

开一个定时器, 每隔一会读取一下剪贴板,

我们的目的是翻译单词, 不想等太久, 所以用300ms, 大家可以自行修改时间

切换焦点的问题

频繁切换焦点, 当我们要聊天界面有输入框出现的时候, 焦点会在悬浮窗和聊天输入框之间频繁切换,

甚至无法操作界面, 因此我们要增加一个停止切换焦点的功能, 以便我们可以正常打字聊天输入文字

必须用悬浮窗获取剪贴板内容吗

不想用悬浮窗, 也可以试试adb, 手机用usb连接电脑, 然后执行下面的命令

adb -d shell appops set org.autojs.autojspro SYSTEM_ALERT_WINDOW allow;
adb -d shell pm grant org.autojs.autojspro android.permission.READ_LOGS;
adb shell am force-stop org.autojs.autojspro;

实测, 这个方法没用, 所以, 必须用悬浮窗.

不过那个scrcpy投屏软件就可以直接获取剪贴板, 有经验的大佬可以去看看研究下scrcpy的代码

翻译单词

翻译单词可以用在线的百度, 有道, 也可以用离线的词典.

百度和有道都有免费额度,

百度

免费调用量:标准版免费调用量由不限额度改为5万字符/月

有道

每小时1000次免费访问,超过访问次数后会进行封禁暂停服务,1小时后会自然恢复。

每个平台都要申请自己的key, 这里以有道为例

这是有道的官网

ai.youdao.com/#/

更换自己的秘钥和应用id

var appKey = "xxxxxxxxxxxxxxx";// 应用id
var key = "xxxxxxxxxxxxxxx"; // 秘钥
var salt = "" + new Date().getTime();
var curtime = Math.round(new Date().getTime() / 1000);
var query = "upvote";
var from = "en";
var to = "zh-CHS";
var str1 = appKey + truncate(query) + salt + curtime + key;
var sign = $crypto.digest(str1, "SHA-256", { output: "hex" });
let url = "https://openapi.youdao.com/api";
let data = {
    q: query,
    appKey: appKey,
    salt: salt,
    from: from,
    to: to,
    sign: sign,
    signType: "v3",
    curtime: curtime,
};
let r = http.post(url, data);
let info = r.body.json();
let translation = info.translation;
let explains = info.basic ? info.basic.explains.join("\n") : "";
log(translation + "\n" + explains);
/* -------------------------------------------------------------------------- */
function truncate(q) {
    var len = q.length;
    log("len = " + len);
    if (len <= 20) return q;
    let r = q.substring(0, 10) + len + q.substring(len - 10, len);
    log(r);
    return r;
}

返回的主要信息

upvote
vt. (线上)赞同,点赞
n. (线上)有利的投票 

悬浮窗显示翻译内容

显示单词, 翻译, 再加一个关闭按钮

let info = `vt. (线上)赞同,点赞
n. (线上)有利的投票`;
setInterval(() => {}, 1000);
let w = floaty.window(
    <vertical bg="#adb5bd" padding="8">
        <horizontal h="wrap_content">
            <text>upvote</text>
            <text layout_weight="1" gravity="right">
                X
            </text>
        </horizontal>
        <text id="info" textColor="#ffffff" textSize="16sp" />
    </vertical>
);
w.info.setText(info);

Android autojs随时翻译剪贴板单词实现示例

给悬浮窗加上触摸移动

//记录按键被按下时的触摸坐标
var x = 0,
    y = 0;
//记录按键被按下时的悬浮窗位置
var windowX, windowY;
w.move.setOnTouchListener(function (view, event) {
    switch (event.getAction()) {
        case event.ACTION_DOWN:
            x = event.getRawX();
            y = event.getRawY();
            windowX = w.getX();
            windowY = w.getY();
            return true;
        case event.ACTION_MOVE:
            //移动手指时调整悬浮窗位置
            w.setPosition(windowX + (event.getRawX() - x), windowY + (event.getRawY() - y));
            return true;
        case event.ACTION_UP:
            return true;
    }
    return true;
});

触摸移动效果

Android autojs随时翻译剪贴板单词实现示例

添加记忆悬浮窗位置的功能

也许你想要自己调整悬浮窗, 到自己觉得舒服的位置, 那么每次移动悬浮窗后, 就记住悬浮窗左上角的坐标,

下次显示, 也显示到这个位置

这个记忆位置的动作放在松开手指的事件(ACTION_UP)里面做

case event.ACTION_UP:
    storage.put("windowX", w.getX());
    storage.put("windowY", w.getY());
    return true;

之后如果要显示悬浮窗, 就先读取位置信息, 再设置悬浮窗位置

let windowX = storage.get("windowX", 0);
let windowY = storage.get("windowY", 0);
w.setPosition(windowX, windowY);

停止切换焦点

这个停止切换焦点, 需要用另外一个悬浮窗来控制, 就用那个切换焦点的来做

悬浮窗按钮点击有两个, 功能分别是

  • 停止切换焦点
  • 退出脚本
let w = floaty.window(
    <vertical bg="#adb5bd" w="32dp" padding="3">
        <text id="focus" w="*" h="36dp" gravity="center" textSize="20dp">
            焦
        </text>
        <View bg="#000000" h="1px"></View>
        <text id="exit" w="*" h="36dp" gravity="center" textSize="20dp">
            退
        </text>
    </vertical>
);

Android autojs随时翻译剪贴板单词实现示例

这个悬浮窗默认放在右侧边缘

w.setPosition(-6666, -6666);
ui.post(function () {
    let windowWidth = w.getWidth();
    let windowHeight = w.getHeight();
    let deviceWidth = device.width;
    let deviceHeight = device.height;
    // 悬浮窗放到右侧边缘
    w.setPosition(deviceWidth - windowWidth, (deviceHeight - windowHeight) / 2);
}, 300);

Android autojs随时翻译剪贴板单词实现示例

工作状态我们用文字的颜色来表示

  • 白色, 工作中, 白天工作的意思
  • 黑色, 休息, 晚上睡觉

如果焦, 这个字是白色, 那么就是切换焦点一致在进行, 如果焦点击以后变成黑色, 就是说切换焦点不工作了;

退, 表示退出脚本的意思

let focus = true;
w.focus.click(() => {
    focus = !focus;
    if (focus) {
        w.focus.attr("textColor", "#ffffff");
    } else {
        w.focus.attr("textColor", "#000000");
    }
});
w.exit.click(() => {
    engines.myEngine().forceStop();
});

同时, 这个foucus变量, 应当可以控制是否切换焦点, 在这之前, 还有一个问题要确定,

什么时候触发翻译指令, 显示悬浮窗

这里的触发指令设置为, 脚本开始获取一次剪贴板内容,

如果循环获取剪贴板内容和之前的内容不一样, 那么就触发翻译指令, 显示悬浮窗

ui.post(function () {
    w2.requestFocus();
    setTimeout(() => {
        clipboardContent = getClip();
        w2.disableFocus();
        /* -------------------------------------------------------------------------- */
        intervalID = setInterval(function () {
            if (!focus) {
                return;
            }
            w2.requestFocus();
            setTimeout(() => {
                let currentClipboardContent = getClip();
                w2.disableFocus();
                if (currentClipboardContent !== clipboardContent) {
                    clipboardContent = currentClipboardContent;
                    let info = translate(clipboardContent);
                    showInfo(info);
                }
            }, 100);
        }, 300);
    }, 1000);
});

切换焦点, 影响长按复制单词

实际使用发现, 如果频繁切换焦点, 那么长按菜单都出不来, 因此, 不可以频繁切换焦点,

基于这个原因, 翻译的时机要改一下, 改为当用户主动点击按钮, 再去读取剪贴板

这个主要是修改右侧按钮的点击事件, 点击按钮后读取剪贴板内容, 再进行翻译, 显示悬浮窗

最终效果展示

点击右侧按钮, 译, 显示翻译结果

Android autojs随时翻译剪贴板单词实现示例

环境

设备: 小米11Pro
Android版本: 12
Autojs版本: 9.2.10

以上就是Android autojs随时翻译剪贴板单词实现示例的详细内容,更多关于Android autojs 剪贴板翻译的资料请关注其它相关文章!

返回顶部
顶部