解决安卓键盘按键输入和扫码输入冲突问题

贴代码,扫码枪解析类:

import android.annotation.SuppressLint;
import android.os.Handler;
import android.view.KeyEvent;
import java.lang.reflect.Field;

/**
 * 扫码枪事件解析类
 */
public class ScanGunKeyEventHolder {

    //延迟500ms,判断扫码是否完成。
    private final static long MESSAGE_DELAY = 200;
    private final static long BAN_INPUT_DURATION = 1000; //禁止输入时间
    private boolean mAllow = true;
    //扫码内容
    private final StringBuffer mStringBufferResult = new StringBuffer();
    //大小写区分
    private boolean isShift;
    private OnScanSuccessListener mOnScanSuccessListener;
    private final Handler mHandler = new Handler();

    private EventRunnable mScanningFishedRunnable;

    private final Runnable mAllowInputRunnable = () -> mAllow = true;

    public boolean analysisKeyEvent(KeyEvent event) {

        int keyCode = event.getKeyCode();
        //字母大小写判断
        checkLetterStatus(event);
        if (event.getAction() == KeyEvent.ACTION_UP) {

            char aChar = getInputCode(event);

            if (aChar != 0) {
                mStringBufferResult.append(aChar);
            }

            mScanningFishedRunnable = new EventRunnable(event);

            if (keyCode == KeyEvent.KEYCODE_ENTER) {
                //若为回车键,直接返回
                mHandler.removeCallbacks(mScanningFishedRunnable);
                mHandler.post(mScanningFishedRunnable);
            } else {
                //延迟post,若500ms内,有其他事件
                mHandler.removeCallbacks(mScanningFishedRunnable);
                mHandler.postDelayed(mScanningFishedRunnable, MESSAGE_DELAY);
            }
            return true;
        }
        return false;
    }

    //检查shift键
    private void checkLetterStatus(KeyEvent event) {
        int keyCode = event.getKeyCode();
        if (keyCode == KeyEvent.KEYCODE_SHIFT_RIGHT || keyCode == KeyEvent.KEYCODE_SHIFT_LEFT) {
            //按着shift键,表示大写
            //松开shift键,表示小写
            isShift = event.getAction() == KeyEvent.ACTION_DOWN;
        }
    }


    //获取扫描内容
    private char getInputCode(KeyEvent event) {

        int keyCode = event.getKeyCode();

        //其他符号
        switch (keyCode) {

            //数字键10个 + 符号10个
            case KeyEvent.KEYCODE_0: return isShift ? ')' : '0';
            case KeyEvent.KEYCODE_1: return isShift ? '!' : '1';
            case KeyEvent.KEYCODE_2: return isShift ? '@' : '2';
            case KeyEvent.KEYCODE_3: return isShift ? '#' : '3';
            case KeyEvent.KEYCODE_4: return isShift ? '$' : '4';
            case KeyEvent.KEYCODE_5: return isShift ? '%' : '5';
            case KeyEvent.KEYCODE_6: return isShift ? '^' : '6';
            case KeyEvent.KEYCODE_7: return isShift ? '&' : '7';
            case KeyEvent.KEYCODE_8: return isShift ? '*' : '8';
            case KeyEvent.KEYCODE_9: return isShift ? '(' : '9';

            //字母键26个小写 + 26个大写
            case KeyEvent.KEYCODE_A: return isShift ? 'A' : 'a';
            case KeyEvent.KEYCODE_B: return isShift ? 'B' : 'b';
            case KeyEvent.KEYCODE_C: return isShift ? 'C' : 'c';
            case KeyEvent.KEYCODE_D: return isShift ? 'D' : 'd';
            case KeyEvent.KEYCODE_E: return isShift ? 'E' : 'e';
            case KeyEvent.KEYCODE_F: return isShift ? 'F' : 'f';
            case KeyEvent.KEYCODE_G: return isShift ? 'G' : 'g';
            case KeyEvent.KEYCODE_H: return isShift ? 'H' : 'h';
            case KeyEvent.KEYCODE_I: return isShift ? 'I' : 'i';
            case KeyEvent.KEYCODE_J: return isShift ? 'J' : 'j';
            case KeyEvent.KEYCODE_K: return isShift ? 'K' : 'k';
            case KeyEvent.KEYCODE_L: return isShift ? 'L' : 'l';
            case KeyEvent.KEYCODE_M: return isShift ? 'M' : 'm';
            case KeyEvent.KEYCODE_N: return isShift ? 'N' : 'n';
            case KeyEvent.KEYCODE_O: return isShift ? 'O' : 'o';
            case KeyEvent.KEYCODE_P: return isShift ? 'P' : 'p';
            case KeyEvent.KEYCODE_Q: return isShift ? 'Q' : 'q';
            case KeyEvent.KEYCODE_R: return isShift ? 'R' : 'r';
            case KeyEvent.KEYCODE_S: return isShift ? 'S' : 's';
            case KeyEvent.KEYCODE_T: return isShift ? 'T' : 't';
            case KeyEvent.KEYCODE_U: return isShift ? 'U' : 'u';
            case KeyEvent.KEYCODE_V: return isShift ? 'V' : 'v';
            case KeyEvent.KEYCODE_W: return isShift ? 'W' : 'w';
            case KeyEvent.KEYCODE_X: return isShift ? 'X' : 'x';
            case KeyEvent.KEYCODE_Y: return isShift ? 'Y' : 'y';
            case KeyEvent.KEYCODE_Z: return isShift ? 'Z' : 'z';

            //符号键11个 + 11个
            case KeyEvent.KEYCODE_COMMA: return isShift ? '<' : ',';
            case KeyEvent.KEYCODE_PERIOD: return isShift ? '>' : '.';
            case KeyEvent.KEYCODE_SLASH: return isShift ? '?' : '/';
            case KeyEvent.KEYCODE_BACKSLASH: return isShift ? '|' : '\\';
            case KeyEvent.KEYCODE_APOSTROPHE: return isShift ? '\"' : '\'';
            case KeyEvent.KEYCODE_SEMICOLON: return isShift ? ':' : ';';
            case KeyEvent.KEYCODE_LEFT_BRACKET: return isShift ? '{' : '[';
            case KeyEvent.KEYCODE_RIGHT_BRACKET: return isShift ? '}' : ']';
            case KeyEvent.KEYCODE_GRAVE: return isShift ? '~' : '`';
            case KeyEvent.KEYCODE_EQUALS: return isShift ? '+' : '=';
            case KeyEvent.KEYCODE_MINUS: return isShift ? '_' : '-';
            default: return 0;
        }
    }

