mirror of
https://github.com/0PandaDEV/Qopy.git
synced 2025-04-21 13:14:04 +02:00
added ability to save hotkey into settings
This commit is contained in:
parent
1370408129
commit
79dd783bf7
4 changed files with 171 additions and 48 deletions
|
@ -2,13 +2,7 @@
|
||||||
<div class="bg">
|
<div class="bg">
|
||||||
<div class="keybind-container">
|
<div class="keybind-container">
|
||||||
<h2>Set New Keybind</h2>
|
<h2>Set New Keybind</h2>
|
||||||
<div
|
<div class="keybind-input" tabindex="0" @keydown="onKeyDown" @keyup="onKeyUp" @focus="onFocus" ref="keybindInput">
|
||||||
class="keybind-input"
|
|
||||||
tabindex="0"
|
|
||||||
@focus="startCapture"
|
|
||||||
@blur="stopCapture"
|
|
||||||
ref="keybindInput"
|
|
||||||
>
|
|
||||||
{{ currentKeybind || 'Click here, then press your desired key combination' }}
|
{{ currentKeybind || 'Click here, then press your desired key combination' }}
|
||||||
</div>
|
</div>
|
||||||
<button @click="saveKeybind" :disabled="!currentKeybind">Save Keybind</button>
|
<button @click="saveKeybind" :disabled="!currentKeybind">Save Keybind</button>
|
||||||
|
@ -17,35 +11,93 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, onUnmounted } from 'vue';
|
import { ref } from 'vue';
|
||||||
import { invoke } from '@tauri-apps/api/core';
|
import { invoke } from '@tauri-apps/api/core';
|
||||||
import { listen } from '@tauri-apps/api/event';
|
|
||||||
|
|
||||||
const currentKeybind = ref('');
|
const currentKeybind = ref('');
|
||||||
const keybindInput = ref<HTMLElement | null>(null);
|
const keybindInput = ref<HTMLElement | null>(null);
|
||||||
|
const keys = ref<Set<string>>(new Set());
|
||||||
|
const recording = ref(false);
|
||||||
|
|
||||||
const startCapture = async () => {
|
const keyToDisplayMap: Record<string, string> = {
|
||||||
await invoke('start_keybind_capture');
|
" ": "Space",
|
||||||
|
Alt: "Alt",
|
||||||
|
ArrowDown: "↓",
|
||||||
|
ArrowLeft: "←",
|
||||||
|
ArrowRight: "→",
|
||||||
|
ArrowUp: "↑",
|
||||||
|
Control: "Ctrl",
|
||||||
|
Enter: "↵",
|
||||||
|
Escape: "Esc",
|
||||||
|
Meta: "Meta",
|
||||||
|
Shift: "⇧",
|
||||||
};
|
};
|
||||||
|
|
||||||
const stopCapture = async () => {
|
const modifierKeySet = new Set(["Alt", "Control", "Meta", "Shift"]);
|
||||||
await invoke('stop_keybind_capture');
|
|
||||||
|
function keyCodeToKey(keyCode: string): string {
|
||||||
|
if (keyCode.startsWith("Key")) return keyCode.slice(3);
|
||||||
|
if (keyCode.endsWith("Left")) return keyCode.slice(0, -4);
|
||||||
|
if (keyCode.startsWith("Digit")) return keyCode.slice(5);
|
||||||
|
if (keyCode.endsWith("Right")) return keyCode.slice(0, -5);
|
||||||
|
return keyCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyToDisplay(keyCode: string): string {
|
||||||
|
const key = keyCodeToKey(keyCode);
|
||||||
|
return keyToDisplayMap[key] || key;
|
||||||
|
}
|
||||||
|
|
||||||
|
function keyCombToDisplay(keyComb: Set<string>): string {
|
||||||
|
return Array.from(keyComb).map(keyToDisplay).join("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
function mapKeyToTauriKey(key: string): string {
|
||||||
|
return key === "Meta" ? "Command" : key;
|
||||||
|
}
|
||||||
|
|
||||||
|
const onKeyDown = (event: KeyboardEvent) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const key = keyCodeToKey(event.code);
|
||||||
|
|
||||||
|
if (modifierKeySet.has(key) && !keys.value.has(key)) {
|
||||||
|
keys.value = new Set(Array.from(keys.value).filter(k => modifierKeySet.has(k)));
|
||||||
|
}
|
||||||
|
|
||||||
|
keys.value.add(key);
|
||||||
|
updateCurrentKeybind();
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveKeybind = () => {
|
const onKeyUp = (event: KeyboardEvent) => {
|
||||||
console.log('Saving keybind:', currentKeybind.value);
|
event.preventDefault();
|
||||||
// Implement saving logic here
|
const key = keyCodeToKey(event.code);
|
||||||
|
if (!modifierKeySet.has(key)) {
|
||||||
|
recording.value = false;
|
||||||
|
updateCurrentKeybind();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(async () => {
|
const onFocus = () => {
|
||||||
const unlisten = await listen('keybind_captured', (event: any) => {
|
resetKeybind();
|
||||||
currentKeybind.value = event.payload as string;
|
};
|
||||||
});
|
|
||||||
|
|
||||||
onUnmounted(() => {
|
const updateCurrentKeybind = () => {
|
||||||
unlisten();
|
currentKeybind.value = keyCombToDisplay(keys.value);
|
||||||
});
|
};
|
||||||
});
|
|
||||||
|
const resetKeybind = () => {
|
||||||
|
keys.value.clear();
|
||||||
|
currentKeybind.value = '';
|
||||||
|
recording.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveKeybind = async () => {
|
||||||
|
console.log(await invoke("get_keybind"));
|
||||||
|
};
|
||||||
|
|
||||||
|
const startCapture = () => {
|
||||||
|
resetKeybind();
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
use sqlx::sqlite::SqlitePoolOptions;
|
|
||||||
use std::fs;
|
|
||||||
use tokio::runtime::Runtime;
|
|
||||||
use tauri::Manager;
|
|
||||||
use rand::{thread_rng, Rng};
|
|
||||||
use rand::distributions::Alphanumeric;
|
use rand::distributions::Alphanumeric;
|
||||||
|
use rand::{thread_rng, Rng};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::sqlite::{SqlitePool, SqlitePoolOptions};
|
||||||
|
use std::fs;
|
||||||
|
use tauri::Manager;
|
||||||
|
use tauri::State;
|
||||||
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
|
#[derive(Deserialize, Serialize)]
|
||||||
|
struct KeybindSetting {
|
||||||
|
keybind: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
let rt = Runtime::new().expect("Failed to create Tokio runtime");
|
||||||
|
@ -27,6 +34,46 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
});
|
});
|
||||||
|
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
|
// Setup settings table
|
||||||
|
sqlx::query(
|
||||||
|
"CREATE TABLE IF NOT EXISTS settings (
|
||||||
|
key TEXT PRIMARY KEY,
|
||||||
|
value TEXT NOT NULL
|
||||||
|
)"
|
||||||
|
)
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to create settings table");
|
||||||
|
|
||||||
|
let existing_keybind = sqlx::query_scalar::<_, Option<String>>(
|
||||||
|
"SELECT value FROM settings WHERE key = 'keybind'"
|
||||||
|
)
|
||||||
|
.fetch_one(&pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
match existing_keybind {
|
||||||
|
Ok(Some(_)) => {
|
||||||
|
},
|
||||||
|
Ok(None) => {
|
||||||
|
let default_keybind = KeybindSetting {
|
||||||
|
keybind: vec!["Meta".to_string(), "V".to_string()],
|
||||||
|
};
|
||||||
|
let json = serde_json::to_string(&default_keybind).unwrap();
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT INTO settings (key, value) VALUES ('keybind', ?)"
|
||||||
|
)
|
||||||
|
.bind(json)
|
||||||
|
.execute(&pool)
|
||||||
|
.await
|
||||||
|
.expect("Failed to insert default keybind");
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Failed to check existing keybind: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup history table
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
"CREATE TABLE IF NOT EXISTS history (
|
"CREATE TABLE IF NOT EXISTS history (
|
||||||
id TEXT PRIMARY KEY,
|
id TEXT PRIMARY KEY,
|
||||||
|
@ -38,7 +85,7 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
)
|
)
|
||||||
.execute(&pool)
|
.execute(&pool)
|
||||||
.await
|
.await
|
||||||
.expect("Failed to create table");
|
.expect("Failed to create history table");
|
||||||
|
|
||||||
sqlx::query(
|
sqlx::query(
|
||||||
"CREATE INDEX IF NOT EXISTS idx_timestamp ON history (timestamp)"
|
"CREATE INDEX IF NOT EXISTS idx_timestamp ON history (timestamp)"
|
||||||
|
@ -68,3 +115,40 @@ pub fn setup(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn save_keybind(
|
||||||
|
keybind: Vec<String>,
|
||||||
|
pool: State<'_, SqlitePool>,
|
||||||
|
) -> Result<(), String> {
|
||||||
|
let setting = KeybindSetting { keybind };
|
||||||
|
let json = serde_json::to_string(&setting).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
sqlx::query(
|
||||||
|
"INSERT OR REPLACE INTO settings (key, value) VALUES ('keybind', ?)"
|
||||||
|
)
|
||||||
|
.bind(json)
|
||||||
|
.execute(&*pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tauri::command]
|
||||||
|
pub async fn get_keybind(pool: State<'_, SqlitePool>) -> Result<Vec<String>, String> {
|
||||||
|
let result = sqlx::query_scalar::<_, String>(
|
||||||
|
"SELECT value FROM settings WHERE key = 'keybind'"
|
||||||
|
)
|
||||||
|
.fetch_optional(&*pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Some(json) => {
|
||||||
|
let setting: KeybindSetting = serde_json::from_str(&json).map_err(|e| e.to_string())?;
|
||||||
|
Ok(setting.keybind)
|
||||||
|
},
|
||||||
|
None => Ok(vec!["Meta".to_string(), "V".to_string()]),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -121,16 +121,3 @@ pub fn start_keybind_capture() {
|
||||||
pub fn stop_keybind_capture() {
|
pub fn stop_keybind_capture() {
|
||||||
IS_CAPTURING_KEYBIND.store(false, Ordering::SeqCst);
|
IS_CAPTURING_KEYBIND.store(false, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn get_current_keybind() -> String {
|
|
||||||
// Implement logic to retrieve the current keybind from your configuration
|
|
||||||
"Meta+V".to_string() // Placeholder
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tauri::command]
|
|
||||||
pub fn save_keybind(keybind: String) -> Result<(), String> {
|
|
||||||
// Implement logic to save the new keybind to your configuration
|
|
||||||
println!("Saving keybind: {}", keybind);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
|
@ -31,10 +31,10 @@ fn main() {
|
||||||
.setup(|app| {
|
.setup(|app| {
|
||||||
let app_handle = app.handle().clone();
|
let app_handle = app.handle().clone();
|
||||||
|
|
||||||
// #[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
api::hotkeys::setup(app_handle.clone());
|
api::hotkeys::setup(app_handle.clone());
|
||||||
api::tray::setup(app)?;
|
api::tray::setup(app)?;
|
||||||
api::database::setup(app)?;
|
let _ = api::database::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());
|
||||||
|
|
||||||
|
@ -76,8 +76,8 @@ fn main() {
|
||||||
api::clipboard::read_image,
|
api::clipboard::read_image,
|
||||||
api::hotkeys::start_keybind_capture,
|
api::hotkeys::start_keybind_capture,
|
||||||
api::hotkeys::stop_keybind_capture,
|
api::hotkeys::stop_keybind_capture,
|
||||||
api::hotkeys::get_current_keybind,
|
api::database::save_keybind,
|
||||||
api::hotkeys::save_keybind,
|
api::database::get_keybind
|
||||||
])
|
])
|
||||||
.run(tauri::generate_context!())
|
.run(tauri::generate_context!())
|
||||||
.expect("error while running tauri application");
|
.expect("error while running tauri application");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue