12085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka/*
28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project
32085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka *
48aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
58aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * you may not use this file except in compliance with the License.
68aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * You may obtain a copy of the License at
72085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka *
88aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi 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
118aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
128aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * See the License for the specific language governing permissions and
148aa9963a895f9dd5bb1bc92ab2e4f461e058f87aTadashi G. Takaoka * limitations under the License.
152085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka */
162085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard;
182085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
19ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka/**
20ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka * This class handles key detection.
21ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka */
22ac78633be28e8990fc3b3a8de192c80966e746e3Tadashi G. Takaokapublic class KeyDetector {
23a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    private final int mKeyHysteresisDistanceSquared;
24f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka    private final int mKeyHysteresisDistanceForSlidingModifierSquared;
25a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
26dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private Keyboard mKeyboard;
27dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private int mCorrectionX;
28dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    private int mCorrectionY;
292085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
30ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka    public KeyDetector() {
31ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka        this(0.0f /* keyHysteresisDistance */, 0.0f /* keyHysteresisDistanceForSlidingModifier */);
32f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka    }
33f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka
34f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka    /**
35ef8a03685f46c7a3ce02ad4a568217c9ef7fe677Tadashi G. Takaoka     * Key detection object constructor with key hysteresis distances.
36f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     *
37f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     * @param keyHysteresisDistance if the pointer movement distance is smaller than this, the
38f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     * movement will not be handled as meaningful movement. The unit is pixel.
39f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     * @param keyHysteresisDistanceForSlidingModifier the same parameter for sliding input that
40f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     * starts from a modifier key such as shift and symbols key.
41f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka     */
429fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public KeyDetector(final float keyHysteresisDistance,
439fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka            final float keyHysteresisDistanceForSlidingModifier) {
44a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka        mKeyHysteresisDistanceSquared = (int)(keyHysteresisDistance * keyHysteresisDistance);
45f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka        mKeyHysteresisDistanceForSlidingModifierSquared = (int)(
46f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka                keyHysteresisDistanceForSlidingModifier * keyHysteresisDistanceForSlidingModifier);
47a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    }
48a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
499fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public void setKeyboard(final Keyboard keyboard, final float correctionX,
509fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka            final float correctionY) {
514e9e6cd1544f59be2ae02536af62fe5301e0cebbTadashi G. Takaoka        if (keyboard == null) {
522085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka            throw new NullPointerException();
534e9e6cd1544f59be2ae02536af62fe5301e0cebbTadashi G. Takaoka        }
54400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        mCorrectionX = (int)correctionX;
55400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        mCorrectionY = (int)correctionY;
562085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka        mKeyboard = keyboard;
57a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka    }
58a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka
599fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public int getKeyHysteresisDistanceSquared(final boolean isSlidingFromModifier) {
60f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka        return isSlidingFromModifier
61f731eb1760a5693492a34bc11aa755053aa65c19Tadashi G. Takaoka                ? mKeyHysteresisDistanceForSlidingModifierSquared : mKeyHysteresisDistanceSquared;
622085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka    }
632085d43daf44752deae1b6b00a14cb0f517d69cbTadashi G. Takaoka
649fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public int getTouchX(final int x) {
65400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        return x + mCorrectionX;
66400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    }
67400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka
685c641a9f59735f0eaa772bde027993275b1bdfd7Tadashi G. Takaoka    // TODO: Remove vertical correction.
699fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public int getTouchY(final int y) {
70400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka        return y + mCorrectionY;
71400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka    }
72400046d62e22899e28efd2a62321c637c7831f81Tadashi G. Takaoka
735a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka    public Keyboard getKeyboard() {
745a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        return mKeyboard;
756bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka    }
766bfb234f294b6ad95176f987256c85e8607d23f5Tadashi G. Takaoka
772fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    public boolean alwaysAllowsKeySelectionByDraggingFinger() {
7832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka        return false;
7932572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka    }
8032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka
810529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka    /**
82723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     * Detect the key whose hitbox the touch point is in.
83723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     *
84723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     * @param x The x-coordinate of a touch point
85723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     * @param y The y-coordinate of a touch point
86723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     * @return the key that the touch point hits.
87723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka     */
889fd7447d6c814aa48cd0b41acf9ff5fc0f62abb8Tadashi G. Takaoka    public Key detectHitKey(final int x, final int y) {
89f8a45cfd2fe3ed68d0e9ccbbed5d0beb2d1e9f06Tadashi G. Takaoka        if (mKeyboard == null) {
90f8a45cfd2fe3ed68d0e9ccbbed5d0beb2d1e9f06Tadashi G. Takaoka            return null;
91f8a45cfd2fe3ed68d0e9ccbbed5d0beb2d1e9f06Tadashi G. Takaoka        }
92723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka        final int touchX = getTouchX(x);
93723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka        final int touchY = getTouchY(y);
94dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka
951caff47ecdfcf413df709371a919cf9377e26bf7satok        int minDistance = Integer.MAX_VALUE;
961caff47ecdfcf413df709371a919cf9377e26bf7satok        Key primaryKey = null;
971caff47ecdfcf413df709371a919cf9377e26bf7satok        for (final Key key: mKeyboard.getNearestKeys(touchX, touchY)) {
983f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            // An edge key always has its enlarged hitbox to respond to an event that occurred in
993f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            // the empty area around the key. (@see Key#markAsLeftEdge(KeyboardParams)} etc.)
1003f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            if (!key.isOnKey(touchX, touchY)) {
1013f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka                continue;
1023f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            }
1031caff47ecdfcf413df709371a919cf9377e26bf7satok            final int distance = key.squaredDistanceToEdge(touchX, touchY);
1043f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            if (distance > minDistance) {
1053f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka                continue;
1063f00c6151fb7140fb7752bad3b978daacd9ec5aaTadashi G. Takaoka            }
1077dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka            // To take care of hitbox overlaps, we compare key's code here too.
1087dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka            if (primaryKey == null || distance < minDistance
1097dc60f9db729e93cb591492574a436418c553ebfTadashi G. Takaoka                    || key.getCode() > primaryKey.getCode()) {
1101caff47ecdfcf413df709371a919cf9377e26bf7satok                minDistance = distance;
1111caff47ecdfcf413df709371a919cf9377e26bf7satok                primaryKey = key;
112723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka            }
113723aaa2eebcfea0d285f11fc265941057332664dTadashi G. Takaoka        }
1141caff47ecdfcf413df709371a919cf9377e26bf7satok        return primaryKey;
115dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka    }
1160529a04b6aece3db34b4e7c895c67ad0858c8bd9Tadashi G. Takaoka}
117