    public interface OnScanSuccessListener {
        void onScanSuccess(KeyEvent event, String code, boolean isScan);
    }

    public void setOnBarCodeCatchListener(OnScanSuccessListener onScanSuccessListener) {
        mOnScanSuccessListener = onScanSuccessListener;
    }

    public void onDestroy() {
        mHandler.removeCallbacks(mScanningFishedRunnable);
        mOnScanSuccessListener = null;
    }

    class EventRunnable implements Runnable {

        private final KeyEvent event;

        public EventRunnable(KeyEvent event){
            this.event = event;
        }

        @Override
        public void run() {

            String barcode = mStringBufferResult.toString();

            if (barcode.length()>2 && mAllow) {
                if (mOnScanSuccessListener != null) mOnScanSuccessListener.onScanSuccess(event, barcode, true);
                mAllow = false; //每次扫码完成500ms内禁止输入
                mHandler.postDelayed(mAllowInputRunnable, BAN_INPUT_DURATION);
                mStringBufferResult.setLength(0);
                return;
            }

            Class clazz = event.getClass();
            try {
                @SuppressLint("DiscouragedPrivateApi")
                Field field = clazz.getDeclaredField("mAction");
                field.setAccessible(true);
                field.setInt(event, KeyEvent.ACTION_DOWN);
            } catch (NoSuchFieldException | IllegalAccessException e) {
                e.printStackTrace();
            }

            if (mOnScanSuccessListener != null && mAllow) mOnScanSuccessListener.onScanSuccess(event, barcode.toUpperCase(), false);
            mStringBufferResult.setLength(0);
        }
    }

}

Activity调用:

private val scanGunKeyEventHolder = ScanGunKeyEventHolder()
    
scanGunKeyEventHolder.setOnBarCodeCatchListener { event, code, isScan ->
            "".log("code $code isScan $isScan")
            if (isScan) submitOrder(code)
            else super.dispatchKeyEvent(event)
        }
    
override fun dispatchKeyEvent(event: KeyEvent?): Boolean {
        if (event!!.action==KeyEvent.ACTION_UP) if (!scanGunKeyEventHolder.analysisKeyEvent(event)) return super.dispatchKeyEvent(event)
        return true
    }

这个是我修改之后的解析类,主要实现思路是,判断一段时间内读取到的输入字符长度,大于2个的时候判定为扫码输入,少于2的时候,判定为单个按键输入。为什么检测是2个,而不是1个?因为用户可能在一段时间内按得很快,如果是1就会增加误判的几率。在按键分发这里,当按键松开的时候,再把KeyEvent传入analysisKeyEvent(event),进行解析。为什么是松开的时候呢?因为会有一种情况是用户一直按着按键,那么一段时间内读到的KeyEvent就非常多,那么在判断是扫码还是单个按键输入的时候就会误以为是扫码进行来的。最后是回调接口这里,如果是单个按键,那么希望是直接输入到ExitText框内,而传入KeyEvent进来解析的是已经松开的时的按键状态,所以这里需要用反射把action改为KeyEvent.ACTION_DOWN。回调接口实现这里,判断如果时扫描的,那么就调用功能逻辑,如果不是,就调用分发按键事件,交给系统处理,这样就可以实现按键输入到输入框。

你可能感兴趣的:(解决安卓键盘按键输入和扫码输入冲突问题)