Files
Genarrative/apps/ai-game-creator-shell/src-tauri/src/context_menu.rs
T
kdletters 16a5d28ed3 修复 release 默认网页右键菜单
release 客户端关闭 WebView 默认上下文菜单

保留 contextmenu 事件供业务组件处理

补充 release/debug 行为测试与技术方案约定
2026-08-26 21:19:39 +08:00

85 lines
2.7 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use tauri::{
plugin::{Builder, TauriPlugin},
Runtime,
};
/// Release 客户端只取消浏览器的默认上下文菜单。
///
/// 这里刻意只调用 `preventDefault``contextmenu` 事件仍会继续沿 DOM
/// 传播,业务组件可以照常接收并打开自己的菜单。捕获阶段用于覆盖没有
/// 自己右键处理的页面空白区域,但不会调用 `stopPropagation`。
const RELEASE_CONTEXT_MENU_INIT_SCRIPT: &str = r#"
document.addEventListener(
'contextmenu',
(event) => {
event.preventDefault();
},
true,
);
"#;
fn context_menu_init_script(is_release: bool) -> Option<&'static str> {
is_release.then_some(RELEASE_CONTEXT_MENU_INIT_SCRIPT)
}
#[cfg(all(windows, not(debug_assertions)))]
fn disable_windows_default_context_menus<R: Runtime>(webview: tauri::Webview<R>) {
let _ = webview.with_webview(|platform_webview| {
// WebView2 的原生设置只关闭浏览器菜单,不会取消 DOM 的
// `contextmenu` 事件,因此业务右键菜单仍然可以正常工作。
// SAFETY: Tauri 在 WebView2 UI 线程上提供当前存活的 controller
// 这些 COM 接口调用只使用该闭包期间有效的句柄。
let _ = unsafe {
platform_webview
.controller()
.CoreWebView2()
.and_then(|webview| webview.Settings())
.and_then(|settings| settings.SetAreDefaultContextMenusEnabled(false))
};
});
}
/// 注册 release-only 的默认网页上下文菜单策略。
pub(crate) fn init<R: Runtime>() -> TauriPlugin<R> {
let mut builder = Builder::new("release-context-menu");
if let Some(script) = context_menu_init_script(!cfg!(debug_assertions)) {
builder = builder.js_init_script_on_all_frames(script);
}
#[cfg(all(windows, not(debug_assertions)))]
{
builder = builder.on_webview_ready(disable_windows_default_context_menus);
}
builder.build()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn release_build_gets_a_context_menu_init_script() {
assert_eq!(
context_menu_init_script(true),
Some(RELEASE_CONTEXT_MENU_INIT_SCRIPT)
);
}
#[test]
fn debug_build_keeps_the_default_context_menu_strategy_untouched() {
assert_eq!(context_menu_init_script(false), None);
}
#[test]
fn init_script_prevents_only_the_default_action() {
let script = RELEASE_CONTEXT_MENU_INIT_SCRIPT;
assert!(script.contains("contextmenu"));
assert!(script.contains("event.preventDefault()"));
assert!(script.contains("true"));
assert!(!script.contains("stopPropagation"));
assert!(!script.contains("stopImmediatePropagation"));
}
}