android 安卓按键事件:长按和正常按(无法使其按需工作)

wfveoks0  于 2023-01-19  发布在  Android
关注(0)|答案(1)|浏览(129)

我正在尝试为我的电视应用程序创建一个左键按下操作。
我的遥控器有左/右向上和向下键
我想运行两个不同的功能时,正常按下和长按。
我正在尝试以下操作
如果我长按,它只是做正常按下的动作更多次。

@Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                if (event.isLongPress()) {
                    goBackward();
                    return true;
                }else{
                    goBackward2();
                }
                return true;
            default:
                return super.onKeyDown(keyCode, event);

我怎么能这么做。
也无法成功,如下所示

boolean leftDownLongPressed = false;

    boolean rightDownLongPressed = false;

    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int keyCode = event.getKeyCode();
        int action = event.getAction();

        switch (keyCode) {
            case KeyEvent.KEYCODE_DPAD_LEFT:
                if (action == KeyEvent.ACTION_DOWN && event.isLongPress()) {
                    goBackward();
                    leftDownLongPressed = true;
                    return true;
                }

                if (action == KeyEvent.ACTION_DOWN && !event.isLongPress()) {
                    if(!leftDownLongPressed){
                        goBackward2();
                        leftDownLongPressed=false;
                        return true;
                    }
                }
            default:
                return super.dispatchKeyEvent(event);
        }
    }
798qvoo8

798qvoo81#

更新日期(2023年1月18日)

由于OP更新了问题,并且他希望多个DPAD键具有相同的逻辑,因此我们需要记住所有按键开始时间,而不是单个按键。
所以解决方案很简单,因为它是根据前面的例子修改,只是替换示例变量mKeyDownStartTime到一个Map。

示例(在尝试下面的代码之前删除前面的示例实现)

...
    // An instance map var, key=${key code pressed}, value=${key down start time}
    Map<Integer, Long> mKeyIdToKeyDownStartTsMap = new HashMap<>();

    // Step 1: Pass the keyCode and action to keyEventAction()
    @Override
    public boolean dispatchKeyEvent(KeyEvent event) {
        int keyCode = event.getKeyCode();
        int action = event.getAction();
        
        keyEventAction(keyCode, action);
        
        return super.dispatchKeyEvent(event);
    }

    // Step 2: Switch between ACTION_DOWN and ACTION_UP, call corresponding methods
    private void keyEventAction(int keyCode, int action) {
        switch (action) {
            case KeyEvent.ACTION_DOWN:
                startKeyDown(keyCode);
                break;
            case KeyEvent.ACTION_UP:
                endKeyDown(keyCode);
                break;
        }
    }

    // Step 3: Logic for action down, just similar to previous but we will store the data to the instance map now
    private void startKeyDown(int key) {
        @Nullable Long keyDownStartTs = mKeyIdToKeyDownStartTsMap.get(key);
        if (keyDownStartTs == null) {
            keyDownStartTs = SystemClock.elapsedRealtime();
            Log.d(TAG, "startKeyDown: key down start, add data to map [ " +
                    "key=" + KeyEvent.keyCodeToString(key) +
                    ", value=" + keyDownStartTs +
                    " ]");

            mKeyIdToKeyDownStartTsMap.put(key, keyDownStartTs);
        }
        // Else keyDownStartTs already recorded for the DPAD key, ignore the logic here
    }

    // Step 4: Logic for action up
    private void endKeyDown(int key) {
        @Nullable Long keyDownStartTs = mKeyIdToKeyDownStartTsMap.get(key);
        if (keyDownStartTs != null) { // True indicates that the start key down time has been recorded for the [key]
            long endKeyDownTs = SystemClock.elapsedRealtime();

            // Remove the kvp in mapping to allow the start time can be set again in the map for the [key]
            mKeyIdToKeyDownStartTsMap.remove(key);

            long pressDuration = endKeyDownTs - keyDownStartTs;

            Log.d(TAG, "endKeyDown: [ keyPressDuration=" + pressDuration + " ]");

            if (pressDuration > 5000) {
                Log.d(TAG, "endKeyDown: LONG press of " + KeyEvent.keyCodeToString(key) + " detected");
            } else {
                Log.d(TAG, "endKeyDown: SHORT press of " + KeyEvent.keyCodeToString(key) + " detected");
            }
        }
        // Else keyDownStartTs has never been recorded for the key pressed, ignore the logic here
    }

日志目录

D/PlaygroundActivity: startKeyDown: key down start, add data to map [ key=KEYCODE_DPAD_LEFT, value=25132778 ]
D/PlaygroundActivity: endKeyDown: [ keyPressDuration=6963 ]
D/PlaygroundActivity: endKeyDown: LONG press of KEYCODE_DPAD_LEFT detected

D/PlaygroundActivity: startKeyDown: key down start, add data to map [ key=KEYCODE_DPAD_DOWN, value=26550861 ]
D/PlaygroundActivity: endKeyDown: [ keyPressDuration=2046 ]
D/PlaygroundActivity: endKeyDown: SHORT press of KEYCODE_DPAD_DOWN detected

D/PlaygroundActivity: startKeyDown: key down start, add data to map [ key=KEYCODE_DPAD_UP, value=26554383 ]
D/PlaygroundActivity: endKeyDown: [ keyPressDuration=1403 ]
D/PlaygroundActivity: endKeyDown: SHORT press of KEYCODE_DPAD_UP detected

通过观察,当按下DPAD键时,会调度多次按键事件(即离散的按键事件)
因此,为了检测长按KEY_CODE_DPAD_LEFT,你需要自己计算持续时间,然后确定按钮按下的时间对你来说是(例如,5秒)。
要计算持续时间,您需要检测:
1.什么时候有人按这个键
1.什么时候有人留下钥匙
我相信覆盖方法onKeyDownonKeyUp都有能力做到这一点,所以这里是我刚刚编写的一个示例。

示例

  • 要检测按键按下开始时间(KeyEvent.KEYCODE_DPAD_LEFT),我们需要一个示例变量
long mKeyDownStartTime = 0;
    
    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
            startKeyDown(SystemClock.elapsedRealtime());
        }
        return super.onKeyDown(keyCode, event);
    }

    private void startKeyDown(long startKeyDownTime) {
        if (mKeyDownStartTime == 0) { // this is added to prevent identical discrete key down event reset the value
            mKeyDownStartTime = startKeyDownTime;
        }
    }
  • 要计算按键释放事件发生时的按键释放持续时间
@Override
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
            endKeyDown(SystemClock.elapsedRealtime());
        }
        return super.onKeyUp(keyCode, event);
    }

    private void endKeyDown(long endKeyDownTime) {
        long pressDuration = endKeyDownTime - mKeyDownStartTime;
        mKeyDownStartTime = 0; // reset to zero to allow startKeyDown() set the value in again
        Log.d(TAG, "endKeyDown: [ keyPressDuration=" + pressDuration + " ]");

        if (pressDuration > 5000) {
            Log.d(TAG, "endKeyDown: LONG press of DPAD_LEFT detected");
        } else {
            Log.d(TAG, "endKeyDown: SHORT press of DPAD_LEFT detected");
        }
    }

相关问题