Skip to content

Commit

Permalink
fix: get selected text in macOS (#142)
Browse files Browse the repository at this point in the history
  • Loading branch information
yetone committed May 25, 2023
1 parent f29a9d3 commit 1843a79
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 73 deletions.
11 changes: 11 additions & 0 deletions src-tauri/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions src-tauri/Cargo.toml
Expand Up @@ -31,12 +31,13 @@ windows = {version="0.44.0",features= ["Win32_UI_WindowsAndMessaging", "Win32_Fo
window-shadows = "0.2"
arboard = "3.2.0"

[target.'cfg(target_os = "macos")'.dependencies ]
[target.'cfg(target_os = "macos")'.dependencies]
window-shadows = "0.2"
core-graphics = "0.22.3"
arboard = "3.2.0"
macos-accessibility-client = "0.0.1"

[target.'cfg(target_os = "linux")'.dependencies ]
[target.'cfg(target_os = "linux")'.dependencies]
mouse_position = "0.1.3"
x11-clipboard = "0.7.1"
wl-clipboard-rs = "0.7.0"
Expand Down
20 changes: 20 additions & 0 deletions src-tauri/src/main.rs
Expand Up @@ -24,12 +24,32 @@ use trayicon::*;
use utils::*;
use window::*;

#[cfg(target_os = "macos")]
fn query_accessibility_permissions() -> bool {
let trusted = macos_accessibility_client::accessibility::application_is_trusted_with_prompt();
if trusted {
print!("Application is totally trusted!");
} else {
print!("Application isn't trusted :(");
}
trusted
}

#[cfg(not(target_os = "macos"))]
fn query_accessibility_permissions() -> bool {
return true;
}

// 全局AppHandle
pub static APP: OnceCell<AppHandle> = OnceCell::new();
// 存待翻译文本
pub struct StringWrapper(pub Mutex<String>);

fn main() {
if !query_accessibility_permissions() {
return
}

tauri::Builder::default()
// 单例运行
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
Expand Down
93 changes: 26 additions & 67 deletions src-tauri/src/selection.rs
Expand Up @@ -142,84 +142,43 @@ pub fn get_selection_text() -> Result<String, String> {
#[cfg(target_os = "macos")]
pub fn get_selection_text() -> Result<String, String> {
let apple_script = r#"
use sys : application "System Events"
use AppleScript version "2.4"
use scripting additions
use framework "Foundation"
use framework "AppKit"
-- Use the following delay to choose an application window
-- and highlight some text. Then ensure that the window remains
-- in focus until the script terminates.
-- delay 5
tell application "System Events"
set frontmostProcess to first process whose frontmost is true
set appName to name of frontmostProcess
end tell
set P to the first application process whose frontmost is true
if appName is equal to "OpenAI Translator" then
return
end if
set appName to name of P
-- Back up clipboard contents:
set savedClipboard to the clipboard
if appName is equal to "Mail" then
error "not support " & appName
end
set thePasteboard to current application's NSPasteboard's generalPasteboard()
set theCount to thePasteboard's changeCount()
if appName is equal to "Safari" then
try
tell application "Safari"
set theText to (do JavaScript "getSelection().toString()" in document 1)
end tell
return theText
end try
error "not support Safari"
end
-- Copy selected text to clipboard:
tell application "System Events" to keystroke "c" using {command down}
delay 0.1 -- Without this, the clipboard may have stale data.
if appName is equal to "Google Chrome" then
try
tell application "Google Chrome" to tell active tab of window 1
set theText to (execute javascript "getSelection().toString()")
end tell
return theText
end try
error "not support Google Chrome"
end
if thePasteboard's changeCount() is theCount then
return ""
end if
if appName is equal to "Microsoft Edge" then
try
tell application "Microsoft Edge" to tell active tab of window 1
set theText to (execute javascript "getSelection().toString()")
end tell
return theText
end try
error "not support Microsoft Edge"
end
set theSelectedText to the clipboard
set _W to a reference to the first window of P
set the clipboard to savedClipboard
set _U to a reference to ¬
(UI elements of P whose ¬
name of attributes contains "AXSelectedText" and ¬
value of attribute "AXSelectedText" is not "" and ¬
class of value of attribute "AXSelectedText" is not class)
tell sys to if (count _U) ≠ 0 then ¬
return the value of ¬
attribute "AXSelectedText" of ¬
_U's contents's first item
set _U to a reference to UI elements of _W
with timeout of 1 seconds
tell sys to repeat while (_U exists)
tell (a reference to ¬
(_U whose ¬
name of attributes contains "AXSelectedText" and ¬
value of attribute "AXSelectedText" is not "" and ¬
class of value of attribute "AXSelectedText" is not class)) ¬
to if (count) ≠ 0 then return the value of ¬
attribute "AXSelectedText" of its contents's first item
set _U to a reference to (UI elements of _U)
end repeat
end timeout
error "not found AXSelectedText"
theSelectedText
"#;

match std::process::Command::new("osascript")
.arg("-e")
.arg(apple_script)
.output()
{
Expand All @@ -228,7 +187,7 @@ error "not found AXSelectedText"
if output.status.success() {
// get output content
let content = String::from_utf8(output.stdout)
.expect("failed to parse get-selected-text-by-ax.applescript output");
.expect("failed to parse get-selected-text.applescript output");
// trim content
let content = content.trim();
Ok(content.to_string())
Expand Down
11 changes: 7 additions & 4 deletions src-tauri/src/window.rs
Expand Up @@ -213,10 +213,13 @@ fn get_mouse_location() -> Result<(f64, f64), String> {
// 划词翻译
pub fn translate_window() {
// 获取选择文本
let mut text = String::new();
if let Ok(v) = get_selection_text() {
text = v;
}
let text = match get_selection_text() {
Ok(v) => v,
Err(err) => {
println!("get selection text error: {:?}", err);
String::new()
}
};
let handle = APP.get().unwrap();
// 写入状态备用
let state: tauri::State<StringWrapper> = handle.state();
Expand Down

0 comments on commit 1843a79

Please sign in to comment.