关于Android 5.1 LatinIME的分析
来源:互联网 发布:剖腹产 知乎 编辑:程序博客网 时间:2024/04/30 02:28
因为公司产品是一款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方法中进行处理
- 关于Android 5.1 LatinIME的分析
- Android AOSP输入法(LatinIME)大写判断分析
- LatinIME输入法分析
- LatinIME输入法分析
- Android 如何调节LatinIME键盘上的字体大小
- Android 如何调节LatinIME键盘上的字体大小
- 修改Android 自带输入法(LatinIME)空格键的显示
- LatinIME输入法的一些总结
- LatinIME输入法分析(只为备忘)
- Android AOSP输入法(LatinIME)输入流程二
- 关于Android 5.1 Launcher的分析
- 在Android原生输入法LatinIME中添加自定义按键
- android关于AsyncTask的分析
- 关于Android 5.1系统的Settings的分析
- 关于这个android源码分析的博客
- 关于Android屏幕适应的一些分析
- 关于android电话录音问题的详细分析
- 关于android电话录音问题的详细分析
- 优化UITableView性能
- Hive学习之一:安装与初步使用
- vsftpd配置文件详解
- Centos7 从零配置Nginx+PHP+MySql
- Device Tree 入门
- 关于Android 5.1 LatinIME的分析
- 产品和需求分析文档
- Manacher算法求最长回文子串模板
- springMVC之mvc:interceptors拦截器的用法
- Spark常用设置,API和错误解决方法
- Xml 三种解析方法
- WCF的创建、部署,引用、调用
- ListView更新单个item
- [BZOJ1087][SCOI2005]互不侵犯king