diff --git a/java/res/xml-sw600dp/key_styles_common.xml b/java/res/xml-sw600dp/key_styles_common.xml
index 6b06ce77aaf1124ba4d2f49cac2e7ca16bb5c849..a2d2fd827e09de59cc9b24ee52e2ae57e1a6196f 100644
--- a/java/res/xml-sw600dp/key_styles_common.xml
+++ b/java/res/xml-sw600dp/key_styles_common.xml
@@ -36,34 +36,38 @@
         </default>
     </switch>
     <!-- Functional key styles -->
+    <!-- Base style for shift key. A single space is used for dummy label in moreKeys. -->
+    <key-style
+        latin:styleName="baseForShiftKeyStyle"
+        latin:code="!code/key_shift"
+        latin:keyActionFlags="noKeyPreview"
+        latin:keyLabelFlags="preserveCase"
+        latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" />
     <switch>
         <case
             latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetAutomaticShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <case
             latin:keyboardLayoutSetElement="alphabetShiftLocked|alphabetShiftLockShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOn" />
+                latin:backgroundType="stickyOn"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </default>
     </switch>
     <key-style
diff --git a/java/res/xml-sw768dp/key_styles_common.xml b/java/res/xml-sw768dp/key_styles_common.xml
index 4d10f5b60775cd4b43dea6af1ab5df659af85690..e69bc3020bcf553cf4a8ce3db269a22d44d9ed83 100644
--- a/java/res/xml-sw768dp/key_styles_common.xml
+++ b/java/res/xml-sw768dp/key_styles_common.xml
@@ -35,34 +35,38 @@
                 latin:keyLabelFlags="hasShiftedLetterHint" />
         </default>
     </switch>
+    <!-- Base style for shift key. A single space is used for dummy label in moreKeys. -->
+    <key-style
+        latin:styleName="baseForShiftKeyStyle"
+        latin:code="!code/key_shift"
+        latin:keyActionFlags="noKeyPreview"
+        latin:keyLabelFlags="preserveCase"
+        latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" />
     <switch>
         <case
             latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetAutomaticShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <case
             latin:keyboardLayoutSetElement="alphabetShiftLocked|alphabetShiftLockShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOn" />
+                latin:backgroundType="stickyOn"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </default>
     </switch>
     <key-style
diff --git a/java/res/xml/key_styles_common.xml b/java/res/xml/key_styles_common.xml
index 0834adf20679c148a83a4e1c2d2cf0aefd0a9aca..6590d0a4ca5c2d77945e0c296d44b1f58f198b7c 100644
--- a/java/res/xml/key_styles_common.xml
+++ b/java/res/xml/key_styles_common.xml
@@ -25,34 +25,38 @@
     <include
         latin:keyboardLayout="@xml/key_styles_f1" />
     <!-- Functional key styles -->
+    <!-- Base style for shift key. A single space is used for dummy label in moreKeys. -->
+    <key-style
+        latin:styleName="baseForShiftKeyStyle"
+        latin:code="!code/key_shift"
+        latin:keyActionFlags="noKeyPreview"
+        latin:keyLabelFlags="preserveCase"
+        latin:moreKeys="!noPanelAutoMoreKey!, |!code/key_capslock" />
     <switch>
         <case
             latin:keyboardLayoutSetElement="alphabetManualShifted|alphabetAutomaticShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <case
             latin:keyboardLayoutSetElement="alphabetShiftLocked|alphabetShiftLockShifted"
         >
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key_shifted"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOn" />
+                latin:backgroundType="stickyOn"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </case>
         <default>
             <key-style
                 latin:styleName="shiftKeyStyle"
-                latin:code="!code/key_shift"
                 latin:keyIcon="!icon/shift_key"
-                latin:keyActionFlags="noKeyPreview"
-                latin:backgroundType="stickyOff" />
+                latin:backgroundType="stickyOff"
+                latin:parentStyle="baseForShiftKeyStyle" />
         </default>
     </switch>
     <key-style
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index b77544bc3def0e5cdde625bde516736c820e3317..291018a14542ffcb7e8e951401710d2f538da774 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -117,7 +117,7 @@
                 <Key
                     latin:code="0x002F"
                     latin:keyLabel="/ :"
