Queuing PointerTracker to support n-key roll-over and shift modifier.

Bug: 2910379
Change-Id: I5cfae33e72a406585137842a2260310813cee07f
main
Tadashi G. Takaoka 2010-09-02 01:35:24 +09:00
parent f7d71c338f
commit 40a05f62ed
4 changed files with 153 additions and 7 deletions

View File

@ -227,6 +227,9 @@ public class LatinIME extends InputMethodService
private int mDeleteCount; private int mDeleteCount;
private long mLastKeyTime; private long mLastKeyTime;
// Shift modifier key state
private ModifierKeyState mShiftKeyState = new ModifierKeyState();
private Tutorial mTutorial; private Tutorial mTutorial;
private AudioManager mAudioManager; private AudioManager mAudioManager;
@ -976,7 +979,8 @@ public class LatinIME extends InputMethodService
public void updateShiftKeyState(EditorInfo attr) { public void updateShiftKeyState(EditorInfo attr) {
InputConnection ic = getCurrentInputConnection(); InputConnection ic = getCurrentInputConnection();
if (ic != null && attr != null && mKeyboardSwitcher.isAlphabetMode()) { if (ic != null && attr != null && mKeyboardSwitcher.isAlphabetMode()) {
mKeyboardSwitcher.setShifted(mCapsLock || getCursorCapsMode(ic, attr) != 0); mKeyboardSwitcher.setShifted(mShiftKeyState.isMomentary() || mCapsLock
|| getCursorCapsMode(ic, attr) != 0);
} }
} }
@ -1233,12 +1237,20 @@ public class LatinIME extends InputMethodService
ic.endBatchEdit(); ic.endBatchEdit();
} }
private void resetShift() {
handleShiftInternal(true);
}
private void handleShift() { private void handleShift() {
handleShiftInternal(false);
}
private void handleShiftInternal(boolean forceNormal) {
mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE); mHandler.removeMessages(MSG_UPDATE_SHIFT_STATE);
KeyboardSwitcher switcher = mKeyboardSwitcher; KeyboardSwitcher switcher = mKeyboardSwitcher;
LatinKeyboardView inputView = switcher.getInputView(); LatinKeyboardView inputView = switcher.getInputView();
if (switcher.isAlphabetMode()) { if (switcher.isAlphabetMode()) {
if (mCapsLock) { if (mCapsLock || forceNormal) {
mCapsLock = false; mCapsLock = false;
switcher.setShifted(false); switcher.setShifted(false);
} else if (inputView != null) { } else if (inputView != null) {
@ -2146,15 +2158,26 @@ public class LatinIME extends InputMethodService
vibrate(); vibrate();
playKeyClick(primaryCode); playKeyClick(primaryCode);
if (primaryCode == Keyboard.KEYCODE_SHIFT) { if (primaryCode == Keyboard.KEYCODE_SHIFT) {
mShiftKeyState.onPress();
handleShift(); handleShift();
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
// TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well.
} else {
mShiftKeyState.onOtherKeyPressed();
} }
// TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well.
} }
public void onRelease(int primaryCode) { public void onRelease(int primaryCode) {
// Reset any drag flags in the keyboard // Reset any drag flags in the keyboard
((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased(); ((LatinKeyboard) mKeyboardSwitcher.getInputView().getKeyboard()).keyReleased();
//vibrate(); //vibrate();
if (primaryCode == Keyboard.KEYCODE_SHIFT) {
if (mShiftKeyState.isMomentary())
resetShift();
mShiftKeyState.onRelease();
} else if (primaryCode == Keyboard.KEYCODE_MODE_CHANGE) {
// TODO: We should handle KEYCODE_MODE_CHANGE (symbol) here as well.
}
} }
private FieldContext makeFieldContext() { private FieldContext makeFieldContext() {

View File

@ -33,6 +33,7 @@ import android.inputmethodservice.Keyboard.Key;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue; import android.util.TypedValue;
import android.view.GestureDetector; import android.view.GestureDetector;
import android.view.Gravity; import android.view.Gravity;
@ -45,6 +46,7 @@ import android.widget.TextView;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map; import java.util.Map;
/** /**
@ -62,6 +64,7 @@ import java.util.Map;
*/ */
public class LatinKeyboardBaseView extends View implements View.OnClickListener, public class LatinKeyboardBaseView extends View implements View.OnClickListener,
PointerTracker.UIProxy { PointerTracker.UIProxy {
private static final String TAG = "LatinKeyboardBaseView";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
public static final int NOT_A_TOUCH_COORDINATE = -1; public static final int NOT_A_TOUCH_COORDINATE = -1;
@ -199,6 +202,7 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
private OnKeyboardActionListener mKeyboardActionListener; private OnKeyboardActionListener mKeyboardActionListener;
private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>(); private final ArrayList<PointerTracker> mPointerTrackers = new ArrayList<PointerTracker>();
private final PointerQueue mPointerQueue = new PointerQueue();
private final float mDebounceHysteresis; private final float mDebounceHysteresis;
protected KeyDetector mKeyDetector = new ProximityKeyDetector(); protected KeyDetector mKeyDetector = new ProximityKeyDetector();
@ -316,6 +320,41 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
} }
}; };
static class PointerQueue {
private LinkedList<PointerTracker> mQueue = new LinkedList<PointerTracker>();
public void add(PointerTracker tracker) {
mQueue.add(tracker);
}
public int lastIndexOf(PointerTracker tracker) {
LinkedList<PointerTracker> queue = mQueue;
for (int index = queue.size() - 1; index >= 0; index--) {
PointerTracker t = queue.get(index);
if (t == tracker)
return index;
}
return -1;
}
public void releasePointersOlderThan(PointerTracker tracker, long eventTime) {
LinkedList<PointerTracker> queue = mQueue;
int oldestPos = 0;
for (PointerTracker t = queue.get(oldestPos); t != tracker; t = queue.get(oldestPos)) {
if (t.isModifier()) {
oldestPos++;
} else {
t.onUpEvent(t.getLastX(), t.getLastY(), eventTime);
queue.remove(oldestPos);
}
}
}
public void remove(PointerTracker tracker) {
mQueue.remove(tracker);
}
}
public LatinKeyboardBaseView(Context context, AttributeSet attrs) { public LatinKeyboardBaseView(Context context, AttributeSet attrs) {
this(context, attrs, R.attr.keyboardViewStyle); this(context, attrs, R.attr.keyboardViewStyle);
} }
@ -1107,14 +1146,14 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
switch (action) { switch (action) {
case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_DOWN:
tracker.onDownEvent(touchX, touchY, eventTime); onDownEvent(tracker, touchX, touchY, eventTime);
break; break;
case MotionEvent.ACTION_UP: case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP: case MotionEvent.ACTION_POINTER_UP:
tracker.onUpEvent(touchX, touchY, eventTime); onUpEvent(tracker, touchX, touchY, eventTime);
break; break;
case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_CANCEL:
tracker.onCancelEvent(touchX, touchY, eventTime); onCancelEvent(tracker, touchX, touchY, eventTime);
break; break;
} }
} }
@ -1122,6 +1161,28 @@ public class LatinKeyboardBaseView extends View implements View.OnClickListener,
return true; return true;
} }
private void onDownEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) {
tracker.onDownEvent(touchX, touchY, eventTime);
mPointerQueue.add(tracker);
}
private void onUpEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) {
int index = mPointerQueue.lastIndexOf(tracker);
if (index >= 0) {
mPointerQueue.releasePointersOlderThan(tracker, eventTime);
} else {
Log.w(TAG, "onUpEvent: corresponding down event not found for pointer "
+ tracker.mPointerId);
}
tracker.onUpEvent(touchX, touchY, eventTime);
mPointerQueue.remove(tracker);
}
private void onCancelEvent(PointerTracker tracker, int touchX, int touchY, long eventTime) {
tracker.onCancelEvent(touchX, touchY, eventTime);
mPointerQueue.remove(tracker);
}
protected void swipeRight() { protected void swipeRight() {
mKeyboardActionListener.swipeRight(); mKeyboardActionListener.swipeRight();
} }

View File

@ -0,0 +1,42 @@
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.android.inputmethod.latin;
class ModifierKeyState {
private static final int RELEASING = 0;
private static final int PRESSING = 1;
private static final int MOMENTARY = 2;
private int mState = RELEASING;
public void onPress() {
mState = PRESSING;
}
public void onRelease() {
mState = RELEASING;
}
public void onOtherKeyPressed() {
if (mState == PRESSING)
mState = MOMENTARY;
}
public boolean isMomentary() {
return mState == MOMENTARY;
}
}

View File

@ -21,9 +21,13 @@ import com.android.inputmethod.latin.LatinKeyboardBaseView.UIHandler;
import android.inputmethodservice.Keyboard; import android.inputmethodservice.Keyboard;
import android.inputmethodservice.Keyboard.Key; import android.inputmethodservice.Keyboard.Key;
import android.util.Log;
import android.view.ViewConfiguration; import android.view.ViewConfiguration;
public class PointerTracker { public class PointerTracker {
private static final String TAG = "PointerTracker";
private static final boolean DEBUG = false;
public interface UIProxy { public interface UIProxy {
public void invalidateKey(Key key); public void invalidateKey(Key key);
public void showPreview(int keyIndex, PointerTracker tracker); public void showPreview(int keyIndex, PointerTracker tracker);
@ -108,6 +112,15 @@ public class PointerTracker {
return isValidKeyIndex(keyIndex) ? mKeys[keyIndex] : null; return isValidKeyIndex(keyIndex) ? mKeys[keyIndex] : null;
} }
public boolean isModifier() {
Key key = getKey(mCurrentKey);
if (key == null)
return false;
int primaryCode = key.codes[0];
// TODO: KEYCODE_MODE_CHANGE (symbol) will be also a modifier key
return primaryCode == Keyboard.KEYCODE_SHIFT;
}
public void updateKey(int keyIndex) { public void updateKey(int keyIndex) {
int oldKeyIndex = mPreviousKey; int oldKeyIndex = mPreviousKey;
mPreviousKey = keyIndex; mPreviousKey = keyIndex;
@ -146,6 +159,8 @@ public class PointerTracker {
} }
showKeyPreviewAndUpdateKey(keyIndex); showKeyPreviewAndUpdateKey(keyIndex);
updateMoveDebouncing(touchX, touchY); updateMoveDebouncing(touchX, touchY);
if (DEBUG)
Log.d(TAG, "onDownEvent: [" + mPointerId + "] modifier=" + isModifier());
} }
public void onMoveEvent(int touchX, int touchY, long eventTime) { public void onMoveEvent(int touchX, int touchY, long eventTime) {
@ -178,6 +193,8 @@ public class PointerTracker {
} }
public void onUpEvent(int touchX, int touchY, long eventTime) { public void onUpEvent(int touchX, int touchY, long eventTime) {
if (DEBUG)
Log.d(TAG, "onUpEvent: [" + mPointerId + "] modifier=" + isModifier());
int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null); int keyIndex = mKeyDetector.getKeyIndexAndNearbyCodes(touchX, touchY, null);
boolean wasInKeyRepeat = mHandler.isInKeyRepeat(); boolean wasInKeyRepeat = mHandler.isInKeyRepeat();
mHandler.cancelKeyTimers(); mHandler.cancelKeyTimers();
@ -204,6 +221,8 @@ public class PointerTracker {
} }
public void onCancelEvent(int touchX, int touchY, long eventTime) { public void onCancelEvent(int touchX, int touchY, long eventTime) {
if (DEBUG)
Log.d(TAG, "onCancelEvent: [" + mPointerId + "]");
mHandler.cancelKeyTimers(); mHandler.cancelKeyTimers();
mHandler.cancelPopupPreview(); mHandler.cancelPopupPreview();
mProxy.dismissPopupKeyboard(); mProxy.dismissPopupKeyboard();
@ -305,7 +324,8 @@ public class PointerTracker {
private void showKeyPreviewAndUpdateKey(int keyIndex) { private void showKeyPreviewAndUpdateKey(int keyIndex) {
updateKey(keyIndex); updateKey(keyIndex);
mProxy.showPreview(keyIndex, this); if (!isModifier())
mProxy.showPreview(keyIndex, this);
} }
private void detectAndSendKey(int index, int x, int y, long eventTime) { private void detectAndSendKey(int index, int x, int y, long eventTime) {