扫码枪扫描带中文的二维码qrcode,在微信或者企业微信中正常,在浏览器或word中中文显示异常

扫码枪实际是模拟了键盘的输入过程,首先排查输入时扫码枪具体输入了什么内容

编码验证脚本
// 在浏览器控制台运行此代码后扫描测试,或者在页面中执行下方代码后扫描测试
document.addEventListener('keydown', e => {
  console.log('Raw input:', 
    `Char: ${e.key}, Code: ${e.code}, Hex: ${e.key.charCodeAt(0).toString(16)}`
  );
});

根据键盘事件日志分析,扫码枪正在使用 Alt+Numpad组合键方式 模拟输入,这是典型的ASCII码输入方式。

index.tsx:13 Raw input: Char: Alt, Code: AltLeft, Hex: 41
31index.tsx:13 Raw input: Char: 3, Code: Numpad3, Hex: 33
31index.tsx:13 Raw input: Char: 1, Code: Numpad1, Hex: 31
31index.tsx:13 Raw input: Char: 5, Code: Numpad5, Hex: 35
31index.tsx:13 Raw input: Char: 0, Code: Numpad0, Hex: 30
31index.tsx:13 Raw input: Char: 8, Code: Numpad8, Hex: 38
32index.tsx:13 Raw input: Char: Alt, Code: AltLeft, Hex: 41
32index.tsx:13 Raw input: Char: 3, Code: Numpad3, Hex: 33
32index.tsx:13 Raw input: Char: 5, Code: Numpad5, Hex: 35
32index.tsx:13 Raw input: Char: 7, Code: Numpad7, Hex: 37
32index.tsx:13 Raw input: Char: 6, Code: Numpad6, Hex: 36
32index.tsx:13 Raw input: Char: 0, Code: Numpad0, Hex: 30
33index.tsx:13 Raw input: Char: Alt, Code: AltLeft, Hex: 41
33index.tsx:13 Raw input: Char: 2, Code: Numpad2, Hex: 32
33index.tsx:13 Raw input: Char: 6, Code: Numpad6, Hex: 36
33index.tsx:13 Raw input: Char: 4, Code: Numpad4, Hex: 34
33index.tsx:13 Raw input: Char: 1, Code: Numpad1, Hex: 31
33index.tsx:13 Raw input: Char: 2, Code: Numpad2, Hex: 32
34index.tsx:13 Raw input: Char: -, Code: Minus, Hex: 2d
71index.tsx:13 Raw input: Char: 0, Code: Digit0, Hex: 30
37index.tsx:13 Raw input: Char: 1, Code: Digit1, Hex: 31

尝试使用Alt+Numpad组合键方式 模拟输入,发现:
在微信中输入ASCII 编码 alt+35760显示中文 记
在网页中输入ASCII 编码 alt+35760显示乱码

出现不同环境显示差异的原因在于 Alt+Numpad输入模式的实现机制:
  • 微信:直接使用Windows系统的字符映射表(CP936/GBK)
  • 浏览器:遵循Unicode标准处理键盘事件
  • 35760的特殊性:实际对应十六进制 0x8BB0(即 "记" 的Unicode码点)
前端解码实现(React示例)
import { useEffect, useRef } from 'react';

/**
 * 特殊输入组件 - 处理Alt+Numpad方式的Unicode字符输入
 * 主要用于解决扫码枪等设备通过键盘模拟输入Unicode字符的场景
 */
const UnicodeInput = () => {
  // 获取输入框的DOM引用
  const inputRef = useRef<HTMLInputElement>(null);
  
  // 标记Alt键是否处于按下状态
  const altActive = useRef(false);
  
  // 存储通过小键盘输入的数字序列(用于组合Unicode码点)
  const codeBuffer = useRef<string[]>([]);

  useEffect(() => {
    /**
     * 处理键盘按下事件
     * @param e 键盘事件对象
     */
    const handleKeyDown = (e: KeyboardEvent) => {
      // 检测左Alt键按下(扫码枪输入通常以Alt键开始)
      if (e.key === 'Alt' && e.code === 'AltLeft') {
        altActive.current = true;  // 标记Alt键已按下
        codeBuffer.current = [];   // 清空之前的数字缓冲区
        e.preventDefault();       // 阻止默认的Alt键行为(如菜单激活)
        return;
      }

      // 当Alt键处于按下状态时,捕获小键盘的数字输入
      // 注意:必须使用Numpad数字键(右侧小键盘),主键盘数字键无效
      if (altActive.current && e.code.startsWith('Numpad')) {
        codeBuffer.current.push(e.key);  // 存储按下的数字键
        e.preventDefault();             // 阻止默认的数字输入行为
      }
    };

    /**
     * 处理键盘释放事件
     * @param e 键盘事件对象
     */
    const handleKeyUp = (e: KeyboardEvent) => {
      // 当Alt键释放时,处理之前记录的数字序列
      if (e.key === 'Alt' && altActive.current) {
        // 如果缓冲区有数字输入
        if (codeBuffer.current.length > 0) {
          // 将数字序列组合成十进制Unicode码点
          // 例如:输入3,5,7,6,0 → 35760 → "记"的Unicode码点
          const charCode = parseInt(codeBuffer.current.join(''));
          
          // 将码点转换为实际字符
          // 使用fromCodePoint而不是fromCharCode,支持更大的Unicode范围
          const char = String.fromCodePoint(charCode);
          
          // 将字符添加到输入框
          if (inputRef.current) {
            inputRef.current.value += char;
          }
        }
        
        // 重置状态
        altActive.current = false;
        codeBuffer.current = [];
        e.preventDefault();
      }
    };

    // 注册全局键盘事件监听
    window.addEventListener('keydown', handleKeyDown);
    window.addEventListener('keyup', handleKeyUp);
    
    // 组件卸载时清理事件监听
    return () => {
      window.removeEventListener('keydown', handleKeyDown);
      window.removeEventListener('keyup', handleKeyUp);
    };
  }, []);  // 空依赖数组表示只在组件挂载/卸载时执行

  // 渲染一个普通的文本输入框
  return <input ref={inputRef} type="text" />;
};
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容