-                    latin:moreKeys="!embeddedMoreKey!,:"
+                    latin:moreKeys="!noPanelAutoMoreKey!,:"
                     latin:keyStyle="numKeyStyle" />
             </case>
             <default>
diff --git a/java/res/xml/rows_phone.xml b/java/res/xml/rows_phone.xml
index 9299c2aa50dcd1fb40716776b8704c9def344fcf..d8dcfbd62e9db3dcd153c93fa72fb690ae68cf31 100644
--- a/java/res/xml/rows_phone.xml
+++ b/java/res/xml/rows_phone.xml
@@ -70,7 +70,7 @@
             latin:keyStyle="num0KeyStyle"
             latin:code="0x0030"
             latin:keyLabel="0 +"
-            latin:moreKeys="!embeddedMoreKey!,+" />
+            latin:moreKeys="!noPanelAutoMoreKey!,+" />
         <Key
             latin:keyStyle="numSpaceKeyStyle" />
         <Key
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index ae72b4a6b0cae61cd26cb153234b558b24bbffaa..4ef8653f628b33e28d7bc715b9a4ff7a3243b6a8 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -113,12 +113,12 @@ public class Key implements Comparable<Key> {
     private static final int MORE_KEYS_FLAGS_FIXED_COLUMN_ORDER = 0x80000000;
     private static final int MORE_KEYS_FLAGS_HAS_LABELS = 0x40000000;
     private static final int MORE_KEYS_FLAGS_NEEDS_DIVIDERS = 0x20000000;
-    private static final int MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY = 0x10000000;
+    private static final int MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY = 0x10000000;
     private static final String MORE_KEYS_AUTO_COLUMN_ORDER = "!autoColumnOrder!";
     private static final String MORE_KEYS_FIXED_COLUMN_ORDER = "!fixedColumnOrder!";
     private static final String MORE_KEYS_HAS_LABELS = "!hasLabels!";
     private static final String MORE_KEYS_NEEDS_DIVIDERS = "!needsDividers!";
-    private static final String MORE_KEYS_EMBEDDED_MORE_KEY = "!embeddedMoreKey!";
+    private static final String MORE_KEYS_NO_PANEL_AUTO_MORE_KEY = "!noPanelAutoMoreKey!";
 
     /** Background type that represents different key background visual than normal one. */
     public final int mBackgroundType;
@@ -281,8 +281,8 @@ public class Key implements Comparable<Key> {
         if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_NEEDS_DIVIDERS)) {
             moreKeysColumn |= MORE_KEYS_FLAGS_NEEDS_DIVIDERS;
         }
-        if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_EMBEDDED_MORE_KEY)) {
-            moreKeysColumn |= MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY;
+        if (KeySpecParser.getBooleanValue(moreKeys, MORE_KEYS_NO_PANEL_AUTO_MORE_KEY)) {
+            moreKeysColumn |= MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY;
         }
         mMoreKeysColumnAndFlags = moreKeysColumn;
 
@@ -657,8 +657,8 @@ public class Key implements Comparable<Key> {
         return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NEEDS_DIVIDERS) != 0;
     }
 
-    public final boolean hasEmbeddedMoreKey() {
-        return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_EMBEDDED_MORE_KEY) != 0;
+    public final boolean hasNoPanelAutoMoreKey() {
+        return (mMoreKeysColumnAndFlags & MORE_KEYS_FLAGS_NO_PANEL_AUTO_MORE_KEY) != 0;
     }
 
     public final String getOutputText() {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index 7295efab1a08c3284c5e1a913e659487018ee656..4323f7171fbcf6629036a199581ae8549fd9770b 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -32,7 +32,6 @@ import com.android.inputmethod.keyboard.KeyboardLayoutSet.KeyboardLayoutSetExcep
 import com.android.inputmethod.keyboard.PointerTracker.TimerProxy;
 import com.android.inputmethod.keyboard.internal.KeyboardState;
 import com.android.inputmethod.latin.AudioAndHapticFeedbackManager;
-import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.InputView;
 import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.LatinImeLogger;
@@ -300,26 +299,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
                 ? keyboardView.getTimerProxy().isInDoubleTapShiftKeyTimeout() : false;
     }
 
