fix: more reliable copy/paste with focus polling, clipboard save/restore, toast feedback

This commit is contained in:
Dávid Ádám
2026-06-06 14:19:13 +02:00
parent 96ef83c904
commit 303aa97e07
3 changed files with 91 additions and 11 deletions
+63 -11
View File
@@ -111,7 +111,8 @@ async function executeAction(action) {
const stealsFocus = ['keystroke', 'copy', 'paste', 'cut'].includes(type);
if (stealsFocus) {
app.hide();
await sleep(80);
// Várjuk meg, amíg tényleg az előző app kapja vissza a fókuszt
await waitForAppFocus();
}
try {
@@ -135,9 +136,15 @@ async function executeAction(action) {
/* ─── Clipboard: copy ──────────────────────────────────────────────── */
case 'copy': {
await execPromise(`osascript -e 'tell application "System Events" to keystroke "c" using command down'`);
await sleep(100);
const text = clipboard.readText();
// Többször próbálkozunk, mert néha a fókuszváltás + billentyűzés nem elég gyors
let text = '';
for (let attempt = 0; attempt < 3; attempt++) {
await execPromise(`osascript -e 'tell application "System Events" to keystroke "c" using command down'`);
await sleep(120);
text = clipboard.readText();
if (text) break;
await sleep(50);
}
console.log(`Copied: "${text.substring(0, 80)}..."`);
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('clipboard-result', { action: 'copy', text });
@@ -147,18 +154,35 @@ async function executeAction(action) {
/* ─── Clipboard: paste ─────────────────────────────────────────────── */
case 'paste': {
const stored = value || clipboard.readText();
clipboard.writeText(stored);
await execPromise(`osascript -e 'tell application "System Events" to keystroke "v" using command down'`);
// Ha value meg van adva, azt illesztjük be (és utána visszaállítjuk a régit)
if (value) {
const prevClip = clipboard.readText();
clipboard.writeText(value);
await execPromise(`osascript -e 'tell application "System Events" to keystroke "v" using command down'`);
await sleep(150);
// Visszaállítjuk az eredeti vágólap tartalmat
// (kis késleltetéssel, hogy a cél app befejezze a fogadást)
clipboard.writeText(prevClip);
} else {
// Nincs value simán illesszük be, ami a vágólapon van
await execPromise(`osascript -e 'tell application "System Events" to keystroke "v" using command down'`);
}
break;
}
/* ─── Clipboard: cut ───────────────────────────────────────────────── */
case 'cut': {
await execPromise(`osascript -e 'tell application "System Events" to keystroke "x" using command down'`);
await sleep(100);
let text = '';
for (let attempt = 0; attempt < 3; attempt++) {
await execPromise(`osascript -e 'tell application "System Events" to keystroke "x" using command down'`);
await sleep(120);
text = clipboard.readText();
if (text) break;
await sleep(50);
}
console.log(`Cut: "${text.substring(0, 80)}..."`);
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.webContents.send('clipboard-result', { action: 'cut', text: clipboard.readText() });
mainWindow.webContents.send('clipboard-result', { action: 'cut', text });
}
break;
}
@@ -214,7 +238,8 @@ async function executeAction(action) {
// Visszahozzuk az ablakot
if (stealsFocus) {
await sleep(50);
// Várjunk egy kicsit, hogy a cél app megkapja a billentyűzet parancsot
await sleep(150);
app.show();
if (mainWindow && !mainWindow.isDestroyed()) {
mainWindow.show();
@@ -376,6 +401,33 @@ function execPromise(cmd) {
function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }
/**
* Várunk amíg az aktuális fókusz átvált a StreamDeck-ről az előző app-ra.
* app.hide() után pollozzuk a frontmost app-ot, max 500ms-ig.
*/
async function waitForAppFocus() {
const maxWait = 800; // max 800ms
const interval = 40; // 40ms-ként ellenőrizzük
let waited = 0;
while (waited < maxWait) {
try {
const frontApp = execSync(
`osascript -e 'tell application "System Events" to get name of first process whose frontmost is true' 2>/dev/null`,
{ timeout: 500, encoding: 'utf-8' }
).trim();
// Ha már nem a StreamDeck az aktív app, kész
if (frontApp && frontApp !== 'StreamDeck') {
return;
}
} catch (e) {
// Ha hiba van, próbáljuk tovább
}
await sleep(interval);
waited += interval;
}
// Timeout után is folytatjuk hátha működik
}
function parseKeystroke(str) {
if (!str) return null;
const parts = str.toLowerCase().split('+');