最近做了一个Android外接USB读卡器刷手环读取数据,模拟键盘输入事件的项目;

借鉴了https://github.com/githubRonda/BarcodeScanner

连接电子牌板子调试,可以将板子上OTG跳帽取下,然后用一根双USB口的线连接电脑就可以调试了(ps:板子上一般连接靠近网线的USB口)

因为之前公司的Android系统的电子牌的读卡器是通过串口开发的,最近由于换了电子牌的厂商,手环读取方式也更改了,无奈研究了一番,从网上找了相关文章,但是没有找到具体的,其中根据某个大神的外接扫码器的项目,结合实际终于实现了;

不管外接扫码枪还是外接读卡器,其实原理就我了解的原理是一样的,都是会将扫描到或者刷卡读取到的数据模拟成键盘输入的事件,你会发现,当Android界面有一个焦点输入框时候,扫码或者刷卡,数据都会自动填充输入框, 那问题也随之而来,我们需要做的其实就是监听按键输入事件,然后获取扫到或者读取到的数据,之后进行一些其他方面的操作.

回归正文:

后台无障碍服务AccessibilityService配置

import android.accessibilityservice.AccessibilityService;
import android.util.Log;
import android.view.KeyEvent;
import android.view.accessibility.AccessibilityEvent;/*** Created by Administrator on 2019/4/22.*/
public class ReadCardService extends AccessibilityService {private static final String TAG = ReadCardService.class.getSimpleName();@Overridepublic void onAccessibilityEvent(AccessibilityEvent event) {Log.e(TAG, "onAccessibilityEvent --> " + event);}@Overridepublic void onInterrupt() {Log.e(TAG, "onInterrupt");}/*** 复写这个方法可以捕获按键事件** @param event* @return*/@Overrideprotected boolean onKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();Log.e(TAG, "keyEvent:" + event + "keyCode: " + keyCode + "char: " + KeyEvent.keyCodeToString(keyCode));return super.onKeyEvent(event);}
}

在AndroidManifest.xml文件中记得配置

<serviceandroid:name=".readService.ReadCardService"android:enabled="true"android:exported="true"android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"><intent-filter><action android:name="android.accessibilityservice.AccessibilityService"/></intent-filter><meta-dataandroid:name="android.accessibilityservice"android:resource="@xml/accessibility"/></service>

res目录下创建xml文件夹,并在xml文件夹内创建accessibility.xml文件内容如下

<?xml version="1.0" encoding="utf-8"?>
<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"android:accessibilityEventTypes="typeAllMask"android:accessibilityFeedbackType="feedbackGeneric"android:accessibilityFlags="flagRequestFilterKeyEvents"android:canRetrieveWindowContent="true"android:canRequestFilterKeyEvents="true"android:description="@string/accessibility_description"android:packageNames="com.xxx.xxxdemo你的项目包名"/>accessibility_description在res的values文件夹内strings中设置你想要说明的,例如
<string name="accessibility_description">xxx按键监听的无障碍辅助服务</string>

ReadCardUtils工具类

