diff --git a/java/src/com/android/inputmethod/event/Event.java b/java/src/com/android/inputmethod/event/Event.java
index ed487e13fcccbc3b3022491c62d93266acf3b2cc..41bf36b366e73ccc40fd51d735efd6e7ebc7b952 100644
--- a/java/src/com/android/inputmethod/event/Event.java
+++ b/java/src/com/android/inputmethod/event/Event.java
@@ -168,4 +168,8 @@ public class Event {
     public boolean isCommittable() {
         return EVENT_INPUT_KEYPRESS == mType || EVENT_MODE_KEY == mType || EVENT_TOGGLE == mType;
     }
+
+    public boolean isHandled() {
+        return EVENT_NOT_HANDLED != mType;
+    }
 }
diff --git a/java/src/com/android/inputmethod/event/EventInterpreter.java b/java/src/com/android/inputmethod/event/EventInterpreter.java
index 726b9206bdc966b4f5f76bafed937f96b274cb2b..bcf10fc58ca5e43197e2e632075421042912cadd 100644
--- a/java/src/com/android/inputmethod/event/EventInterpreter.java
+++ b/java/src/com/android/inputmethod/event/EventInterpreter.java
@@ -16,11 +16,6 @@
 
 package com.android.inputmethod.event;
 
-import android.util.SparseArray;
-import android.view.KeyEvent;
-
-import com.android.inputmethod.latin.Constants;
-import com.android.inputmethod.latin.LatinIME;
 import com.android.inputmethod.latin.utils.CollectionUtils;
 
 import java.util.ArrayList;
@@ -37,25 +32,9 @@ public class EventInterpreter {
     // TODO: Implement an object pool for events, as we'll create a lot of them
     // TODO: Create a combiner
     // TODO: Create an object type to represent input material + visual feedback + decoding state
-    // TODO: Create an interface to call back to Latin IME through the above object
 
-    final EventDecoderSpec mDecoderSpec;
-    final SparseArray<HardwareEventDecoder> mHardwareEventDecoders;
-    final SoftwareEventDecoder mSoftwareEventDecoder;
-    final LatinIME mLatinIme;
-    final ArrayList<Combiner> mCombiners;
-
-    /**
-     * Create a default interpreter.
-     *
-     * This creates a default interpreter that does nothing. A default interpreter should normally
-     * only be used for fallback purposes, when we really don't know what we want to do with input.
-     *
-     * @param latinIme a reference to the ime.
-     */
-    public EventInterpreter(final LatinIME latinIme) {
-        this(null, latinIme);
-    }
+    private final EventDecoderSpec mDecoderSpec;
+    private final ArrayList<Combiner> mCombiners;
 
     /**
      * Create an event interpreter according to a specification.
@@ -70,64 +49,10 @@ public class EventInterpreter {
      * interpreter that does no specific combining, and assumes the most common cases.
      *
      * @param specification the specification for event interpretation. null for default.
-     * @param latinIme a reference to the ime.
      */
-    public EventInterpreter(final EventDecoderSpec specification, final LatinIME latinIme) {
+    public EventInterpreter(final EventDecoderSpec specification) {
         mDecoderSpec = null != specification ? specification : new EventDecoderSpec();
-        // For both, we expect to have only one decoder in almost all cases, hence the default
-        // capacity of 1.
-        mHardwareEventDecoders = new SparseArray<HardwareEventDecoder>(1);
-        mSoftwareEventDecoder = new SoftwareKeyboardEventDecoder();
         mCombiners = CollectionUtils.newArrayList();
         mCombiners.add(new DeadKeyCombiner());
-        mLatinIme = latinIme;
-    }
-
-    // Helper method to decode a hardware key event into a generic event, and execute any
-    // necessary action.
-    public boolean onHardwareKeyEvent(final KeyEvent hardwareKeyEvent) {
-        final Event decodedEvent = getHardwareKeyEventDecoder(hardwareKeyEvent.getDeviceId())
-                .decodeHardwareKey(hardwareKeyEvent);
-        return onEvent(decodedEvent);
-    }
-
-    public boolean onSoftwareEvent() {
-        final Event decodedEvent = getSoftwareEventDecoder().decodeSoftwareEvent();
-        return onEvent(decodedEvent);
-    }
-
-    private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) {
-        final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId);
-        if (null != decoder) return decoder;
-        // TODO: create the decoder according to the specification
-        final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId);
-        mHardwareEventDecoders.put(deviceId, newDecoder);
-        return newDecoder;
-    }
-
-    private SoftwareEventDecoder getSoftwareEventDecoder() {
-        // Within the context of Latin IME, since we never present several software interfaces
-        // at the time, we should never need multiple software event decoders at a time.
-        return mSoftwareEventDecoder;
-    }
-
-    private boolean onEvent(final Event event) {
-        Event currentlyProcessingEvent = event;
-        boolean processed = false;
-        for (int i = 0; i < mCombiners.size(); ++i) {
-            currentlyProcessingEvent = mCombiners.get(i).combine(event);
-        }
-        while (null != currentlyProcessingEvent) {
-            if (currentlyProcessingEvent.isCommittable()) {
-                mLatinIme.onCodeInput(currentlyProcessingEvent.mCodePoint,
-                        Constants.EXTERNAL_KEYBOARD_COORDINATE,
-                        Constants.EXTERNAL_KEYBOARD_COORDINATE);
-                processed = true;
-            } else if (event.isDead()) {
-                processed = true;
-            }
-            currentlyProcessingEvent = currentlyProcessingEvent.mNextEvent;
-        }
-        return processed;
     }
 }
