12085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka/*
28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project
32085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka *
42085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not
52085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of
62085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * the License at
72085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka *
82085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0
92085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka *
102085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
112085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
122085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
132085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * License for the specific language governing permissions and limitations under
142085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka * the License.
152085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka */
162085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard;
182085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
19dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaokaimport android.util.Log;
20dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
216bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaokaimport java.util.Arrays;
222085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaokaimport java.util.List;
232085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
24dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaokapublic class KeyDetector {
25dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private static final String TAG = KeyDetector.class.getSimpleName();
26dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private static final boolean DEBUG = false;
270529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka
28dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    public static final int NOT_A_CODE = -1;
29dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    public static final int NOT_A_KEY = -1;
300529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka
31a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    private final int mKeyHysteresisDistanceSquared;
32a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
33dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private Keyboard mKeyboard;
34dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private int mCorrectionX;
35dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private int mCorrectionY;
36dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private boolean mProximityCorrectOn;
37dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private int mProximityThresholdSquare;
380529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka
39dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    // working area
40dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private static final int MAX_NEARBY_KEYS = 12;
41dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private final int[] mDistances = new int[MAX_NEARBY_KEYS];
42dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private final int[] mIndices = new int[MAX_NEARBY_KEYS];
432085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
44a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    /**
45a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka     * This class handles key detection.
46a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka     *
47a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka     * @param keyHysteresisDistance if the pointer movement distance is smaller than this, the
48a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka     * movement will not been handled as meaningful movement. The unit is pixel.
49a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka     */
50a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    public KeyDetector(float keyHysteresisDistance) {
51a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka        mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
52a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    }
53a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
54dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    public void setKeyboard(Keyboard keyboard, float correctionX, float correctionY) {
552085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        if (keyboard == null)
562085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka            throw new NullPointerException();
57400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        mCorrectionX = (int)correctionX;
58400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        mCorrectionY = (int)correctionY;
592085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        mKeyboard = keyboard;
608da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka        final int threshold = keyboard.mMostCommonKeyWidth;
61a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka        mProximityThresholdSquare = threshold * threshold;
62a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    }
63a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
64a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    public int getKeyHysteresisDistanceSquared() {
65a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka        return mKeyHysteresisDistanceSquared;
662085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    }
672085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
68400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    protected int getTouchX(int x) {
69400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        return x + mCorrectionX;
70400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    }
71400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka
72400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    protected int getTouchY(int y) {
73400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        return y + mCorrectionY;
74400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    }
75400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka
765a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka    public Keyboard getKeyboard() {
77dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        if (mKeyboard == null)
786bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka            throw new IllegalStateException("keyboard isn't set");
795a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        return mKeyboard;
806bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka    }
816bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka
822085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    public void setProximityCorrectionEnabled(boolean enabled) {
832085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        mProximityCorrectOn = enabled;
842085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    }
852085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
862085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    public boolean isProximityCorrectionEnabled() {
872085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        return mProximityCorrectOn;
882085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    }
892085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
902085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    public void setProximityThreshold(int threshold) {
912085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        mProximityThresholdSquare = threshold * threshold;
922085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    }
932085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
9432572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka    public boolean alwaysAllowsSlidingInput() {
9532572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        return false;
9632572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka    }
9732572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
980529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka    /**
99dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * Computes maximum size of the array that can contain all nearby key indices returned by
100dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * {@link #getKeyIndexAndNearbyCodes}.
101dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     *
102dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * @return Returns maximum size of the array that can contain all nearby key indices returned
103dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     *         by {@link #getKeyIndexAndNearbyCodes}.
104dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     */
105dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    protected int getMaxNearbyKeys() {
106dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        return MAX_NEARBY_KEYS;
107dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
108dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
109dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    /**
1100529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * Allocates array that can hold all key indices returned by {@link #getKeyIndexAndNearbyCodes}
1110529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * method. The maximum size of the array should be computed by {@link #getMaxNearbyKeys}.
1120529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     *
1130529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * @return Allocates and returns an array that can hold all key indices returned by
1140529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     *         {@link #getKeyIndexAndNearbyCodes} method. All elements in the returned array are
11544fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka     *         initialized by {@link #NOT_A_CODE} value.
1160529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     */
1176bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka    public int[] newCodeArray() {
1186bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka        int[] codes = new int[getMaxNearbyKeys()];
11944fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka        Arrays.fill(codes, NOT_A_CODE);
1206bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka        return codes;
1216bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka    }
1226bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka
123dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private void initializeNearbyKeys() {
124dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        Arrays.fill(mDistances, Integer.MAX_VALUE);
125dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        Arrays.fill(mIndices, NOT_A_KEY);
126dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
127dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
1280529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka    /**
129dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * Insert the key into nearby keys buffer and sort nearby keys by ascending order of distance.
13044fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka     * If the distance of two keys are the same, the key which the point is on should be considered
13144fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka     * as a closer one.
1320529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     *
133dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * @param keyIndex index of the key.
134dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * @param distance distance between the key's edge and user touched point.
13544fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka     * @param isOnKey true if the point is on the key.
136dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka     * @return order of the key in the nearby buffer, 0 if it is the nearest key.
1370529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     */
13844fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka    private int sortNearbyKeys(int keyIndex, int distance, boolean isOnKey) {
139dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        final int[] distances = mDistances;
140dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        final int[] indices = mIndices;
141dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        for (int insertPos = 0; insertPos < distances.length; insertPos++) {
14244fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka            final int comparingDistance = distances[insertPos];
14344fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka            if (distance < comparingDistance || (distance == comparingDistance && isOnKey)) {
144dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                final int nextPos = insertPos + 1;
145dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                if (nextPos < distances.length) {
146dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                    System.arraycopy(distances, insertPos, distances, nextPos,
147dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                            distances.length - nextPos);
148dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                    System.arraycopy(indices, insertPos, indices, nextPos,
149dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                            indices.length - nextPos);
150dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                }
151dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                distances[insertPos] = distance;
152dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                indices[insertPos] = keyIndex;
153dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                return insertPos;
154dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            }
155dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        }
156dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        return distances.length;
157dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
158dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
159dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private void getNearbyKeyCodes(final int[] allCodes) {
1601be29abab2e112f0253a8a5da3478740bb866d27Tadashi G. Takaoka        final List<Key> keys = getKeyboard().mKeys;
161dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        final int[] indices = mIndices;
162dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
163dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        // allCodes[0] should always have the key code even if it is a non-letter key.
164dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        if (indices[0] == NOT_A_KEY) {
165dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            allCodes[0] = NOT_A_CODE;
166dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            return;
167dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        }
168dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
169dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        int numCodes = 0;
170dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        for (int j = 0; j < indices.length && numCodes < allCodes.length; j++) {
171dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            final int index = indices[j];
172dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            if (index == NOT_A_KEY)
173dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                break;
174dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            final int code = keys.get(index).mCode;
175dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            // filter out a non-letter key from nearby keys
176dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            if (code < Keyboard.CODE_SPACE)
177dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                continue;
178dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            allCodes[numCodes++] = code;
179dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        }
180dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
1812085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
1820529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka    /**
1830529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * Finds all possible nearby key indices around a touch event point and returns the nearest key
1840529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * index. The algorithm to determine the nearby keys depends on the threshold set by
1850529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * {@link #setProximityThreshold(int)} and the mode set by
1860529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * {@link #setProximityCorrectionEnabled(boolean)}.
1870529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     *
1880529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * @param x The x-coordinate of a touch point
1890529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * @param y The y-coordinate of a touch point
190887f11ee43ad621aa6ad93d535ab7f48dec73fc7Tadashi G. Takaoka     * @param allCodes All nearby key code except functional key are returned in this array
1910529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     * @return The nearest key index
1920529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka     */
193dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    public int getKeyIndexAndNearbyCodes(int x, int y, final int[] allCodes) {
1941be29abab2e112f0253a8a5da3478740bb866d27Tadashi G. Takaoka        final List<Key> keys = getKeyboard().mKeys;
195dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        final int touchX = getTouchX(x);
196dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        final int touchY = getTouchY(y);
197dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
198dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        initializeNearbyKeys();
199dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        int primaryIndex = NOT_A_KEY;
200dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        for (final int index : mKeyboard.getNearestKeys(touchX, touchY)) {
201dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            final Key key = keys.get(index);
20244fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka            final boolean isOnKey = key.isOnKey(touchX, touchY);
203dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            final int distance = key.squaredDistanceToEdge(touchX, touchY);
20444fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka            if (isOnKey || (mProximityCorrectOn && distance < mProximityThresholdSquare)) {
20544fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka                final int insertedPosition = sortNearbyKeys(index, distance, isOnKey);
20644fe4a0598d831ad33e62cd7742709fd45c60387Tadashi G. Takaoka                if (insertedPosition == 0 && isOnKey)
207dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                    primaryIndex = index;
208dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            }
209dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        }
210dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
211dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        if (allCodes != null && allCodes.length > 0) {
212dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            getNearbyKeyCodes(allCodes);
213dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            if (DEBUG) {
214dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                Log.d(TAG, "x=" + x + " y=" + y
215dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                        + " primary="
216dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                        + (primaryIndex == NOT_A_KEY ? "none" : keys.get(primaryIndex).mCode)
217dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka                        + " codes=" + Arrays.toString(allCodes));
218dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka            }
219dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        }
220dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
221dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka        return primaryIndex;
222dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
2230529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka}
224