Android6.0 按键流程(七)无线鼠标右键无效 -- Framework层

之前我们分析了无线鼠标右键无效,hal层的分析,我们可以把修改成返回键。

uint32_t CursorButtonAccumulator::getButtonState() const {  
    uint32_t result = 0;  
    if (mBtnLeft) {  
        result |= AMOTION_EVENT_BUTTON_PRIMARY;  
    }  
    if (mBtnRight) {  
        //result |= AMOTION_EVENT_BUTTON_SECONDARY;  
        result |= AMOTION_EVENT_BUTTON_BACK;//修改成返回键  
    }  

但是具体AMOTION_EVENT_BUTTON_SECONDARY在哪里被过滤了,我们还没有分析到,现在我们来分析下鼠标按键机制的Framework层的分析,为什么之前的右键会被上层过滤?

 

我们先来看下ViewRootImpl.java这个文件,至于如何从hal层的按键进程,到Framework层的应用进程我们不分析了,之前的博客都分析过了。我们直接从鼠标处理的地方分析:

    final class ViewPostImeInputStage extends InputStage {
        public ViewPostImeInputStage(InputStage next) {
            super(next);
        }

        @Override
        protected int onProcess(QueuedInputEvent q) {
            if (q.mEvent instanceof KeyEvent) {
                return processKeyEvent(q);//普通按键处理
            } else {
                // If delivering a new non-key event, make sure the window is
                // now allowed to start updating.
                handleDispatchWindowAnimationStopped();
                final int source = q.mEvent.getSource();
                if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
                    return processPointerEvent(q);//鼠标按键处理
                } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
                    return processTrackballEvent(q);
                } else {
                    return processGenericMotionEvent(q);
                }
            }
        }

ViewRootImpl文件处理按键消息会经过各个InputStage,而鼠标按键的处理是在ViewPostImeInputStage 和普通按键处理一样,会调用processPointerEvent来处理鼠标按键。

        private int processPointerEvent(QueuedInputEvent q) {
            final MotionEvent event = (MotionEvent)q.mEvent;

            mAttachInfo.mUnbufferedDispatchRequested = false;
            boolean handled = mView.dispatchPointerEvent(event);
            if (mAttachInfo.mUnbufferedDispatchRequested && !mUnbufferedInputDispatch) {
                mUnbufferedInputDispatch = true;
                if (mConsumeBatchedInputScheduled) {
                    scheduleConsumeBatchedInputImmediately();
                }
            }
            return handled ? FINISH_HANDLED : FORWARD;
        }

processPointerEvent又调用了dispatchPointerEvent函数

 

    public final boolean dispatchPointerEvent(MotionEvent event) {
        if (event.isTouchEvent()) {
            return dispatchTouchEvent(event);//第一次鼠标按键进入这个函数
        } else {
            return dispatchGenericMotionEvent(event);
        }
    }

第一次鼠标按键进入dispatchTouchEvent这个函数

 

 

 

    public boolean dispatchTouchEvent(MotionEvent event) {
        // If the event should be handled by accessibility focus first.
        if (event.isTargetAccessibilityFocus()) {
            // We don't have focus or no virtual descendant has it, do not handle the event.
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            // We have focus and got the event, then use normal event dispatch.
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            // Defensive cleanup for new gesture
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            //noinspection SimplifiableIfStatement
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {//关键看onTouchEvent函数
                result = true;
            }
        }
        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }

        // Clean up after nested scrolls if this is the end of a gesture;
        // also cancel it if we tried an ACTION_DOWN but we didn't want the rest
        // of the gesture.
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }		

下面我们再来看下onTouchEvent函数,在对aciton进行分别处理,当是MotionEvent.ACTION_DOWN:会先调用performButtonActionOnTouchDown函数

 

 

 

    public boolean onTouchEvent(MotionEvent event) {
        ......

        if (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
                (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
            switch (action) {
                ......

                case MotionEvent.ACTION_DOWN:
                    mHasPerformedLongPress = false;

                    if (performButtonActionOnTouchDown(event)) {
                        break;
                    }

                    // Walk up the hierarchy to determine if we're inside a scrolling container.
                    boolean isInScrollingContainer = isInScrollingContainer();

                    // For views inside a scrolling container, delay the pressed feedback for
                    // a short period in case this is a scroll.
                    if (isInScrollingContainer) {
                        mPrivateFlags |= PFLAG_PREPRESSED;
                        if (mPendingCheckForTap == null) {
                            mPendingCheckForTap = new CheckForTap();
                        }
                        mPendingCheckForTap.x = event.getX();
                        mPendingCheckForTap.y = event.getY();
                        Log.e(TAG, "kangchen postDelayed setPressed");
                        postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                    } else {
                        // Not inside a scrolling container, so show the feedback right away
                        setPressed(true, x, y);
                        Log.e(TAG, "kangchen setPressed");
                        checkForLongClick(0);
                    }
                    break;
		......

主要是下面这个函数,当获取ButtonState是MotionEvent.BUTTON_SECONDARY,就返回true,而在onTouchEvent函数中当performButtonActionOnTouchDown返回true,就会执行break,下面代码就不执行了。也就是因为这个导致右键无效,具体代码这边就不继续跟下去了,比较复杂。

 

 

 

    protected boolean performButtonActionOnTouchDown(MotionEvent event) {
        if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE &&
            (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
            showContextMenu(event.getX(), event.getY(), event.getMetaState());
            mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
            return true;//返回true
        }
        return false;
    }

 

 

 

 

 

这样我们就大致分析了Framework层把鼠标右键过滤的分析。


 



你可能感兴趣的:(android按键)