import android.content.Context;
import android.content.res.Configuration;
import android.os.Handler;
import android.util.Log;
import android.view.InputDevice;
import android.view.KeyEvent;/*** Created by Administrator on 2019/4/22.** 使用说明:*  * 1. 在Activity中先创建ReadCardUtils对象,并设置扫码成功监听器: setReadSuccessListener() [一般在onCreate()方法中初始化]*  * 2. 接着在Activity#dispatchKeyEvent() 或者 Activity#onKeyDown() 中调用本类中的resolveKeyEvent()方法。当扫码结束之后,会自动回调第一步设置的监听器中的方法*  **  * 原理分析:*  * 1. 扫码枪就是一个外部的输入设备(和键盘一样)。扫码的时候,就是在极短的时间内输入了一系列的数字或字母*  * 2. 这样就可以在键盘事件中抓捕这些输入的字符,但是又会产生一个问题(快速扫两次的情形):在键盘事件中应该抓捕多少个字符呢?即一个条码应该在哪个位置结束呢? (有的扫码枪会以一个回车或者换行作为一次扫码的结束符,但是有的就纯粹的是一系列的条码。这个得需要设置)*  * 所以为了兼容性,应当是当短时间内不再输入字符的时候,就表示扫码已结束。这样只能定性描述,不能定量,只能自己在程序中用一个具体的数字来表示这个“短时间”,eg:500ms。(如果每个条码结束的时候都有一个结束符那该多好,直接判断这个结束符,就可以知道当前扫码已完成)*  **  * 接下来就产生了ReadCardUtils这个类。*  * 核心原理就一句话:在Activity的键盘监听事件中,每抓捕到一个字符的时候,就先向 Handler 一次一个runnable对象,再延迟500ms发送一个runnable. 这样若两个输入字符的间隔时间超过了500ms,则视为两次扫码**/
public class ReadCardUtils {private static final String TAG = ReadCardUtils.class.getSimpleName();// 若500ms之内无字符输入,则表示扫码完成. (若觉得时间还长,则可以设置成更小的值)private final static long MESSAGE_DELAY = 500;private boolean mCaps;//大写或小写private StringBuilder mResult = new StringBuilder();//扫码内容private OnReadSuccessListener mOnReadSuccessListener;private Handler mHandler = new Handler();private final Runnable mReadingEndRunnable = new Runnable() {@Overridepublic void run() {performScanSuccess();}};//调用回调方法private void performScanSuccess() {String barcode = mResult.toString();//Log.i(TAG, "performScanSuccess -> barcode: "+barcode);if (mOnReadSuccessListener != null) {mOnReadSuccessListener.onScanSuccess(barcode);}mResult.setLength(0);}//key事件处理public void resolveKeyEvent(KeyEvent event) {int keyCode = event.getKeyCode();checkLetterStatus(event);//字母大小写判断Log.w(TAG, "keyEvent:" + event + "keyCode: " + keyCode + "char: " + KeyEvent.keyCodeToString(keyCode));if (event.getAction() == KeyEvent.ACTION_DOWN) {char aChar = getInputCode(event);Log.w(TAG, "aChar: " + aChar);if (aChar != 0) {mResult.append(aChar);}if (keyCode == KeyEvent.KEYCODE_ENTER) {//若为回车键,直接返回mHandler.removeCallbacks(mReadingEndRunnable);mHandler.post(mReadingEndRunnable);} else {//延迟post,若500ms内,有其他事件mHandler.removeCallbacks(mReadingEndRunnable);mHandler.postDelayed(mReadingEndRunnable, MESSAGE_DELAY);}}}//检查shift键private void checkLetterStatus(KeyEvent event) {int keyCode = event.getKeyCode();if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT) {if (event.getAction() == KeyEvent.ACTION_DOWN) {//按着shift键,表示大写mCaps = true;} else {//松开shift键,表示小写mCaps = false;}}}//获取扫描内容private char getInputCode(KeyEvent event) {int keyCode = event.getKeyCode();char aChar;if (keyCode >= KeyEvent.KEYCODE_A && keyCode <= KeyEvent.KEYCODE_Z) {//字母aChar = (char) ((mCaps ? 'A' : 'a') + keyCode - KeyEvent.KEYCODE_A);} else if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {//数字aChar = (char) ('0' + keyCode - KeyEvent.KEYCODE_0);} else {//其他符号switch (keyCode) {case KeyEvent.KEYCODE_PERIOD:aChar = '.';break;case KeyEvent.KEYCODE_MINUS:aChar = mCaps ? '_' : '-';break;case KeyEvent.KEYCODE_SLASH:aChar = '/';break;case KeyEvent.KEYCODE_BACKSLASH:aChar = mCaps ? '|' : '\\';break;default:aChar = 0;break;}}return aChar;}/*** 检测输入设备是否是读卡器** @param context* @return 是的话返回true,否则返回false*/public static boolean isInputFromReader(Context context, KeyEvent event) {if (event.getDevice() == null) {return false;}
//        event.getDevice().getControllerNumber();if (event.getKeyCode() == KeyEvent.KEYCODE_BACK || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_DOWN || event.getKeyCode() == KeyEvent.KEYCODE_VOLUME_UP) {//实体按键,若按键为返回、音量加减、返回falsereturn false;}if (event.getDevice().getSources() == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD | InputDevice.SOURCE_CLASS_BUTTON)) {//虚拟按键返回falsereturn false;}Configuration cfg = context.getResources().getConfiguration();return cfg.keyboard != Configuration.KEYBOARD_UNDEFINED;}public interface OnReadSuccessListener {void onScanSuccess(String barcode);}public void setReadSuccessListener(OnReadSuccessListener onReadSuccessListener) {mOnReadSuccessListener = onReadSuccessListener;}public void removeScanSuccessListener() {mHandler.removeCallbacks(mReadingEndRunnable);mOnReadSuccessListener = null;}}

在你的MainActivity类中

声明读取工具类ReadCardUtils服务,并在合适的位置初始化

    //U口读卡器,类似于外接键盘private ReadCardUtils readCardUtils;

初始化

    //读卡器声明readCardUtils = new ReadCardUtils();initCardReader();
 /*** 读卡器初始化*/private void initCardReader() {readCardUtils.setReadSuccessListener(new ReadCardUtils.OnReadSuccessListener() {@Overridepublic void onScanSuccess(String barcode) {Log.e(TAG, "barcode: " + barcode);}});}@Overridepublic boolean dispatchKeyEvent(KeyEvent event) {if (ReadCardUtils.isInputFromReader(this, event)) {if (readCardUtils != null){readCardUtils.resolveKeyEvent(event);}}return super.dispatchKeyEvent(event);}
    @Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) {return super.onKeyDown(keyCode, event);}@Overrideprotected void onDestroy() {readCardUtils.removeScanSuccessListener();readCardUtils = null;super.onDestroy();}

