我是靠谱客的博主 如意玉米,最近开发中收集的这篇文章主要介绍Android 增加对鼠标的支持,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

Android系统对鼠标的支持并不好,因为Android系统原本是为手机量身定做的,手机系统基本上是不需要鼠标的。但是随着Android系统移植到其他领域,对鼠标的支持也越来越有意义。
在android中鼠标的绘制代码在:
frameworksbaseservicesjavacomandroidserverWindowManagerService.java ,
       在performLayoutAndPlaceSurfacesLockedInner方法中:
        if (mMouseSurface == null)
        {
            int mMx, mMy, mMw, mMh;
            Canvas mCanvas;
            Path mPath = new Path();
            mMw = 13;
            mMh = 22;
            mMx = (mDisplay.getWidth() - mMw) / 2;
            mMy = (mDisplay.getHeight() - mMh) / 2;
            try
            {
                /*
                 *  First Mouse event, create Surface
                 */
                mMouseSurface =
                    new Surface(mFxSession,
                                0, -1, mMw, mMh,
                                PixelFormat.TRANSPARENT,
                                Surface.FX_SURFACE_NORMAL);
                mCanvas = mMouseSurface.lockCanvas(null);
                Paint tPaint = new Paint();
                tPaint.setStyle(Paint.Style.STROKE);
                tPaint.setStrokeWidth(2);
                tPaint.setColor(0xffffffff);
                mPath.moveTo(0.0f, 0.0f);
                mPath.lineTo(12.0f, 12.0f);
                mPath.lineTo(7.0f, 12.0f);
                mPath.lineTo(11.0f, 20.0f);
                mPath.lineTo(8.0f, 21.0f);
                mPath.lineTo(4.0f, 13.0f);
                mPath.lineTo(0.0f, 17.0f);
                mPath.close();
                mCanvas.clipPath(mPath);
                mCanvas.drawColor(0xff000000);
                mCanvas.drawPath(mPath, tPaint);


                mMouseSurface.unlockCanvasAndPost(mCanvas);
                mMouseSurface.openTransaction();
                mMouseSurface.setSize(mMw, mMh);
                mMouseSurface.closeTransaction();
            }
            catch (Exception e)
            {
                Slog.e(TAG, "Exception creating mouse surface",e);
            }
            mMlx = mMx;
            mMly = mMy;
            mMlw = mMw;
            mMlh = mMh;
        }
        直接利用Surface绘制鼠标光标的形状,一般情况下都是利用bitmap位图资源进行绘制,这里简化了。
对于android2.3版本来说,发布的arm/sh4版本没有提供鼠标功能,直到前几天才发现mips社区已经将这块代码加入进去了,之间我在arm上搞这个功能时,重新进行实现,不过增加了一点功能,比如可以通过java 更换鼠标光标,并编写了一个服务用于光标隐藏的方法等。
        接口函数如下:
int cursor_util_initialize();
int cursor_util_finalize();
int cursor_util_start();
     int cursor_util_stop();
     int cursor_util_locate(int x,int y);
     int cursor_util_move(int dx,int dy);
     int cursor_util_get_location(int *x,int *y);
     int cursor_util_set_timeout(int timeout);
     int cursor_util_get_timeout(int *timeout);
     int cursor_util_set_bitmap(const char*buf,int w,int h);
由于代码涉及到版权问题,这里就将mips做的改动介绍一下吧:


