Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 29215257 authored by Arthur Hung's avatar Arthur Hung
Browse files

Consuming common key combinations in app priority

Some apps or games could use the combo keys such as holding Ctrl or Alt
to trigger its own shortcut or behavior. To prevent the system shortcut
might be handled before dispatching to the app, we move these keys
handling to 'dispatchUnhandledKey' when the app didn't handle.

This will also fix the corresponding state when the modifier key is
released.

Bug: 156619364
Bug: 213096704
Test: atest AppKeyCombinationsTest
Change-Id: I42770045c61ad6396b27132b8a61d34fc121d77e
parent 9278335f
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -15272,7 +15272,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @param event the KeyEvent object that defines the button action
     */
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        if (KeyEvent.isConfirmKey(keyCode)) {
        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                return true;
            }
@@ -15329,7 +15329,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     * @param event   The KeyEvent object that defines the button action.
     */
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if (KeyEvent.isConfirmKey(keyCode)) {
        if (event.hasNoModifiers() && KeyEvent.isConfirmKey(keyCode)) {
            if ((mViewFlags & ENABLED_MASK) == DISABLED) {
                return true;
            }
+1 −1
Original line number Diff line number Diff line
@@ -7596,7 +7596,7 @@ public final class ViewRootImpl implements ViewParent,
        // When a new focused view is selected, we consume the navigation key because
        // navigation doesn't make much sense unless a view already has focus so
        // the key's purpose is to set focus.
        if (isNavigationKey(event)) {
        if (event.hasNoModifiers() && isNavigationKey(event)) {
            return ensureTouchMode(false);
        }

+6 −1
Original line number Diff line number Diff line
@@ -560,7 +560,12 @@ public class InputShellCommand extends ShellCommand {
        sleep(duration);

        for (KeyEvent event: events) {
            injectKeyEventAsync(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));
            final int keyCode = event.getKeyCode();
            final KeyEvent upEvent = new KeyEvent(now, now, KeyEvent.ACTION_UP, keyCode,
                    0, metaState, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /*scancode*/, 0 /*flags*/,
                    inputSource);
            injectKeyEventAsync(upEvent);
            metaState &= ~MODIFIER.getOrDefault(keyCode, 0);
        }
    }

+6 −1
Original line number Diff line number Diff line
@@ -112,10 +112,15 @@ class ModifierShortcutManager {
     * @return The intent that matches the shortcut, or null if not found.
     */
    private Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
        // If a modifier key other than shift is also pressed, skip it.
        final boolean isShiftOn = KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_SHIFT_ON);
        if (!isShiftOn && !KeyEvent.metaStateHasNoModifiers(metaState)) {
            return null;
        }

        ShortcutInfo shortcut = null;

        // If the Shift key is pressed, then search for the shift shortcuts.
        boolean isShiftOn = (metaState & KeyEvent.META_SHIFT_ON) == KeyEvent.META_SHIFT_ON;
        SparseArray<ShortcutInfo> shortcutMap = isShiftOn ? mShiftShortcuts : mIntentShortcuts;

        // First try the exact keycode (with modifiers).
+44 −19
Original line number Diff line number Diff line
@@ -2696,6 +2696,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        final boolean canceled = event.isCanceled();
        final int displayId = event.getDisplayId();
        final long key_consumed = -1;
        final long key_not_consumed = 0;

        if (DEBUG_INPUT) {
            Log.d(TAG, "interceptKeyTi keyCode=" + keyCode + " down=" + down + " repeatCount="
@@ -2885,7 +2886,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            case KeyEvent.KEYCODE_TAB:
                if (event.isMetaPressed()) {
                    // Pass through keyboard navigation keys.
                    return 0;
                    return key_not_consumed;
                }
                // Display task switcher for ALT-TAB.
                if (down && repeatCount == 0) {
@@ -2916,9 +2917,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                return key_consumed;

            case KeyEvent.KEYCODE_SPACE:
                // Handle keyboard layout switching.
                if ((metaState & (KeyEvent.META_CTRL_MASK | KeyEvent.META_META_MASK)) == 0) {
                    return 0;
                // Handle keyboard layout switching. (META + SPACE)
                if ((metaState & KeyEvent.META_META_MASK) == 0) {
                    return key_not_consumed;
                }
                // Share the same behavior with KEYCODE_LANGUAGE_SWITCH.
            case KeyEvent.KEYCODE_LANGUAGE_SWITCH:
@@ -2992,7 +2993,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        }

        // Let the application handle the key.
        return 0;
        return key_not_consumed;
    }

    /**
@@ -3058,6 +3059,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                    + ", policyFlags=" + policyFlags);
        }

        if (interceptUnhandledKey(event)) {
            return null;
        }

        KeyEvent fallbackEvent = null;
        if ((event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
            final KeyCharacterMap kcm = event.getKeyCharacterMap();
@@ -3112,13 +3117,46 @@ public class PhoneWindowManager implements WindowManagerPolicy {
        return fallbackEvent;
    }

    private boolean interceptUnhandledKey(KeyEvent event) {
        final int keyCode = event.getKeyCode();
        final int repeatCount = event.getRepeatCount();
        final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;
        final int metaState = event.getModifiers();

        switch(keyCode) {
            case KeyEvent.KEYCODE_SPACE:
                if (down && repeatCount == 0) {
                    // Handle keyboard layout switching. (CTRL + SPACE)
                    if (KeyEvent.metaStateHasModifiers(metaState, KeyEvent.META_CTRL_ON)) {
                        int direction = (metaState & KeyEvent.META_SHIFT_MASK) != 0 ? -1 : 1;
                        mWindowManagerFuncs.switchKeyboardLayout(event.getDeviceId(), direction);
                        return true;
                    }
                }
                break;
            case KeyEvent.KEYCODE_Z:
                if (down && KeyEvent.metaStateHasModifiers(metaState,
                        KeyEvent.META_CTRL_ON | KeyEvent.META_ALT_ON)) {
                    // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
                    if (mAccessibilityShortcutController
                            .isAccessibilityShortcutAvailable(isKeyguardLocked())) {
                        mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
                        return true;
                    }
                }
                break;
        }

        return false;
    }

    private boolean interceptFallback(IBinder focusedToken, KeyEvent fallbackEvent,
            int policyFlags) {
        int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
        if ((actions & ACTION_PASS_TO_USER) != 0) {
            long delayMillis = interceptKeyBeforeDispatching(
                    focusedToken, fallbackEvent, policyFlags);
            if (delayMillis == 0) {
            if (delayMillis == 0 && !interceptUnhandledKey(fallbackEvent)) {
                return true;
            }
        }
@@ -3989,19 +4027,6 @@ public class PhoneWindowManager implements WindowManagerPolicy {
            }
        }

        // Intercept the Accessibility keychord (CTRL + ALT + Z) for keyboard users.
        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(isKeyguardLocked())) {
            switch (keyCode) {
                case KeyEvent.KEYCODE_Z: {
                    if (down && event.isCtrlPressed() && event.isAltPressed()) {
                        mHandler.sendMessage(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT));
                        result &= ~ACTION_PASS_TO_USER;
                    }
                    break;
                }
            }
        }

        if (useHapticFeedback) {
            performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, false,
                    "Virtual Key - Press");