因为公司产品是一款vr,是没有触摸屏的,所有要想用蓝牙手柄操控LatinIME就得进行修改
LatinIME最主要的就是一个继承InputMethodService的服务,类名就是LatinIME.java
而MainKeyboardView.java就是画出来的那块键盘了,主要的响应触摸,传递键值都绕不过它调用的PointerTracker.java
直接看响应触摸的吧
通过onTouchEvent找到processMotionEvent(me);然后在processMotionEvent(me);看到tracker.processMotionEvent(me, mKeyDetector);
@Override
public boolean onTouchEvent(final MotionEvent me) {
if (getKeyboard() == null) {
return false;
}
if (mNonDistinctMultitouchHelper != null) {
if (me.getPointerCount() > 1 && mKeyTimerHandler.isInKeyRepeat()) {
// Key repeating timer will be canceled if 2 or more keys are in action.
mKeyTimerHandler.cancelKeyRepeatTimers();
}
// Non distinct multitouch screen support
mNonDistinctMultitouchHelper.processMotionEvent(me, mKeyDetector);
return true;
}
return processMotionEvent(me);
}
public boolean processMotionEvent(final MotionEvent me) {
final int index = me.getActionIndex();
final int id = me.getPointerId(index);
final PointerTracker tracker = PointerTracker.getPointerTracker(id);
// When a more keys panel is showing, we should ignore other fingers' single touch events
// other than the finger that is showing the more keys panel.
if (isShowingMoreKeysPanel() && !tracker.isShowingMoreKeysPanel()
&& PointerTracker.getActivePointerTrackerCount() == 1) {
return true;
}
tracker.processMotionEvent(me, mKeyDetector);
return true;
}
触摸是在PointerTracker.java的processMotionEvent(me, mKeyDetector);里进行处理的
而PointerTracker.java里还有两个接口DrawingProxy和TimerProxy
public interface DrawingProxy {
public void invalidateKey(Key key);
public void showKeyPreview(Key key);
public void dismissKeyPreview(Key key);
public void showSlidingKeyInputPreview(PointerTracker tracker);
public void dismissSlidingKeyInputPreview();
public void showGestureTrail(PointerTracker tracker, boolean showsFloatingPreviewText);
}
public interface TimerProxy {
public void startTypingStateTimer(Key typedKey);
public boolean isTypingState();
public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay);
public void startLongPressTimerOf(PointerTracker tracker, int delay);
public void cancelLongPressTimerOf(PointerTracker tracker);
public void cancelLongPressShiftKeyTimers();
public void cancelKeyTimersOf(PointerTracker tracker);
public void startDoubleTapShiftKeyTimer();
public void cancelDoubleTapShiftKeyTimer();
public boolean isInDoubleTapShiftKeyTimeout();
public void startUpdateBatchInputTimer(PointerTracker tracker);
public void cancelUpdateBatchInputTimer(PointerTracker tracker);
public void cancelAllUpdateBatchInputTimers();
public static class Adapter implements TimerProxy {
@Override
public void startTypingStateTimer(Key typedKey) {}
@Override
public boolean isTypingState() { return false; }
@Override
public void startKeyRepeatTimerOf(PointerTracker tracker, int repeatCount, int delay) {}
@Override
public void startLongPressTimerOf(PointerTracker tracker, int delay) {}
@Override
public void cancelLongPressTimerOf(PointerTracker tracker) {}
@Override
public void cancelLongPressShiftKeyTimers() {}
@Override
public void cancelKeyTimersOf(PointerTracker tracker) {}
@Override
public void startDoubleTapShiftKeyTimer() {}
@Override
public void cancelDoubleTapShiftKeyTimer() {}
@Override
public boolean isInDoubleTapShiftKeyTimeout() { return false; }
@Override
public void startUpdateBatchInputTimer(PointerTracker tracker) {}
@Override
public void cancelUpdateBatchInputTimer(PointerTracker tracker) {}
@Override
public void cancelAllUpdateBatchInputTimers() {}
}
}
TimerProxy是按下去时计时的,不用管,而DrawingProxy就是画的接口了
包括按下去时字母背景变黑和弹出pop,抬起时恢复等等
接着看processMotionEvent
public void processMotionEvent(final MotionEvent me, final KeyDetector keyDetector) {
final int action = me.getActionMasked();
final long eventTime = me.getEventTime();
if (action == MotionEvent.ACTION_MOVE) {
// When this pointer is the only active pointer and is showing a more keys panel,
// we should ignore other pointers' motion event.
final boolean shouldIgnoreOtherPointers =
isShowingMoreKeysPanel() && getActivePointerTrackerCount() == 1;
final int pointerCount = me.getPointerCount();
for (int index = 0; index < pointerCount; index++) {
final int id = me.getPointerId(index);
if (shouldIgnoreOtherPointers && id != mPointerId) {
continue;
}
final int x = (int)me.getX(index);
final int y = (int)me.getY(index);
final PointerTracker tracker = getPointerTracker(id);
tracker.onMoveEvent(x, y, eventTime, me);
}
return;
}
final int index = me.getActionIndex();
final int x = (int)me.getX(index);
final int y = (int)me.getY(index);
switch (action) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_POINTER_DOWN:
onDownEvent(x, y, eventTime, keyDetector);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_POINTER_UP:
onUpEvent(x, y, eventTime);
break;
case MotionEvent.ACTION_CANCEL:
onCancelEvent(x, y, eventTime);
break;
}
}
响应触摸主要是onDownEvent(x, y, eventTime, keyDetector);和onUpEvent(x, y, eventTime);两个方法
private void onDownEvent(final int x, final int y, final long eventTime,
final KeyDetector keyDetector) {
setKeyDetectorInner(keyDetector);
if (DEBUG_EVENT) {
printTouchEvent("onDownEvent:", x, y, eventTime);
}
// Naive up-to-down noise filter.
final long deltaT = eventTime - mUpTime;
if (deltaT < sParams.mTouchNoiseThresholdTime) {
final int distance = getDistance(x, y, mLastX, mLastY);
if (distance < sParams.mTouchNoiseThresholdDistance) {
if (DEBUG_MODE)
Log.w(TAG, String.format("[%d] onDownEvent:"
+ " ignore potential noise: time=%d distance=%d",
mPointerId, deltaT, distance));
cancelTrackingForAction();
return;
}
}
final Key key = getKeyOn(x, y);
mBogusMoveEventDetector.onActualDownEvent(x, y);
if (key != null && key.isModifier()) {
// Before processing a down event of modifier key, all pointers already being
// tracked should be released.
sPointerTrackerQueue.releaseAllPointers(eventTime);
}
sPointerTrackerQueue.add(this);
onDownEventInternal(x, y, eventTime);
if (!sGestureEnabler.shouldHandleGesture()) {
return;
}
// A gesture should start only from a non-modifier key. Note that the gesture detection is
// disabled when the key is repeating.
mIsDetectingGesture = (mKeyboard != null) && mKeyboard.mId.isAlphabetKeyboard()
&& key != null && !key.isModifier();
if (mIsDetectingGesture) {
mBatchInputArbiter.addDownEventPoint(x, y, eventTime,
sTypingTimeRecorder.getLastLetterTypingTime(), getActivePointerTrackerCount());
mGestureStrokeDrawingPoints.onDownEvent(
x, y, mBatchInputArbiter.getElapsedTimeSinceFirstDown(eventTime));
}
}
/* package */ boolean isShowingMoreKeysPanel() {
return (mMoreKeysPanel != null);
}
private void onUpEvent(final int x, final int y, final long eventTime) {
if (DEBUG_EVENT) {
printTouchEvent("onUpEvent :", x, y, eventTime);
}
sTimerProxy.cancelUpdateBatchInputTimer(this);
if (!sInGesture) {
if (mCurrentKey != null && mCurrentKey.isModifier()) {
// Before processing an up event of modifier key, all pointers already being
// tracked should be released.
sPointerTrackerQueue.releaseAllPointersExcept(this, eventTime);
} else {
sPointerTrackerQueue.releaseAllPointersOlderThan(this, eventTime);
}
}
onUpEventInternal(x, y, eventTime);
sPointerTrackerQueue.remove(this);
}
onDownEvent中的onDownEventInternal(final int x, final int y, final long eventTime)和onUpEvent中的onUpEventInternal(final int x, final int y, final long eventTime)方法对触摸进行了处理
private void onDownEventInternal(final int x, final int y, final long eventTime) {
Key key = onDownKey(x, y, eventTime);
// Key selection by dragging finger is allowed when 1) key selection by dragging finger is
// enabled by configuration, 2) this pointer starts dragging from modifier key, or 3) this
// pointer's KeyDetector always allows key selection by dragging finger, such as
// {@link MoreKeysKeyboard}.
mIsAllowedDraggingFinger = sParams.mKeySelectionByDraggingFinger
|| (key != null && key.isModifier())
|| mKeyDetector.alwaysAllowsKeySelectionByDraggingFinger();
mKeyboardLayoutHasBeenChanged = false;
mIsTrackingForActionDisabled = false;
resetKeySelectionByDraggingFinger();
if (key != null) {
// This onPress call may have changed keyboard layout. Those cases are detected at
// {@link #setKeyboard}. In those cases, we should update key according to the new
// keyboard layout.
if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onDownKey(x, y, eventTime);
}
startRepeatKey(key);
startLongPressTimer(key);
setPressedKeyGraphics(key, eventTime);
}
}
private void onUpEventInternal(final int x, final int y, final long eventTime) {
sTimerProxy.cancelKeyTimersOf(this);
final boolean isInDraggingFinger = mIsInDraggingFinger;
final boolean isInSlidingKeyInput = mIsInSlidingKeyInput;
resetKeySelectionByDraggingFinger();
mIsDetectingGesture = false;
final Key currentKey = mCurrentKey;
mCurrentKey = null;
final int currentRepeatingKeyCode = mCurrentRepeatingKeyCode;
mCurrentRepeatingKeyCode = Constants.NOT_A_CODE;
// Release the last pressed key.
setReleasedKeyGraphics(currentKey);
if (isShowingMoreKeysPanel()) {
if (!mIsTrackingForActionDisabled) {
final int translatedX = mMoreKeysPanel.translateX(x);
final int translatedY = mMoreKeysPanel.translateY(y);
mMoreKeysPanel.onUpEvent(translatedX, translatedY, mPointerId, eventTime);
}
dismissMoreKeysPanel();
return;
}
if (sInGesture) {
if (currentKey != null) {
callListenerOnRelease(currentKey, currentKey.getCode(), true /* withSliding */);
}
if (mBatchInputArbiter.mayEndBatchInput(
eventTime, getActivePointerTrackerCount(), this)) {
sInGesture = false;
}
showGestureTrail();
return;
}
if (mIsTrackingForActionDisabled) {
return;
}
if (currentKey != null && currentKey.isRepeatable()
&& (currentKey.getCode() == currentRepeatingKeyCode) && !isInDraggingFinger) {
return;
}
detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);
if (isInSlidingKeyInput) {
callListenerOnFinishSlidingInput();
}
}
而这两个方法中分别有setPressedKeyGraphics(key, eventTime);和setReleasedKeyGraphics(currentKey);两个方法通过DrawingProxy接口传到MainKeyboardView.java,
然后由MainKeyboardView.java画出触摸按下去和释放在键盘上的显示效果
onDownEventInternal中的
if (callListenerOnPressAndCheckKeyboardLayoutChange(key, 0 /* repeatCount */)) {
key = onDownKey(x, y, eventTime);
}
是按下大写键后,整个键盘改变大小写状态的
而onUpEventInternal中的detectAndSendKey(currentKey, mKeyX, mKeyY, eventTime);方法调用callListenerOnCodeInput(key, code, x, y, eventTime, false /* isKeyRepeat */);
通过KeyboardActionListener接口将key传到LatinIME.java中的onCodeInput方法中进行处理