1、首先在eventhub.cpp中增加鼠标的支持:
        代码路径: frameworksbaselibsuiEventHub.cpp
        /* The input device has mouse. */
        INPUT_DEVICE_CLASS_MOUSE        = 0x00000100,
       if (test_bit(BTN_MOUSE, key_bitmask)) {
        uint8_t rel_bitmask[sizeof_bit_array(REL_MAX + 1)];
        memset(rel_bitmask, 0, sizeof(rel_bitmask));
        LOGV("Getting relative controllers...");
        if (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bitmask)), rel_bitmask) >= 0) {
            if (test_bit(REL_X, rel_bitmask) && test_bit(REL_Y, rel_bitmask)) {
         /* 增加鼠标类的事件处理流程 */
         if (test_bit(BTN_LEFT, key_bitmask) && test_bit(BTN_RIGHT, key_bitmask))
               device->classes |= INPUT_DEVICE_CLASS_MOUSE;
                else
             device->classes |= INPUT_DEVICE_CLASS_TRACKBALL;
            }
        }
     }
     
     2、inputreader中增加mousemapper的处理代码:
      代码路径: frameworksbaselibsuiInputReader.cpp
     重点就是下面两个函数:(注意鼠标传上来的值是相对坐标,如果需要处理绝对坐标,在process函数进行转换即可,比较简单)
    void MouseInputMapper::process(const RawEvent* rawEvent) {
    switch (rawEvent->type)
    {
    case EV_KEY:
        switch (rawEvent->scanCode)
        {
        case BTN_MOUSE:
            mAccumulator.fields |= Accumulator::FIELD_BTN_MOUSE;
            mAccumulator.btnMouse = rawEvent->value != 0;
            sync(rawEvent->when);
            break;
        case BTN_RIGHT:
            mAccumulator.fields |= Accumulator::FIELD_BTN_RIGHT;
            mAccumulator.btnRight = rawEvent->value != 0;
            sync(rawEvent->when);
            break;
        case BTN_MIDDLE:
            mAccumulator.fields |= Accumulator::FIELD_BTN_MIDDLE;
            mAccumulator.btnMiddle = rawEvent->value != 0;
            sync(rawEvent->when);
            break;
        }
        break;




    case EV_REL:
        switch (rawEvent->scanCode)
        {
        case REL_X:
            mAccumulator.fields |= Accumulator::FIELD_REL_X;
            mAccumulator.relX = rawEvent->value;
            break;
        case REL_Y:
            mAccumulator.fields |= Accumulator::FIELD_REL_Y;
            mAccumulator.relY = rawEvent->value;
            break;
        }
        break;




    case EV_SYN:
        switch (rawEvent->scanCode)
        {
        case SYN_REPORT:
            sync(rawEvent->when);
            break;
        }
        break;
    }
}


void MouseInputMapper::sync(nsecs_t when)
{
    uint32_t fields = mAccumulator.fields;
    if (fields == 0)
    {
        return; // no new state changes, so nothing to do
    }




    int motionEventAction;
    PointerCoords pointerCoords;
    nsecs_t downTime;
    { // acquire lock
        AutoMutex _l(mLock);




        if (fields & Accumulator::FIELD_BTN_RIGHT)
        {
            getDispatcher()->notifyKey(when, getDeviceId(), AINPUT_SOURCE_DPAD, 0,
                                   mAccumulator.btnRight ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                                   AKEY_EVENT_FLAG_FROM_SYSTEM, 0x4 /*Keycode for back key*/,
                                   0x18 /*Scancode*/, mContext->getGlobalMetaState(), when);
        }




        if (fields & Accumulator::FIELD_BTN_MIDDLE)
        {
            getDispatcher()->notifyKey(when, getDeviceId(),AINPUT_SOURCE_DPAD, 0,
                                   mAccumulator.btnMiddle ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
                                   AKEY_EVENT_FLAG_FROM_SYSTEM, 0x52 /*Keycode for menu key*/,
                                   0x19 /*Scancode*/, mContext->getGlobalMetaState(), when);
        }




        bool downChanged = fields & Accumulator::FIELD_BTN_MOUSE;
        if (downChanged)
        {
            if (mAccumulator.btnMouse)
            {
                mLocked.down = true;
                mLocked.downTime = when;
            }
            else
            {
                mLocked.down = false;
            }
            motionEventAction = mLocked.down ? AMOTION_EVENT_ACTION_DOWN : AMOTION_EVENT_ACTION_UP;
        }
        else
        {
            motionEventAction = AMOTION_EVENT_ACTION_MOVE;
        }




        downTime = mLocked.downTime;




        float x = fields & Accumulator::FIELD_REL_X ? mAccumulator.relX : 0.0f;
        float y = fields & Accumulator::FIELD_REL_Y ? mAccumulator.relY : 0.0f;




        int32_t screenWidth;
        int32_t screenHeight;
        int32_t orientation;




        if (mAssociatedDisplayId  < 0 || ! getPolicy()->getDisplayInfo(mAssociatedDisplayId, &screenWidth, &screenHeight, &orientation))
        {
            return;
        }




        float temp;
        switch (orientation)
        {
            case InputReaderPolicyInterface::ROTATION_90:
            {
                temp = x;
                x = y;
                y = - temp;
                temp = screenHeight;
                screenHeight = screenWidth;
                screenWidth = temp;
                break;
            }
            case InputReaderPolicyInterface::ROTATION_180:
            {
                x = - x;
                y = - y;
                break;
            }
            case InputReaderPolicyInterface::ROTATION_270:
            {
                temp = x;
                x = - y;
                y = temp;
                temp = screenHeight;
                screenHeight = screenWidth;
                screenWidth = temp;
                break;
            }
        }




        mAccumulator.absX =
            (mAccumulator.absX + x) > screenWidth ? screenWidth -1 :
                 ((mAccumulator.absX + x) < 0 ? 0 : mAccumulator.absX + x);
        mAccumulator.absY = (mAccumulator.absY + y) > screenHeight ? screenHeight -1 :
                 ((mAccumulator.absY + y) < 0 ? 0 : mAccumulator.absY + y);
        pointerCoords.x = mAccumulator.absX;
        pointerCoords.y = mAccumulator.absY;
        pointerCoords.pressure = mLocked.down ? 1.0f : 0.0f;
        pointerCoords.size = 0;
        pointerCoords.touchMajor = 0;
        pointerCoords.touchMinor = 0;
        pointerCoords.toolMajor = 0;
        pointerCoords.toolMinor = 0;
        pointerCoords.orientation = 0;




    } // release lock




    int32_t metaState = mContext->getGlobalMetaState();
    int32_t pointerId = 0;
    getDispatcher()->notifyMotion(when, getDeviceId(), AINPUT_SOURCE_MOUSE, 0,
            motionEventAction, 0, metaState, AMOTION_EVENT_EDGE_FLAG_NONE,
            1, &pointerId, &pointerCoords, 1, 1, downTime);
    mAccumulator.clear();
}
     3、事件分发InputDispatcher.cpp 函数修改
    bool isPointerEvent = entry->source & AINPUT_SOURCE_CLASS_POINTER;
    bool isMouseEvent = entry->source & (AINPUT_SOURCE_MOUSE & ~AINPUT_SOURCE_CLASS_POINTER);
    bool isTouchEvent = entry->source & (AINPUT_SOURCE_TOUCHSCREEN & ~AINPUT_SOURCE_CLASS_POINTER);
    bool isDownEvent = (entry->action & AMOTION_EVENT_ACTION_MASK) == AMOTION_EVENT_ACTION_DOWN;


    // Identify targets.
    if (! mCurrentInputTargetsValid) {
        int32_t injectionResult;
        if ( isPointerEvent && (isTouchEvent || (isMouseEvent && (isDownEvent || mTouchState.down))))
        {
            // Touch-like event.  (eg. touchscreen or mouse drag-n-drop )
            injectionResult = findTouchedWindowTargetsLocked(currentTime, entry, nextWakeupTime);
        }
        else
        {
            // Non touch event.  (eg. trackball or mouse simple move)
            injectionResult = findFocusedWindowTargetsLocked(currentTime, entry, nextWakeupTime);
        }     
     
      4、java 处理鼠标事件
    private void dispatchMotion(MotionEvent event, boolean sendDone) {
        int source = event.getSource();
        if ((source & (InputDevice.SOURCE_MOUSE & ~InputDevice.SOURCE_CLASS_POINTER)) != 0) {
            try{
                wm.moveMouseSurface((int)event.getX() - (int)event.getXOffset(),
                                    (int)event.getY() - (int)event.getYOffset());
            }catch (RemoteException e){
                Log.e(TAG,"RemoteException thrown in moveMouseSurface");
            }
            dispatchPointer(event, sendDone);
        } else if ((source & InputDevice.SOURCE_CLASS_POINTER) != 0) {
            dispatchPointer(event, sendDone);
        } else if ((source & InputDevice.SOURCE_CLASS_TRACKBALL) != 0) {
            dispatchTrackball(event, sendDone);
        } else {
            // TODO
            Log.v(TAG, "Dropping unsupported motion event (unimplemented): " + event);
            if (sendDone) {
                finishInputEvent();
            }
        }
    }
    
   5、利用binder传递到WindowManagerService.java 中
       代码路径: frameworksbaseservicesjavaandroidserverWindowManagerService.java
       如果没有硬件光标层,可能就需要在此进行修改.
       /* 移动光标 ,如果有硬件光标层,直接利用jni调用即可 */
       public boolean moveMouseSurface(int x, int y)
{
   if (mMouseSurface != null && (x != 0 || y != 0))
   {
       synchronized(mWindowMap)
       {
           Surface.openTransaction();
           WindowState top =
               (WindowState)mWindows.get(mWindows.size() - 1);
           try
           {
               int mDisplayWidth = mDisplay.getWidth();
               mMlx = x;
               mMly = y;
               mMouseSurface.setPosition(mMlx, mMly);
               mMouseSurface.setLayer(top.mAnimLayer + 1);
               if (!mMouseDisplayed)
               {
                   mMouseSurface.show();
                   mMouseDisplayed = !mMouseDisplayed;
               }
           }
           catch ( RuntimeException e)
           {
               Slog.e(TAG, "Failure showing mouse surface",e);
           }

           Surface.closeTransaction();
       }
   }

   return true;
}

        /* 绘制光标图形 */
private final void performLayoutAndPlaceSurfacesLockedInner(
       boolean recoveringMemory) {
...
   if (mMouseSurface == null)
   {
       int mMx, mMy, mMw, mMh;
       Canvas mCanvas;
       Path mPath = new Path();
       mMw = 13;
       mMh = 22;
       mMx = (mDisplay.getWidth() - mMw) / 2;
       mMy = (mDisplay.getHeight() - mMh) / 2;
       try
       {
           /*
            *  First Mouse event, create Surface
            */
           mMouseSurface =
               new Surface(mFxSession,
                           0, -1, mMw, mMh,
                           PixelFormat.TRANSPARENT,
                           Surface.FX_SURFACE_NORMAL);
           mCanvas = mMouseSurface.lockCanvas(null);
           Paint tPaint = new Paint();
           tPaint.setStyle(Paint.Style.STROKE);
           tPaint.setStrokeWidth(2);
           tPaint.setColor(0xffffffff);
           mPath.moveTo(0.0f, 0.0f);
           mPath.lineTo(12.0f, 12.0f);
           mPath.lineTo(7.0f, 12.0f);
           mPath.lineTo(11.0f, 20.0f);
           mPath.lineTo(8.0f, 21.0f);
           mPath.lineTo(4.0f, 13.0f);
           mPath.lineTo(0.0f, 17.0f);
           mPath.close();
           mCanvas.clipPath(mPath);
           mCanvas.drawColor(0xff000000);
           mCanvas.drawPath(mPath, tPaint);

           mMouseSurface.unlockCanvasAndPost(mCanvas);
           mMouseSurface.openTransaction();
           mMouseSurface.setSize(mMw, mMh);
           mMouseSurface.closeTransaction();

       }
       catch (Exception e)
       {
           Slog.e(TAG, "Exception creating mouse surface",e);
       }
       mMlx = mMx;
       mMly = mMy;
       mMlw = mMw;
       mMlh = mMh;
   }

...



   6、直接利用jni实现硬件光标层
       frameworksbaseservicesjnicom_android_server_WindowManagerService.cpp
   
   ok,基本上的工作已经完成,此时鼠标将可以正常工作。可以看出Android系统鼠标光标的定制不是非常容易,需要修改不少的代码。不过mips社区已经将功能完成了90%了,仅需要简单与光标层对接一下接口即可。

最后

以上就是如意玉米为你收集整理的Android 增加对鼠标的支持的全部内容,希望文章能够帮你解决Android 增加对鼠标的支持所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部