import { app } from "@tauri-apps/api" import { getAllWindows, getCurrentWindow, type Window } from "@tauri-apps/api/window" import { isRegistered, register, unregister } from "@tauri-apps/plugin-global-shortcut" import { debug, info, warn } from "@tauri-apps/plugin-log" import * as os from "@tauri-apps/plugin-os" import * as userInput from "tauri-plugin-user-input-api" import { sendNotificationWithPermission } from "./notification" import { sleep } from "./time" /** * Tauri global shortcut doesn't accept 'Meta' Key. This function maps browser detected keys to Tauri-accepted keys. * @param key */ export function mapKeyToTauriKey(key: string): string { if (key === "Meta") { return "Command" } return key } /** * Registers a global hotkey for the application. If the hotkey is already registered, it will be unregistered first. * When the hotkey is pressed, it toggles the visibility and focus of the main window. * @param hotkeyStr - The hotkey string to register. */ export async function registerAppHotkey(hotkeyStr: string) { if (await isRegistered(hotkeyStr)) { warn(`Hotkey (${hotkeyStr}) already registered`) await unregister(hotkeyStr) } info(`Registering hotkey: ${hotkeyStr}`) return register(hotkeyStr, async (e) => { if (e.state === "Released") { const wins = await getAllWindows() const mainWin = wins.find((w) => w.label === "main") if (!mainWin) { return sendNotificationWithPermission( "No main window found", "Please open main window first" ) } const isVisible = await mainWin.isVisible() const isFocused = await mainWin.isFocused() if (isVisible) { if (isFocused) { mainWin.hide() } else { mainWin.setFocus() } } else { mainWin.show().then(() => mainWin.setFocus()) } } }) } /** * Updates the application's global hotkey. If an old hotkey is provided, it will be unregistered first. * @param newHotkey - The new hotkey combination to register. * @param oldHotkey - The old hotkey combination to unregister, if any. */ export async function updateAppHotkey(newHotkey: string[], oldHotkey?: string[] | null) { if (oldHotkey) { const hotkeyStr = oldHotkey.map(mapKeyToTauriKey).join("+") if (await isRegistered(hotkeyStr)) { await unregister(hotkeyStr) } } const hotkeyStr = newHotkey.map(mapKeyToTauriKey).join("+") return registerAppHotkey(hotkeyStr) } /** * Simulates a key combination press and release. * @param keys - The array of keys to press and release. */ export async function applyKeyComb(keys: userInput.Key[]) { // await Promise.all(keys.map((key) => userInput.key("KeyPress", key))) for (const key of keys) { await userInput.key("KeyPress", key) await sleep(100) } await sleep(150) for (const key of keys) { await userInput.key("KeyRelease", key) await sleep(100) } } /** * Simulates a paste operation based on the operating system. * On macOS, it uses Command+V. On Windows and Linux, it uses Shift+Insert. */ export async function paste() { const _platform = os.platform() if (_platform === "macos") { return applyKeyComb(["MetaLeft", "KeyV"]) } else if (_platform === "windows" || _platform === "linux") { return applyKeyComb(["ShiftLeft", "Insert"]) } else { console.error("Unsupported platform: " + _platform) } } export async function hideAndPaste(win?: Window) { return app .hide() .then(() => sleep(60)) .then(() => (win ?? getCurrentWindow()).hide()) .then(() => sleep(60)) .then(() => paste()) }