diff --git a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java b/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java
deleted file mode 100644
index d81ee0b37abc5023d809e148e9004ec4520f0bdd..0000000000000000000000000000000000000000
--- a/java/src/com/android/inputmethod/event/SoftwareEventDecoder.java
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.event;
-
-/**
- * An event decoder for events out of a software keyboard.
- *
- * This defines the interface for an event decoder that supports events out of a software keyboard.
- * This differs significantly from hardware keyboard event decoders in several respects. First,
- * a software keyboard does not have a scancode/layout system; the keypresses that insert
- * characters output unicode characters directly.
- */
-public interface SoftwareEventDecoder extends EventDecoder {
-    public Event decodeSoftwareEvent();
-}
diff --git a/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java b/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java
deleted file mode 100644
index de91567c73765fff01e6bdacb8e20bdaa68f1f7e..0000000000000000000000000000000000000000
--- a/java/src/com/android/inputmethod/event/SoftwareKeyboardEventDecoder.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.inputmethod.event;
-
-/**
- * A decoder for events from software keyboard, like the ones displayed by Latin IME.
- */
-public class SoftwareKeyboardEventDecoder implements SoftwareEventDecoder {
-    @Override
-    public Event decodeSoftwareEvent() {
-        return null;
-    }
-}
diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java
index 222e7352988f201ab410dbbb55c5eb096e13fcf9..b7a822d79f1a300fe0b57899fa7e1d2221b5ca59 100644
--- a/java/src/com/android/inputmethod/latin/LatinIME.java
+++ b/java/src/com/android/inputmethod/latin/LatinIME.java
@@ -45,6 +45,7 @@ import android.text.TextUtils;
 import android.util.Log;
 import android.util.PrintWriterPrinter;
 import android.util.Printer;
+import android.util.SparseArray;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewGroup.LayoutParams;
@@ -60,6 +61,8 @@ import com.android.inputmethod.annotations.UsedForTesting;
 import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
 import com.android.inputmethod.dictionarypack.DictionaryPackConstants;
 import com.android.inputmethod.event.Event;
+import com.android.inputmethod.event.HardwareEventDecoder;
+import com.android.inputmethod.event.HardwareKeyboardEventDecoder;
 import com.android.inputmethod.event.InputTransaction;
 import com.android.inputmethod.keyboard.Keyboard;
 import com.android.inputmethod.keyboard.KeyboardActionListener;
