Loading core/java/android/hardware/input/input_framework.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -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" } core/java/android/view/KeyCharacterMap.java +12 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt +30 −11 Original line number Diff line number Diff line Loading @@ -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 /** Loading @@ -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) } } Loading
core/java/android/hardware/input/input_framework.aconfig +7 −0 Original line number Diff line number Diff line Loading @@ -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" }
core/java/android/view/KeyCharacterMap.java +12 −1 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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(); Loading
tests/Input/src/com/android/test/input/KeyCharacterMapTest.kt +30 −11 Original line number Diff line number Diff line Loading @@ -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 /** Loading @@ -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) } }