try fix cmd-a
This commit is contained in:
parent
dc32a2a80f
commit
5696727a50
3 changed files with 55 additions and 11 deletions
2
desktop/src-tauri/Cargo.lock
generated
2
desktop/src-tauri/Cargo.lock
generated
|
|
@ -2302,6 +2302,7 @@ checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.13.1",
|
"bitflags 2.13.1",
|
||||||
"block2",
|
"block2",
|
||||||
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
@ -2744,6 +2745,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"objc2",
|
"objc2",
|
||||||
"objc2-app-kit",
|
"objc2-app-kit",
|
||||||
|
"objc2-foundation",
|
||||||
"objc2-web-kit",
|
"objc2-web-kit",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"tauri",
|
"tauri",
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,9 @@ libc = "0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "macos")'.dependencies]
|
[target.'cfg(target_os = "macos")'.dependencies]
|
||||||
objc2 = "0.6"
|
objc2 = "0.6"
|
||||||
objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSEvent"] }
|
objc2-app-kit = { version = "0.3", features = ["NSApplication", "NSEvent", "NSWindow", "NSView"] }
|
||||||
objc2-web-kit = { version = "0.3", features = ["WKWebView"] }
|
objc2-web-kit = { version = "0.3", features = ["WKWebView"] }
|
||||||
|
objc2-foundation = { version = "0.3", features = ["NSString", "NSArray"] }
|
||||||
block2 = "0.6"
|
block2 = "0.6"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,44 @@ fn layout(app: &tauri::AppHandle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evaluates `js` on every WKWebView in the key window's view hierarchy. This
|
||||||
|
/// reaches the Web Inspector (devtools) webview too — which is not a
|
||||||
|
/// Tauri-managed webview — so select-all/undo/redo work in the console.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn eval_js_on_focused_webviews(js: &str) {
|
||||||
|
use objc2::MainThreadMarker;
|
||||||
|
use objc2_app_kit::NSApplication;
|
||||||
|
use objc2_foundation::NSString;
|
||||||
|
|
||||||
|
let Some(mtm) = MainThreadMarker::new() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let app = NSApplication::sharedApplication(mtm);
|
||||||
|
let Some(window) = app.keyWindow() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(content) = window.contentView() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let js = NSString::from_str(js);
|
||||||
|
walk_and_eval(&content, &js);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn walk_and_eval(view: &objc2_app_kit::NSView, js: &objc2_foundation::NSString) {
|
||||||
|
use objc2_web_kit::WKWebView;
|
||||||
|
|
||||||
|
if let Some(webview) = view.downcast_ref::<WKWebView>() {
|
||||||
|
unsafe {
|
||||||
|
webview.evaluateJavaScript_completionHandler(js, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for subview in view.subviews().iter() {
|
||||||
|
walk_and_eval(&subview, js);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Installs a local NSEvent monitor that intercepts Cmd+X/C/V/A/Z and
|
/// Installs a local NSEvent monitor that intercepts Cmd+X/C/V/A/Z and
|
||||||
/// dispatches the matching native editing selector to the first responder.
|
/// dispatches the matching native editing selector to the first responder.
|
||||||
///
|
///
|
||||||
|
|
@ -143,7 +181,7 @@ fn layout(app: &tauri::AppHandle) {
|
||||||
/// this is the only reliable way to make cut/copy/paste work in the devtools
|
/// this is the only reliable way to make cut/copy/paste work in the devtools
|
||||||
/// console.
|
/// console.
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
fn install_edit_shortcut_monitor(handle: &tauri::AppHandle) {
|
fn install_edit_shortcut_monitor() {
|
||||||
use objc2::runtime::{AnyObject, Sel};
|
use objc2::runtime::{AnyObject, Sel};
|
||||||
use objc2::MainThreadMarker;
|
use objc2::MainThreadMarker;
|
||||||
use objc2_app_kit::{NSApplication, NSEvent, NSEventMask, NSEventModifierFlags};
|
use objc2_app_kit::{NSApplication, NSEvent, NSEventMask, NSEventModifierFlags};
|
||||||
|
|
@ -153,7 +191,6 @@ fn install_edit_shortcut_monitor(handle: &tauri::AppHandle) {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let app = NSApplication::sharedApplication(mtm);
|
let app = NSApplication::sharedApplication(mtm);
|
||||||
let handle = handle.clone();
|
|
||||||
|
|
||||||
let block = block2::RcBlock::new(move |event: NonNull<NSEvent>| -> *mut NSEvent {
|
let block = block2::RcBlock::new(move |event: NonNull<NSEvent>| -> *mut NSEvent {
|
||||||
let event = unsafe { event.as_ref() };
|
let event = unsafe { event.as_ref() };
|
||||||
|
|
@ -194,18 +231,22 @@ fn install_edit_shortcut_monitor(handle: &tauri::AppHandle) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// selectAll:/undo:/redo: don't always dispatch through the responder
|
// selectAll:/undo:/redo: don't dispatch through the responder chain in
|
||||||
// chain in WKWebView, so drive the content webview via execCommand too.
|
// WKWebView, so drive the focused webview(s) via execCommand too — but
|
||||||
|
// only when an editable element is actually focused, otherwise we'd
|
||||||
|
// select the whole document.
|
||||||
let js = match key.as_str() {
|
let js = match key.as_str() {
|
||||||
"a" => Some("document.execCommand('selectAll')"),
|
"a" => Some(
|
||||||
"z" if flags.contains(NSEventModifierFlags::Shift) => Some("document.execCommand('redo')"),
|
"(function(){var e=document.activeElement;if(e&&(e.tagName==='INPUT'||e.tagName==='TEXTAREA'||e.isContentEditable))document.execCommand('selectAll')})()",
|
||||||
|
),
|
||||||
|
"z" if flags.contains(NSEventModifierFlags::Shift) => {
|
||||||
|
Some("document.execCommand('redo')")
|
||||||
|
}
|
||||||
"z" => Some("document.execCommand('undo')"),
|
"z" => Some("document.execCommand('undo')"),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(js) = js {
|
if let Some(js) = js {
|
||||||
if let Some(content) = handle.get_webview("content") {
|
eval_js_on_focused_webviews(js);
|
||||||
let _ = content.eval(js);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ptr::null_mut()
|
std::ptr::null_mut()
|
||||||
|
|
@ -280,7 +321,7 @@ pub fn run() {
|
||||||
enable_swipe_navigation(app.handle());
|
enable_swipe_navigation(app.handle());
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
install_edit_shortcut_monitor(app.handle());
|
install_edit_shortcut_monitor();
|
||||||
|
|
||||||
if let Some(toolbar) = app.get_webview("main") {
|
if let Some(toolbar) = app.get_webview("main") {
|
||||||
let _ = toolbar.emit("url-changed", mask.mask(&navidrome_url));
|
let _ = toolbar.emit("url-changed", mask.mask(&navidrome_url));
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue