add hotkeys to show window and launch terminal

This commit is contained in:
Joseph Montanaro 2023-09-09 07:29:57 -07:00
parent c98a065587
commit 5685948608
5 changed files with 69 additions and 1 deletions

View File

@ -25,7 +25,7 @@ tauri-build = { version = "1.0.4", features = [] }
[dependencies] [dependencies]
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.2", features = ["dialog", "dialog-open", "os-all", "system-tray"] } tauri = { version = "1.2", features = ["dialog", "dialog-open", "os-all", "system-tray", "global-shortcut"] }
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" } tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" }
sodiumoxide = "0.2.7" sodiumoxide = "0.2.7"
tokio = { version = ">=1.19", features = ["full"] } tokio = { version = ">=1.19", features = ["full"] }

View File

@ -10,6 +10,7 @@ use tauri::{
App, App,
AppHandle, AppHandle,
Manager, Manager,
GlobalShortcutManager,
async_runtime as rt, async_runtime as rt,
}; };
@ -83,6 +84,7 @@ async fn setup(app: &mut App) -> Result<(), Box<dyn Error>> {
let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?; let srv = Server::new(conf.listen_addr, conf.listen_port, app.handle()).await?;
config::set_auto_launch(conf.start_on_login)?; config::set_auto_launch(conf.start_on_login)?;
config::register_hotkeys(&conf.hotkeys)?;
// if session is empty, this is probably the first launch, so don't autohide // if session is empty, this is probably the first launch, so don't autohide
if !conf.start_minimized || is_first_launch { if !conf.start_minimized || is_first_launch {
app.get_window("main") app.get_window("main")

View File

@ -5,6 +5,12 @@ use auto_launch::AutoLaunchBuilder;
use is_terminal::IsTerminal; use is_terminal::IsTerminal;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use sqlx::SqlitePool; use sqlx::SqlitePool;
use tauri::{
AppHandle,
Manager,
GlobalShortcutManager,
async_runtime as rt,
};
use crate::errors::*; use crate::errors::*;
@ -20,6 +26,14 @@ pub struct TermConfig {
} }
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
pub struct HotkeyConfig {
// tauri uses strings to represent keybinds, so we will as well
pub show_window: String,
pub launch_terminal: String,
}
#[derive(Clone, Debug, Serialize, Deserialize)] #[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AppConfig { pub struct AppConfig {
#[serde(default = "default_listen_addr")] #[serde(default = "default_listen_addr")]
@ -34,6 +48,8 @@ pub struct AppConfig {
pub start_on_login: bool, pub start_on_login: bool,
#[serde(default = "default_term_config")] #[serde(default = "default_term_config")]
pub terminal: TermConfig, pub terminal: TermConfig,
#[serde(default = "default_hotkey_config")]
pub hotkeys: HotkeyConfig,
} }
@ -46,6 +62,7 @@ impl Default for AppConfig {
start_minimized: default_start_minimized(), start_minimized: default_start_minimized(),
start_on_login: default_start_on_login(), start_on_login: default_start_on_login(),
terminal: default_term_config(), terminal: default_term_config(),
hotkeys: default_hotkey_config(),
} }
} }
} }
@ -170,6 +187,47 @@ fn default_term_config() -> TermConfig {
} }
fn default_hotkey_config() -> HotkeyConfig {
HotkeyConfig {
show_window: "alt+shift+C".into(),
launch_terminal: "alt+shift+T".into(),
}
}
// note: will panic if called before APP is set
pub fn register_hotkeys(hotkeys: &HotkeyConfig) -> tauri::Result<()> {
let app = crate::app::APP.get().unwrap();
let mut manager = app.global_shortcut_manager();
manager.unregister_all()?;
let h = app.app_handle();
manager.register(
&hotkeys.show_window,
move || {
h.get_window("main")
.map(|w| w.show().error_popup("Failed to show"))
.ok_or(HandlerError::NoMainWindow)
.error_popup("No main window");
},
)?;
// register() doesn't take an async fn, so we have to use spawn
manager.register(
&hotkeys.launch_terminal,
|| {
rt::spawn(async {
crate::terminal::launch(false)
.await
.error_popup("Failed to launch");
});
}
)?;
Ok(())
}
fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST } fn default_listen_addr() -> Ipv4Addr { Ipv4Addr::LOCALHOST }
fn default_rehide_ms() -> u64 { 1000 } fn default_rehide_ms() -> u64 { 1000 }
// start minimized and on login only in production mode // start minimized and on login only in production mode

View File

@ -95,6 +95,8 @@ pub enum SetupError {
ServerSetupError(#[from] std::io::Error), ServerSetupError(#[from] std::io::Error),
#[error("Failed to resolve data directory: {0}")] #[error("Failed to resolve data directory: {0}")]
DataDir(#[from] DataDirError), DataDir(#[from] DataDirError),
#[error("Failed to register hotkeys: {0}")]
RegisterHotkeys(#[from] tauri::Error),
} }

View File

@ -59,15 +59,21 @@ impl AppState {
pub async fn update_config(&self, new_config: AppConfig) -> Result<(), SetupError> { pub async fn update_config(&self, new_config: AppConfig) -> Result<(), SetupError> {
let mut live_config = self.config.write().await; let mut live_config = self.config.write().await;
// update autostart if necessary
if new_config.start_on_login != live_config.start_on_login { if new_config.start_on_login != live_config.start_on_login {
config::set_auto_launch(new_config.start_on_login)?; config::set_auto_launch(new_config.start_on_login)?;
} }
// rebind socket if necessary
if new_config.listen_addr != live_config.listen_addr if new_config.listen_addr != live_config.listen_addr
|| new_config.listen_port != live_config.listen_port || new_config.listen_port != live_config.listen_port
{ {
let mut sv = self.server.write().await; let mut sv = self.server.write().await;
sv.rebind(new_config.listen_addr, new_config.listen_port).await?; sv.rebind(new_config.listen_addr, new_config.listen_port).await?;
} }
// re-register hotkeys if necessary
if new_config.hotkeys != live_config.hotkeys {
config::register_hotkeys(&new_config.hotkeys)?;
}
new_config.save(&self.pool).await?; new_config.save(&self.pool).await?;
*live_config = new_config; *live_config = new_config;