Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: get selected text in macOS #142

Merged
merged 1 commit into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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