From ede3fbec950de8586bd3db4ce061e15eac887ebe Mon Sep 17 00:00:00 2001 From: Justin Date: Wed, 5 Aug 2026 23:15:20 +0000 Subject: [PATCH] OBLS-822 disable DataWedge keystroke output for barcode inputs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scans were delivered both as an intent broadcast (useScanListener) and as keystroke output typed into the focused field, so a barcode input applied the value twice — the scanned string was appended to itself (e.g. a scan of "4354210" was submitted as "43542104354210"). Reproduced on TC52 and TC53e. Keystroke output is a profile-wide DataWedge setting and cannot be scoped to one field, so toggle it at runtime: mute it while any barcode input is active (scans then arrive only via the intent broadcast) and restore it when none is, so plain inputs elsewhere can still be populated by scanning. Reference counted so overlapping inputs keep it muted until the last one unmounts. Manual keyboard entry is unaffected — this only controls the scanner's keystroke output. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_018esj4qV5h4teD7M6WfHahM --- src/hooks/constant.ts | 18 ++++++++++++++++++ src/hooks/useScanListener.ts | 27 ++++++++++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/hooks/constant.ts b/src/hooks/constant.ts index 3a106eec..44299bb2 100644 --- a/src/hooks/constant.ts +++ b/src/hooks/constant.ts @@ -64,3 +64,21 @@ export const PROFILE_CONFIG2 = { } } }; + +// Keystroke output is a profile-wide DataWedge setting, so it cannot be scoped to +// a single field. It is toggled at runtime: disabled while a barcode input owns +// the scanner (so a scan arrives only via the intent broadcast and is not also +// typed into the focused field as keystrokes), and re-enabled otherwise so plain +// inputs elsewhere can still be populated by scanning. +export const getKeystrokeOutputConfig = (enabled: boolean) => ({ + PROFILE_NAME: 'OPENBOXES', + PROFILE_ENABLED: 'true', + CONFIG_MODE: 'UPDATE', + PLUGIN_CONFIG: { + PLUGIN_NAME: 'KEYSTROKE', + RESET_CONFIG: 'true', + PARAM_LIST: { + keystroke_output_enabled: enabled ? 'true' : 'false' + } + } +}); diff --git a/src/hooks/useScanListener.ts b/src/hooks/useScanListener.ts index 8068365d..669c5235 100644 --- a/src/hooks/useScanListener.ts +++ b/src/hooks/useScanListener.ts @@ -6,6 +6,7 @@ import { ACTION, FILTER_ACTIONS, FILTER_CATEGORY, + getKeystrokeOutputConfig, LISTENER, PROFILE, PROFILE_CONFIG, @@ -19,6 +20,10 @@ export type ScanResult = { let profileConfigured = false; +// Number of barcode inputs currently listening for scans. Keystroke output is +// muted while this is > 0 (see below). +let activeConsumerCount = 0; + function sendDataWedgeCommand(extraName: string, extraValue: unknown): void { DataWedgeIntents.sendBroadcastWithExtras({ action: ACTION.API_ACTION, @@ -36,6 +41,10 @@ function configureProfileOnce(): void { sendDataWedgeCommand(PROFILE.SET_CONFIG_PROFILE, PROFILE_CONFIG2); } +function setKeystrokeOutput(enabled: boolean): void { + sendDataWedgeCommand(PROFILE.SET_CONFIG_PROFILE, getKeystrokeOutputConfig(enabled)); +} + function extractScan(intent: Record): ScanResult | null { const data = intent?.[ACTION.DATA_STRING] ?? intent?.data; if (!data) { @@ -60,6 +69,16 @@ export function useScanListener(onScan: (result: ScanResult) => void, enabled = filterCategories: FILTER_CATEGORY }); + // A barcode input is now listening via the intent broadcast. While any is + // active, mute DataWedge keystroke output so the scan is not also typed into + // the focused field (which would duplicate/append the value). Reference + // counted so overlapping inputs (e.g. a screen input and a modal input) keep + // it muted until the last one goes away, then restore it for plain inputs. + activeConsumerCount += 1; + if (activeConsumerCount === 1) { + setKeystrokeOutput(false); + } + const handleIntent = (intent: Record) => { const result = extractScan(intent); if (result) { @@ -68,6 +87,12 @@ export function useScanListener(onScan: (result: ScanResult) => void, enabled = }; const subscription = DeviceEventEmitter.addListener(LISTENER.BROADCAST_INTENT, handleIntent); - return () => subscription.remove(); + return () => { + subscription.remove(); + activeConsumerCount -= 1; + if (activeConsumerCount === 0) { + setKeystrokeOutput(true); + } + }; }, [enabled]); }