diff --git a/java/src/com/android/inputmethod/latin/KeyDetector.java b/java/src/com/android/inputmethod/latin/KeyDetector.java
new file mode 100644
index 0000000000000000000000000000000000000000..11d5f861d3786719e9093181c3ff358872d3e79c
--- /dev/null
+++ b/java/src/com/android/inputmethod/latin/KeyDetector.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2010 Google Inc.
+ *
+ * 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.latin;
+
+import android.inputmethodservice.Keyboard;
+import android.inputmethodservice.Keyboard.Key;
+
+import java.util.List;
+
+abstract class KeyDetector {
+    protected Keyboard mKeyboard;
+    protected Key[] mKeys;
+
+    protected boolean mProximityCorrectOn;
+    protected int mProximityThresholdSquare;
+
+    public Key[] setKeyboard(Keyboard keyboard) {
+        if (keyboard == null)
+            throw new NullPointerException();
+        mKeyboard = keyboard;
+        List<Key> keys = mKeyboard.getKeys();
+        Key[] array = keys.toArray(new Key[keys.size()]);
+        mKeys = array;
+        return array;
+    }
+
+    public void setProximityCorrectionEnabled(boolean enabled) {
+        mProximityCorrectOn = enabled;
+    }
+
+    public boolean isProximityCorrectionEnabled() {
+        return mProximityCorrectOn;
+    }
+
+    public void setProximityThreshold(int threshold) {
+        mProximityThresholdSquare = threshold * threshold;
+    }
+
+    abstract public int[] newCodeArray();
+
+    abstract public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys);
+}
\ No newline at end of file
diff --git a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
index d1a5cd8e4e4463d3662f7aa74283f5f219213cc3..9ebab256da1fc957717a758dde0bf8caafc5bc7a 100644
--- a/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
+++ b/java/src/com/android/inputmethod/latin/LatinKeyboardBaseView.java
@@ -45,7 +45,6 @@ import android.widget.TextView;
 
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.List;
 import java.util.Map;
 
 /**
@@ -202,7 +201,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
     private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
     private final float mDebounceHysteresis;
 
-    private final ProximityKeyDetector mProximityKeyDetector = new ProximityKeyDetector();
+    protected KeyDetector mKeyDetector = new ProximityKeyDetector();
 
     // Swipe gesture detector
     private final GestureDetector mGestureDetector;
@@ -473,8 +472,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
     public void setOnKeyboardActionListener(OnKeyboardActionListener listener) {
         mKeyboardActionListener = listener;
         for (PointerTracker tracker : mPointerTrackers) {
-            if (tracker != null)
-                tracker.setOnKeyboardActionListener(listener);
+            tracker.setOnKeyboardActionListener(listener);
         }
     }
 
@@ -501,13 +499,10 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
         mHandler.cancelKeyTimers();
         mHandler.cancelPopupPreview();
         mKeyboard = keyboard;
-        LatinImeLogger.onSetKeyboard(mKeyboard);
-        List<Key> keys = mKeyboard.getKeys();
-        mKeys = keys.toArray(new Key[keys.size()]);
-        mProximityKeyDetector.setKeyboard(keyboard, mKeys);
+        LatinImeLogger.onSetKeyboard(keyboard);
+        mKeys = mKeyDetector.setKeyboard(keyboard);
         for (PointerTracker tracker : mPointerTrackers) {
-            if (tracker != null)
-                tracker.setKeyboard(mKeys, mDebounceHysteresis);
+            tracker.setKeyboard(mKeys, mDebounceHysteresis);
         }
         requestLayout();
         // Hint to reallocate the buffer if the size changed
@@ -599,14 +594,14 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
      * @param enabled whether or not the proximity correction is enabled
      */
     public void setProximityCorrectionEnabled(boolean enabled) {
-        mProximityKeyDetector.setProximityCorrectionEnabled(enabled);
+        mKeyDetector.setProximityCorrectionEnabled(enabled);
     }
 
     /**
      * Returns true if proximity correction is enabled.
      */
     public boolean isProximityCorrectionEnabled() {
-        return mProximityKeyDetector.isProximityCorrectionEnabled();
+        return mKeyDetector.isProximityCorrectionEnabled();
     }
 
     /**
@@ -658,7 +653,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
             dimensionSum += Math.min(key.width, key.height) + key.gap;
         }
         if (dimensionSum < 0 || length == 0) return;
-        mProximityKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
+        mKeyDetector.setProximityThreshold((int) (dimensionSum * 1.4f / length));
     }
 
     @Override
@@ -1052,7 +1047,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
         // Create pointer trackers until we can get 'id+1'-th tracker, if needed.
         for (int i = pointers.size(); i <= id; i++) {
             final PointerTracker tracker =
-                new PointerTracker(mHandler, mProximityKeyDetector, this);
+                new PointerTracker(mHandler, mKeyDetector, this);
             if (keys != null)
                 tracker.setKeyboard(keys, mDebounceHysteresis);
             if (listener != null)
diff --git a/java/src/com/android/inputmethod/latin/PointerTracker.java b/java/src/com/android/inputmethod/latin/PointerTracker.java
index 3c67ebece38a924875d0651dedb7dcf7d895073e..8c85e97f917cf568d3e6050cda2414de621538b1 100644
--- a/java/src/com/android/inputmethod/latin/PointerTracker.java
+++ b/java/src/com/android/inputmethod/latin/PointerTracker.java
@@ -45,7 +45,7 @@ public class PointerTracker {
 
     private final UIProxy mProxy;
     private final UIHandler mHandler;
-    private final ProximityKeyDetector mKeyDetector;
+    private final KeyDetector mKeyDetector;
     private OnKeyboardActionListener mListener;
 
     private Key[] mKeys;
@@ -77,7 +77,7 @@ public class PointerTracker {
     // pressed key
     private int mPreviousKey = NOT_A_KEY;
 
-    public PointerTracker(UIHandler handler, ProximityKeyDetector keyDetector, UIProxy proxy) {
+    public PointerTracker(UIHandler handler, KeyDetector keyDetector, UIProxy proxy) {
         if (proxy == null || handler == null || keyDetector == null)
             throw new NullPointerException();
         mProxy = proxy;
diff --git a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java
index eae2d7f08df45d161e299496b14a896c1d9abc06..6ee0055100cbda50a1b61673a76bf2bb217a4241 100644
--- a/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java
+++ b/java/src/com/android/inputmethod/latin/ProximityKeyDetector.java
@@ -16,48 +16,24 @@
 
 package com.android.inputmethod.latin;
 
-import android.inputmethodservice.Keyboard;
 import android.inputmethodservice.Keyboard.Key;
 
 import java.util.Arrays;
 
-class ProximityKeyDetector {
+class ProximityKeyDetector extends KeyDetector {
     private static final int MAX_NEARBY_KEYS = 12;
 
-    private Keyboard mKeyboard;
-    private Key[] mKeys;
-
-    private boolean mProximityCorrectOn;
-    private int mProximityThresholdSquare;
-
     // working area
     private int[] mDistances = new int[MAX_NEARBY_KEYS];
 
-    public void setKeyboard(Keyboard keyboard, Key[] keys) {
-        if (keyboard == null || keys == null)
-            throw new NullPointerException();
-        mKeyboard = keyboard;
-        mKeys = keys;
-    }
-
-    public void setProximityCorrectionEnabled(boolean enabled) {
-        mProximityCorrectOn = enabled;
-    }
-
-    public boolean isProximityCorrectionEnabled() {
-        return mProximityCorrectOn;
-    }
-
-    public void setProximityThreshold(int threshold) {
-        mProximityThresholdSquare = threshold * threshold;
-    }
-
+    @Override
     public int[] newCodeArray() {
         int[] codes = new int[MAX_NEARBY_KEYS];
         Arrays.fill(codes, LatinKeyboardBaseView.NOT_A_KEY);
         return codes;
     }
 
+    @Override
     public int getKeyIndexAndNearbyCodes(int x, int y, int[] allKeys) {
         final Key[] keys = mKeys;
         if (keys == null)