Android 扫码枪 读取(外接键盘读取)

本文详细探讨了在Android设备上如何处理和拦截外接扫码枪的输入事件,尤其是在没有EditText界面的情况下。通过分析扫码枪与外接键盘的工作原理,对比软键盘的输入事件,提供了在Activity中重写dispatchKeyEvent方法的具体策略,以实现对扫码枪事件的有效管理和利用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、概述

android 设备外接一个 标准扫码枪,要把扫码枪扫到的内容取出来。界面上放一个EditTextView 直接就把内容显示到EditTextView中了。 然而有些界面上并不能摆EditTextView 。针对没有EditTextView的界面展开下文。扫码枪和外接键盘原理是一样的,类比,也特意拿了个外接键盘一起调研了。

2、扫码枪-输入设备

项目中使用的是标准的扫码枪(实验的是新大陆的NLS-FR40),标准的意思就是它都不给开发文档。查了下说是走的标准“输入事件”,和外接键盘是一样的。既然是输入事件,就掐Activity 的 dispatchKeyEvent 方法了。

    public boolean dispatchKeyEvent(KeyEvent event) {

扫码枪在识别到扫的码后,会多一个KEYCODE_ENTER,和KEYCODE_DPAD_DOWN 事件,查阅的资料里都有说到KEYCODE_ENTER,没提到KEYCODE_DPAD_DOWN,也不知道其它扫码枪会不会生成这个事件

3、实验结果

在Activity 的dispatchKeyEvent 方法中把 KeyEvent log 打印了下:(只打出action=ACTION_UP 躺起的log,按下action=ACTION_DOWN 是结队的 忽略)

  • 3.1、android 设备软键盘的log
    在这里插入图片描述

  • 3.2、外接扫码枪的log (新大陆的NLS-FR40)
    在这里插入图片描述

  • 3.2、外接键盘的log (普通的键盘)
    在这里插入图片描述
    这里附一句,若小键盘的num按钮锁住,metaState= meta_num_lock_on

对比结论小结:

  1. 标准外接扫描枪和标准外接键盘是类似的输入设备
  2. 自带软件盘的输入事件里,deviceId,source,scanCode,flag 和外接的设备不同
  3. 扫码枪和外接键盘的 deviceId,source 不同

4、查看KeyEvent源码进行比较

简单的查看下keyEvent 的源码,可以明显的看到,设备的虚拟软键盘是把deiveId=KeyCharacterMap.VIRTUAL_KEYBOARD (-1),写死了,所以取该字段的不同来区分是软键盘还是 外接键盘。 目前不打算区分扫描枪和外接键盘。

     * Create a new key event.
     *
     * @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
     * at which this key code originally went down.
     * @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
     * at which this event happened.
     * @param action Action code: either {@link #ACTION_DOWN},
     * {@link #ACTION_UP}, or {@link #ACTION_MULTIPLE}.
     * @param code The key code.
     * @param repeat A repeat count for down events (> 0 if this is after the
     * initial down) or event count for multiple events.
     */
    public KeyEvent(long downTime, long eventTime, int action,
                    int code, int repeat) {
        mDownTime = downTime;
        mEventTime = eventTime;
        mAction = action;
        mKeyCode = code;
        mRepeatCount = repeat;
        mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
    }

    

    /**
     * Create a new key event.
     *
     * @param downTime The time (in {@link android.os.SystemClock#uptimeMillis})
     * at which this key code originally went down.
     * @param eventTime The time (in {@link android.os.SystemClock#uptimeMillis})
     * at which this event happened.
     * @param action Action code: either {@link #ACTION_DOWN},
     * {@link #ACTION_UP}, or {@link #ACTION_MULTIPLE}.
     * @param code The key code.
     * @param repeat A repeat count for down events (> 0 if this is after the
     * initial down) or event count for multiple events.
     * @param metaState Flags indicating which meta keys are currently pressed.
     * @param deviceId The device ID that generated the key event.
     * @param scancode Raw device scan code of the event.
     */
    public KeyEvent(long downTime, long eventTime, int action,
                    int code, int repeat, int metaState,
                    int deviceId, int scancode) {
        mDownTime = downTime;
        mEventTime = eventTime;
        mAction = action;
        mKeyCode = code;
        mRepeatCount = repeat;
        mMetaState = metaState;
        mDeviceId = deviceId;
        mScanCode = scancode;
    }

5、拦截策略

需要一点android “事件传递” 的基础知识,面试必备知识。以前也记录过:Android 事件传递与焦点处理(tv)
在Activity 中事件传递,特别是按键的拦截其实很方便,重写dispatchKeyEvent 方法就可以了。重写的思路也很简单:判断是不是扫描枪用deviceId == -1 来判断。
伪代码

   public boolean dispatchKeyEvent(KeyEvent event) {
        Log.d(TAG, "event= " + event);

        if (如果是扫描枪的事件) {
         //直接消费掉,不继续向下传,editTextView也不自动填充了,KEYCODE_ENTER 事件也不影响 其它控件了,比如button 的点击事件
            return true;
        }

        return super.dispatchKeyEvent(event);
    }

实际使用中,往往没有这么暴力,比如要对是否完全拦截进行控制,单独封装管理工具类,这些属于封装技巧了,在章末有简单封装

     * 处理输入事件
     *
     * @param event
     * @return true 表示消费掉,拦截不在传递, false 不管
     */
    public boolean dispatchKeyEvent(KeyEvent event) {

        /**
         * 系统的软键盘  按下去是 -1, 不管,不拦截
         */
        if (event.getDeviceId() == -1) {
            return false;
        }

        //按下弹起,识别到弹起的话算一次 有效输入
        //只要是 扫码枪的事件  都要把他消费掉 不然会被editText 显示出来
        if (event.getAction() == KeyEvent.ACTION_UP) {

            //只要数字,一维码里面没有 字母
            int code = event.getKeyCode();
            if (code >= KeyEvent.KEYCODE_0 && code <= KeyEvent.KEYCODE_9) {

                codeStr += (code - KeyEvent.KEYCODE_0);
            }

            //识别到结束,当下使用的设备是  是还会有个KEYCODE_DPAD_DOWN 事件,不知道其它设备有没有  先忽略
            if (code == KeyEvent.KEYCODE_ENTER) {

                if (listener != null) {
                    listener.onResult(codeStr);
                    codeStr = "";
                }
            }

        }
        //都是扫码枪来的事件,选择消费掉

        return isInterrupt;
    }

6、其它处理

项目需要外接扫码枪,扫码枪有几种模式:

  1. 短按触发扫码,松开停止
  2. 短按触发,连续扫码
  3. 感应触发,超时停止 (项目中会用这种方式)

描述这个的原因是,会涉及不相关界面的误操作,比如在x界面,我们去扫码了。如果不处理会导致KEYCODE_ENTER 会响应该界面中的某个按钮点击事件,造成干扰。so 我们需要在这个项目的基类BaseActivity 中对扫码枪的输入事件进行处理。目前我打算使用的处理策略是,BaseActivity 完全拦截扫码枪事件,需要使用到的界面自行打开。这边的处理算封装上的处理就不熬述了,具体见demo代码

7、付例与参考

注:

AccessibilityService 的方式,需要手动在:设置->无障碍->服务,中开启,需要人力培训交互不够友好放弃了

参考:

[1]、https://stackoverflow.com/questions/11349542/handle-barcode-scanner-value-via-android-device
[2]、https://blog.csdn.net/csdnno/article/details/79639426

工程demo

代码:https://github.com/lckj686/BarcodeScannerGunMaster

<think>嗯,用户问的是扫码枪根据回车事件读取数据,我需要详细解释这个过程。首先,得理解扫码枪的工作原理,它其实相当于一个输入设备,模拟键盘输入。当用户扫描条码时,扫码枪会快速将条码内容转换为字符,并自动加上回车键。这样,系统就能通过监听回车事件来获取数据。 接下来要考虑的是实现方式。不同的平台可能有不同的方法,比如在Web前端,可能需要用JavaScript监听键盘事件,检测回车键的按下,然后获取之前输入的内容。需要注意的是,扫码枪输入速度很快,所以可能会有多个字符在短时间内输入,需要处理输入间隔的问题,确保正确捕获完整的条码。 然后,在桌面应用程序中,比如Windows或macOS,可能需要使用特定的API来监听键盘事件,或者直接读取输入缓冲区。这里要提到不同操作系统的处理方式可能不同,但核心思路是一致的:捕获回车事件并获取之前的输入内容。 还要考虑一些常见的问题和解决方案,比如防止重复扫描,可以通过去重或者时间间隔控制。另外,输入延迟的问题,需要设置合适的等待时间,确保所有字符都被接收后再处理。还有,不同扫码枪的配置可能不同,比如是否需要自动添加回车,用户可能需要根据设备手册进行配置。 最后,给出一个简单的示例代码,比如用JavaScript实现监听回车事件,并在控制台输出扫描结果。同时提醒用户在实际应用中要考虑错误处理和兼容性,确保不同设备和浏览器的正常工作。 整个思考过程中需要确保逻辑清晰,分步骤解释,让用户能够理解从扫码枪的工作原理到具体实现的每个环节。同时,语言要口语化,避免使用过于专业的术语,让不同技术背景的用户都能明白。</think>扫码枪通过“回车事件”读取数据的过程及原理如下,我分步骤为你解释: 1. **工作原理** - 扫码枪本质是模拟键盘输入的光学识别设备 - 扫描时自动完成三个动作: ▸ 光电识别条码/二维码 ▸ 将图形转换为对应字符 ▸ 自动追加回车键(Enter)作为结束符 2. **事件触发机制** ```javascript // 示例:Web端监听实现 let buffer = ''; document.addEventListener('keypress', (e) => { if(e.key === 'Enter') { console.log('扫描结果:', buffer); buffer = ''; // 清空缓存 } else { buffer += e.key; // 累积字符 } }); ``` 3. **关键实现要点** - **输入间隔检测**:需设置50-100ms超时判定(扫码枪输入速度通常在30ms/字符) - **防抖处理**:避免真实键盘输入的干扰 - **特殊字符处理**:应对二维码可能包含的换行符(\n)、Tab(\t)等控制字符 4. **不同平台的适配方案** | 平台 | 实现方式 | 注意事项 | |-----------|-------------------------------|---------------------------| | Web浏览器 | 监听keydown/keypress事件 | 需处理中文输入法兼容性问题 | | Windows | 使用ReadFile读取HID设备原始数据 | 需要驱动支持或配置为键盘模拟模式 | | Android | 使用onKeyMultiple监听快速输入 | 需区分物理键盘扫码枪输入 | | iOS | 外接扫码枪需MFi认证,推荐使用原生SDK集成 | 系统限制较多,建议使用专业扫码库 | 5. **常见问题排查** - **数据不完整**:检查扫码枪是否设置为自动追加回车 - **重复扫描**:添加时间戳校验(如:500ms内禁止重复提交) - **字符乱码**:调整扫码枪的输出编码(UTF-8/GBK等) - **响应延迟**:优化输入缓冲区处理逻辑,避免使用同步阻塞代码 实际项目中推荐结合以下优化策略: 1. 添加起始符/终止符校验(如:]C1前缀) 2. 实现自动焦点控制(扫描时自动聚焦到输入框) 3. 采用WebSocket保持长连接(适用于高频扫描场景) 4. 数据加密验证(防止恶意伪造扫码请求) 示例:完整的工业级实现逻辑 ```javascript class BarcodeScanner { constructor() { this.buffer = ''; this.timer = null; this.TIMEOUT = 100; // 单位:毫秒 document.addEventListener('keydown', (e) => { if(e.key === 'Enter') { this.handleComplete(); return; } // 数字/字母的直接处理 if(e.key.length === 1) { this.buffer += e.key; this.resetTimer(); } }); } handleComplete() { if(this.buffer.length > 0) { console.log('Decoded:', this.validateBarcode(this.buffer)); this.buffer = ''; } } resetTimer() { clearTimeout(this.timer); this.timer = setTimeout(() => { if(this.buffer.length > 0) { console.warn('Timeout:', this.buffer); this.buffer = ''; } }, this.TIMEOUT); } validateBarcode(code) { // 实现校验逻辑(如:校验位计算、格式验证等) return code.replace(/[^\w-]/g, ''); // 示例:过滤特殊字符 } } ``` 这种实现方式能有效区分人工键盘输入和扫码枪输入(通过输入速度判断),同时具备异常输入处理能力。对于需要高安全性的场景,建议增加硬件校验环节,如通过USB HID接口直接读取设备信息。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值