Fixing barcode scanner adding unnecessary CR/LF line breaks into web forms

Root Cause Diagnosis

Most barcode scanners operate in USB HID keyboard-wedge mode. After the decoded data, they append a configurable suffix, usually a carriage return (0x0D), a line feed (0x0A), or both, which the host receives as an Enter (or Ctrl+Enter, or Tab) keystroke. In a web form, Enter inside an <input> triggers implicit form submission, and inside a <textarea> it inserts a literal newline. A newline that is captured as part of the value corrupts the data, and an unwanted submit fires the form before the operator finishes. The suffix is a scanner firmware setting, so it persists across every host application until it is reprogrammed.

Quick Fix

Scan the manufacturer’s “Disable suffix” or “No terminator” configuration barcode from the scanner’s programming manual. Common commands:

  • Zebra/Symbol: scan Scan Options > Suffix > None (or Enter Key off), then scan Set Defaults if the setting persists.
  • Honeywell: scan Remove Suffix (Suffix Off); or send serial command SUFBK2, and SUFCK2, with empty values.
  • Datalogic: scan Enter/Exit Programming Mode, then Global Suffix > None.
  • Generic Chinese HID scanners (Tera, Netum, Eyoyo): scan Enter Setting > Add CR/LF suffix: Disable > Exit Setting.

If no manual is available and the scanner cannot be reprogrammed, use the software workaround in step 5.

Step-by-Step Resolution

1. Confirm the terminator is coming from the scanner

Open a plain text editor and scan a barcode. If the cursor jumps to the next line, the scanner is sending CR, LF, or CRLF. To see the exact bytes in the browser, open DevTools > Console and paste:

document.addEventListener('keydown', e => console.log(e.key, e.code, e.keyCode, e.timeStamp), true);

Scan a code. Characters arrive at intervals under roughly 10–30 ms, followed by Enter (keyCode 13). Human typing produces intervals above 50 ms.

2. Identify the scanner interface mode

The fix depends on the mode. Check the manual or the OS device listing:

  • HID keyboard (keyboard wedge): the scanner types keystrokes. Suffixes apply. This is the default for most units.
  • USB CDC / virtual COM or SPP (Bluetooth serial): the scanner sends raw bytes to a serial port. Applications must read the port and strip terminators themselves.
  • HID POS / USB-OEM: data is delivered as a vendor report. It does not act as a keyboard and requires a driver or the Web HID API.
See also  Label printer printing inverted black background with white text: Driver polarity fix

Windows: Device Manager > Human Interface Devices (HID keyboard) or Ports (COM & LPT) (CDC). Linux: lsusb and dmesg | tail after plugging in the scanner.

3. Remove or change the suffix in scanner firmware

Scan the vendor’s programming barcodes from the official manual (PDF). The relevant setting names vary:

Vendor termMeaning
Suffix / Postamble / TerminatorCharacters appended after data
Enter Key / Carriage ReturnSends 0x0D
Line FeedSends 0x0A
TabSends 0x09 (moves focus to next field)

Set the suffix to None. To keep a delimiter for the application, pick Tab instead of Enter when the form expects field-to-field navigation, since Tab does not submit the form.

Some scanners can be configured through vendor software over USB (Zebra 123Scan, Honeywell EZConfig, Datalogic Aladdin). These generate the same programming barcodes and can push settings via serial commands.

4. Prevent submission in the form (when the scanner cannot be changed)

Block Enter from submitting on the barcode field:

<input type="text" id="barcode" name="barcode" autocomplete="off" />
<script>
document.getElementById('barcode').addEventListener('keydown', function (e) {
  if (e.key === 'Enter') {
    e.preventDefault();
  }
});
</script>

5. Detect scanner input and strip terminators programmatically

Use inter-key timing to distinguish scanner input from typing, buffer the characters, and handle the terminator explicitly:

(function () {
  const input = document.getElementById('barcode');
  const MAX_GAP_MS = 50;
  let buffer = '';
  let lastTime = 0;

  input.addEventListener('keydown', function (e) {
    const now = e.timeStamp;
    if (now - lastTime > MAX_GAP_MS) buffer = '';
    lastTime = now;

    if (e.key === 'Enter') {
      e.preventDefault();
      if (buffer.length >= 4) {
        input.value = buffer.replace(/[\r\n]+$/g, '');
        input.dispatchEvent(new Event('change', { bubbles: true }));
        // Optional explicit submit:
        // input.form.requestSubmit();
      }
      buffer = '';
      return;
    }

    if (e.key.length === 1) buffer += e.key;
  });
})();