Android电子牌外接USB读卡器读取内容模拟键盘事件相关推荐

  1. 身份证读取设备开发解决方案:2、Android下通过usb转串口读取身份证信息

    身份证读取设备开发解决方案:2.Android下通过usb转串口读取身份证信息 文章目录 身份证读取设备开发解决方案:2.Android下通过usb转串口读取身份证信息 1. 前言 2. 准备 3. ...

  2. 高通android usb otg,Android OTG支持USB读卡器

    我们知道,三星Android手机将USB读卡器通过OTG线插入Micro USB插口后,插拔读卡器里的SD卡,文件管理器也能够识别卡的插拔:而很多手机的OTG连上USB读卡器也来插拔SD卡,会发现文件 ...

  3. uinput 用法 android 上层使用uinput 的用法来模拟 input 事件

    android 上层使用uinput 的用法来模拟 input 事件 #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif#include <stdio. ...

  4. selenium 模拟键盘事件 复制粘贴、右键、回车等

    [selenium 模拟键盘事件 复制粘贴.右键.回车等] #coding=utf-8 ''' selenium ''' from selenium import webdriver as wd im ...

  5. 【键盘】jQuery+CSS3模拟键盘事件(精)

    jQuery+CSS3模拟键盘事件是一款基于jQuery的模拟键盘事件的应用,键盘上除了功能键,其他键都可以用这款插件来模拟.当你敲击键盘上的键时,这款应用会帮助你获取到这个键的事件,并在页面上的模拟 ...

  6. 初识 jquery.simulate.js 模拟键盘事件

    用jquery 和 jquery.simulate.js 实现模拟键盘事件,点击上下左右div相当于点击键盘的上下左右键 <!DOCTYPE html> <html><h ...

  7. web自动化测试第7步:模拟键盘事件(Keys)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/CCGGAAG/article/deta ...

  8. JAVA usb发卡器_USB模拟键盘输出发卡器

    原标题:USB模拟键盘输出发卡器 1.1 产品简介 广州盛炬智能科技的发卡器FC2-A是一款模拟键盘输出发卡器,采用USB无驱安装,即插即用,通过刷卡方式,卡片数据直接输出到电脑桌面光标处.支持读取M ...

  9. Web自动化测试:模拟键盘事件(Keys)

    如何使用引入的common.keys库来模拟键盘来操控浏览器 一.基础写法 具体用法其实和我们之前对浏览器输入框所用的方法:send_keys()是一样的,只不过我们通过keys类,可以输入webdr ...

最新文章

  1. Linux系统文件目录
  2. “深度学习不能拿来乱用”,Nature论文引发激烈争论
  3. zabbix监控利用Python脚本发邮件
  4. quasar_Quasar和Akka –比较
  5. no value specified for java.sql.date,求助No value specified for parameter 2
  6. 基于OpenCV实现图像平移
  7. java eight,Java语法基础学习DayEight
  8. 一个.NET通用JSON解析/构建类的实现(c#)
  9. [转]Http Message结构学习总结
  10. vm centos 网络配置
  11. CuteFtp通用注册码
  12. HDU1862 FLY
  13. 《明朝那些事儿》读后感
  14. 我本可以忍受黑暗,如果我不曾见过太阳。
  15. 前端js面试题(高级)
  16. 纯纯的爬虫知识,python scrapy 下载中间件知多少
  17. Winform中给下拉框(ComboBox或LookUpEdit)添加内容
  18. three.js例子
  19. 电磁元件(电阻,电容与电感)
  20. HTML+CSS大作业:购物商城网页设计与实现——手机主题网站

热门文章

  1. 《带你体验程序员专属编辑器Markdown编辑器|CSDN编辑器测评》
  2. ChatGPT国内怎么用?官网实在太麻烦了,ChatGPT可以直接国内使用吗?
  3. C:\Users\123\AppData\Roaming\Python\Python38\Scripts which is not on PATH
  4. Google大神每天写多少行代码?真相让你吃惊!
  5. 基于主定理以及递推树求解递归算法的时间复杂度
  6. 荣耀猎人游戏本散热怎么样?测试一下就知道
  7. J2ME平台的的RPG游戏开发历程(1)-盘古开天辟地,j2me创造游戏世界
  8. 电子元器件行业B2B交易系统:规范企业交易流程,提升销售管理效率
  9. 【转贴】百度贴吧成就一段姻缘!一句被五重密码保护的表白破译全记录
  10. vue.runtime.esm.js?2b0e:619 [Vue warn]: Error in v-on handler (Promise/async): “Error: 失败“found in