fix: bug when autocall for cw keyer is on which was

autocalling no matter which macro now only on CQ
fix: ESC stop transmission but also autocall
This commit is contained in:
2026-06-20 02:05:12 +02:00
parent 079d0c32df
commit 32878c17be
4 changed files with 182 additions and 96 deletions
+30 -16
View File
@@ -598,7 +598,7 @@ export default function App() {
const [cwStatus, setCwStatus] = useState<{ wpm: number; pitch: number; level: number; active: boolean }>({ wpm: 0, pitch: 0, level: 0, active: false });
const cwOn = cwEnabled && mode === 'CW';
useEffect(() => {
const offT = EventsOn('cw:text', (t: string) => setCwText((s) => (s + t).slice(-2000)));
const offT = EventsOn('cw:text', (t: string) => setCwText((s) => (s + t).slice(-200)));
const offS = EventsOn('cw:status', (st: any) => setCwStatus(st));
const offE = EventsOn('cw:error', (e: string) => { setError(String(e)); setCwEnabled(false); });
return () => { offT?.(); offS?.(); offE?.(); };
@@ -1476,8 +1476,16 @@ export default function App() {
function wkSendMacro(i: number) {
const m = wkMacros[i];
if (!m) return;
if (wkAutoCallRef.current) runAutoCall(i); // loop this macro until a reply / stop
else wkSend(m.text);
// Auto-call only loops CQ-type macros. Sending any other macro (e.g. a
// report once someone answers) sends ONCE and cancels a running loop —
// otherwise a report would keep repeating.
const isCQ = (m.text || '').toUpperCase().includes('CQ');
if (wkAutoCallRef.current && isCQ) {
runAutoCall(i); // loop this CQ until a reply is sent / Stop / ESC
} else {
stopAutoCall();
wkSend(m.text);
}
}
wkSendMacroRef.current = wkSendMacro;
function wkToggleAutoCall(on: boolean) {
@@ -2046,7 +2054,9 @@ export default function App() {
return;
}
const keyerLive = wkActiveRef.current;
if (keyerLive) WinkeyerStop().catch(() => {});
// ESC aborts the current CW transmission AND the auto-call loop, so it
// won't resend after the gap — you must click a CQ macro to restart it.
if (keyerLive) { stopAutoCall(); WinkeyerStop().catch(() => {}); }
if (!keyerLive || wkEscClearsRef.current) {
resetEntry();
callsignRef.current?.focus();
@@ -3202,21 +3212,25 @@ export default function App() {
<span className="shrink-0 font-mono text-[10px] text-muted-foreground tabular-nums">
{cwStatus.wpm > 0 ? `${cwStatus.wpm} WPM` : '— WPM'} · {cwStatus.pitch > 0 ? `${cwStatus.pitch} Hz` : '— Hz'}
</span>
<div className="flex-1 min-w-0 overflow-x-auto whitespace-nowrap font-mono leading-5">
{/* Single-line rolling ticker — no scrollbar; newest text stays
pinned to the right, older text scrolls off the left. */}
<div className="flex-1 min-w-0 overflow-hidden font-mono leading-5">
{cwText.trim() === '' ? (
<span className="text-muted-foreground italic">listening</span>
) : (
cwText.trim().split(/\s+/).map((tok, i) => (
<button
key={i}
type="button"
className="mr-1 rounded px-1 hover:bg-emerald-200/70"
title="Use as callsign"
onClick={() => onCallsignInput(tok, { force: true })}
>
{tok}
</button>
))
<div className="flex justify-end whitespace-nowrap">
{cwText.trim().split(/\s+/).map((tok, i) => (
<button
key={i}
type="button"
className="ml-1 shrink-0 rounded px-1 hover:bg-emerald-200/70"
title="Use as callsign"
onClick={() => onCallsignInput(tok, { force: true })}
>
{tok}
</button>
))}
</div>
)}
</div>
<button type="button" className="shrink-0 text-muted-foreground hover:text-foreground" title="Clear" onClick={() => setCwText('')}>
+2 -2
View File
@@ -181,7 +181,7 @@ export function WinkeyerPanel({
someone answers. The seconds box is the gap AFTER the message. */}
<div className="flex items-center gap-2">
<label className="flex items-center gap-1.5 text-xs cursor-pointer select-none"
title="After you click a macro (e.g. F1 CQ), resend it on a loop — message, then the gap, then repeat — until a callsign is entered or you press Stop">
title="Click a CQ macro (one whose text contains CQ) to resend it on a loop — message, gap, repeat — until you send another macro (e.g. a report), press Stop, or hit ESC. Non-CQ macros send once.">
<input type="checkbox" className="accent-primary" checked={autoCall} disabled={!connected}
onChange={(e) => onToggleAutoCall(e.target.checked)} />
Auto-call
@@ -193,7 +193,7 @@ export function WinkeyerPanel({
value={autoCallSecs} onChange={(e) => onSetAutoCallSecs(parseInt(e.target.value) || 0)} />
<span className="text-[9px] text-muted-foreground">sec</span>
</div>
{autoCall && <span className="text-[10px] text-amber-600/80">click a macro to loop it</span>}
{autoCall && <span className="text-[10px] text-amber-600/80">click a CQ macro to loop it</span>}
</div>
{/* Macro buttons F1… — single-line (F-key + label) to keep the panel short. */}