@@ -120,6 +123,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
     private final Settings mSettings;
     private final InputLogic mInputLogic = new InputLogic(this /* LatinIME */,
             this /* SuggestionStripViewAccessor */);
+    // We expect to have only one decoder in almost all cases, hence the default capacity of 1.
+    // If it turns out we need several, it will get grown seamlessly.
+    final SparseArray<HardwareEventDecoder> mHardwareEventDecoders
+            = new SparseArray<HardwareEventDecoder>(1);
 
     private View mExtractArea;
     private View mKeyPreviewBackingView;
@@ -1588,19 +1595,31 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
         }
     }
 
+    private HardwareEventDecoder getHardwareKeyEventDecoder(final int deviceId) {
+        final HardwareEventDecoder decoder = mHardwareEventDecoders.get(deviceId);
+        if (null != decoder) return decoder;
+        // TODO: create the decoder according to the specification
+        final HardwareEventDecoder newDecoder = new HardwareKeyboardEventDecoder(deviceId);
+        mHardwareEventDecoders.put(deviceId, newDecoder);
+        return newDecoder;
+    }
+
     // Hooks for hardware keyboard
     @Override
-    public boolean onKeyDown(final int keyCode, final KeyEvent event) {
-        if (!ProductionFlag.IS_HARDWARE_KEYBOARD_SUPPORTED) return super.onKeyDown(keyCode, event);
-        // onHardwareKeyEvent, like onKeyDown returns true if it handled the event, false if
-        // it doesn't know what to do with it and leave it to the application. For example,
-        // hardware key events for adjusting the screen's brightness are passed as is.
-        if (mInputLogic.mEventInterpreter.onHardwareKeyEvent(event)) {
-            final long keyIdentifier = event.getDeviceId() << 32 + event.getKeyCode();
-            mInputLogic.mCurrentlyPressedHardwareKeys.add(keyIdentifier);
+    public boolean onKeyDown(final int keyCode, final KeyEvent keyEvent) {
+        if (!ProductionFlag.IS_HARDWARE_KEYBOARD_SUPPORTED) {
+            return super.onKeyDown(keyCode, keyEvent);
+        }
+        final Event event = getHardwareKeyEventDecoder(
+                keyEvent.getDeviceId()).decodeHardwareKey(keyEvent);
+        // If the event is not handled by LatinIME, we just pass it to the parent implementation.
+        // If it's handled, we return true because we did handle it.
+        if (event.isHandled()) {
+            mInputLogic.onCodeInput(mSettings.getCurrent(), event,
+                    mKeyboardSwitcher.getKeyboardShiftMode(), mHandler);
             return true;
         }
-        return super.onKeyDown(keyCode, event);
+        return super.onKeyDown(keyCode, keyEvent);
     }
 
     @Override
diff --git a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
index cb55aa06c4c071a2c0f68645aebafde86d5bfd28..67e56fd8b8339a2a0ff1d99393e294775409691d 100644
--- a/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
+++ b/java/src/com/android/inputmethod/latin/inputlogic/InputLogic.java
@@ -80,8 +80,6 @@ public final class InputLogic {
     public SuggestedWords mSuggestedWords = SuggestedWords.EMPTY;
     // TODO: mSuggest should be touched by a single thread.
     public volatile Suggest mSuggest;
-    // The event interpreter should never be null.
-    public final EventInterpreter mEventInterpreter;
 
     public LastComposedWord mLastComposedWord = LastComposedWord.NOT_A_COMPOSED_WORD;
     public final WordComposer mWordComposer;
@@ -104,7 +102,6 @@ public final class InputLogic {
         mLatinIME = latinIME;
         mSuggestionStripViewAccessor = suggestionStripViewAccessor;
         mWordComposer = new WordComposer();
-        mEventInterpreter = new EventInterpreter(latinIME);
         mConnection = new RichInputConnection(latinIME);
         mInputLogicHandler = InputLogicHandler.NULL_HANDLER;
     }