diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 3540577ca781fdcd5e53e6c2eabfb25d6572b4a3..fad12cc1f03cf9f6f5ca4f72b331afe3bf41bd8b 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -67,7 +67,9 @@ import java.util.Set;
 public class Keyboard {
     private static final String TAG = Keyboard.class.getSimpleName();
 
-    /** Some common keys code.  These should be aligned with values/keycodes.xml */
+    /** Some common keys code. Must be positive.
+     * These should be aligned with values/keycodes.xml
+     */
     public static final int CODE_ENTER = '\n';
     public static final int CODE_TAB = '\t';
     public static final int CODE_SPACE = ' ';
@@ -85,7 +87,9 @@ public class Keyboard {
     public static final int CODE_DIGIT0 = '0';
     public static final int CODE_PLUS = '+';
 
-    /** Special keys code.  These should be aligned with values/keycodes.xml */
+    /** Special keys code. Must be non-positive.
+     * These should be aligned with values/keycodes.xml
+     */
     public static final int CODE_DUMMY = 0;
     public static final int CODE_SHIFT = -1;
     public static final int CODE_SWITCH_ALPHA_SYMBOL = -2;
@@ -248,6 +252,10 @@ public class Keyboard {
         return label;
     }
 
+    public static boolean isLetterCode(int code) {
+        return code > CODE_DUMMY;
+    }
+
     public static class Params {
         public KeyboardId mId;
         public int mThemeId;
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
index fa073b6714aa4292f9f5e7d91323d17e0ef61f06..e5097152b1132e5c6b7e19ea8b192f07cd2636ad 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSwitcher.java
@@ -332,7 +332,7 @@ public class KeyboardSwitcher implements KeyboardState.SwitchActions,
      * Updates state machine to figure out when to automatically snap back to the previous mode.
      */
     public void onCodeInput(int code) {
-        mState.onCodeInput(code, isSinglePointer());
+        mState.onCodeInput(code, isSinglePointer(), mInputMethodService.getCurrentAutoCapsState());
     }
 
     public LatinKeyboardView getKeyboardView() {
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
index 623cab303f91b51bb7525cd908fb3e3b228e38e1..c0adf970a56ab01285caa222a0d07ae0ad26ffb1 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardState.java
@@ -29,9 +29,10 @@ import com.android.inputmethod.keyboard.Keyboard;
  *
  * The input events are {@link #onLoadKeyboard(String, boolean)}, {@link #onSaveKeyboardState()},
  * {@link #onPressShift(boolean)}, {@link #onReleaseShift(boolean)}, {@link #onPressSymbol()},
- * {@link #onReleaseSymbol()}, {@link #onOtherKeyPressed()}, {@link #onCodeInput(int, boolean)},
- * {@link #onCancelInput(boolean)}, {@link #onUpdateShiftState(boolean)}, {@link #onToggleShift()},
- * {@link #onToggleCapsLock()}, and {@link #onToggleAlphabetAndSymbols()}.
+ * {@link #onReleaseSymbol()}, {@link #onOtherKeyPressed()},
+ * {@link #onCodeInput(int, boolean, boolean)}, {@link #onCancelInput(boolean)},
+ * {@link #onUpdateShiftState(boolean)}, {@link #onToggleShift()}, {@link #onToggleCapsLock()},
+ * and {@link #onToggleAlphabetAndSymbols()}.
  *
  * The actions are {@link SwitchActions}'s methods.
  */
@@ -267,6 +268,10 @@ public class KeyboardState {
         if (DEBUG_STATE) {
             Log.d(TAG, "onUpdateShiftState: autoCaps=" + autoCaps + " " + this);
         }
+        onUpdateShiftStateInternal(autoCaps);
+    }
+
+    private void onUpdateShiftStateInternal(boolean autoCaps) {
         if (mIsAlphabetMode) {
             if (!mKeyboardShiftState.isShiftLocked() && !mShiftKeyState.isIgnoring()) {
                 if (mShiftKeyState.isReleasing() && autoCaps) {
@@ -381,10 +386,10 @@ public class KeyboardState {
         return false;
     }
 
-    public void onCodeInput(int code, boolean isSinglePointer) {
+    public void onCodeInput(int code, boolean isSinglePointer, boolean autoCaps) {
         if (DEBUG_STATE) {
             Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer
-                    + " " + this);
+                    + " autoCaps=" + autoCaps + " " + this);
         }
         switch (mSwitchState) {
         case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
@@ -446,6 +451,11 @@ public class KeyboardState {
             }
             break;
         }
+
+        // If the code is a letter, update keyboard shift state.
+        if (Keyboard.isLetterCode(code)) {
+            onUpdateShiftStateInternal(autoCaps);
+        }
     }
 
     public void onToggleShift() {
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index d2b1e9bca8e97d372e93bc2ae7d0f02152b204b8..e6478b68355724e413a247d496a95ca30ab94b25 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -1496,7 +1496,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
             if (null != ic) swapSwapperAndSpaceWhileInBatchEdit(ic);
         }
 
-        switcher.updateShiftState();
         if (mSettingsValues.isWordSeparator(code)) {
             Utils.Stats.onSeparator((char)code, x, y);
         } else {
@@ -1581,7 +1580,6 @@ public class LatinIME extends InputMethodServiceCompatWrapper implements Keyboar
 
         Utils.Stats.onSeparator((char)primaryCode, x, y);
 
-        mKeyboardSwitcher.updateShiftState();
         if (ic != null) {
             ic.endBatchEdit();
         }
diff --git a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java
index 3cd6a89445f00949938857f6caccbad1044ce090..1f6141e50f5fd4c3087d6a492e2128c8add30a43 100644
--- a/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java
+++ b/tests/src/com/android/inputmethod/keyboard/internal/KeyboardStateTests.java
@@ -90,7 +90,8 @@ public class KeyboardStateTests extends AndroidTestCase {
     // Argument for KeyboardState.onCodeInput.
     private static final boolean SINGLE = true;
     private static final boolean MULTI = false;
-
+    private static final boolean NO_AUTO_CAPS = false;
+    private static final boolean AUTO_CAPS = true;
 
     private void assertAlphabetNormal() {
         assertEquals(ALPHABET_UNSHIFTED, mSwitcher.mLayout);
@@ -213,7 +214,7 @@ public class KeyboardStateTests extends AndroidTestCase {
         // Long press recognized in LatinKeyboardView.KeyTimerHandler.
         mState.onToggleCapsLock();
         assertAlphabetShiftLocked();
-        mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE);
+        mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE, NO_AUTO_CAPS);
         assertAlphabetShiftLocked();
         mState.onReleaseShift(NOT_SLIDING);
         assertAlphabetShiftLocked();
@@ -224,7 +225,7 @@ public class KeyboardStateTests extends AndroidTestCase {
         // Long press recognized in LatinKeyboardView.KeyTimerHandler.
         mState.onToggleCapsLock();
         assertAlphabetNormal();
-        mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE);
+        mState.onCodeInput(Keyboard.CODE_CAPSLOCK, SINGLE, NO_AUTO_CAPS);
         assertAlphabetNormal();
         mState.onReleaseShift(NOT_SLIDING);
         assertAlphabetNormal();
@@ -236,7 +237,7 @@ public class KeyboardStateTests extends AndroidTestCase {
         // First shift key tap.
         mState.onPressShift(NOT_SLIDING);
         assertAlphabetManualShifted();
-        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE, NO_AUTO_CAPS);
         assertAlphabetManualShifted();
         mState.onReleaseShift(NOT_SLIDING);
         assertAlphabetManualShifted();
@@ -244,13 +245,13 @@ public class KeyboardStateTests extends AndroidTestCase {
         // Double tap recognized in LatinKeyboardView.KeyTimerHandler.
         mState.onToggleCapsLock();
         assertAlphabetShiftLocked();
-        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE, NO_AUTO_CAPS);
         assertAlphabetShiftLocked();
 
         // First shift key tap.
         mState.onPressShift(NOT_SLIDING);
         assertAlphabetManualShifted();
-        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE);
+        mState.onCodeInput(Keyboard.CODE_SHIFT, SINGLE, NO_AUTO_CAPS);
         assertAlphabetManualShifted();
         mState.onReleaseShift(NOT_SLIDING);
         assertAlphabetNormal();