From 9044b87170d7376579e7e12b25c9ebf414ebae92 Mon Sep 17 00:00:00 2001 From: huqianghui Date: Fri, 10 Apr 2026 10:22:12 +0800 Subject: [PATCH 1/2] fix: macOS sendMacro uses Ctrl+C and clipboard paste for terminal compatibility The original implementation used Cmd+C (copy shortcut) instead of Ctrl+C (terminal interrupt), causing a stray 'c' character. The keystroke command also dropped characters and failed to send Enter reliably in terminal apps. Changes: - Use {control down} instead of {command down} for Ctrl+C interrupt - Replace keystroke typing with pbcopy + Cmd+V paste to avoid character drops and reordering - Split into two-step execution with 300ms delay for reliable sequencing - Add separate delay before Enter key to ensure it registers Co-Authored-By: Claude Opus 4.6 --- main.js | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/main.js b/main.js index 526d9ec..e3b1980 100644 --- a/main.js +++ b/main.js @@ -222,20 +222,35 @@ function sendMacroWindows(text) { } function sendMacroMac(text) { - const escaped = text.replace(/\\/g, '\\\\').replace(/"/g, '\\"'); - const script = [ + // Step 1: Ctrl+C interrupt (not Cmd+C which is copy on macOS) + const step1 = [ 'tell application "System Events"', - ' key code 8 using {command down}', // Cmd+C - ' delay 0.03', - ` keystroke "${escaped}"`, - ' key code 36', // Enter + ' key code 8 using {control down}', 'end tell' ].join('\n'); - execFile('osascript', ['-e', script], err => { - if (err) { - console.warn('mac macro failed (enable Accessibility for terminal/app):', err.message); - } + execFile('osascript', ['-e', step1], err => { + if (err) console.warn('Ctrl+C failed:', err.message); + // Step 2: paste text via clipboard + Enter + setTimeout(() => { + const { execFileSync } = require('child_process'); + try { + execFileSync('pbcopy', { input: text }); + } catch (e) { + console.warn('pbcopy failed:', e.message); + return; + } + const step2 = [ + 'tell application "System Events"', + ' key code 9 using {command down}', // Cmd+V paste + ' delay 0.1', + ' key code 36', // Enter + 'end tell' + ].join('\n'); + execFile('osascript', ['-e', step2], err => { + if (err) console.warn('paste+enter failed:', err.message); + }); + }, 300); }); } From 5901596548067d0aaaf39a94433c6e587b6b3ceb Mon Sep 17 00:00:00 2001 From: huqianghui Date: Fri, 10 Apr 2026 10:28:48 +0800 Subject: [PATCH 2/2] fix: split Enter into separate osascript step for reliable auto-send The previous two-step approach (paste + Enter in one osascript) still failed to send Enter in multi-pane terminal setups. Now uses three fully separate osascript calls with proper delays between each: 1. Ctrl+C interrupt (300ms wait) 2. Cmd+V paste (200ms wait) 3. Enter key Co-Authored-By: Claude Opus 4.6 --- main.js | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/main.js b/main.js index e3b1980..32e16d3 100644 --- a/main.js +++ b/main.js @@ -231,7 +231,7 @@ function sendMacroMac(text) { execFile('osascript', ['-e', step1], err => { if (err) console.warn('Ctrl+C failed:', err.message); - // Step 2: paste text via clipboard + Enter + // Step 2: paste text via clipboard setTimeout(() => { const { execFileSync } = require('child_process'); try { @@ -240,15 +240,24 @@ function sendMacroMac(text) { console.warn('pbcopy failed:', e.message); return; } - const step2 = [ + const paste = [ 'tell application "System Events"', ' key code 9 using {command down}', // Cmd+V paste - ' delay 0.1', - ' key code 36', // Enter 'end tell' ].join('\n'); - execFile('osascript', ['-e', step2], err => { - if (err) console.warn('paste+enter failed:', err.message); + execFile('osascript', ['-e', paste], err => { + if (err) console.warn('paste failed:', err.message); + // Step 3: Enter after paste completes + setTimeout(() => { + const enter = [ + 'tell application "System Events"', + ' key code 36', // Enter + 'end tell' + ].join('\n'); + execFile('osascript', ['-e', enter], err => { + if (err) console.warn('enter failed:', err.message); + }); + }, 200); }); }, 300); });