From 3e41ea904f668eae21f05205a6e07bd1d95a08b5 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Tue, 21 Oct 2025 11:21:25 +0200 Subject: [PATCH 1/5] Revert "Setup ctrl+q keyboard shortcut (#618)" This reverts commit 8706cead2abc2483a7d1dbd84ce27c61b050433b. --- src-tauri/Cargo.lock | 40 ---------------------------- src-tauri/Cargo.toml | 1 - src-tauri/src/bin/defguard-client.rs | 15 ----------- 3 files changed, 56 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3c7eba8d..f9647ce4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1293,7 +1293,6 @@ dependencies = [ "tauri-plugin-deep-link", "tauri-plugin-dialog", "tauri-plugin-fs", - "tauri-plugin-global-shortcut", "tauri-plugin-http", "tauri-plugin-log", "tauri-plugin-notification", @@ -2299,24 +2298,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "global-hotkey" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" -dependencies = [ - "crossbeam-channel", - "keyboard-types", - "objc2 0.6.2", - "objc2-app-kit", - "once_cell", - "serde", - "thiserror 2.0.16", - "windows-sys 0.59.0", - "x11rb", - "xkeysym", -] - [[package]] name = "gloo-timers" version = "0.3.0" @@ -6310,21 +6291,6 @@ dependencies = [ "url", ] -[[package]] -name = "tauri-plugin-global-shortcut" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6df9f0f7bf2fe768b85fee4951c2505a35b72c44df1f6403e74e110bc13c5f58" -dependencies = [ - "global-hotkey", - "log", - "serde", - "serde_json", - "tauri", - "tauri-plugin", - "thiserror 2.0.16", -] - [[package]] name = "tauri-plugin-http" version = "2.5.2" @@ -8465,12 +8431,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "xkeysym" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" - [[package]] name = "yoke" version = "0.8.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 85b570e7..466a0b5d 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -110,7 +110,6 @@ x25519-dalek = { version = "2", features = [ "serde", "static_secrets", ] } -tauri-plugin-global-shortcut = "2.3.0" [target.'cfg(unix)'.dependencies] hyper-util = "0.1" diff --git a/src-tauri/src/bin/defguard-client.rs b/src-tauri/src/bin/defguard-client.rs index 76514a4a..c9a337d3 100644 --- a/src-tauri/src/bin/defguard-client.rs +++ b/src-tauri/src/bin/defguard-client.rs @@ -28,7 +28,6 @@ use log::{Level, LevelFilter}; #[cfg(target_os = "macos")] use tauri::{process, Env}; use tauri::{AppHandle, Builder, Manager, RunEvent, WindowEvent}; -use tauri_plugin_global_shortcut::{Code, GlobalShortcutExt, Modifiers, Shortcut, ShortcutState}; use tauri_plugin_log::{Target, TargetKind}; #[macro_use] @@ -264,20 +263,6 @@ fn main() { .build(), )?; - // Setup ctrl-q keyboard shortcut - let ctrl_q_shortcut = Shortcut::new(Some(Modifiers::CONTROL), Code::KeyQ); - app_handle.plugin( - tauri_plugin_global_shortcut::Builder::new() - .with_handler(move |app, shortcut, event| { - if shortcut == &ctrl_q_shortcut && event.state() == ShortcutState::Pressed { - info!("Ctrl-Q pressed, closing active connections and exiting"); - app.exit(0); - } - }) - .build(), - )?; - app.global_shortcut().register(ctrl_q_shortcut)?; - let state = AppState::new(config); app.manage(state); From d9a443e62feb1fdce7a3553f66a951fd18315559 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 22 Oct 2025 09:56:27 +0200 Subject: [PATCH 2/5] ctrl+q keyboard shortcut using the process plugin --- package.json | 1 + pnpm-lock.yaml | 10 ++++++++++ src-tauri/Cargo.lock | 11 +++++++++++ src-tauri/Cargo.toml | 1 + src-tauri/capabilities/default.json | 1 + src-tauri/src/bin/defguard-client.rs | 1 + src/components/App/App.tsx | 16 +++++++++++++++- 7 files changed, 40 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index f3cd54b6..20420055 100644 --- a/package.json +++ b/package.json @@ -64,6 +64,7 @@ "@tauri-apps/plugin-notification": "^2.3.1", "@tauri-apps/plugin-opener": "^2.5.0", "@tauri-apps/plugin-os": "^2.3.1", + "@tauri-apps/plugin-process": "^2.3.0", "@tauri-apps/plugin-window-state": "^2.4.0", "@types/byte-size": "^8.1.2", "@use-gesture/react": "^10.3.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b2cd5ffb..fad8ab5a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -59,6 +59,9 @@ importers: '@tauri-apps/plugin-os': specifier: ^2.3.1 version: 2.3.1 + '@tauri-apps/plugin-process': + specifier: ^2.3.0 + version: 2.3.0 '@tauri-apps/plugin-window-state': specifier: ^2.4.0 version: 2.4.0 @@ -1207,6 +1210,9 @@ packages: '@tauri-apps/plugin-os@2.3.1': resolution: {integrity: sha512-ty5V8XDUIFbSnrk3zsFoP3kzN+vAufYzalJSlmrVhQTImIZa1aL1a03bOaP2vuBvfR+WDRC6NgV2xBl8G07d+w==} + '@tauri-apps/plugin-process@2.3.0': + resolution: {integrity: sha512-0DNj6u+9csODiV4seSxxRbnLpeGYdojlcctCuLOCgpH9X3+ckVZIEj6H7tRQ7zqWr7kSTEWnrxtAdBb0FbtrmQ==} + '@tauri-apps/plugin-window-state@2.4.0': resolution: {integrity: sha512-hRSzPNi2NG0lPFthfVY0V5C1MyWN/gGaQtQYw7i9zZhLzrhZveHZ2omHG1rIiIsjfTGbO7fhjydSoeTTK9GqLw==} @@ -3845,6 +3851,10 @@ snapshots: dependencies: '@tauri-apps/api': 2.8.0 + '@tauri-apps/plugin-process@2.3.0': + dependencies: + '@tauri-apps/api': 2.8.0 + '@tauri-apps/plugin-window-state@2.4.0': dependencies: '@tauri-apps/api': 2.8.0 diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index f9647ce4..dc335b73 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1298,6 +1298,7 @@ dependencies = [ "tauri-plugin-notification", "tauri-plugin-opener", "tauri-plugin-os", + "tauri-plugin-process", "tauri-plugin-single-instance", "tauri-plugin-window-state", "thiserror 2.0.16", @@ -6396,6 +6397,16 @@ dependencies = [ "thiserror 2.0.16", ] +[[package]] +name = "tauri-plugin-process" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7461c622a5ea00eb9cd9f7a08dbd3bf79484499fd5c21aa2964677f64ca651ab" +dependencies = [ + "tauri", + "tauri-plugin", +] + [[package]] name = "tauri-plugin-single-instance" version = "2.3.4" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 466a0b5d..6fc6485b 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -110,6 +110,7 @@ x25519-dalek = { version = "2", features = [ "serde", "static_secrets", ] } +tauri-plugin-process = "2.3.0" [target.'cfg(unix)'.dependencies] hyper-util = "0.1" diff --git a/src-tauri/capabilities/default.json b/src-tauri/capabilities/default.json index c171d2b6..d8b4de1b 100644 --- a/src-tauri/capabilities/default.json +++ b/src-tauri/capabilities/default.json @@ -48,6 +48,7 @@ "os:allow-hostname", "dialog:default", "clipboard-manager:allow-write-text", + "process:allow-exit", { "identifier": "http:default", "allow": [ diff --git a/src-tauri/src/bin/defguard-client.rs b/src-tauri/src/bin/defguard-client.rs index c9a337d3..0b4411e6 100644 --- a/src-tauri/src/bin/defguard-client.rs +++ b/src-tauri/src/bin/defguard-client.rs @@ -184,6 +184,7 @@ fn main() { .plugin(tauri_plugin_window_state::Builder::new().build()) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_os::init()) + .plugin(tauri_plugin_process::init()) .setup(|app| { // Register for linux and dev windows builds #[cfg(any(target_os = "linux", all(debug_assertions, windows)))] diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 5bc83de6..692167c3 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -4,7 +4,7 @@ import '../../shared/scss/index.scss'; import { QueryClient } from '@tanstack/query-core'; import { QueryClientProvider } from '@tanstack/react-query'; -import { debug } from '@tauri-apps/plugin-log'; +import { debug, info } from '@tauri-apps/plugin-log'; import { openUrl } from '@tauri-apps/plugin-opener'; import dayjs from 'dayjs'; import customParseData from 'dayjs/plugin/customParseFormat'; @@ -38,6 +38,7 @@ import { useTheme } from '../../shared/defguard-ui/hooks/theme/useTheme'; import { ThemeProvider } from '../../shared/providers/ThemeProvider/ThemeProvider'; import { routes } from '../../shared/routes'; import { ApplicationUpdateManager } from '../ApplicationUpdateManager/ApplicationUpdateManager'; +import { exit } from '@tauri-apps/plugin-process'; dayjs.extend(duration); dayjs.extend(utc); @@ -186,6 +187,19 @@ export const App = () => { }; }, []); + useEffect(() => { + const handler = (e: KeyboardEvent) => { + if (e.ctrlKey && e.key.toLowerCase() === 'q') { + info("Ctrl-Q pressed, exiting."); + e.preventDefault(); + exit(0); + } + }; + + window.addEventListener('keydown', handler); + return () => window.removeEventListener('keydown', handler); + }, []); + if (!appLoaded) return null; return ( From 0ecae300854ddb80eea06bcad5006b969d7b1f73 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 22 Oct 2025 10:58:10 +0200 Subject: [PATCH 3/5] update cargo-deny ignores --- src-tauri/deny.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src-tauri/deny.toml b/src-tauri/deny.toml index f0d3f368..e9839624 100644 --- a/src-tauri/deny.toml +++ b/src-tauri/deny.toml @@ -87,6 +87,11 @@ ignore = [ { id = "RUSTSEC-2024-0420", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, { id = "RUSTSEC-2025-0052", reason = "Discontinued, but dark-light v2.0.0 needs it" }, { id = "RUSTSEC-2025-0057", reason = "Tauri needs it" }, + { id = "RUSTSEC-2025-0075", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0080", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0081", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0098", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0100", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, ] # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. From ee43a969048e95981e0b8017f1ec1a94943bcc6b Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 22 Oct 2025 11:10:36 +0200 Subject: [PATCH 4/5] fix deny.toml comments --- src-tauri/deny.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src-tauri/deny.toml b/src-tauri/deny.toml index e9839624..d7769622 100644 --- a/src-tauri/deny.toml +++ b/src-tauri/deny.toml @@ -87,11 +87,11 @@ ignore = [ { id = "RUSTSEC-2024-0420", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, { id = "RUSTSEC-2025-0052", reason = "Discontinued, but dark-light v2.0.0 needs it" }, { id = "RUSTSEC-2025-0057", reason = "Tauri needs it" }, - { id = "RUSTSEC-2025-0075", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, - { id = "RUSTSEC-2025-0080", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, - { id = "RUSTSEC-2025-0081", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, - { id = "RUSTSEC-2025-0098", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, - { id = "RUSTSEC-2025-0100", reason = "Tauri v2 GTK3 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0075", reason = "Tauri v2 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0080", reason = "Tauri v2 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0081", reason = "Tauri v2 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0098", reason = "Tauri v2 dependency (unmaintained)" }, + { id = "RUSTSEC-2025-0100", reason = "Tauri v2 dependency (unmaintained)" }, ] # If this is true, then cargo deny will use the git executable to fetch advisory database. # If this is false, then it uses a built-in git library. From 95f1d6a95e607fc6fd2ecb78735537b3db055834 Mon Sep 17 00:00:00 2001 From: Jacek Chmielewski Date: Wed, 22 Oct 2025 11:15:42 +0200 Subject: [PATCH 5/5] use useHotkeys react hook --- package.json | 1 + pnpm-lock.yaml | 14 ++++++++++++++ src/components/App/App.tsx | 18 ++++++------------ 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 20420055..83aa787e 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "react-click-away-listener": "^2.4.0", "react-dom": "^19.1.1", "react-hook-form": "^7.63.0", + "react-hotkeys-hook": "^5.2.1", "react-loading-skeleton": "^3.5.0", "react-markdown": "^10.1.0", "react-qr-code": "^2.0.18", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fad8ab5a..524c4d09 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -146,6 +146,9 @@ importers: react-hook-form: specifier: ^7.63.0 version: 7.63.0(react@19.1.1) + react-hotkeys-hook: + specifier: ^5.2.1 + version: 5.2.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1) react-loading-skeleton: specifier: ^3.5.0 version: 3.5.0(react@19.1.1) @@ -2464,6 +2467,12 @@ packages: peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 + react-hotkeys-hook@5.2.1: + resolution: {integrity: sha512-xbKh6zJxd/vJHT4Bw4+0pBD662Fk20V+VFhLqciCg+manTVO4qlqRqiwFOYelfHN9dBvWj9vxaPkSS26ZSIJGg==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -5295,6 +5304,11 @@ snapshots: dependencies: react: 19.1.1 + react-hotkeys-hook@5.2.1(react-dom@19.1.1(react@19.1.1))(react@19.1.1): + dependencies: + react: 19.1.1 + react-dom: 19.1.1(react@19.1.1) + react-is@16.13.1: {} react-is@18.3.1: {} diff --git a/src/components/App/App.tsx b/src/components/App/App.tsx index 692167c3..df7132cf 100644 --- a/src/components/App/App.tsx +++ b/src/components/App/App.tsx @@ -39,6 +39,7 @@ import { ThemeProvider } from '../../shared/providers/ThemeProvider/ThemeProvide import { routes } from '../../shared/routes'; import { ApplicationUpdateManager } from '../ApplicationUpdateManager/ApplicationUpdateManager'; import { exit } from '@tauri-apps/plugin-process'; +import { useHotkeys } from 'react-hotkeys-hook'; dayjs.extend(duration); dayjs.extend(utc); @@ -187,18 +188,11 @@ export const App = () => { }; }, []); - useEffect(() => { - const handler = (e: KeyboardEvent) => { - if (e.ctrlKey && e.key.toLowerCase() === 'q') { - info("Ctrl-Q pressed, exiting."); - e.preventDefault(); - exit(0); - } - }; - - window.addEventListener('keydown', handler); - return () => window.removeEventListener('keydown', handler); - }, []); + // register ctrl+q keyboard shortcut + useHotkeys('ctrl+q', () => { + info("Ctrl-Q pressed, exiting."); + exit(0); + }); if (!appLoaded) return null;