-    // Implements {@link KeyboardState.SwitchActions}.
-    @Override
-    public void startLongPressTimer(final int code) {
-        final MainKeyboardView keyboardView = getMainKeyboardView();
-        if (keyboardView != null) {
-            final TimerProxy timer = keyboardView.getTimerProxy();
-            timer.startLongPressTimer(code);
-        }
-    }
-
-    // Implements {@link KeyboardState.SwitchActions}.
-    @Override
-    public void cancelLongPressTimer() {
-        final MainKeyboardView keyboardView = getMainKeyboardView();
-        if (keyboardView != null) {
-            final TimerProxy timer = keyboardView.getTimerProxy();
-            timer.cancelLongPressTimer();
-        }
-    }
-
     private void hapticAndAudioFeedback(final int code) {
         if (mKeyboardView == null || mKeyboardView.isInSlidingKeyInput()) {
             return;
@@ -327,14 +306,6 @@ public final class KeyboardSwitcher implements KeyboardState.SwitchActions {
         AudioAndHapticFeedbackManager.getInstance().hapticAndAudioFeedback(code, mKeyboardView);
     }
 
-    public void onLongPressTimeout(final int code) {
-        mState.onLongPressTimeout(code);
-        final Keyboard keyboard = getKeyboard();
-        if (keyboard != null && keyboard.mId.isAlphabetKeyboard() && code == Constants.CODE_SHIFT) {
-            hapticAndAudioFeedback(code);
-        }
-    }
-
     /**
      * Updates state machine to figure out when to automatically switch back to the previous mode.
      */
diff --git a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
index 435adb6f5fedb5e2f37d485d26b5516972c344b1..2e8772635e2529803a7eed601090d17834099ff0 100644
--- a/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/MainKeyboardView.java
@@ -248,11 +248,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
                 }
                 break;
             case MSG_LONGPRESS_KEY:
-                if (tracker != null) {
-                    keyboardView.onLongPress(tracker);
-                } else {
-                    KeyboardSwitcher.getInstance().onLongPressTimeout(msg.arg1);
-                }
+                keyboardView.onLongPress(tracker);
                 break;
             case MSG_UPDATE_BATCH_INPUT:
                 tracker.updateBatchInputByTimer(SystemClock.uptimeMillis());
@@ -283,23 +279,6 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
             return hasMessages(MSG_REPEAT_KEY);
         }
 
-        @Override
-        public void startLongPressTimer(final int code) {
-            cancelLongPressTimer();
-            final int delay;
-            switch (code) {
-            case Constants.CODE_SHIFT:
-                delay = mLongPressShiftLockTimeout;
-                break;
-            default:
-                delay = 0;
-                break;
-            }
-            if (delay > 0) {
-                sendMessageDelayed(obtainMessage(MSG_LONGPRESS_KEY, code, 0), delay);
-            }
-        }
-
         @Override
         public void startLongPressTimer(final PointerTracker tracker) {
             cancelLongPressTimer();
@@ -1002,7 +981,7 @@ public final class MainKeyboardView extends KeyboardView implements PointerTrack
             ResearchLogger.mainKeyboardView_onLongPress();
         }
         final int code = key.mCode;
