You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

onkeyup事件中如何处理USB条码扫描器的Shift前置按键识别问题

问题根因

  • 你当前使用keyup事件监听输入,而条码扫描器模拟上档字符(如大写字母、:这类需要按Shift才能输出的符号)的逻辑是:先按下Shift → 按下对应字符键 → 松开Shift → 松开字符键。你在keyup阶段直接过滤了Shift事件,此时拿到的字符键的event.key已经丢失了Shift激活状态,只能拿到原始下档字符(比如;而不是:)
  • event.key受当前系统的键盘布局影响,Win7设备如果是多语言键盘布局,就会出现你测试结果里的ò、ç这类错误字符
  • 不同型号扫描器的键事件触发时序存在差异,Win7的键盘事件响应逻辑也和新系统不同,才会出现换设备就失效的问题

修复方案

1. 替换监听事件为keydown,使用event.code做物理键位映射

keydown触发时event.shiftKey的状态是准确的,event.code是物理键位标识,不受系统键盘布局影响,我们可以固定映射英文标准键盘的字符,避免布局干扰。

2. 新增英文键盘上档字符映射表

提前定义好Shift激活时对应物理键的输出字符,直接覆盖event.key的取值。

3. 可选:加输入超时判断区分扫描输入和手动输入

扫描器输入每个字符的间隔通常小于10ms,加超时可以避免手动误触键盘产生脏数据。

修改后的参考代码:

// 英文标准键盘上档字符映射表,按需补充你需要的符号
const shiftKeyMap = {
  'Semicolon': ':',
  'Digit1': '!',
  'Digit2': '@',
  'Digit3': '#',
  'Digit4': '$',
  'Digit5': '%',
  'Digit6': '^',
  'Digit7': '&',
  'Digit8': '*',
  'Digit9': '(',
  'Digit0': ')',
  'Minus': '_',
  'Equal': '+',
  'BracketLeft': '{',
  'BracketRight': '}',
  'Backslash': '|',
  'Quote': '"',
  'Comma': '<',
  'Period': '>',
  'Slash': '?',
  'Backquote': '~'
};

let barcode = '';
let scanTimer = null;
// 扫描输入超时时间,超过50ms没有新输入就认为本次扫描结束,可按需调整
const SCAN_TIMEOUT = 50;

document.addEventListener("keydown", (event) => {
  // 过滤修饰键本身的事件,保留修饰键状态给后续字符键使用
  if (event.isComposing || ['Shift', 'Control', 'Meta', 'Alt'].includes(event.key)) {
    return;
  }

  if (containerLoading.classList.contains("d-none")) {
    showLoading();
  }

  if (!containerLoading.classList.contains("d-none")) {
    // 清掉上一次的超时计时器
    clearTimeout(scanTimer);
    
    if (event.key === "Enter" || event.key === "Tab") {
      if (barcode !== "") {
        websocket.send(`<ART>${barcode}</ART>`);
        barcode = "";
      }
    } else {
      let currentChar = event.key;
      // Shift激活时,优先用映射表取上档字符,字母直接转大写
      if (event.shiftKey) {
        if (shiftKeyMap[event.code]) {
          currentChar = shiftKeyMap[event.code];
        } else if (currentChar.length === 1 && /[a-z]/.test(currentChar)) {
          currentChar = currentChar.toUpperCase();
        }
      }
      barcode += currentChar;
    }

    // 超时重置条码,避免和手动输入混淆
    scanTimer = setTimeout(() => {
      barcode = '';
    }, SCAN_TIMEOUT);
  }
});

注意事项

如果还有其他符号映射错误,你可以打印event.code和event.shiftKey的取值,补充到shiftKeyMap映射表里即可覆盖所有错误情况。

内容的提问来源于stack exchange,提问作者NiceToMytyuk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 18:15:02