diff --git a/package.json b/package.json index df3c694..3e6d950 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pasteme", "private": true, - "version": "0.1.1", + "version": "0.2.0", "type": "module", "scripts": { "dev": "vite", diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e8d606e..0fb57dc 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -1003,6 +1003,25 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3d8a32ae18130a3c84dd492d4215c3d913c3b07c6b63c2eb3eb7ff1101ab7bf" +[[package]] +name = "enigo" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cf6f550bbbdd5fe66f39d429cb2604bcdacbf00dca0f5bbe2e9306a0009b7c6" +dependencies = [ + "core-foundation 0.10.0", + "core-graphics 0.24.0", + "foreign-types-shared 0.3.1", + "libc", + "log", + "objc2", + "objc2-app-kit", + "objc2-foundation", + "windows", + "xkbcommon", + "xkeysym", +] + [[package]] name = "enumflags2" version = "0.7.11" @@ -2236,6 +2255,15 @@ version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" +[[package]] +name = "memmap2" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd3f7eed9d3848f8b98834af67102b720745c4ec028fcd0aa0239277e7de374f" +dependencies = [ + "libc", +] + [[package]] name = "memoffset" version = "0.9.1" @@ -2720,8 +2748,9 @@ dependencies = [ [[package]] name = "pasteme" -version = "0.1.1" +version = "0.2.0" dependencies = [ + "enigo", "mouse_position", "serde", "serde_json", @@ -5543,6 +5572,23 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "xkbcommon" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9" +dependencies = [ + "libc", + "memmap2", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + [[package]] name = "yoke" version = "0.7.5" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 736ee8f..0d2c999 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "pasteme" -version = "0.1.1" +version = "0.2.0" description = "A simple clipboard manager" authors = ["CKylinMC"] edition = "2021" @@ -26,6 +26,7 @@ serde_json = "1" mouse_position = "0.1.3" tauri-plugin-clipboard-manager = "2" tauri-plugin-store = "2" +enigo = "0.3.0" [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] tauri-plugin-autostart = "2" diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index b347945..4dc67a5 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,5 +1,9 @@ mod tray; +use enigo::{ + Direction, + Enigo, Key, Keyboard, Settings, +}; use mouse_position::mouse_position::Mouse; use tauri::{AppHandle, Manager}; use tauri_plugin_autostart::MacosLauncher; @@ -17,6 +21,22 @@ fn get_mouse_position() -> Vec { } } +#[tauri::command] +async fn input_text(text: &str) -> Result<(), String> { + let mut enigo = Enigo::new(&Settings::default()).unwrap(); + enigo.text(text).unwrap(); + Ok(()) +} + +#[tauri::command] +async fn simulate_paste() -> Result<(), String> { + let mut enigo = Enigo::new(&Settings::default()).unwrap(); + let _ = enigo.key(Key::Control, Direction::Press); + let _ = enigo.key(Key::V, Direction::Click); + let _ = enigo.key(Key::Control, Direction::Release); + Ok(()) +} + fn show_window(app: &AppHandle) { let windows = app.webview_windows(); @@ -50,7 +70,7 @@ pub fn run() { Ok(()) }) .plugin(tauri_plugin_opener::init()) - .invoke_handler(tauri::generate_handler![get_mouse_position]) + .invoke_handler(tauri::generate_handler![get_mouse_position, input_text, simulate_paste]) .run(tauri::generate_context!()) .expect("error while running tauri application"); } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 3374901..cfeca0b 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "$schema": "https://schema.tauri.app/config/2", "productName": "PasteMe", - "version": "0.1.1", + "version": "0.2.0", "identifier": "in.ckyl.pasteme", "build": { "beforeDevCommand": "yarn dev", diff --git a/src/composables/useConfig.ts b/src/composables/useConfig.ts index 3f86e78..e0b89c3 100644 --- a/src/composables/useConfig.ts +++ b/src/composables/useConfig.ts @@ -1,5 +1,6 @@ import { ref } from 'vue'; import { Store } from '@tauri-apps/plugin-store'; +import { tryParse } from '@/libs/utils'; export interface AIConfig { enabled: boolean; @@ -8,9 +9,17 @@ export interface AIConfig { model: string; } +export interface Snippet { + id: string; + name: string; + system: string; + prompt: string; +} + export interface Config { globalShortcut: string; ai: AIConfig; + snippets: Snippet[]; } export function useConfig() { @@ -23,13 +32,14 @@ export function useConfig() { endpoint: 'https://api.openai.com/v1', model: 'gpt-4o', }, + snippets: [] }); const loadConfig = async () => { noSave.value = true; try { const store = await Store.load('store.bin'); - config.value.globalShortcut = + config.value.globalShortcut = (await store.get('globalShortcut')) || 'CommandOrControl+Shift+C'; config.value.ai = { enabled: !!(await store.get('ai.enabled')), @@ -37,6 +47,13 @@ export function useConfig() { endpoint: (await store.get('ai.endpoint')) || 'https://api.openai.com/v1', model: (await store.get('ai.model')) || 'gpt-4o', }; + config.value.snippets = tryParse(await store.get('snippets') || "[]", [ + { + id: 'intro', + name: '翻译成中文', + system: '请辅助用户完成任务,不要输出任何其他多余内容', + prompt: '请将内容翻译成中文', + }]); await store.close(); } finally { noSave.value = false; @@ -51,6 +68,7 @@ export function useConfig() { await store.set('ai.apiKey', config.value.ai.apiKey); await store.set('ai.endpoint', config.value.ai.endpoint); await store.set('ai.model', config.value.ai.model); + await store.set('snippets', JSON.stringify(Array.isArray(config.value.snippets) ? config.value.snippets : [])); await store.save(); await store.close(); }; diff --git a/src/composables/usePanelWindow.ts b/src/composables/usePanelWindow.ts index 7e14064..b4e0dd1 100644 --- a/src/composables/usePanelWindow.ts +++ b/src/composables/usePanelWindow.ts @@ -1,9 +1,8 @@ import { ref } from 'vue'; import { window as appWindow } from '@tauri-apps/api'; -import { useConfig } from './useConfig'; import type { useClipboard } from './useClipboard'; -export type PanelPage = 'index' | 'calc' | 'edit' | 'tojson' | 'askai' | 'aicreate'; +export type PanelPage = 'index' | 'calc' | 'edit' | 'tojson' | 'askai' | 'aicreate' | 'snippets' | 'snippets-ai' | 'snippets-edit'; export function usePanelWindow(clipboard: ReturnType) { const page = ref('index'); @@ -12,27 +11,31 @@ export function usePanelWindow(clipboard: ReturnType) { const gotoPage = (targetPage: PanelPage, onPageChange?: (page: PanelPage) => void) => { page.value = targetPage; - showPreview.value = targetPage === 'index' || - ['tojson', 'askai', 'aicreate'].includes(targetPage); + showPreview.value = targetPage === 'index' || + ['tojson', 'askai', 'aicreate', 'snippets-ai'].includes(targetPage); onPageChange?.(targetPage); }; - const setupWindowListeners = async (onHide: () => void) => { - const { loadConfig } = useConfig(); + const setupWindowListeners = async (onHide: () => void, loadConfig?: ()=>Promise) => { + const isBlured = ref(true); const listeners = await Promise.all([ appWindow.getCurrentWindow().listen('tauri://blur', event => { if (!mouseInRange.value) { console.log('blur', event); + isBlured.value = true; onHide(); } }), appWindow.getCurrentWindow().listen('tauri://focus', async () => { - showPreview.value = true; - page.value = 'index'; - await Promise.all([ - loadConfig(), - clipboard.refresh() - ]); + if (isBlured.value) { + showPreview.value = true; + page.value = 'index'; + await Promise.all([ + loadConfig?.(), + clipboard.refresh() + ]); + isBlured.value = false; + } }) ]); diff --git a/src/libs/bridges.ts b/src/libs/bridges.ts index d76a277..8d2712d 100644 --- a/src/libs/bridges.ts +++ b/src/libs/bridges.ts @@ -1,5 +1,13 @@ import { invoke } from "@tauri-apps/api/core"; -export async function getMousePosition(){ +export async function getMousePosition() { return await invoke("get_mouse_position") as number[]; } + +export async function inputText(text: string) { + return await invoke("input_text", { text }); +} + +export async function simulatePaste(){ + return await invoke("simulate_paste"); +} diff --git a/src/libs/utils.ts b/src/libs/utils.ts new file mode 100644 index 0000000..e8bedc6 --- /dev/null +++ b/src/libs/utils.ts @@ -0,0 +1,8 @@ +// biome-ignore lint/suspicious/noExplicitAny: +export function tryParse(str: string, fallback: any = null) { + try { + return JSON.parse(str); + } catch (e) { + return fallback; + } +} \ No newline at end of file diff --git a/src/pages/Home.vue b/src/pages/Home.vue index af46453..63c70df 100644 --- a/src/pages/Home.vue +++ b/src/pages/Home.vue @@ -177,7 +177,7 @@ function closeShortcutSetter() { - + diff --git a/src/pages/Panel.vue b/src/pages/Panel.vue index f0453ad..bc4f815 100644 --- a/src/pages/Panel.vue +++ b/src/pages/Panel.vue @@ -1,6 +1,13 @@