mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-21 13:14:04 +02:00
fix: custom hotkey
This commit is contained in:
parent
32a43c6c2d
commit
b545f2e0fb
2 changed files with 103 additions and 66 deletions
|
@ -1,59 +1,78 @@
|
||||||
use crate::api::database::get_keybind;
|
|
||||||
use crate::utils::commands::center_window_on_current_monitor;
|
use crate::utils::commands::center_window_on_current_monitor;
|
||||||
use global_hotkey::{
|
use global_hotkey::{
|
||||||
hotkey::{Code, HotKey, Modifiers},
|
hotkey::{Code, HotKey, Modifiers},
|
||||||
GlobalHotKeyEvent, GlobalHotKeyManager,
|
GlobalHotKeyEvent, GlobalHotKeyManager, HotKeyState,
|
||||||
};
|
};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use tauri::{AppHandle, Listener, Manager};
|
use tauri::{AppHandle, Listener, Manager};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub fn setup(app_handle: tauri::AppHandle) {
|
pub fn setup(app_handle: tauri::AppHandle) {
|
||||||
let app_handle_clone = app_handle.clone();
|
let app_handle_clone = app_handle.clone();
|
||||||
|
|
||||||
tauri::async_runtime::spawn(async move {
|
let manager = Arc::new(GlobalHotKeyManager::new().expect("Failed to initialize hotkey manager"));
|
||||||
match get_keybind(app_handle_clone.clone()).await {
|
let manager_clone = manager.clone();
|
||||||
Ok(keybind) => {
|
let manager_clone2 = manager.clone();
|
||||||
if !keybind.is_empty() {
|
|
||||||
let keybind_str = keybind.join("+");
|
let rt = app_handle.state::<tokio::runtime::Runtime>();
|
||||||
println!("Keybind: {:?}", keybind_str);
|
let initial_keybind = rt.block_on(crate::api::database::get_keybind(app_handle_clone.clone()))
|
||||||
if let Err(e) = register_shortcut(&app_handle_clone, &keybind_str) {
|
.expect("Failed to get initial keybind");
|
||||||
eprintln!("Error registering shortcut: {:?}", e);
|
let initial_shortcut = initial_keybind.join("+");
|
||||||
}
|
|
||||||
}
|
let initial_shortcut_clone = initial_shortcut.clone();
|
||||||
}
|
|
||||||
Err(e) => {
|
if let Err(e) = register_shortcut(&manager, &initial_shortcut) {
|
||||||
eprintln!("Error getting keybind: {:?}", e);
|
eprintln!("Error registering initial shortcut: {:?}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
app_handle.listen("update-shortcut", move |event| {
|
||||||
|
let payload_str = event.payload().to_string();
|
||||||
|
|
||||||
|
if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut_clone) {
|
||||||
|
let _ = manager_clone.unregister(old_hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = register_shortcut(&manager_clone, &payload_str) {
|
||||||
|
eprintln!("Error re-registering shortcut: {:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let app_handle_for_listener = app_handle.clone();
|
app_handle.listen("save_keybind", move |event| {
|
||||||
app_handle.listen("update-shortcut", move |event| {
|
|
||||||
let payload_str = event.payload().to_string();
|
let payload_str = event.payload().to_string();
|
||||||
if let Err(e) = register_shortcut(&app_handle_for_listener, &payload_str) {
|
|
||||||
eprintln!("Error re-registering shortcut: {:?}", e);
|
if let Ok(old_hotkey) = parse_hotkey(&initial_shortcut) {
|
||||||
|
let _ = manager_clone2.unregister(old_hotkey);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = register_shortcut(&manager_clone2, &payload_str) {
|
||||||
|
eprintln!("Error registering saved shortcut: {:?}", e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let app_handle_for_hotkey = app_handle.clone();
|
let app_handle_for_hotkey = app_handle.clone();
|
||||||
tauri::async_runtime::spawn(async move {
|
tauri::async_runtime::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
if let Ok(_) = GlobalHotKeyEvent::receiver().recv() {
|
match GlobalHotKeyEvent::receiver().recv() {
|
||||||
handle_hotkey_event(&app_handle_for_hotkey);
|
Ok(event) => {
|
||||||
|
if event.state == HotKeyState::Released {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
handle_hotkey_event(&app_handle_for_hotkey);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Error receiving hotkey event: {:?}", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_shortcut(
|
fn register_shortcut(
|
||||||
_app_handle: &tauri::AppHandle,
|
manager: &Arc<GlobalHotKeyManager>,
|
||||||
shortcut: &str,
|
shortcut: &str,
|
||||||
) -> Result<(), Box<dyn std::error::Error>> {
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let manager = GlobalHotKeyManager::new()?;
|
|
||||||
let hotkey = parse_hotkey(shortcut)?;
|
let hotkey = parse_hotkey(shortcut)?;
|
||||||
manager.register(hotkey)?;
|
manager.register(hotkey)?;
|
||||||
|
|
||||||
println!("Listening for keybind: {}", shortcut);
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,35 +80,32 @@ fn parse_hotkey(shortcut: &str) -> Result<HotKey, Box<dyn std::error::Error>> {
|
||||||
let mut modifiers = Modifiers::empty();
|
let mut modifiers = Modifiers::empty();
|
||||||
let mut code = None;
|
let mut code = None;
|
||||||
|
|
||||||
for part in shortcut.split('+') {
|
let shortcut = shortcut.replace("\"", "");
|
||||||
let part = part;
|
|
||||||
if part.to_lowercase().starts_with("ctrl") || part.to_lowercase().starts_with("control") {
|
|
||||||
modifiers |= Modifiers::CONTROL;
|
|
||||||
} else if part.to_lowercase().starts_with("alt") {
|
|
||||||
modifiers |= Modifiers::ALT;
|
|
||||||
} else if part.to_lowercase().starts_with("shift") {
|
|
||||||
modifiers |= Modifiers::SHIFT;
|
|
||||||
} else if part.to_lowercase().starts_with("super") || part.to_lowercase().starts_with("meta") || part.to_lowercase().starts_with("cmd") {
|
|
||||||
|
|
||||||
modifiers |= Modifiers::META;
|
for part in shortcut.split('+') {
|
||||||
} else {
|
let part = part.trim().to_lowercase();
|
||||||
let pascal_case_key = part
|
match part.as_str() {
|
||||||
.split(|c: char| !c.is_alphanumeric())
|
"ctrl" | "control" | "controlleft" => modifiers |= Modifiers::CONTROL,
|
||||||
.map(|word| {
|
"alt" | "altleft" | "optionleft" => modifiers |= Modifiers::ALT,
|
||||||
let mut chars = word.chars();
|
"shift" | "shiftleft" => modifiers |= Modifiers::SHIFT,
|
||||||
let first_char = chars.next().unwrap().to_uppercase().collect::<String>();
|
"super" | "meta" | "cmd" | "metaleft" => modifiers |= Modifiers::META,
|
||||||
let rest = chars.as_str();
|
key => {
|
||||||
first_char + rest
|
let key_code = if key.starts_with("key") {
|
||||||
})
|
"Key".to_string() + &key[3..].to_uppercase()
|
||||||
.collect::<String>();
|
} else if key.len() == 1 && key.chars().next().unwrap().is_alphabetic() {
|
||||||
code = Some(
|
"Key".to_string() + &key.to_uppercase()
|
||||||
Code::from_str(&pascal_case_key)
|
} else {
|
||||||
.map_err(|_| format!("Invalid key: {}", pascal_case_key))?,
|
key.to_string()
|
||||||
);
|
};
|
||||||
|
|
||||||
|
code = Some(Code::from_str(&key_code)
|
||||||
|
.map_err(|_| format!("Invalid key code: {}", key_code))?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(HotKey::new(Some(modifiers), code.unwrap()))
|
let key_code = code.ok_or_else(|| format!("No valid key code found in shortcut: {}", shortcut))?;
|
||||||
|
Ok(HotKey::new(Some(modifiers), key_code))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_hotkey_event(app_handle: &AppHandle) {
|
fn handle_hotkey_event(app_handle: &AppHandle) {
|
||||||
|
@ -97,8 +113,16 @@ fn handle_hotkey_event(app_handle: &AppHandle) {
|
||||||
if window.is_visible().unwrap() {
|
if window.is_visible().unwrap() {
|
||||||
window.hide().unwrap();
|
window.hide().unwrap();
|
||||||
} else {
|
} else {
|
||||||
|
window.set_always_on_top(true).unwrap();
|
||||||
window.show().unwrap();
|
window.show().unwrap();
|
||||||
window.set_focus().unwrap();
|
window.set_focus().unwrap();
|
||||||
|
|
||||||
|
let window_clone = window.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||||
|
window_clone.set_always_on_top(false).unwrap();
|
||||||
|
});
|
||||||
|
|
||||||
center_window_on_current_monitor(&window);
|
center_window_on_current_monitor(&window);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,12 @@ mod api;
|
||||||
mod utils;
|
mod utils;
|
||||||
|
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
|
use tauri::WebviewUrl;
|
||||||
|
use tauri::WebviewWindow;
|
||||||
use tauri_plugin_autostart::MacosLauncher;
|
use tauri_plugin_autostart::MacosLauncher;
|
||||||
use tauri_plugin_prevent_default::Flags;
|
use tauri_plugin_prevent_default::Flags;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[allow(unused_variables)]
|
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_clipboard::init())
|
.plugin(tauri_plugin_clipboard::init())
|
||||||
.plugin(tauri_plugin_os::init())
|
.plugin(tauri_plugin_os::init())
|
||||||
|
@ -31,23 +32,35 @@ fn main() {
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let app_handle = app.handle().clone();
|
let app_handle = app.handle().clone();
|
||||||
|
|
||||||
|
let main_window = if let Some(window) = app.get_webview_window("main") {
|
||||||
|
window
|
||||||
|
} else {
|
||||||
|
WebviewWindow::builder(
|
||||||
|
app.handle(),
|
||||||
|
"main",
|
||||||
|
WebviewUrl::App("index.html".into())
|
||||||
|
)
|
||||||
|
.title("Qopy")
|
||||||
|
.resizable(false)
|
||||||
|
.fullscreen(false)
|
||||||
|
.inner_size(750.0, 474.0)
|
||||||
|
.focused(true)
|
||||||
|
.skip_taskbar(true)
|
||||||
|
.visible(false)
|
||||||
|
.decorations(false)
|
||||||
|
.transparent(true)
|
||||||
|
.always_on_top(false)
|
||||||
|
.build()?
|
||||||
|
};
|
||||||
|
|
||||||
let _ = api::database::setup(app);
|
let _ = api::database::setup(app);
|
||||||
api::hotkeys::setup(app_handle.clone());
|
api::hotkeys::setup(app_handle.clone());
|
||||||
api::tray::setup(app)?;
|
api::tray::setup(app)?;
|
||||||
api::clipboard::setup(app.handle());
|
api::clipboard::setup(app.handle());
|
||||||
let _ = api::clipboard::start_monitor(app_handle.clone());
|
let _ = api::clipboard::start_monitor(app_handle.clone());
|
||||||
|
|
||||||
if let Some(window) = app.get_webview_window("main") {
|
utils::commands::center_window_on_current_monitor(&main_window);
|
||||||
utils::commands::center_window_on_current_monitor(&window);
|
main_window.hide()?;
|
||||||
window.hide().unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
// #[cfg(dev)]
|
|
||||||
// {
|
|
||||||
// let window = app.get_webview_window("main").unwrap();
|
|
||||||
// window.open_devtools();
|
|
||||||
// window.close_devtools();
|
|
||||||
// }
|
|
||||||
|
|
||||||
let app_data_dir = app
|
let app_data_dir = app
|
||||||
.path()
|
.path()
|
||||||
|
@ -61,10 +74,10 @@ fn main() {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.on_window_event(|app, event| {
|
.on_window_event(|_app, _event| {
|
||||||
#[cfg(not(dev))]
|
#[cfg(not(dev))]
|
||||||
if let tauri::WindowEvent::Focused(false) = event {
|
if let tauri::WindowEvent::Focused(false) = _event {
|
||||||
if let Some(window) = app.get_webview_window("main") {
|
if let Some(window) = _app.get_webview_window("main") {
|
||||||
let _ = window.hide();
|
let _ = window.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue