PointerTracker.java revision 9d5601e9013c5ec9a7ac75db16f4a0a8218b02bf
16a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka/* 28632bff2d5a8e1160989008dea6eff4b94b065ddTadashi G. Takaoka * Copyright (C) 2010 The Android Open Source Project 36a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 46a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); you may not 56a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * use this file except in compliance with the License. You may obtain a copy of 66a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License at 76a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 86a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 96a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * 106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 126a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 136a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * License for the specific language governing permissions and limitations under 146a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka * the License. 156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka */ 166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 19f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaokaimport android.content.Context; 20c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.content.res.Resources; 21c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaokaimport android.util.Log; 224692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaokaimport android.widget.TextView; 23c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 2472934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 25faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 265a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 276a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaokaimport java.util.ArrayList; 29dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaokaimport java.util.Arrays; 30dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaokaimport java.util.List; 31dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 326a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaokapublic class PointerTracker { 33dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final String TAG = PointerTracker.class.getSimpleName(); 34dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_EVENT = false; 35dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_MOVE_EVENT = false; 36dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final boolean DEBUG_LISTENER = false; 37faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private static boolean DEBUG_MODE = LatinImeLogger.sDBG; 3840a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 39f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public interface KeyEventHandler { 40f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 41f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyDetector object that is used for this PointerTracker. 42f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyDetector object that is used for this PointerTracker 43f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 44f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyDetector getKeyDetector(); 45f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 46f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 47f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get KeyboardActionListener object that is used to register key code and so on. 48f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the KeyboardActionListner for this PointerTracker 49f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 50f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public KeyboardActionListener getKeyboardActionListener(); 51f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 52f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 53f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get DrawingProxy object that is used for this PointerTracker. 54f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the DrawingProxy object that is used for this PointerTracker 55f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 56f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public DrawingProxy getDrawingProxy(); 57f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 58f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka /** 59f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * Get TimerProxy object that handles key repeat and long press timer event for this 60f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * PointerTracker. 61f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka * @return the TimerProxy object that handles key repeat and long press timer event. 62f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka */ 63f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public TimerProxy getTimerProxy(); 64f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka } 65f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka 669d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public interface DrawingProxy extends MoreKeysPanel.Controller { 676a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 684692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka public TextView inflateKeyPreviewText(); 69d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void showKeyPreview(int keyIndex, PointerTracker tracker); 705f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelShowKeyPreview(PointerTracker tracker); 71d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 726a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 736a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 742321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 752321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker); 762321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); 7798b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka public void cancelLongPressTimer(); 782321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelKeyTimers(); 792321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka } 802321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka 815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static KeyboardSwitcher sKeyboardSwitcher; 825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static boolean sConfigSlidingKeyInputEnabled; 836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka // Timing constants 845c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sDelayBeforeKeyRepeatStart; 855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sLongPressKeyTimeout; 865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sLongPressShiftKeyTimeout; 8798b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka private static int sLongPressSpaceKeyTimeout; 885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sTouchNoiseThresholdMillis; 895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sTouchNoiseThresholdDistanceSquared; 905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static final List<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); 925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static PointerTrackerQueue sPointerTrackerQueue; 935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 956a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 960efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 970efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 98a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 99dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 100baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1015a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 102dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka private List<Key> mKeys; 103faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private int mKeyQuarterWidthSquared; 1044692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka private final TextView mKeyPreviewText; 1056a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1068a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 1078a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 1088a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 1098a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1108a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The current key index where this pointer is. 1118a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyIndex = KeyDetector.NOT_A_KEY; 1128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position where mKeyIndex was recognized for the first time. 1138a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 1148a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 1158a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 1178a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 1188a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 1196a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1201a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 1211a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 1221a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 1239ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka // true if event is already translated to a key action. 124c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 125c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 1269d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka // true if this pointer has been long-pressed and is showing a more keys panel. 1279d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka private boolean mIsShowingMoreKeysPanel; 1289ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 1296252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka // true if this pointer is repeatable key 1306252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka private boolean mIsRepeatableKey; 1316252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka 132cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka // true if this pointer is in sliding key input 1335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 134cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 13567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // true if sliding key is allowed. 13667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 13767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 138996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka // ignore modifier key if true 139996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private boolean mIgnoreModifierKey; 140996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 141dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 142e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = 143e3be3bcebc11892b536fdf650f74bba21af13383Tadashi G. Takaoka new KeyboardActionListener.Adapter(); 1446e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 1455c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void init(boolean hasDistinctMultitouch, Context context) { 1465c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (hasDistinctMultitouch) { 1475c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = new PointerTrackerQueue(); 1485c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else { 1495c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = null; 1505c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1515c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 152f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final Resources res = context.getResources(); 1535c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled); 1545c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); 1555c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout); 1565c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sLongPressShiftKeyTimeout = res.getInteger(R.integer.config_long_press_shift_key_timeout); 15798b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka sLongPressSpaceKeyTimeout = res.getInteger(R.integer.config_long_press_space_key_timeout); 1585c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sTouchNoiseThresholdMillis = res.getInteger(R.integer.config_touch_noise_threshold_millis); 159baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final float touchNoiseThresholdDistance = res.getDimension( 160baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka R.dimen.config_touch_noise_threshold_distance); 1615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sTouchNoiseThresholdDistanceSquared = (int)( 162baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka touchNoiseThresholdDistance * touchNoiseThresholdDistance); 1635c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sKeyboardSwitcher = KeyboardSwitcher.getInstance(); 1646a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1656a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1665c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { 1675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final List<PointerTracker> trackers = sTrackers; 1685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1695c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 1705c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 1715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 1725c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 1735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 1765c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1775c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 1795c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false; 1805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void setKeyboardActionListener(KeyboardActionListener listener) { 1835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 1845c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 1855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void setKeyDetector(KeyDetector keyDetector) { 1895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 1905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 1915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 1925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 1935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void dismissAllKeyPreviews() { 1975c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 198d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka tracker.setReleasedKeyGraphics(tracker.mKeyIndex); 1995c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public PointerTracker(int id, KeyEventHandler handler) { 2035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (handler == null) 2045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 2055c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 2065c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 2075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 2085c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 2095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 2104692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka mKeyPreviewText = mDrawingProxy.inflateKeyPreviewText(); 2114692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka } 2124692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka 2134692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka public TextView getKeyPreviewText() { 2144692af50daefea9498faebeaa8d7e7a444afda4cTadashi G. Takaoka return mKeyPreviewText; 2156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2166a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2171a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 218e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) { 219996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 220dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 221996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka Log.d(TAG, "onPress : " + keyCodePrintable(key.mCode) + " sliding=" + withSliding 222996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey); 223996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 224996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 225e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 226e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka mListener.onPress(key.mCode, withSliding); 227690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 228690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 229690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 230690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 231690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 232dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 233dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 234690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 235690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 236690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) { 237996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 238dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 2398aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode) 240996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y 241996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey); 242996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 243996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 244e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 245690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mListener.onCodeInput(primaryCode, keyCodes, x, y); 246dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 247dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 248690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka private void callListenerOnTextInput(Key key) { 249dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 250690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka Log.d(TAG, "onTextInput: text=" + key.mOutputText); 251e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 252690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mListener.onTextInput(key.mOutputText); 253dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 254dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 255690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 256690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 257e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { 258996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 259dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 260996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka Log.d(TAG, "onRelease : " + keyCodePrintable(primaryCode) + " sliding=" 261996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + withSliding + " ignoreModifier=" + ignoreModifierKey); 262996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 263996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 264e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 265e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka mListener.onRelease(primaryCode, withSliding); 266dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 267dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 2688aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 269dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 2708aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCancelInput"); 2718aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 272dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 273dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 27446286874f30c4a6ef44646c4e4adf36fe55c74b9Tadashi G. Takaoka private void setKeyDetectorInner(KeyDetector keyDetector) { 275a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 2765a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 2771be29abab2e112f0253a8a5da3478740bb866d27Tadashi G. Takaoka mKeys = mKeyboard.mKeys; 2788da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka final int keyQuarterWidth = mKeyboard.mMostCommonKeyWidth / 4; 279faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; 2805a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 2815a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 282cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 283cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 284cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 285cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 286c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka private boolean isValidKeyIndex(int keyIndex) { 287dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka return keyIndex >= 0 && keyIndex < mKeys.size(); 288c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 289c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka 2906a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public Key getKey(int keyIndex) { 291dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka return isValidKeyIndex(keyIndex) ? mKeys.get(keyIndex) : null; 2926a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2936a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 294dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static boolean isModifierCode(int primaryCode) { 295571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka return primaryCode == Keyboard.CODE_SHIFT 296e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka || primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; 29740a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka } 29840a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 299dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private boolean isModifierInternal(int keyIndex) { 300dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final Key key = getKey(keyIndex); 301c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka return key == null ? false : isModifierCode(key.mCode); 302dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 303dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 3042aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 3058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return isModifierInternal(mKeyIndex); 3062aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3072aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 3081d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka private boolean isOnModifierKey(int x, int y) { 3092aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); 3102aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3112aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 312418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka public boolean isOnShiftKey(int x, int y) { 313418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); 314c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka return key != null && key.mCode == Keyboard.CODE_SHIFT; 315418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka } 316418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka 317a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka public int getKeyIndexOn(int x, int y) { 318a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 319a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 320a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 321d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka private void setReleasedKeyGraphics(int keyIndex) { 322d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 323d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key key = getKey(keyIndex); 324d4b533774df4db403ecf2a7126f2637c451aefeeTadashi G. Takaoka if (key != null && key.isEnabled()) { 325d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka key.onReleased(); 326f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 3276a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3286a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3296a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 330d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka private void setPressedKeyGraphics(int keyIndex) { 331d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key key = getKey(keyIndex); 332e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key != null && key.isEnabled()) { 333d4b533774df4db403ecf2a7126f2637c451aefeeTadashi G. Takaoka if (isKeyPreviewRequired(key)) { 334d4b533774df4db403ecf2a7126f2637c451aefeeTadashi G. Takaoka mDrawingProxy.showKeyPreview(keyIndex, this); 335d4b533774df4db403ecf2a7126f2637c451aefeeTadashi G. Takaoka } 336d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka key.onPressed(); 337f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 338d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 339c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 340c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 341d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka // The modifier key, such as shift key, should not show its key preview. 342d4b533774df4db403ecf2a7126f2637c451aefeeTadashi G. Takaoka private static boolean isKeyPreviewRequired(Key key) { 343d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka final int code = key.mCode; 344d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka if (isModifierCode(code) || code == Keyboard.CODE_DELETE 345d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka || code == Keyboard.CODE_ENTER || code == Keyboard.CODE_SPACE) 346d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka return false; 347d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka return true; 348d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka } 349d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka 3508a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 3518a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 3528a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3538a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 3558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 3568a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 3598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 3608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3618a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3628a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onDownKey(int x, int y, long eventTime) { 3638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 3648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 3658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveKeyInternal(int x, int y) { 3688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 3698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 3708a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 3718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3728a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3738a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveKey(int x, int y) { 3748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 3758a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3778a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveToNewKey(int keyIndex, int x, int y) { 3788a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyIndex = keyIndex; 3798a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 3808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 3818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return keyIndex; 3828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3838a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3848a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onUpKey(int x, int y, long eventTime) { 3858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mUpTime = eventTime; 3868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyIndex = KeyDetector.NOT_A_KEY; 3878a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 3888a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3898a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 390f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) { 391dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 392dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 3931d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 394f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 39563c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 396f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 397f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 398baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 3998a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 4005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (deltaT < sTouchNoiseThresholdMillis) { 4018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dx = x - mLastX; 4028a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dy = y - mLastY; 403baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final int distanceSquared = (dx * dx + dy * dy); 4045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (distanceSquared < sTouchNoiseThresholdDistanceSquared) { 405faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 406faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT 407faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + " distance=" + distanceSquared); 408d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 409baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 410baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 411baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 412baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 4135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 4141d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 4151d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (isOnModifierKey(x, y)) { 4161d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 4171d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 4181d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointers(eventTime); 4191d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4201d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.add(this); 4211d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4221d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 4231d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4241d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 425baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onDownEventInternal(int x, int y, long eventTime) { 4268a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int keyIndex = onDownKey(x, y, eventTime); 42767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 42832572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka // from modifier key, or 3) this pointer's KeyDetector always allows sliding input. 4295c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) 43032572948d7e3956efebcbd69d7c7d8403bb659e6Tadashi G. Takaoka || mKeyDetector.alwaysAllowsSlidingInput(); 4311a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 432c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 4336252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka mIsRepeatableKey = false; 434cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 435996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = false; 436d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (isValidKeyIndex(keyIndex)) { 4371a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 4381a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new 4391a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 440d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false)) 4418a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onDownKey(x, y, eventTime); 442996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 443a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka startRepeatKey(keyIndex); 444adf24e2eb49acd32d2655a3964f68da1e54c05ecTadashi G. Takaoka startLongPressTimer(keyIndex); 445d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 4466a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4476a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4486a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 449996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private void startSlidingKeyInput(Key key) { 450996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (!mIsInSlidingKeyInput) 451996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = isModifierCode(key.mCode); 452996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 453996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 454996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 455906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onMoveEvent(int x, int y, long eventTime) { 456dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_MOVE_EVENT) 457dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 458e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka if (mKeyAlreadyProcessed) 459e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 460baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 4618a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 4628a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 4638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int oldKeyIndex = mKeyIndex; 464d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key oldKey = getKey(oldKeyIndex); 4658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int keyIndex = onMoveKey(x, y); 466c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (isValidKeyIndex(keyIndex)) { 467c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (oldKey == null) { 4689e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 4699e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 4701a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 4711a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update keyIndex according to the 4721a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // new keyboard layout. 473e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) 4748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onMoveKey(x, y); 4758a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 476adf24e2eb49acd32d2655a3964f68da1e54c05ecTadashi G. Takaoka startLongPressTimer(keyIndex); 477d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 478e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka } else if (isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { 4799e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 4809e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 4819e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onPress() to notify that the new key is being pressed. 482d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 483e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 484996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 4852321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 486a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka startRepeatKey(keyIndex); 48767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 4881a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 4891a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update keyIndex according 4901a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // to the new keyboard layout. 491e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) 4928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onMoveKey(x, y); 4938a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 49467a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka startLongPressTimer(keyIndex); 495d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 49667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 497faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be translated to sudden 498faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move by touch panel firmware. This hack detects the case and translates the 499faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move event to successive up and down events. 500faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dx = x - lastX; 501faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dy = y - lastY; 502faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int lastMoveSquared = dx * dx + dy * dy; 503faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (lastMoveSquared >= mKeyQuarterWidthSquared) { 504faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 505faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, String.format("onMoveEvent: sudden move is translated to " 506faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); 507d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka onUpEventInternal(lastX, lastY, eventTime); 508faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 509faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } else { 510d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 511d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 512faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 51367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 514c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 5156a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 516e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { 5179e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 5189e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // notify that the previous key has been released. 519d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 520e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 521996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 52298b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.cancelLongPressTimer(); 52367a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 5248a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 52567a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 526d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 52767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 52807221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 5296a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5306a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5316a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 532906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onUpEvent(int x, int y, long eventTime) { 533dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 534dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 5351d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 5365c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 5371d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 5381d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (isModifier()) { 5391d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 5401d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 541d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime); 5421d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } else { 5431d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointersOlderThan(this, eventTime); 5441d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5451d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 5461d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 547d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka onUpEventInternal(x, y, eventTime); 5481d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5491d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 550d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 551d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 552d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 553d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka public void onPhantomUpEvent(int x, int y, long eventTime) { 554c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (DEBUG_EVENT) 555c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka printTouchEvent("onPhntEvent:", x, y, eventTime); 556d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka onUpEventInternal(x, y, eventTime); 557d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 5581d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5591d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 560d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka private void onUpEventInternal(int x, int y, long eventTime) { 5612321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 562f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.cancelShowKeyPreview(this); 563cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 564d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final int keyX, keyY; 5658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { 566d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka keyX = x; 567d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka keyY = y; 568d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } else { 569d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka // Use previous fixed key coordinates. 5708a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyX = mKeyX; 5718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyY = mKeyY; 5726a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5738a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int keyIndex = onUpKey(keyX, keyY, eventTime); 574d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka setReleasedKeyGraphics(keyIndex); 5759d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 5769d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 5779d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 5789ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 579d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (mKeyAlreadyProcessed) 580d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 5816252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka if (!mIsRepeatableKey) { 582d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka detectAndSendKey(keyIndex, keyX, keyY); 5836a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5846a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5856a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 5869d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka public void onShowMoreKeysPanel(int x, int y, long eventTime, KeyEventHandler handler) { 5879ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onLongPressed(); 5889ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka onDownEvent(x, y, eventTime, handler); 5899d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = true; 5909ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 5919ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka 592906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 593d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 594d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka setReleasedKeyGraphics(mKeyIndex); 5955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 5961ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka if (queue != null) { 597d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.remove(this); 5981ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka } 599d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 600d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 601906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onCancelEvent(int x, int y, long eventTime) { 602dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 603dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 6041d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 6055c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 606c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (queue != null) { 607d3002aa8cd5339d59123e0c96174f6701e2c72ccTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime); 6081d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 609c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 610baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 6111d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6121d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 613baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 6142321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 615f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.cancelShowKeyPreview(this); 6168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka setReleasedKeyGraphics(mKeyIndex); 617cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 6189d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka if (mIsShowingMoreKeysPanel) { 6199d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mDrawingProxy.dismissMoreKeysPanel(); 6209d5601e9013c5ec9a7ac75db16f4a0a8218b02bfTadashi G. Takaoka mIsShowingMoreKeysPanel = false; 6219ec80d9d89eb599329c354451acdc482cc3de836Tadashi G. Takaoka } 6226a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6236a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 624a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka private void startRepeatKey(int keyIndex) { 625a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka final Key key = getKey(keyIndex); 626101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka if (key != null && key.mRepeatable) { 627a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka onRepeatKey(keyIndex); 6285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, keyIndex, this); 629a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka mIsRepeatableKey = true; 630a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } else { 631a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka mIsRepeatableKey = false; 632a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 633a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 634a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 635a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka public void onRepeatKey(int keyIndex) { 636c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka Key key = getKey(keyIndex); 637c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 638c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka detectAndSendKey(keyIndex, key.mX, key.mY); 639c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 6406a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6416a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 642e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, int newKey) { 643a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka if (mKeys == null || mKeyDetector == null) 644a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 6458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int curKey = mKeyIndex; 6466a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 647e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 648c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } else if (isValidKeyIndex(curKey)) { 649a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka return mKeys.get(curKey).squaredDistanceToEdge(x, y) 650a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka >= mKeyDetector.getKeyHysteresisDistanceSquared(); 6516a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 652e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 6536a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6546a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6556a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 65666e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka private void startLongPressTimer(int keyIndex) { 65766e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka Key key = getKey(keyIndex); 6580a5345c7b6e9282ea401a4017c2c2f9835e623b1Tadashi G. Takaoka if (key == null) return; 659c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka if (key.mCode == Keyboard.CODE_SHIFT) { 66098b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka if (sLongPressShiftKeyTimeout > 0) { 66198b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressShiftKeyTimeout, keyIndex, this); 66298b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka } 66398b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka } else if (key.mCode == Keyboard.CODE_SPACE) { 66498b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka if (sLongPressSpaceKeyTimeout > 0) { 66598b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressSpaceKeyTimeout, keyIndex, this); 66698b5c982b93cbfc74b221af30079ecb69dd4e0a1Tadashi G. Takaoka } 6679d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { 6682b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka // We need not start long press timer on the key which has manual temporary upper case 6692b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka // code defined and the keyboard is in manual temporary upper case mode. 6702b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka return; 6715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else if (sKeyboardSwitcher.isInMomentarySwitchState()) { 6729e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // We use longer timeout for sliding finger input started from the symbols mode key. 6735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, keyIndex, this); 6744189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 6755c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, keyIndex, this); 6764189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 67766e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 67866e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 679c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka private void detectAndSendKey(int index, int x, int y) { 68083e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka final Key key = getKey(index); 68183e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 6828aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 683dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 684dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 685dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (key.mOutputText != null) { 686690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka callListenerOnTextInput(key); 687e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(key, key.mCode, false); 68883e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } else { 689c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka int code = key.mCode; 690dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final int[] codes = mKeyDetector.newCodeArray(); 691dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); 69266e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 693dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // If keyboard is in manual temporary upper case state and key has manual temporary 6949d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka // uppercase letter as key hint letter, alternate character code should be sent. 6959d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) { 696520a297ad1d148a57bcf6559a9802d5d49182d70Tadashi G. Takaoka code = key.mHintLabel.charAt(0); 697dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[0] = code; 698dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 69966e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 700dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Swap the first and second values in the codes array if the primary code is not the 701dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // first value but the second value in the array. This happens when key debouncing is 702dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // in effect. 703dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (codes.length >= 2 && codes[0] != code && codes[1] == code) { 704dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[1] = codes[0]; 705dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[0] = code; 7066a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 707690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka callListenerOnCodeInput(key, code, codes, x, y); 708e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(key, code, false); 7096a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7106a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7116a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 712dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private long mPreviousEventTime; 713dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 714dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private void printTouchEvent(String title, int x, int y, long eventTime) { 715dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 716dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final Key key = getKey(keyIndex); 717c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka final String code = (key == null) ? "----" : keyCodePrintable(key.mCode); 718dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final long delta = eventTime - mPreviousEventTime; 719dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %3d(%s)", title, 720dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, keyIndex, code)); 721dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka mPreviousEventTime = eventTime; 722dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 723dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 724dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static String keyCodePrintable(int primaryCode) { 725dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final String modifier = isModifierCode(primaryCode) ? " modifier" : ""; 726dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode) + modifier; 7273d4123fabb51a0c929401d98fca496759a5aa0d6Tadashi G. Takaoka } 7286e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 729