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

Commit c1df907e authored by Jeff Brown's avatar Jeff Brown
Browse files

Support invoking key shortcuts using Control.

This enables Select All, Cut, Copy and Paste behavior in TextViews
and provides a general pattern for implementing additional keyboard
accelerators based on Control key shortcuts.  The same shortcuts
also apply to menu accelerators.

Bug: 3286262
Change-Id: I7d458ee26abf51e0de1735ce490ce3baf504b471
parent 68e8ed38
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -990,6 +990,22 @@ public class KeyEvent extends InputEvent implements Parcelable {
     */
    public static final int META_SCROLL_LOCK_ON = 0x400000;

    /** {@hide} */
    public static final int META_SHIFT_MASK = META_SHIFT_ON
            | META_SHIFT_LEFT_ON | META_SHIFT_RIGHT_ON;

    /** {@hide} */
    public static final int META_ALT_MASK = META_ALT_ON
            | META_ALT_LEFT_ON | META_ALT_RIGHT_ON;

    /** {@hide} */
    public static final int META_CTRL_MASK = META_CTRL_ON
            | META_CTRL_LEFT_ON | META_CTRL_RIGHT_ON;

    /** {@hide} */
    public static final int META_META_MASK = META_ALT_ON
            | META_META_LEFT_ON | META_META_RIGHT_ON;

    /**
     * This mask is set if the device woke because of this key event.
     */
+10 −0
Original line number Diff line number Diff line
@@ -2626,6 +2626,16 @@ public final class ViewRoot extends Handler implements ViewParent,
            return;
        }

        // If the Control modifier is held, try to interpret the key as a shortcut.
        if (event.getAction() == KeyEvent.ACTION_UP
                && event.isCtrlPressed()
                && !KeyEvent.isModifierKey(event.getKeyCode())) {
            if (mView.dispatchKeyShortcutEvent(event)) {
                finishKeyEvent(event, sendDone, true);
                return;
            }
        }

        // Apply the fallback event policy.
        if (mFallbackEventHandler.dispatchKeyEvent(event)) {
            finishKeyEvent(event, sendDone, true);
+52 −73
Original line number Diff line number Diff line
@@ -7530,36 +7530,31 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

    @Override
    public boolean onKeyShortcut(int keyCode, KeyEvent event) {
        final int filteredMetaState = event.getMetaState() & ~KeyEvent.META_CTRL_MASK;
        if (KeyEvent.metaStateHasNoModifiers(filteredMetaState)) {
            switch (keyCode) {
            case KeyEvent.KEYCODE_A:
                if (canSelectText()) {
                    return onTextContextMenuItem(ID_SELECT_ALL);
                }

                break;

            case KeyEvent.KEYCODE_X:
                if (canCut()) {
                    return onTextContextMenuItem(ID_CUT);
                }

                break;

            case KeyEvent.KEYCODE_C:
                if (canCopy()) {
                    return onTextContextMenuItem(ID_COPY);
                }

                break;

            case KeyEvent.KEYCODE_V:
                if (canPaste()) {
                    return onTextContextMenuItem(ID_PASTE);
                }

                break;
            }

        }
        return super.onKeyShortcut(keyCode, event);
    }

@@ -7889,7 +7884,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener

    /**
     * Called when a context menu option for the text view is selected.  Currently
     * this will be {@link android.R.id#copyUrl} or {@link android.R.id#selectTextMode}.
     * this will be {@link android.R.id#copyUrl}, {@link android.R.id#selectTextMode},
     * {@link android.R.id#selectAll}, {@link android.R.id#paste}, {@link android.R.id#cut}
     * or {@link android.R.id#copy}.
     */
    public boolean onTextContextMenuItem(int id) {
        int min = 0;
@@ -7934,8 +7931,32 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    startSelectionActionMode();
                }
                return true;

            case ID_SELECT_ALL:
                selectAll();
                // Update controller positions after selection change.
                if (hasSelectionController()) {
                    getSelectionController().show();
                }
                return true;

            case ID_PASTE:
                paste(min, max);
                return true;

            case ID_CUT:
                setPrimaryClip(ClipData.newPlainText(null, null,
                        mTransformed.subSequence(min, max)));
                ((Editable) mText).delete(min, max);
                stopSelectionActionMode();
                return true;

            case ID_COPY:
                setPrimaryClip(ClipData.newPlainText(null, null,
                        mTransformed.subSequence(min, max)));
                stopSelectionActionMode();
                return true;
        }
        return false;
    }

@@ -8292,49 +8313,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 mCustomSelectionActionModeCallback.onActionItemClicked(mode, item)) {
                return true;
            }

            final int itemId = item.getItemId();

            if (itemId == ID_SELECT_ALL) {
                selectAll();
                // Update controller positions after selection change.
                if (hasSelectionController()) {
                    getSelectionController().show();
                }
                return true;
            }

            int min = 0;
            int max = mText.length();

            if (isFocused()) {
                final int selStart = getSelectionStart();
                final int selEnd = getSelectionEnd();

                min = Math.max(0, Math.min(selStart, selEnd));
                max = Math.max(0, Math.max(selStart, selEnd));
            }

            switch (item.getItemId()) {
                case ID_PASTE:
                    paste(min, max);
                    return true;

                case ID_CUT:
                    setPrimaryClip(ClipData.newPlainText(null, null,
                            mTransformed.subSequence(min, max)));
                    ((Editable) mText).delete(min, max);
                    stopSelectionActionMode();
                    return true;

                case ID_COPY:
                    setPrimaryClip(ClipData.newPlainText(null, null,
                            mTransformed.subSequence(min, max)));
                    stopSelectionActionMode();
                    return true;
            }

            return false;
            return onTextContextMenuItem(item.getItemId());
        }

        @Override