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

Commit ac5f93af authored by Jimmy's avatar Jimmy
Browse files

Remove original modifiers from generated fallback keys

Previously generated fallbacks would preserve the original modifiers,
leading to unexpected key events.
Example: Ctrl + Space -> Ctrl + language_switch

This change removes the modifiers used to trigger the fallback.
Example: Ctrl + Space -> language_switch

Fallbacks are triggered only with exact matching, so extra
modifiers will not output a fallback.
Example: Ctrl + Alt + Space -> Ctrl + Alt + Space (no fallback)

Bug: 382545048
Test: atest com.android.test.input.KeyCharacterMapTest

Flag: com.android.hardware.input.remove_fallback_modifiers

Change-Id: I78de4bc131b0c9171a3508ee560135fce6b77e42
parent 8d7d869d
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -204,3 +204,10 @@ flag {
    description: "Allows the user to disable input scrolling acceleration for mouse."
    bug: "383555305"
}

flag {
  name: "remove_fallback_modifiers"
  namespace: "input"
  description: "Removes modifiers from the original key event that activated the fallback, ensuring that only the intended fallback event is sent."
  bug: "382545048"
}
+12 −1
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@

package android.view;


import static com.android.hardware.input.Flags.removeFallbackModifiers;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -458,7 +461,15 @@ public class KeyCharacterMap implements Parcelable {
        FallbackAction action = FallbackAction.obtain();
        metaState = KeyEvent.normalizeMetaState(metaState);
        if (nativeGetFallbackAction(mPtr, keyCode, metaState, action)) {
            if (removeFallbackModifiers()) {
                // Strip all modifiers. This is safe to do since only exact keyCode + metaState
                // modifiers will trigger a fallback.
                // E.g. Ctrl + Space -> language_switch (fallback generated)
                //      Ctrl + Alt + Space -> Ctrl + Alt + Space (no fallback generated)
                action.metaState = 0;
            } else {
                action.metaState = KeyEvent.normalizeMetaState(action.metaState);
            }
            return action;
        }
        action.recycle();
+30 −11
Original line number Diff line number Diff line
@@ -16,10 +16,17 @@

package com.android.test.input

import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule

import android.view.KeyCharacterMap
import android.view.KeyEvent

import com.android.hardware.input.Flags

import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Rule
import org.junit.Test

/**
@@ -30,26 +37,38 @@ import org.junit.Test
 *
 */
class KeyCharacterMapTest {
    @get:Rule
    val setFlagsRule = SetFlagsRule()

    @Test
    @EnableFlags(Flags.FLAG_REMOVE_FALLBACK_MODIFIERS)
    fun testGetFallback() {
        // Based off of VIRTUAL kcm fallbacks.
        val keyCharacterMap = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD)

        // One modifier fallback.
        assertEquals(
            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
                KeyEvent.META_CTRL_ON).keyCode,
            KeyEvent.KEYCODE_LANGUAGE_SWITCH)
        val oneModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
            KeyEvent.META_CTRL_ON)
        assertEquals(KeyEvent.KEYCODE_LANGUAGE_SWITCH, oneModifierFallback.keyCode)
        assertEquals(0, oneModifierFallback.metaState)

        // Multiple modifier fallback.
        assertEquals(
            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
                KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON).keyCode,
            KeyEvent.KEYCODE_BACK)
        val twoModifierFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_DEL,
            KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
        assertEquals(KeyEvent.KEYCODE_BACK, twoModifierFallback.keyCode)
        assertEquals(0, twoModifierFallback.metaState)

        // No default button, fallback only.
        assertEquals(
            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0).keyCode,
            KeyEvent.KEYCODE_DPAD_CENTER)
        val keyOnlyFallback =
            keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_BUTTON_A, 0)
        assertEquals(KeyEvent.KEYCODE_DPAD_CENTER, keyOnlyFallback.keyCode)
        assertEquals(0, keyOnlyFallback.metaState)

        // A key event that is not an exact match for a fallback. Expect a null return.
        // E.g. Ctrl + Space -> LanguageSwitch
        //      Ctrl + Alt + Space -> Ctrl + Alt + Space (No fallback).
        val noMatchFallback = keyCharacterMap.getFallbackAction(KeyEvent.KEYCODE_SPACE,
            KeyEvent.META_CTRL_ON or KeyEvent.META_ALT_ON)
        assertNull(noMatchFallback)
    }
}