Android?autojs隨時(shí)翻譯剪貼板單詞實(shí)現(xiàn)示例
使用場(chǎng)景
在看英文的時(shí)候, 我們會(huì)遇到不懂得單詞, 就需要查閱單詞的意思,
一般步驟是長(zhǎng)按出現(xiàn)菜單, 選中單詞, 菜單里有的有翻譯選項(xiàng), 點(diǎn)擊之后跳轉(zhuǎn)搜索單詞的頁(yè)面,
有的菜單里面沒(méi)有翻譯選項(xiàng), 復(fù)制以后, 需要自行打開(kāi)百度, 或者其他翻譯軟件, 再搜索翻譯
這里面有很多非常干擾我們閱讀的操作, 在app之間跳來(lái)跳去, 不爽;
目標(biāo)
我們今天就做一個(gè), 當(dāng)長(zhǎng)按之后, 選中單詞, 點(diǎn)擊復(fù)制, 直接出翻譯的功能
主要功能
監(jiān)聽(tīng)剪貼板
這個(gè)監(jiān)聽(tīng)剪貼板的功能在高版本安卓是可以實(shí)現(xiàn)的, 只是相比于安卓9之前的版本, 步驟復(fù)雜一點(diǎn)點(diǎn),
Google 在近年來(lái)一直在打擊第三方應(yīng)用程序?qū)羟邪宓脑L(fǎng)問(wèn),目的是增強(qiáng)用戶(hù)的個(gè)人資料安全。 在發(fā)布 Android 10 時(shí)就已經(jīng)禁止后臺(tái)應(yīng)用讀取剪貼板數(shù)據(jù)。
我的手機(jī)是安卓12, 如果我閱讀文章的app在前臺(tái), autojs在后臺(tái)肯定 是讀取不到剪貼板內(nèi)容的
在autojs的菜單中, 有一個(gè)前臺(tái)服務(wù), 打開(kāi)之后, 回到手機(jī)桌面, 測(cè)試讀取剪貼板, 內(nèi)容為空, 讀取不到
懸浮窗算前臺(tái)嗎?
前臺(tái)服務(wù)不行的話(huà), 我們用懸浮窗試試, 懸浮窗算前臺(tái)嗎?
試試就知道了
let w = floaty.window( <vertical> <button id="readClipboard" text="讀取剪貼板" w="auto" /> </vertical> ); w.readClipboard.click(() => { let content = getClip(); toastLog(content); }); setInterval(() => {}, 1000);
經(jīng)過(guò)測(cè)試, toast氣泡內(nèi)容為空, 證明懸浮窗不算安卓所說(shuō)的前臺(tái),
焦點(diǎn)
查閱了一番教程之后, 說(shuō)安卓10獲取剪貼板要獲取焦點(diǎn),
那么我們就給按鈕申請(qǐng)焦點(diǎn)試試
w.readClipboard.click(() => { // 申請(qǐng)焦點(diǎn) w.requestFocus(); setTimeout(() => { let content = getClip(); toastLog(content); }, 500); });
焦點(diǎn)申請(qǐng)了, 第一次點(diǎn)擊沒(méi)有獲取到剪貼板內(nèi)容, 之后的點(diǎn)擊都獲取到了剪貼板內(nèi)容
時(shí)差
再次查閱資料, 說(shuō)申請(qǐng)焦點(diǎn)以后, 還要等一下再獲取剪貼板, 那我們就等一下
w.readClipboard.click((view) => { log(view.text()); // 申請(qǐng)焦點(diǎn) w.requestFocus(); setTimeout(() => { let content = getClip(); toastLog(content); }, 500); });
這下測(cè)試就正常了, 第一次點(diǎn)擊也可以獲取到剪貼板內(nèi)容,
這里有個(gè)問(wèn)題, 我們申請(qǐng)了焦點(diǎn), 用完之后應(yīng)該去除焦點(diǎn)
w.readClipboard.click((view) => { w.requestFocus(); setTimeout(() => { let content = getClip(); toastLog(content); w.disableFocus(); }, 500); });
監(jiān)聽(tīng)剪貼板
獲取剪貼板內(nèi)容解決了, 怎么監(jiān)聽(tīng)呢?
開(kāi)一個(gè)定時(shí)器, 每隔一會(huì)讀取一下剪貼板,
我們的目的是翻譯單詞, 不想等太久, 所以用300ms, 大家可以自行修改時(shí)間
切換焦點(diǎn)的問(wèn)題
頻繁切換焦點(diǎn), 當(dāng)我們要聊天界面有輸入框出現(xiàn)的時(shí)候, 焦點(diǎn)會(huì)在懸浮窗和聊天輸入框之間頻繁切換,
甚至無(wú)法操作界面, 因此我們要增加一個(gè)停止切換焦點(diǎn)的功能, 以便我們可以正常打字聊天輸入文字
必須用懸浮窗獲取剪貼板內(nèi)容嗎
不想用懸浮窗, 也可以試試adb, 手機(jī)用usb連接電腦, 然后執(zhí)行下面的命令
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;
實(shí)測(cè), 這個(gè)方法沒(méi)用, 所以, 必須用懸浮窗.
不過(guò)那個(gè)scrcpy投屏軟件就可以直接獲取剪貼板, 有經(jīng)驗(yàn)的大佬可以去看看研究下scrcpy的代碼
翻譯單詞
翻譯單詞可以用在線(xiàn)的百度, 有道, 也可以用離線(xiàn)的詞典.
百度和有道都有免費(fèi)額度,
百度
免費(fèi)調(diào)用量:標(biāo)準(zhǔn)版免費(fèi)調(diào)用量由不限額度改為5萬(wàn)字符/月
有道
每小時(shí)1000次免費(fèi)訪(fǎng)問(wèn),超過(guò)訪(fǎng)問(wèn)次數(shù)后會(huì)進(jìn)行封禁暫停服務(wù),1小時(shí)后會(huì)自然恢復(fù)。
每個(gè)平臺(tái)都要申請(qǐng)自己的key, 這里以有道為例
這是有道的官網(wǎng)
更換自己的秘鑰和應(yīng)用id
var appKey = "xxxxxxxxxxxxxxx";// 應(yīng)用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. (線(xiàn)上)贊同,點(diǎn)贊
n. (線(xiàn)上)有利的投票
懸浮窗顯示翻譯內(nèi)容
顯示單詞, 翻譯, 再加一個(gè)關(guān)閉按鈕
let info = `vt. (線(xiàn)上)贊同,點(diǎn)贊 n. (線(xià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);
給懸浮窗加上觸摸移動(dòng)
//記錄按鍵被按下時(shí)的觸摸坐標(biāo) var x = 0, y = 0; //記錄按鍵被按下時(shí)的懸浮窗位置 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: //移動(dòng)手指時(shí)調(diào)整懸浮窗位置 w.setPosition(windowX + (event.getRawX() - x), windowY + (event.getRawY() - y)); return true; case event.ACTION_UP: return true; } return true; });
觸摸移動(dòng)效果
添加記憶懸浮窗位置的功能
也許你想要自己調(diào)整懸浮窗, 到自己覺(jué)得舒服的位置, 那么每次移動(dòng)懸浮窗后, 就記住懸浮窗左上角的坐標(biāo),
下次顯示, 也顯示到這個(gè)位置
這個(gè)記憶位置的動(dòng)作放在松開(kāi)手指的事件(ACTION_UP)里面做
case event.ACTION_UP: storage.put("windowX", w.getX()); storage.put("windowY", w.getY()); return true;
之后如果要顯示懸浮窗, 就先讀取位置信息, 再設(shè)置懸浮窗位置
let windowX = storage.get("windowX", 0); let windowY = storage.get("windowY", 0); w.setPosition(windowX, windowY);
停止切換焦點(diǎn)
這個(gè)停止切換焦點(diǎn), 需要用另外一個(gè)懸浮窗來(lái)控制, 就用那個(gè)切換焦點(diǎn)的來(lái)做
懸浮窗按鈕點(diǎn)擊有兩個(gè), 功能分別是
- 停止切換焦點(diǎn)
- 退出腳本
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> );
這個(gè)懸浮窗默認(rèn)放在右側(cè)邊緣
w.setPosition(-6666, -6666); ui.post(function () { let windowWidth = w.getWidth(); let windowHeight = w.getHeight(); let deviceWidth = device.width; let deviceHeight = device.height; // 懸浮窗放到右側(cè)邊緣 w.setPosition(deviceWidth - windowWidth, (deviceHeight - windowHeight) / 2); }, 300);
工作狀態(tài)我們用文字的顏色來(lái)表示
- 白色, 工作中, 白天工作的意思
- 黑色, 休息, 晚上睡覺(jué)
如果焦, 這個(gè)字是白色, 那么就是切換焦點(diǎn)一致在進(jìn)行, 如果焦點(diǎn)擊以后變成黑色, 就是說(shuō)切換焦點(diǎn)不工作了;
退, 表示退出腳本的意思
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(); });
同時(shí), 這個(gè)foucus變量, 應(yīng)當(dāng)可以控制是否切換焦點(diǎn), 在這之前, 還有一個(gè)問(wèn)題要確定,
什么時(shí)候觸發(fā)翻譯指令, 顯示懸浮窗
這里的觸發(fā)指令設(shè)置為, 腳本開(kāi)始獲取一次剪貼板內(nèi)容,
如果循環(huán)獲取剪貼板內(nèi)容和之前的內(nèi)容不一樣, 那么就觸發(fā)翻譯指令, 顯示懸浮窗
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); });
切換焦點(diǎn), 影響長(zhǎng)按復(fù)制單詞
實(shí)際使用發(fā)現(xiàn), 如果頻繁切換焦點(diǎn), 那么長(zhǎng)按菜單都出不來(lái), 因此, 不可以頻繁切換焦點(diǎn),
基于這個(gè)原因, 翻譯的時(shí)機(jī)要改一下, 改為當(dāng)用戶(hù)主動(dòng)點(diǎn)擊按鈕, 再去讀取剪貼板
這個(gè)主要是修改右側(cè)按鈕的點(diǎn)擊事件, 點(diǎn)擊按鈕后讀取剪貼板內(nèi)容, 再進(jìn)行翻譯, 顯示懸浮窗
最終效果展示
點(diǎn)擊右側(cè)按鈕, 譯, 顯示翻譯結(jié)果
環(huán)境
設(shè)備: 小米11Pro
Android版本: 12
Autojs版本: 9.2.10
以上就是Android autojs隨時(shí)翻譯剪貼板單詞實(shí)現(xiàn)示例的詳細(xì)內(nèi)容,更多關(guān)于Android autojs 剪貼板翻譯的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android studio無(wú)法創(chuàng)建類(lèi)和接口和提示問(wèn)題的完美解決辦法
這篇文章主要介紹了Android studio無(wú)法創(chuàng)建類(lèi)和接口和提示問(wèn)題解決辦法,內(nèi)容比較簡(jiǎn)單,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2018-04-04Android實(shí)現(xiàn)房貸計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)房貸計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01Android Studio生成函數(shù)注釋的實(shí)現(xiàn)方法
這篇文章主要介紹了Android Studio生成函數(shù)注釋的實(shí)現(xiàn)方法的相關(guān)資料,希望通過(guò)本文大家能夠?qū)崿F(xiàn)這樣的功能,需要的朋友可以參考下2017-09-09解決Android studio 3.6.1 出現(xiàn)Cause: unable to find valid certifi
這篇文章主要介紹了Android studio 3.6.1 出現(xiàn)Cause: unable to find valid certification path to requested target 報(bào)錯(cuò)的問(wèn)題及解決方法,需要的朋友可以參考下2020-03-03android LinearLayout和RelativeLayout組合實(shí)現(xiàn)精確布局方法介紹
用android LinearLayout和RelativeLayout實(shí)現(xiàn)精確布局此方法適合很適合新人看2012-11-11Android項(xiàng)目實(shí)戰(zhàn)(二十八):使用Zxing實(shí)現(xiàn)二維碼及優(yōu)化實(shí)例
這篇文章主要介紹了Android項(xiàng)目實(shí)戰(zhàn)(二十八):使用Zxing實(shí)現(xiàn)二維碼及優(yōu)化實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-11-11