-        if (key.hasEmbeddedMoreKey()) {
+        if (key.hasNoPanelAutoMoreKey()) {
             final int embeddedCode = key.mMoreKeys[0].mCode;
             tracker.onLongPressed();
             invokeCodeInput(embeddedCode);
diff --git a/java/src/com/android/inputmethod/keyboard/PointerTracker.java b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
index a28bd1a1eb3fe89e8c568cb29ae43813f1ff17e5..958aaf569343cfb8f31b6b44466c9a7083b76726 100644
--- a/java/src/com/android/inputmethod/keyboard/PointerTracker.java
+++ b/java/src/com/android/inputmethod/keyboard/PointerTracker.java
@@ -92,7 +92,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
         public boolean isTypingState();
         public void startKeyRepeatTimer(PointerTracker tracker);
         public void startLongPressTimer(PointerTracker tracker);
-        public void startLongPressTimer(int code);
         public void cancelLongPressTimer();
         public void startDoubleTapShiftKeyTimer();
         public void cancelDoubleTapShiftKeyTimer();
@@ -112,8 +111,6 @@ public final class PointerTracker implements PointerTrackerQueue.Element {
             @Override
             public void startLongPressTimer(PointerTracker tracker) {}
             @Override
-            public void startLongPressTimer(int code) {}
-            @Override
             public void cancelLongPressTimer() {}
             @Override
             public void startDoubleTapShiftKeyTimer() {}
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
index 3e25c3b8680b5d525c112bd29e9641060be71e08..a9e04bccf13f3d5fe224d9f21d918c870de34035 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardCodesSet.java
@@ -43,6 +43,7 @@ public final class KeyboardCodesSet {
         "key_enter",
         "key_space",
         "key_shift",
+        "key_capslock",
         "key_switch_alpha_symbol",
         "key_output_text",
         "key_delete",
@@ -79,6 +80,7 @@ public final class KeyboardCodesSet {
         Constants.CODE_ENTER,
         Constants.CODE_SPACE,
         Constants.CODE_SHIFT,
+        Constants.CODE_CAPSLOCK,
         Constants.CODE_SWITCH_ALPHA_SYMBOL,
         Constants.CODE_OUTPUT_TEXT,
         Constants.CODE_DELETE,
@@ -116,6 +118,7 @@ public final class KeyboardCodesSet {
         DEFAULT[12],
         DEFAULT[13],
         DEFAULT[14],
+        DEFAULT[15],
         CODE_RIGHT_PARENTHESIS,
         CODE_LEFT_PARENTHESIS,
         CODE_GREATER_THAN_SIGN,
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index bb6dec69e03235ae7d1753e819e2dcfed034a07a..e1cee427e08a2f7fc04b42b19a7efd1fc2d5177a 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -30,7 +30,7 @@ import com.android.inputmethod.latin.RecapitalizeStatus;
  * The input events are {@link #onLoadKeyboard()}, {@link #onSaveKeyboardState()},
  * {@link #onPressKey(int,boolean,int)}, {@link #onReleaseKey(int,boolean)},
  * {@link #onCodeInput(int,int)}, {@link #onFinishSlidingInput()}, {@link #onCancelInput()},
- * {@link #onUpdateShiftState(int,int)}, {@link #onLongPressTimeout(int)}.
+ * {@link #onUpdateShiftState(int,int)}.
  *
  * The actions are {@link SwitchActions}'s methods.
  */
@@ -56,8 +56,6 @@ public final class KeyboardState {
         public void startDoubleTapShiftKeyTimer();
         public boolean isInDoubleTapShiftKeyTimeout();
         public void cancelDoubleTapShiftKeyTimer();
-        public void startLongPressTimer(int code);
-        public void cancelLongPressTimer();
     }
 
     private final SwitchActions mSwitchActions;
@@ -320,13 +318,16 @@ public final class KeyboardState {
             Log.d(TAG, "onPressKey: code=" + Constants.printableCode(code)
                    + " single=" + isSinglePointer + " autoCaps=" + autoCaps + " " + this);
         }
+        if (code != Constants.CODE_SHIFT) {
+            // Because the double tap shift key timer is to detect two consecutive shift key press,
+            // it should be canceled when a non-shift key is pressed.
+            mSwitchActions.cancelDoubleTapShiftKeyTimer();
+        }
         if (code == Constants.CODE_SHIFT) {
             onPressShift();
         } else if (code == Constants.CODE_SWITCH_ALPHA_SYMBOL) {
             onPressSymbol();
         } else {
-            mSwitchActions.cancelDoubleTapShiftKeyTimer();
-            mSwitchActions.cancelLongPressTimer();
             mLongPressShiftLockFired = false;
             mShiftKeyState.onOtherKeyPressed();
             mSymbolKeyState.onOtherKeyPressed();
@@ -380,15 +381,6 @@ public final class KeyboardState {
         mSymbolKeyState.onRelease();
     }
 
-    public void onLongPressTimeout(final int code) {
-        if (DEBUG_EVENT) {
-            Log.d(TAG, "onLongPressTimeout: code=" + Constants.printableCode(code) + " " + this);
-        }
-        if (mIsAlphabetMode && code == Constants.CODE_SHIFT) {
-            mLongPressShiftLockFired = true;
-        }
-    }
-
     public void onUpdateShiftState(final int autoCaps, final int recapitalizeMode) {
         if (DEBUG_EVENT) {
             Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + ", recapitalizeMode="
@@ -448,7 +440,9 @@ public final class KeyboardState {
         mLongPressShiftLockFired = false;
         // If we are recapitalizing, we don't do any of the normal processing, including
         // importantly the double tap timer.
-        if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) return;
+        if (RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE != mRecapitalizeMode) {
+            return;
+        }
         if (mIsAlphabetMode) {
             mIsInDoubleTapShiftKey = mSwitchActions.isInDoubleTapShiftKeyTimeout();
             if (!mIsInDoubleTapShiftKey) {
@@ -484,7 +478,6 @@ public final class KeyboardState {
                     setShifted(MANUAL_SHIFT);
                     mShiftKeyState.onPress();
                 }
-                mSwitchActions.startLongPressTimer(Constants.CODE_SHIFT);
             }
         } else {
             // In symbol mode, just toggle symbol and symbol more keyboard.
@@ -617,6 +610,12 @@ public final class KeyboardState {
             break;
         }
 
+        if (code == Constants.CODE_CAPSLOCK) {
+            // Changing shift lock state will be handled at {@link #onPressShift()} when the shift
+            // key is released.
+            mLongPressShiftLockFired = true;
+        }
+
         // If the code is a letter, update keyboard shift state.
         if (Constants.isLetterCode(code)) {
             updateAlphabetShiftState(autoCaps, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
diff --git a/java/src/com/android/inputmethod/latin/Constants.java b/java/src/com/android/inputmethod/latin/Constants.java
index 64c14d32f17aa8170f54b0c5c615ad0e758ad948..bb4a42ededda6a8ae558dfb757d90de39b04f22b 100644
--- a/java/src/com/android/inputmethod/latin/Constants.java
+++ b/java/src/com/android/inputmethod/latin/Constants.java
@@ -172,22 +172,23 @@ public final class Constants {
 
     /**
      * Special keys code. Must be negative.
-     * These should be aligned with KeyboardCodesSet.ID_TO_NAME[],
-     * KeyboardCodesSet.DEFAULT[] and KeyboardCodesSet.RTL[]
+     * These should be aligned with {@link KeyboardCodesSet#ID_TO_NAME},
+     * {@link KeyboardCodesSet#DEFAULT}, and {@link KeyboardCodesSet#RTL}.
      */
     public static final int CODE_SHIFT = -1;
-    public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
-    public static final int CODE_OUTPUT_TEXT = -3;
-    public static final int CODE_DELETE = -4;
-    public static final int CODE_SETTINGS = -5;
-    public static final int CODE_SHORTCUT = -6;
-    public static final int CODE_ACTION_NEXT = -7;
-    public static final int CODE_ACTION_PREVIOUS = -8;
-    public static final int CODE_LANGUAGE_SWITCH = -9;
-    public static final int CODE_RESEARCH = -10;
-    public static final int CODE_SHIFT_ENTER = -11;
+    public static final int CODE_CAPSLOCK = -2;
+    public static final int CODE_SWITCH_ALPHA_SYMBOL = -3;
+    public static final int CODE_OUTPUT_TEXT = -4;
+    public static final int CODE_DELETE = -5;
+    public static final int CODE_SETTINGS = -6;
+    public static final int CODE_SHORTCUT = -7;
+    public static final int CODE_ACTION_NEXT = -8;
+    public static final int CODE_ACTION_PREVIOUS = -9;
+    public static final int CODE_LANGUAGE_SWITCH = -10;
+    public static final int CODE_RESEARCH = -11;
+    public static final int CODE_SHIFT_ENTER = -12;
     // Code value representing the code is not specified.
-    public static final int CODE_UNSPECIFIED = -12;
+    public static final int CODE_UNSPECIFIED = -13;
 
     public static boolean isLetterCode(final int code) {
         return code >= CODE_SPACE;
@@ -196,6 +197,7 @@ public final class Constants {
     public static String printableCode(final int code) {
         switch (code) {
         case CODE_SHIFT: return "shift";
+        case CODE_CAPSLOCK: return "capslock";
         case CODE_SWITCH_ALPHA_SYMBOL: return "symbol";
         case CODE_OUTPUT_TEXT: return "text";
         case CODE_DELETE: return "delete";
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 98008ac1c36a7a73ce085b8ee27b2d55000909f9..0bf167fd441df18cbf1b4893b54f0492f25fe97e 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1420,8 +1420,8 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             LatinImeLogger.logOnDelete(x, y);
             break;
         case Constants.CODE_SHIFT:
-            // Note: calling back to the keyboard on Shift key is handled in onPressKey()
-            // and onReleaseKey().
+            // Note: Calling back to the keyboard on Shift key is handled in
+            // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
             final Keyboard currentKeyboard = switcher.getKeyboard();
             if (null != currentKeyboard && currentKeyboard.mId.isAlphabetKeyboard()) {
                 // TODO: Instead of checking for alphabetic keyboard here, separate keycodes for
@@ -1429,9 +1429,13 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
                 handleRecapitalize();
             }
             break;
+        case Constants.CODE_CAPSLOCK:
+            // Note: Changing keyboard to shift lock state is handled in
+            // {@link KeyboardSwitcher#onCodeInput(int)}.
+            break;
         case Constants.CODE_SWITCH_ALPHA_SYMBOL:
-            // Note: calling back to the keyboard on symbol key is handled in onPressKey()
-            // and onReleaseKey().
+            // Note: Calling back to the keyboard on symbol key is handled in
+            // {@link #onPressKey(int,boolean)} and {@link #onReleaseKey(int,boolean)}.
             break;
         case Constants.CODE_SETTINGS:
             onSettingsKeyPressed();
@@ -1484,8 +1488,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
             break;
         }
         switcher.onCodeInput(primaryCode);
-        // Reset after any single keystroke, except shift and symbol-shift
+        // Reset after any single keystroke, except shift, capslock, and symbol-shift
         if (!didAutoCorrect && primaryCode != Constants.CODE_SHIFT
+                && primaryCode != Constants.CODE_CAPSLOCK
                 && primaryCode != Constants.CODE_SWITCH_ALPHA_SYMBOL)
             mLastComposedWord.deactivate();
         if (Constants.CODE_DELETE != primaryCode) {
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
index e06ca064a3a4d5d30b4378b84657f316d58562d5..6991d05fa9ec82e4b8db738ff32886ad4ce579d7 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTestsBase.java
@@ -18,6 +18,8 @@ package com.android.inputmethod.keyboard.internal;
 
 import android.test.AndroidTestCase;
 
+import com.android.inputmethod.latin.Constants;
+
 public class KeyboardStateTestsBase extends AndroidTestCase
         implements MockKeyboardSwitcher.MockConstants {
     protected MockKeyboardSwitcher mSwitcher;
@@ -119,7 +121,11 @@ public class KeyboardStateTestsBase extends AndroidTestCase
 
     public void longPressKey(final int code, final int afterPress, final int afterLongPress) {
         pressKey(code, afterPress);
-        mSwitcher.onLongPressTimeout(code);
+        // Long press shift key will register {@link Constants#CODE_CAPS_LOCK}. See
+        // {@link R.xml#key_styles_common} and its baseForShiftKeyStyle. We thus emulate the
+        // behavior here.
+        final int longPressCode = code == CODE_SHIFT ? Constants.CODE_CAPSLOCK : code;
+        mSwitcher.onCodeInput(longPressCode);
         assertLayout("afterLongPress", afterLongPress, mSwitcher.getLayoutId());
     }
 
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
index 90dbaabc99811d819acd761ff652f41e4b47e99e..8506e16f2b46c502f2222f789c3d997370c3a3f5 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/MockKeyboardSwitcher.java
@@ -139,24 +139,6 @@ public class MockKeyboardSwitcher implements KeyboardState.SwitchActions {
         return mIsInDoubleTapShiftKeyTimeout;
     }
 
-    @Override
-    public void startLongPressTimer(final int code) {
-        mLongPressTimeoutCode = code;
-    }
-
-    @Override
-    public void cancelLongPressTimer() {
-        mLongPressTimeoutCode = 0;
-    }
-
-    public void onLongPressTimeout(final int code) {
-        // TODO: Handle simultaneous long presses.
-        if (mLongPressTimeoutCode == code) {
-            mLongPressTimeoutCode = 0;
-            mState.onLongPressTimeout(code);
-        }
-    }
-
     public void updateShiftState() {
         mState.onUpdateShiftState(mAutoCapsState, RecapitalizeStatus.NOT_A_RECAPITALIZE_MODE);
     }