diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index afd2472..d9e1179 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -3675,7 +3675,7 @@ export default function App() {
case 'flex':
return (
- { setWkWpm(w); WinkeyerSetSpeed(w).catch(() => {}); saveWk({ wpm: w }); }}
+ { if (cwSourceRef.current === 'flex') setWkWpm(w); }}
onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
);
@@ -4993,7 +4993,7 @@ export default function App() {
backend is a FlexRadio. */}
{catState.backend === 'flex' && (
- { setWkWpm(w); WinkeyerSetSpeed(w).catch(() => {}); saveWk({ wpm: w }); }}
+ { if (cwSourceRef.current === 'flex') setWkWpm(w); }}
onReportRST={(r) => { setRstSent(r); rstUserEditedRef.current = true; }} />
)}
diff --git a/frontend/src/components/FlexPanel.tsx b/frontend/src/components/FlexPanel.tsx
index 61571f5..9e17275 100644
--- a/frontend/src/components/FlexPanel.tsx
+++ b/frontend/src/components/FlexPanel.tsx
@@ -288,6 +288,18 @@ export function FlexPanel({ onCWSpeed, onReportRST }: { onCWSpeed?: (wpm: number
const { t } = useI18n();
const [st, setSt] = useState(ZERO);
const hold = useRef>({});
+ // Keep the host's keyer speed (used for CW-length estimates and the keyer panel)
+ // in step with the radio's ACTUAL CW speed — including when it's changed on the
+ // radio / in SmartSDR, not just via the slider below. Notify only on a real change.
+ const lastCwSpeed = useRef(null);
+ useEffect(() => {
+ const w = st.cw_speed;
+ if (typeof w === 'number' && w > 0 && w !== lastCwSpeed.current) {
+ lastCwSpeed.current = w;
+ onCWSpeed?.(w);
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [st.cw_speed]);
// Peak-hold: keep the highest reading for ~2 s so the jittery VITA-49 meters
// read steadily instead of jumping every poll.
const peak = useRef>({});