feat(rust): register plugins, global shortcut, commands
This commit is contained in:
@@ -34,12 +34,14 @@ pub async fn apply_state<R: Runtime>(
|
|||||||
.set_ignore_cursor_events(new_state)
|
.set_ignore_cursor_events(new_state)
|
||||||
.map_err(|e| e.to_string())?;
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Opacity dip half of the visual pulse. The JS click-through-toggled
|
// Opacity dip — visual pulse to signal the state change.
|
||||||
|
// Tauri 2.11 does not expose set_opacity on WebviewWindow, so we apply
|
||||||
|
// the dip by evaluating JS on the webview. The JS click-through-toggled
|
||||||
// handler is responsible for restoring opacity to the user's actual
|
// handler is responsible for restoring opacity to the user's actual
|
||||||
// target — Rust deliberately does NOT call set_opacity again, so there
|
// target — Rust deliberately does NOT set opacity back, so there is no
|
||||||
// is no possibility of the global-shortcut path "snapping back" to a
|
// possibility of the global-shortcut path "snapping back" to a wrong
|
||||||
// wrong value (we don't have a current-opacity getter).
|
// value (we don't have a current-opacity getter).
|
||||||
let _ = overlay.set_opacity(0.4);
|
let _ = overlay.eval("document.documentElement.style.opacity='0.4'");
|
||||||
tokio::time::sleep(Duration::from_millis(180)).await;
|
tokio::time::sleep(Duration::from_millis(180)).await;
|
||||||
|
|
||||||
app.emit(
|
app.emit(
|
||||||
@@ -102,8 +104,9 @@ pub fn get_hotkey_status(app: AppHandle) -> Result<crate::HotkeyStatus, String>
|
|||||||
Ok(guard.clone())
|
Ok(guard.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set window opacity. Tauri 2's JS WebviewWindow does NOT expose setOpacity
|
/// Set window opacity. Tauri 2's JS WebviewWindow does NOT expose setOpacity,
|
||||||
/// (only the Rust side does), so the JS layer routes through this command.
|
/// so the JS layer routes through this command. Tauri 2.11 also doesn't expose
|
||||||
|
/// set_opacity on the Rust WebviewWindow, so we apply the change via JS eval.
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn set_window_opacity<R: Runtime>(
|
pub fn set_window_opacity<R: Runtime>(
|
||||||
app: AppHandle<R>,
|
app: AppHandle<R>,
|
||||||
@@ -113,5 +116,9 @@ pub fn set_window_opacity<R: Runtime>(
|
|||||||
let Some(window) = app.get_webview_window(&label) else {
|
let Some(window) = app.get_webview_window(&label) else {
|
||||||
return Err(format!("window not found: {label}"));
|
return Err(format!("window not found: {label}"));
|
||||||
};
|
};
|
||||||
window.set_opacity(opacity).map_err(|e| e.to_string())
|
window
|
||||||
|
.eval(&format!(
|
||||||
|
"document.documentElement.style.opacity='{opacity}'"
|
||||||
|
))
|
||||||
|
.map_err(|e| e.to_string())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,95 @@
|
|||||||
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
|
mod commands;
|
||||||
#[tauri::command]
|
|
||||||
fn greet(name: &str) -> String {
|
use std::sync::Mutex;
|
||||||
format!("Hello, {}! You've been greeted from Rust!", name)
|
|
||||||
|
use serde::Serialize;
|
||||||
|
use tauri::Manager;
|
||||||
|
|
||||||
|
#[cfg(desktop)]
|
||||||
|
use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut, ShortcutState};
|
||||||
|
|
||||||
|
pub struct AppState {
|
||||||
|
pub click_through: Mutex<bool>,
|
||||||
|
/// Hotkey registration outcome, set during setup. JS pulls this via
|
||||||
|
/// `get_hotkey_status` after the listener-not-yet-registered window is
|
||||||
|
/// safely past, so the result is never lost to a race.
|
||||||
|
pub hotkey_status: Mutex<HotkeyStatus>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Default)]
|
||||||
|
#[serde(tag = "kind", rename_all = "lowercase")]
|
||||||
|
pub enum HotkeyStatus {
|
||||||
|
#[default]
|
||||||
|
Pending,
|
||||||
|
Ok,
|
||||||
|
Failed { error: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
#[cfg_attr(mobile, tauri::mobile_entry_point)]
|
||||||
pub fn run() {
|
pub fn run() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
|
.manage(AppState {
|
||||||
|
click_through: Mutex::new(false),
|
||||||
|
hotkey_status: Mutex::new(HotkeyStatus::Pending),
|
||||||
|
})
|
||||||
.plugin(tauri_plugin_opener::init())
|
.plugin(tauri_plugin_opener::init())
|
||||||
.invoke_handler(tauri::generate_handler![greet])
|
.plugin(tauri_plugin_store::Builder::new().build())
|
||||||
|
.setup(|app| {
|
||||||
|
#[cfg(desktop)]
|
||||||
|
{
|
||||||
|
app.handle()
|
||||||
|
.plugin(tauri_plugin_window_state::Builder::default().build())?;
|
||||||
|
|
||||||
|
let shortcut = Shortcut::new(
|
||||||
|
Some(Modifiers::CONTROL | Modifiers::ALT),
|
||||||
|
Code::Space,
|
||||||
|
);
|
||||||
|
let shortcut_for_handler = shortcut;
|
||||||
|
|
||||||
|
app.handle().plugin(
|
||||||
|
tauri_plugin_global_shortcut::Builder::new()
|
||||||
|
.with_handler(move |app, sc, event| {
|
||||||
|
if sc != &shortcut_for_handler {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if event.state() != ShortcutState::Pressed {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let app_handle = app.clone();
|
||||||
|
tauri::async_runtime::spawn(async move {
|
||||||
|
if let Err(err) =
|
||||||
|
commands::overlay::toggle_via_global_shortcut(&app_handle).await
|
||||||
|
{
|
||||||
|
eprintln!("global shortcut toggle failed: {err}");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let registration_result = app.global_shortcut().register(shortcut);
|
||||||
|
let status = match ®istration_result {
|
||||||
|
Ok(()) => HotkeyStatus::Ok,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to register Ctrl+Alt+Space: {e}");
|
||||||
|
HotkeyStatus::Failed {
|
||||||
|
error: "Hotkey unavailable — click-through escape disabled".to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
{
|
||||||
|
let state = app.state::<AppState>();
|
||||||
|
*state.hotkey_status.lock().expect("poisoned") = status;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
.invoke_handler(tauri::generate_handler![
|
||||||
|
commands::overlay::toggle_click_through,
|
||||||
|
commands::overlay::sync_click_through_cache,
|
||||||
|
commands::overlay::get_hotkey_status,
|
||||||
|
commands::overlay::set_window_opacity,
|
||||||
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user