android2.3 鼠标输入集成

Android系统对鼠标的支持并不好,因为Android系统原本是为手机量身定做的,手机系统基本上是不需要鼠标的。但是随着Android系统移植到其他领域,对鼠标的支持也越来越有意义。
在android中鼠标的绘制代码在:
\frameworks\base\services\java\com\android\server\WindowManagerService.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中增加鼠标的支持:
        代码路径: \frameworks\base\libs\ui\EventHub.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的处理代码:
      代码路径: \frameworks\base\libs\ui\InputReader.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 中
       代码路径: frameworks\base\services\java\android\server\WindowManagerService.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实现硬件光标层
       frameworks\base\services\jni\com_android_server_WindowManagerService.cpp
       这个文件是一个新建的文件,在onload.cpp中增加调用
       int register_android_server_WindowManagerService(JNIEnv* env);
       并在android.mk将这个文件com_android_server_WindowManagerService.cpp加入编译
 
       

#define LOG_TAG "Input"

#include "jni.h"
#include "JNIHelp.h"
#include <utils/misc.h>
#include <utils/Log.h>

#include <linux/fb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

namespace android {

static int fd = -1;
static struct fb_cursor hw_cur;

static void mouseInit()
{
    if (-1 == fd)
        fd = open("/dev/graphics/cursor", O_RDWR);

    hw_cur.set = FB_CUR_SETALL;

    hw_cur.enable = 0;
    hw_cur.hot.x = 0;
    hw_cur.hot.y = 0;

    ioctl(fd, 0x4608, &hw_cur);
}

static void android_server_WindwManagerService_setHWCursorPosition(JNIEnv *env, jobject obj, jint x, jint y)
{
    if (-1 == fd)
        mouseInit();

    hw_cur.enable = 1;
    hw_cur.set = FB_CUR_SETHOT;
    hw_cur.hot.x = x;
    hw_cur.hot.y = y;

    ioctl(fd, 0x4608, &hw_cur);
}

static JNINativeMethod gWindowManagerMethods[] = {
    /* name, signature, funcPtr */
    { "setHWCursorPosition",              "(II)V",
        (void *) android_server_WindwManagerService_setHWCursorPosition },
};

int register_android_server_WindowManagerService(JNIEnv* env)
{
    jclass input = env->FindClass("com/android/server/WindowManagerService");
    LOG_FATAL_IF(input == NULL, "Unable to find class com/android/server/WindowManagerService");
    int res = jniRegisterNativeMethods(env, "com/android/server/WindowManagerService",
                                        gWindowManagerMethods, NELEM(gWindowManagerMethods));

    return res;
}
}; // namespace android

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



   附注: 我将两者diff出来的代码一起上传,可以有文件遗漏,大家也可从mips网站下载gingerbread代码分析
   

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 17
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值