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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user