浏览器端JavaScript捕获键盘楔式条码/RFID设备输入并区分人工输入方案
网页端区分键盘楔外设与手动输入的实现方案
方案一:无驱动改造,纯前端事件监听实现(适配无权限改驱动的场景)
两类键盘楔模式外设和人手输入的核心差异是输入特征:人手打字单字符间隔通常大于80ms、间隔波动大,外设模拟输入的字符间隔稳定在10-30ms、整串输入耗时极短,配合可配置的前后缀可实现100%准确区分,具体实现逻辑如下:
- 给条码扫描器配置专属起始/结束标记,比如起始字符设为不可见控制字符
\u0002、结束字符保留默认回车再加专属后缀,避免和正常输入冲突。 - 对无法配置前后缀的RFID读卡器,提前采样统计设备的固定特征:包括单字符输入平均间隔、输出编码的固定长度、编码字符集范围,作为后续判定的基准规则。
- 全局绑定
keydown事件做输入缓存,实时计算相邻字符的输入间隔:- 若相邻字符间隔超过80ms,直接清空缓存判定为手动输入,不做拦截
- 捕获到回车符时判定为一串输入结束,统计整串的平均输入间隔、长度、前缀特征,分别匹配条码扫描器、RFID读卡器的规则,匹配成功则触发对应设备的自定义事件,同时阻止默认事件避免字符写入当前聚焦的输入框
- 未匹配到任何外设规则的输入,按正常键盘输入放行
核心逻辑参考代码:
const inputCache = []; let lastKeyTime = 0; // 阈值根据自己设备实际采样结果调整 const CONFIG = { maxManualInterval: 80, maxBarcodeInterval: 30, maxRfidInterval: 20, rfidFixedLength: 10, barcodePrefix: '\u0002' }; document.addEventListener('keydown', (e) => { const currentTime = Date.now(); const keyInterval = currentTime - lastKeyTime; lastKeyTime = currentTime; // 间隔超过手动输入阈值,清空缓存 if (keyInterval > CONFIG.maxManualInterval && inputCache.length) { inputCache.length = 0; return; } // 回车触发输入结束判定 if (e.key === 'Enter') { e.preventDefault(); const inputStr = inputCache.map(i => i.key).join(''); const avgInterval = (currentTime - inputCache[0].time) / inputCache.length; inputCache.length = 0; // 判定RFID输入 if (inputStr.length === CONFIG.rfidFixedLength && avgInterval < CONFIG.maxRfidInterval) { window.dispatchEvent(new CustomEvent('rfid-read', { detail: inputStr })); return; } // 判定条码扫描输入 if (inputStr.startsWith(CONFIG.barcodePrefix) && avgInterval < CONFIG.maxBarcodeInterval) { const barcodeVal = inputStr.replace(CONFIG.barcodePrefix, ''); window.dispatchEvent(new CustomEvent('barcode-scan', { detail: barcodeVal })); return; } // 无匹配则放行正常回车逻辑 return; } inputCache.push({ key: e.key, time: currentTime }); });
方案二:替换驱动转串口,调用Web Serial API通信(稳定性最高,适配内部受控场景)
不需要找第三方通用USB转串口驱动,直接用系统自带驱动即可实现,完全绕过键盘楔模式,从硬件层面区分设备、杜绝和手动输入混淆:
- 打开Zadig工具,选中要改造的条码扫描器/RFID读卡器,记录设备的VID/PID,驱动选择列表里选系统自带的
USB Serial Device(对应底层驱动为usbser.sys),替换原有HID键盘驱动。 - 驱动替换完成后,设备会在系统设备管理器的「端口(COM和LPT)」分类下生成独立的虚拟COM口,此时设备不再触发键盘输入事件。
- 前端代码中调用
navigator.serialAPI,通过之前记录的VID/PID做端口过滤,用户授权后即可打开对应端口,按设备的通信波特率、数据位配置读取数据,两类设备对应不同的VID/PID,可直接区分输入来源,不需要做输入特征判定,稳定性远高于事件监听方案。
注意:驱动替换后原键盘楔模式会失效,仅适合设备完全由你方管控的内部业务场景;如果是面向外部用户的公网应用,无法要求用户替换驱动,优先选择方案一。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

