PointerTracker.java revision 5c73ed628b22fdfa59585803ee86e383c579a7d4
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; 22c2a21786e526cc32e48a577a55b1b7e72ae1a6ddTadashi G. Takaoka 2372934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.PointerTrackerQueue; 24faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 26c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeSwitcher; 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 66f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka public interface DrawingProxy { 676a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public void invalidateKey(Key key); 68d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void showKeyPreview(int keyIndex, PointerTracker tracker); 695f6816fa8bf259f0340a3d12c551d1532f647d66Tadashi G. Takaoka public void cancelShowKeyPreview(PointerTracker tracker); 70d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka public void dismissKeyPreview(PointerTracker tracker); 716a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 726a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 732321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public interface TimerProxy { 742321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void startKeyRepeatTimer(long delay, int keyIndex, PointerTracker tracker); 752321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void startLongPressTimer(long delay, int keyIndex, PointerTracker tracker); 762321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void startLongPressShiftTimer(long delay, int keyIndex, PointerTracker tracker); 772321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka public void cancelLongPressTimers(); 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; 875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sTouchNoiseThresholdMillis; 885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static int sTouchNoiseThresholdDistanceSquared; 895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static final List<PointerTracker> sTrackers = new ArrayList<PointerTracker>(); 915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static PointerTrackerQueue sPointerTrackerQueue; 925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public final int mPointerId; 946a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 950efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private DrawingProxy mDrawingProxy; 960efe174ea43fe576683102effbaef5be27575706Tadashi G. Takaoka private TimerProxy mTimerProxy; 97a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka private KeyDetector mKeyDetector; 98dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private KeyboardActionListener mListener = EMPTY_LISTENER; 99baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 1005a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka private Keyboard mKeyboard; 101dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka private List<Key> mKeys; 102faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka private int mKeyQuarterWidthSquared; 1036a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position and time at which first down event occurred. 1058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mDownTime; 1068a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private long mUpTime; 1078a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1088a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The current key index where this pointer is. 1098a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyIndex = KeyDetector.NOT_A_KEY; 1108a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // The position where mKeyIndex was recognized for the first time. 1118a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyX; 1128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mKeyY; 1138a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 1148a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka // Last pointer position. 1158a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastX; 1168a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int mLastY; 1176a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1181a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // true if keyboard layout has been changed. 1191a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka private boolean mKeyboardLayoutHasBeenChanged; 1201a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka 121c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka // true if event is already translated to a key action (long press or mini-keyboard) 122c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka private boolean mKeyAlreadyProcessed; 123c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 1246252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka // true if this pointer is repeatable key 1256252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka private boolean mIsRepeatableKey; 1266252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka 127cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka // true if this pointer is in sliding key input 1285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka boolean mIsInSlidingKeyInput; 129cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 13067a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // true if sliding key is allowed. 13167a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka private boolean mIsAllowedSlidingKeyInput; 13267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka 133996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka // ignore modifier key if true 134996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private boolean mIgnoreModifierKey; 135996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 136c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // TODO: Remove these hacking variables 137c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // true if this pointer is in sliding language switch 138c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka private boolean mIsInSlidingLanguageSwitch; 139c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka private int mSpaceKeyIndex; 1405c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka private static SubtypeSwitcher sSubtypeSwitcher; 141c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka 142dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Empty {@link KeyboardActionListener} 143dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static final KeyboardActionListener EMPTY_LISTENER = new KeyboardActionListener() { 144dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka @Override 145e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onPress(int primaryCode, boolean withSliding) {} 146dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka @Override 147e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onRelease(int primaryCode, boolean withSliding) {} 148dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka @Override 1498aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCodeInput(int primaryCode, int[] keyCodes, int x, int y) {} 150dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka @Override 1518aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onTextInput(CharSequence text) {} 152dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka @Override 1538aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka public void onCancelInput() {} 154dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka }; 1556e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka 1565c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void init(boolean hasDistinctMultitouch, Context context) { 1575c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (hasDistinctMultitouch) { 1585c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = new PointerTrackerQueue(); 1595c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else { 1605c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sPointerTrackerQueue = null; 1615c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1625c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 163f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka final Resources res = context.getResources(); 1645c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sConfigSlidingKeyInputEnabled = res.getBoolean(R.bool.config_sliding_key_input_enabled); 1655c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sDelayBeforeKeyRepeatStart = res.getInteger(R.integer.config_delay_before_key_repeat_start); 1665c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sLongPressKeyTimeout = res.getInteger(R.integer.config_long_press_key_timeout); 1675c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sLongPressShiftKeyTimeout = res.getInteger(R.integer.config_long_press_shift_key_timeout); 1685c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sTouchNoiseThresholdMillis = res.getInteger(R.integer.config_touch_noise_threshold_millis); 169baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final float touchNoiseThresholdDistance = res.getDimension( 170baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka R.dimen.config_touch_noise_threshold_distance); 1715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sTouchNoiseThresholdDistanceSquared = (int)( 172baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka touchNoiseThresholdDistance * touchNoiseThresholdDistance); 1735c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sKeyboardSwitcher = KeyboardSwitcher.getInstance(); 1745c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka sSubtypeSwitcher = SubtypeSwitcher.getInstance(); 1756a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 1766a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 1775c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static PointerTracker getPointerTracker(final int id, KeyEventHandler handler) { 1785c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final List<PointerTracker> trackers = sTrackers; 1795c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1805c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Create pointer trackers until we can get 'id+1'-th tracker, if needed. 1815c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (int i = trackers.size(); i <= id; i++) { 1825c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTracker tracker = new PointerTracker(i, handler); 1835c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka trackers.add(tracker); 1845c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1855c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1865c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return trackers.get(id); 1875c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1885c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1895c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static boolean isAnyInSlidingKeyInput() { 1905c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka return sPointerTrackerQueue != null ? sPointerTrackerQueue.isAnyInSlidingKeyInput() : false; 1915c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1925c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1935c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void setKeyboardActionListener(KeyboardActionListener listener) { 1945c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 1955c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mListener = listener; 1965c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1975c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 1985c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 1995c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void setKeyDetector(KeyDetector keyDetector) { 2005c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 2015c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setKeyDetectorInner(keyDetector); 2025c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka // Mark that keyboard layout has been changed. 2035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.mKeyboardLayoutHasBeenChanged = true; 2045c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2055c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2065c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public static void dismissAllKeyPreviews() { 2085c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka for (final PointerTracker tracker : sTrackers) { 2095c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.setReleasedKeyGraphics(); 2105c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka tracker.dismissKeyPreview(); 2115c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2125c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } 2135c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka 2145c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka public PointerTracker(int id, KeyEventHandler handler) { 2155c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (handler == null) 2165c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka throw new NullPointerException(); 2175c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mPointerId = id; 2185c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 2195c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mListener = handler.getKeyboardActionListener(); 2205c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 2215c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 2226a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 2236a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 2241a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // Returns true if keyboard has been changed by this callback. 225e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka private boolean callListenerOnPressAndCheckKeyboardLayoutChange(Key key, boolean withSliding) { 226996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 227dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 228996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka Log.d(TAG, "onPress : " + keyCodePrintable(key.mCode) + " sliding=" + withSliding 229996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey); 230996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 231996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return false; 232e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) { 233e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka mListener.onPress(key.mCode, withSliding); 234690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka final boolean keyboardLayoutHasBeenChanged = mKeyboardLayoutHasBeenChanged; 235690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 236690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return keyboardLayoutHasBeenChanged; 237690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka } 238690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka return false; 239dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 240dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 241690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 242690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 243690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka private void callListenerOnCodeInput(Key key, int primaryCode, int[] keyCodes, int x, int y) { 244996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 245dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 2468aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCodeInput: " + keyCodePrintable(primaryCode) 247996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " codes="+ Arrays.toString(keyCodes) + " x=" + x + " y=" + y 248996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + " ignoreModifier=" + ignoreModifierKey); 249996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 250996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 251e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 252690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mListener.onCodeInput(primaryCode, keyCodes, x, y); 253dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 254dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 255690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka private void callListenerOnTextInput(Key key) { 256dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 257690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka Log.d(TAG, "onTextInput: text=" + key.mOutputText); 258e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 259690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka mListener.onTextInput(key.mOutputText); 260dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 261dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 262690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // Note that we need primaryCode argument because the keyboard may in shifted state and the 263690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka // primaryCode is different from {@link Key#mCode}. 264e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka private void callListenerOnRelease(Key key, int primaryCode, boolean withSliding) { 265996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka final boolean ignoreModifierKey = mIgnoreModifierKey && isModifierCode(key.mCode); 266dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 267996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka Log.d(TAG, "onRelease : " + keyCodePrintable(primaryCode) + " sliding=" 268996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka + withSliding + " ignoreModifier=" + ignoreModifierKey); 269996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (ignoreModifierKey) 270996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka return; 271e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key.isEnabled()) 272e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka mListener.onRelease(primaryCode, withSliding); 273dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 274dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 2758aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka private void callListenerOnCancelInput() { 276dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_LISTENER) 2778aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka Log.d(TAG, "onCancelInput"); 2788aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka mListener.onCancelInput(); 279dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 280dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 2815a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka public void setKeyDetectorInner(KeyDetector keyDetector) { 282a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka mKeyDetector = keyDetector; 2835a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboard = keyDetector.getKeyboard(); 2845a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeys = mKeyboard.getKeys(); 2855a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka final int keyQuarterWidth = mKeyboard.getKeyWidth() / 4; 286faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka mKeyQuarterWidthSquared = keyQuarterWidth * keyQuarterWidth; 2875a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka } 2885a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka 289cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isInSlidingKeyInput() { 290cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka return mIsInSlidingKeyInput; 291cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 292cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 293c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka private boolean isValidKeyIndex(int keyIndex) { 294dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka return keyIndex >= 0 && keyIndex < mKeys.size(); 295c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 296c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka 2976a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka public Key getKey(int keyIndex) { 298dc90d0a15f662cdece97bc2c0ddbd95e703af730Tadashi G. Takaoka return isValidKeyIndex(keyIndex) ? mKeys.get(keyIndex) : null; 2996a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3006a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 301dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static boolean isModifierCode(int primaryCode) { 302571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka return primaryCode == Keyboard.CODE_SHIFT 303e18bd3e323e7d7448677bb66e8149eea0169c771Tadashi G. Takaoka || primaryCode == Keyboard.CODE_SWITCH_ALPHA_SYMBOL; 30440a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka } 30540a05f62edc6cdedb4365a722b48a72826ef2bf6Tadashi G. Takaoka 306dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private boolean isModifierInternal(int keyIndex) { 307dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final Key key = getKey(keyIndex); 308c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka return key == null ? false : isModifierCode(key.mCode); 309dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 310dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 3112aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka public boolean isModifier() { 3128a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return isModifierInternal(mKeyIndex); 3132aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3142aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 3151d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka private boolean isOnModifierKey(int x, int y) { 3162aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka return isModifierInternal(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); 3172aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka } 3182aa8078df86029dab394d8dd616f4f6decb39035Tadashi G. Takaoka 319418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka public boolean isOnShiftKey(int x, int y) { 320418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka final Key key = getKey(mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null)); 321c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka return key != null && key.mCode == Keyboard.CODE_SHIFT; 322418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka } 323418d80d7de8d24150fc7e1710f7590a33301e546Tadashi G. Takaoka 324a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka public int getKeyIndexOn(int x, int y) { 325a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 326a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 327a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 3283a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public boolean isSpaceKey(int keyIndex) { 3293a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka Key key = getKey(keyIndex); 330c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka return key != null && key.mCode == Keyboard.CODE_SPACE; 3313a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka } 3323a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka 333d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka public void setReleasedKeyGraphics() { 3348a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka setReleasedKeyGraphics(mKeyIndex); 3354189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 3364189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka 337d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka private void setReleasedKeyGraphics(int keyIndex) { 338d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key key = getKey(keyIndex); 339d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (key != null) { 340d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka key.onReleased(); 341f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 3426a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3436a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 3446a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 345d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka private void setPressedKeyGraphics(int keyIndex) { 346d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key key = getKey(keyIndex); 347e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key != null && key.isEnabled()) { 348d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka key.onPressed(); 349f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.invalidateKey(key); 350d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 351c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka } 352c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka 3538a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastX() { 3548a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastX; 3558a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3568a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3578a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public int getLastY() { 3588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mLastY; 3598a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3618a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka public long getDownTime() { 3628a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mDownTime; 3638a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3648a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3658a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onDownKey(int x, int y, long eventTime) { 3668a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mDownTime = eventTime; 3678a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveToNewKey(onMoveKeyInternal(x, y), x, y); 3688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3698a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3708a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveKeyInternal(int x, int y) { 3718a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastX = x; 3728a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mLastY = y; 3738a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 3748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3758a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveKey(int x, int y) { 3778a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 3788a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3798a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3808a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onMoveToNewKey(int keyIndex, int x, int y) { 3818a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyIndex = keyIndex; 3828a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyX = x; 3838a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyY = y; 3848a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return keyIndex; 3858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 3878a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka private int onUpKey(int x, int y, long eventTime) { 3888a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mUpTime = eventTime; 3898a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka mKeyIndex = KeyDetector.NOT_A_KEY; 3908a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka return onMoveKeyInternal(x, y); 3918a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka } 3928a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka 393f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka public void onDownEvent(int x, int y, long eventTime, KeyEventHandler handler) { 394dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 395dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onDownEvent:", x, y, eventTime); 3961d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 397f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka mDrawingProxy = handler.getDrawingProxy(); 39863c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka mTimerProxy = handler.getTimerProxy(); 399f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyboardActionListener(handler.getKeyboardActionListener()); 400f426cdd5c62452224ac4bb833c3ccf7b26d1a2a8Tadashi G. Takaoka setKeyDetectorInner(handler.getKeyDetector()); 401baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka // Naive up-to-down noise filter. 4028a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final long deltaT = eventTime - mUpTime; 4035c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (deltaT < sTouchNoiseThresholdMillis) { 4048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dx = x - mLastX; 4058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int dy = y - mLastY; 406baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka final int distanceSquared = (dx * dx + dy * dy); 4075c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (distanceSquared < sTouchNoiseThresholdDistanceSquared) { 408faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 409faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, "onDownEvent: ignore potential noise: time=" + deltaT 410faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + " distance=" + distanceSquared); 411d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 412baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka return; 413baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 414baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka } 415baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 4165c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 4171d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 4181d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (isOnModifierKey(x, y)) { 4191d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing a down event of modifier key, all pointers already being 4201d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 4211d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointers(eventTime); 4221d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4231d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.add(this); 4241d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4251d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 4261d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 4271d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 428baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onDownEventInternal(int x, int y, long eventTime) { 4298a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int keyIndex = onDownKey(x, y, eventTime); 43067a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka // Sliding key is allowed when 1) enabled by configuration, 2) this pointer starts sliding 431101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka // from modifier key, or 3) this pointer is on mini-keyboard. 4325c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mIsAllowedSlidingKeyInput = sConfigSlidingKeyInputEnabled || isModifierInternal(keyIndex) 433101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka || mKeyDetector instanceof MiniKeyboardKeyDetector; 4341a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka mKeyboardLayoutHasBeenChanged = false; 435c5d33b16521de56ad01b0b6308217efb009078b7Tadashi G. Takaoka mKeyAlreadyProcessed = false; 4366252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka mIsRepeatableKey = false; 437cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 438c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka mIsInSlidingLanguageSwitch = false; 439996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = false; 440d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (isValidKeyIndex(keyIndex)) { 4411a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 4421a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update keyIndex according to the new 4431a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // keyboard layout. 444d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), false)) 4458a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onDownKey(x, y, eventTime); 446996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 447a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka startRepeatKey(keyIndex); 448adf24e2eb49acd32d2655a3964f68da1e54c05ecTadashi G. Takaoka startLongPressTimer(keyIndex); 449d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka showKeyPreview(keyIndex); 450d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 4516a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4526a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 4536a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 454996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka private void startSlidingKeyInput(Key key) { 455996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka if (!mIsInSlidingKeyInput) 456996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIgnoreModifierKey = isModifierCode(key.mCode); 457996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka mIsInSlidingKeyInput = true; 458996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka } 459996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka 460906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onMoveEvent(int x, int y, long eventTime) { 461dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_MOVE_EVENT) 462dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onMoveEvent:", x, y, eventTime); 463e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka if (mKeyAlreadyProcessed) 464e8f45ab56f3e6f358953dede794a63fc5901961dTadashi G. Takaoka return; 465baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka 466c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // TODO: Remove this hacking code 467c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (mIsInSlidingLanguageSwitch) { 4688a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka ((LatinKeyboard)mKeyboard).updateSpacebarPreviewIcon(x - mKeyX); 469c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka showKeyPreview(mSpaceKeyIndex); 470c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka return; 471c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 4728a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastX = mLastX; 4738a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int lastY = mLastY; 4748a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int oldKeyIndex = mKeyIndex; 475d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final Key oldKey = getKey(oldKeyIndex); 4768a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int keyIndex = onMoveKey(x, y); 477c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (isValidKeyIndex(keyIndex)) { 478c0b5c9c43e5eb7a6ed768d56f462ca9ed5c5f913Tadashi G. Takaoka if (oldKey == null) { 4799e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key, but the finger was not on any keys. 4809e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // In this case, we must call onPress() to notify that the new key is being pressed. 4811a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected at 4821a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // {@link #setKeyboard}. In those cases, we should update keyIndex according to the 4831a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // new keyboard layout. 484e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) 4858a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onMoveKey(x, y); 4868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 487adf24e2eb49acd32d2655a3964f68da1e54c05ecTadashi G. Takaoka startLongPressTimer(keyIndex); 488d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka showKeyPreview(keyIndex); 489d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 490e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka } else if (isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { 4919e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid in to the new key from the previous key, we must call 4929e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onRelease() first to notify that the previous key has been released, then call 4939e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // onPress() to notify that the new key is being pressed. 494d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 495e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 496996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 4972321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 498a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka startRepeatKey(keyIndex); 49967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 5001a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // This onPress call may have changed keyboard layout. Those cases are detected 5011a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // at {@link #setKeyboard}. In those cases, we should update keyIndex according 5021a6fba570260ca9f837e5a6874274f39a3c0a734Tadashi G. Takaoka // to the new keyboard layout. 503e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka if (callListenerOnPressAndCheckKeyboardLayoutChange(getKey(keyIndex), true)) 5048a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyIndex = onMoveKey(x, y); 5058a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 50667a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka startLongPressTimer(keyIndex); 507d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setPressedKeyGraphics(keyIndex); 508d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka showKeyPreview(keyIndex); 50967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 510faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // HACK: On some devices, quick successive touches may be translated to sudden 511faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move by touch panel firmware. This hack detects the case and translates the 512faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka // move event to successive up and down events. 513faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dx = x - lastX; 514faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int dy = y - lastY; 515faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka final int lastMoveSquared = dx * dx + dy * dy; 516faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (lastMoveSquared >= mKeyQuarterWidthSquared) { 517faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka if (DEBUG_MODE) 518faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka Log.w(TAG, String.format("onMoveEvent: sudden move is translated to " 519faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka + "up[%d,%d]/down[%d,%d] events", lastX, lastY, x, y)); 520d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka onUpEventInternal(lastX, lastY, eventTime, true); 521faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka onDownEventInternal(x, y, eventTime); 522faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } else { 523d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 524d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka dismissKeyPreview(); 525d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 526faf437b5078e882b630706cd315c335f204ab861Tadashi G. Takaoka } 52767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 528c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 529c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // TODO: Remove this hack code 530c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka else if (isSpaceKey(keyIndex) && !mIsInSlidingLanguageSwitch 531c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka && mKeyboard instanceof LatinKeyboard) { 532c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka final LatinKeyboard keyboard = ((LatinKeyboard)mKeyboard); 5335c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka if (sSubtypeSwitcher.useSpacebarLanguageSwitcher() 5345c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka && sSubtypeSwitcher.getEnabledKeyboardLocaleCount() > 1) { 5358a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int diff = x - mKeyX; 536c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (keyboard.shouldTriggerSpacebarSlidingLanguageSwitch(diff)) { 537c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // Detect start sliding language switch. 538c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka mIsInSlidingLanguageSwitch = true; 539c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka mSpaceKeyIndex = keyIndex; 540c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka keyboard.updateSpacebarPreviewIcon(diff); 541c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // Display spacebar slide language switcher. 542c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka showKeyPreview(keyIndex); 5435c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 544d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka if (queue != null) 545d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime, true); 546c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 547c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 5486a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5496a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 550e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka if (oldKey != null && isMajorEnoughMoveToBeOnNewKey(x, y, keyIndex)) { 5519e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The pointer has been slid out from the previous key, we must call onRelease() to 5529e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // notify that the previous key has been released. 553d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka setReleasedKeyGraphics(oldKeyIndex); 554e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(oldKey, oldKey.mCode, true); 555996db15d3c018ed2a7b4eee96ea94b9f80d8e379Tadashi G. Takaoka startSlidingKeyInput(oldKey); 5562321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelLongPressTimers(); 55767a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka if (mIsAllowedSlidingKeyInput) { 5588a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka onMoveToNewKey(keyIndex, x, y); 55967a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } else { 560d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 561d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka dismissKeyPreview(); 56267a4ecacc7525c9343cded13fc93e9a2381ea2d8Tadashi G. Takaoka } 56307221a4ad11fa5ae6275c107f1f86260691bd505Tadashi G. Takaoka } 5646a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5656a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 5666a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 567906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onUpEvent(int x, int y, long eventTime) { 568dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 569dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onUpEvent :", x, y, eventTime); 5701d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 5715c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 5721d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (queue != null) { 5731d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka if (isModifier()) { 5741d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // Before processing an up event of modifier key, all pointers already being 5751d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka // tracked should be released. 576c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime, true); 5771d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } else { 5781d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.releaseAllPointersOlderThan(this, eventTime); 5791d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5801d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 5811d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 582d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka onUpEventInternal(x, y, eventTime, true); 5831d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5841d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 585d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // Let this pointer tracker know that one of newer-than-this pointer trackers got an up event. 586d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // This pointer tracker needs to keep the key top graphics "pressed", but needs to get a 587d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka // "virtual" up event. 588c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka public void onPhantomUpEvent(int x, int y, long eventTime, boolean updateReleasedKeyGraphics) { 589c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (DEBUG_EVENT) 590c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka printTouchEvent("onPhntEvent:", x, y, eventTime); 591c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka onUpEventInternal(x, y, eventTime, updateReleasedKeyGraphics); 592d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 5931d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 5941d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 595d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka private void onUpEventInternal(int x, int y, long eventTime, 596d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka boolean updateReleasedKeyGraphics) { 5972321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 598f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.cancelShowKeyPreview(this); 599cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 600d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka final int keyX, keyY; 6018a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka if (isMajorEnoughMoveToBeOnNewKey(x, y, onMoveKey(x, y))) { 602d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka keyX = x; 603d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka keyY = y; 604d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } else { 605d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka // Use previous fixed key coordinates. 6068a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyX = mKeyX; 6078a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka keyY = mKeyY; 6086a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6098a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka final int keyIndex = onUpKey(keyX, keyY, eventTime); 610d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka dismissKeyPreview(); 611d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka if (updateReleasedKeyGraphics) 612d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka setReleasedKeyGraphics(keyIndex); 613d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka if (mKeyAlreadyProcessed) 614d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka return; 615c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // TODO: Remove this hacking code 616c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (mIsInSlidingLanguageSwitch) { 617c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka setReleasedKeyGraphics(mSpaceKeyIndex); 618c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka final int languageDir = ((LatinKeyboard)mKeyboard).getLanguageChangeDirection(); 619c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (languageDir != 0) { 620c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka final int code = (languageDir == 1) 621c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka ? LatinKeyboard.CODE_NEXT_LANGUAGE : LatinKeyboard.CODE_PREV_LANGUAGE; 622c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka // This will change keyboard layout. 623c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka mListener.onCodeInput(code, new int[] {code}, keyX, keyY); 624c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 625c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka mIsInSlidingLanguageSwitch = false; 626f172be448c0787fb67612afe05c2a30f944dab77Tadashi G. Takaoka ((LatinKeyboard)mKeyboard).setSpacebarSlidingLanguageSwitchDiff(0); 627c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka return; 628c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 6296252f468bc1306f71c9933f65b116dbbb5530de8Tadashi G. Takaoka if (!mIsRepeatableKey) { 630d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka detectAndSendKey(keyIndex, keyX, keyY); 6316a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6326a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6336a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 634906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onLongPressed() { 635d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka mKeyAlreadyProcessed = true; 63663c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka setReleasedKeyGraphics(); 63763c233ab9f50d844be6e52e382c6664475606760Tadashi G. Takaoka dismissKeyPreview(); 6385c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 6391ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka if (queue != null) { 640d00d963b9d47c1bba6f65534033a33fe7c30dde5Tadashi G. Takaoka queue.remove(this); 6411ddb4897fee79ec00c68e4a255e653568477a995Tadashi G. Takaoka } 642d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka } 643d2c2b4d112ee17750c1a49ff223b9410aa9e4ec6Tadashi G. Takaoka 644906f03121b6c6a795f35dbc24d2eceac0665f35fTadashi G. Takaoka public void onCancelEvent(int x, int y, long eventTime) { 645dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (DEBUG_EVENT) 646dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka printTouchEvent("onCancelEvt:", x, y, eventTime); 6471d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 6485c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka final PointerTrackerQueue queue = sPointerTrackerQueue; 649c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka if (queue != null) { 650c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka queue.releaseAllPointersExcept(this, eventTime, true); 6511d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka queue.remove(this); 652c5c57b506e97b334a394d23ed73c9597cb55707aTadashi G. Takaoka } 653baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka onCancelEventInternal(); 6541d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka } 6551d7d9664a9850a7c8043651e4b7a055ec034f571Tadashi G. Takaoka 656baf83886be975d804eda3e1519b7255026e5163eTadashi G. Takaoka private void onCancelEventInternal() { 6572321caa1f9eb6c2d616bc36f11f5b48eebf144feTadashi G. Takaoka mTimerProxy.cancelKeyTimers(); 658f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.cancelShowKeyPreview(this); 659d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka dismissKeyPreview(); 6608a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka setReleasedKeyGraphics(mKeyIndex); 661cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka mIsInSlidingKeyInput = false; 6626a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6636a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 664a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka private void startRepeatKey(int keyIndex) { 665a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka final Key key = getKey(keyIndex); 666101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka if (key != null && key.mRepeatable) { 667a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka dismissKeyPreview(); 668a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka onRepeatKey(keyIndex); 6695c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startKeyRepeatTimer(sDelayBeforeKeyRepeatStart, keyIndex, this); 670a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka mIsRepeatableKey = true; 671a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } else { 672a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka mIsRepeatableKey = false; 673a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 674a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka } 675a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka 676a0537fb4c73dff8beecc328720830af9719d0277Tadashi G. Takaoka public void onRepeatKey(int keyIndex) { 677c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka Key key = getKey(keyIndex); 678c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka if (key != null) { 679c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka detectAndSendKey(keyIndex, key.mX, key.mY); 680c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } 6816a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6826a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 683e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka private boolean isMajorEnoughMoveToBeOnNewKey(int x, int y, int newKey) { 684a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka if (mKeys == null || mKeyDetector == null) 685a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka throw new NullPointerException("keyboard and/or key detector not set"); 6868a995157f37365cf79b893e9106d1830d70c39dcTadashi G. Takaoka int curKey = mKeyIndex; 6876a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka if (newKey == curKey) { 688e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return false; 689c6df09182cac288c9a4de2cc05628dac6b6db41eTadashi G. Takaoka } else if (isValidKeyIndex(curKey)) { 690a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka return mKeys.get(curKey).squaredDistanceToEdge(x, y) 691a19b84dcf65bd70caa0fc72089cfe043b023a898Tadashi G. Takaoka >= mKeyDetector.getKeyHysteresisDistanceSquared(); 6926a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } else { 693e6cb8fc234940700ae97af787e62962a98d332e5Tadashi G. Takaoka return true; 6946a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6956a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 6966a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 697101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka // The modifier key, such as shift key, should not show its key preview. 698ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka private boolean isKeyPreviewNotRequired(int keyIndex) { 699967d6073bfd5f3d0e21512754d78d2e87c958e27Tadashi G. Takaoka final Key key = getKey(keyIndex); 700e7759091ddb5ec18268945d70d9212195bf6497bTadashi G. Takaoka if (key == null || !key.isEnabled()) 701ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka return true; 702ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka // Such as spacebar sliding language switch. 703ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka if (mKeyboard.needSpacebarPreview(keyIndex)) 704ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka return false; 705ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka final int code = key.mCode; 706ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka return isModifierCode(code) || code == Keyboard.CODE_DELETE 707ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka || code == Keyboard.CODE_ENTER || code == Keyboard.CODE_SPACE; 708ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka } 709ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka 710ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka private void showKeyPreview(int keyIndex) { 711ba9aefcc188b7f8ac99ba6cfef42a032b7d693a4Tadashi G. Takaoka if (isKeyPreviewNotRequired(keyIndex)) 712d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka return; 713f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.showKeyPreview(keyIndex, this); 714d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka } 715d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka 716d9786ce2e389c8c02af7773b53b5c44fe4fa0b0cTadashi G. Takaoka private void dismissKeyPreview() { 717f60d09ac3086f308cafcee13ebcb94c562f9e58eTadashi G. Takaoka mDrawingProxy.dismissKeyPreview(this); 7186a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7196a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 72066e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka private void startLongPressTimer(int keyIndex) { 72166e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka Key key = getKey(keyIndex); 722c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka if (key.mCode == Keyboard.CODE_SHIFT) { 7235c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startLongPressShiftTimer(sLongPressShiftKeyTimeout, keyIndex, this); 7249d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka } else if (key.hasUppercaseLetter() && mKeyboard.isManualTemporaryUpperCase()) { 7252b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka // We need not start long press timer on the key which has manual temporary upper case 7262b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka // code defined and the keyboard is in manual temporary upper case mode. 7272b13b4f5e55b2bf5086b112f2d5d438810fdd70fTadashi G. Takaoka return; 7285c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka } else if (sKeyboardSwitcher.isInMomentarySwitchState()) { 7299e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // We use longer timeout for sliding finger input started from the symbols mode key. 7305c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressKeyTimeout * 3, keyIndex, this); 7314189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } else { 7325c73ed628b22fdfa59585803ee86e383c579a7d4Tadashi G. Takaoka mTimerProxy.startLongPressTimer(sLongPressKeyTimeout, keyIndex, this); 7334189eb23082fcd4bf8cfb2085d18e226e0e7ce13Tadashi G. Takaoka } 73466e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka } 73566e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 736c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka private void detectAndSendKey(int index, int x, int y) { 73783e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka final Key key = getKey(index); 73883e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka if (key == null) { 7398aa3f5a3ad6095a3355841ce30bce4877319d0a0Tadashi G. Takaoka callListenerOnCancelInput(); 740dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return; 741dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 742dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (key.mOutputText != null) { 743690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka callListenerOnTextInput(key); 744e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(key, key.mCode, false); 74583e63ace2a1bd5b3c27d26d914456c2b0def17c5Tadashi G. Takaoka } else { 746c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka int code = key.mCode; 747dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final int[] codes = mKeyDetector.newCodeArray(); 748dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka mKeyDetector.getKeyIndexAndNearbyCodes(x, y, codes); 74966e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 750dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // If keyboard is in manual temporary upper case state and key has manual temporary 7519d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka // uppercase letter as key hint letter, alternate character code should be sent. 7529d9522abdcee70408c9e99ac20c8e1c224eef19dTadashi G. Takaoka if (mKeyboard.isManualTemporaryUpperCase() && key.hasUppercaseLetter()) { 753520a297ad1d148a57bcf6559a9802d5d49182d70Tadashi G. Takaoka code = key.mHintLabel.charAt(0); 754dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[0] = code; 755dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 75666e306d01c6820d4f4d8b2209438ec086b48ac51Tadashi G. Takaoka 757dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // Swap the first and second values in the codes array if the primary code is not the 758dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // first value but the second value in the array. This happens when key debouncing is 759dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka // in effect. 760dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka if (codes.length >= 2 && codes[0] != code && codes[1] == code) { 761dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[1] = codes[0]; 762dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka codes[0] = code; 7636a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 764690b1360bfda3cbaae896de65dcc3cd347dc8329Tadashi G. Takaoka callListenerOnCodeInput(key, code, codes, x, y); 765e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka callListenerOnRelease(key, code, false); 7666a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7676a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka } 7686a1514a0deac7f3d8ec33430403b2caea05bc8b9Tadashi G. Takaoka 769dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private long mPreviousEventTime; 770dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 771dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private void printTouchEvent(String title, int x, int y, long eventTime) { 772dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(x, y, null); 773dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final Key key = getKey(keyIndex); 774c4f71668d7b8203dc66f0f04c089a363189eb4ceTadashi G. Takaoka final String code = (key == null) ? "----" : keyCodePrintable(key.mCode); 775dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final long delta = eventTime - mPreviousEventTime; 776dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka Log.d(TAG, String.format("%s%s[%d] %4d %4d %5d %3d(%s)", title, 777dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka (mKeyAlreadyProcessed ? "-" : " "), mPointerId, x, y, delta, keyIndex, code)); 778dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka mPreviousEventTime = eventTime; 779dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka } 780dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka 781dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka private static String keyCodePrintable(int primaryCode) { 782dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka final String modifier = isModifierCode(primaryCode) ? " modifier" : ""; 783dbc44989a5be68679c889ae45cde17002b748fdaTadashi G. Takaoka return String.format((primaryCode < 0) ? "%4d" : "0x%02x", primaryCode) + modifier; 7843d4123fabb51a0c929401d98fca496759a5aa0d6Tadashi G. Takaoka } 7856e5a3986854549a45c95770b5a88ae5577e93299Tadashi G. Takaoka} 786