Server-side, always sanitize regardless of client behavior:

value = request.form["barcode"].strip("\r\n\t ")
$value = trim($_POST['barcode'], "\r\n\t ");

6. Handle <textarea> fields

A <textarea> inserts the newline into the value. Strip it on input:

const ta = document.getElementById('scan-area');
ta.addEventListener('input', () => {
  ta.value = ta.value.replace(/[\r\n]+/g, '');
});

Or use <input type="text"> instead. Single-line inputs discard newlines from pasted text automatically.

See also  Fixing OTG USB device unrecognized on Android after major security update

7. Validate the result

Scan a code and check the field value length against the expected barcode length:

console.log(JSON.stringify(document.getElementById('barcode').value));

The output must not contain \r or \n. Compare with the printed code length (EAN-13 = 13, UPC-A = 12, Code 128 = variable).

Why This Fails for Some Users

  • Scanner reverts after power cycle: Some low-cost scanners store settings in volatile memory. Scan the Save settings or Permanent barcode, or use the vendor tool to write to non-volatile flash.
  • Wrong suffix removed: Scanners often have separate settings for Prefix, Suffix, Terminator, and AIM ID. Disabling only “Suffix” can leave a separate “Enter key” terminator active. Check all of them in the manual.
  • Keyboard layout mismatch: In HID mode, the scanner sends key scan codes and the OS maps them through the active layout. On a German (QWERTZ) or French (AZERTY) layout, Z/Y, A/Q, -, /, and @ can appear wrong. Set the scanner’s Keyboard Country/Language to match the OS layout. This is unrelated to CR/LF but commonly diagnosed at the same time.
  • Caps Lock inversion: With Caps Lock on, some scanners send inverted case. Scan the Caps Lock Override or Auto Caps Lock Detect barcode.
  • Bluetooth scanners in HID profile: Bluetooth HID can add the terminator with additional latency, and Android or iOS may pop up the on-screen keyboard on focus. On iOS, HID scanners suppress the on-screen keyboard only if the toggle (often Eject key) is enabled.
  • Mobile browsers and e.key: Some Android WebViews report e.key as "Unidentified" for scanner keystrokes. Use e.keyCode === 13 or the input event with inputType === 'insertLineBreak' as a fallback.
  • Framework-managed forms (React, Vue, Angular): Controlled inputs may not see a value updated with a plain input.value = .... Use the framework’s setter or dispatch a bubbled input event, or handle the terminator inside the framework’s onKeyDown.
  • Autofocus lost: If focus moves to another element between characters, part of the barcode lands in the wrong field. Keep the barcode input focused (autofocus, input.focus() on blur) and disable autocomplete overlays.
  • Enter is needed as a trigger: Some workflows rely on the terminator to submit. Do not delete it in firmware and instead intercept it in code (step 5) so that submission only happens after validation.
  • Ctrl+J or Ctrl+M sequences: Some scanners map LF to Ctrl+J. Browsers may treat this as a shortcut (for example, Chrome opens the downloads page). Set the suffix to CR or Tab.
  • Serial (CDC) scanners feeding a web app: The browser cannot read a COM port directly. Use the Web Serial API (Chromium only, HTTPS required) and split the stream on the configured terminator:const port = await navigator.serial.requestPort(); await port.open({ baudRate: 9600 }); const reader = port.readable.pipeThrough(new TextDecoderStream()).getReader(); let acc = ''; for (;;) { const { value, done } = await reader.read(); if (done) break; acc += value; let m; while ((m = acc.match(/^(.*?)(\r\n|\r|\n)/s))) { handleScan(m[1]); acc = acc.slice(m[0].length); } }
  • Web HID or virtual keyboard drivers: Enterprise mobile-computer devices (Zebra, Honeywell) offer DataWedge or Data Collection profiles that strip suffixes in software. On Zebra Android, set DataWedge > Profile > Keystroke output > Send ENTER key to off.
See also  Android USB Tethering Disconnecting Every 10 Minutes: Power State Fix

Leave a Comment