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加入编译

[cpp] view plain copy print ?
  1. #defineLOG_TAG"Input"
  2. #include"jni.h"
  3. #include"JNIHelp.h"
  4. #include<utils/misc.h>
  5. #include<utils/Log.h>
  6. #include<linux/fb.h>
  7. #include<sys/types.h>
  8. #include<sys/stat.h>
  9. #include<fcntl.h>
  10. namespaceandroid{
  11. staticintfd=-1;
  12. staticstructfb_cursorhw_cur;
  13. staticvoidmouseInit()
  14. {
  15. if(-1==fd)
  16. fd=open("/dev/graphics/cursor",O_RDWR);
  17. hw_cur.set=FB_CUR_SETALL;
  18. hw_cur.enable=0;
  19. hw_cur.hot.x=0;
  20. hw_cur.hot.y=0;
  21. ioctl(fd,0x4608,&hw_cur);
  22. }
  23. staticvoidandroid_server_WindwManagerService_setHWCursorPosition(JNIEnv*env,jobjectobj,jintx,jinty)
  24. {
  25. if(-1==fd)
  26. mouseInit();
  27. hw_cur.enable=1;
  28. hw_cur.set=FB_CUR_SETHOT;
  29. hw_cur.hot.x=x;
  30. hw_cur.hot.y=y;
  31. ioctl(fd,0x4608,&hw_cur);
  32. }
  33. staticJNINativeMethodgWindowManagerMethods[]={
  34. /*name,signature,funcPtr*/
  35. {"setHWCursorPosition","(II)V",
  36. (void*)android_server_WindwManagerService_setHWCursorPosition},
  37. };
  38. intregister_android_server_WindowManagerService(JNIEnv*env)
  39. {
  40. jclassinput=env->FindClass("com/android/server/WindowManagerService");
  41. LOG_FATAL_IF(input==NULL,"Unabletofindclasscom/android/server/WindowManagerService");
  42. intres=jniRegisterNativeMethods(env,"com/android/server/WindowManagerService",
  43. gWindowManagerMethods,NELEM(gWindowManagerMethods));
  44. returnres;
  45. }
  46. };//namespaceandroid

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



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

更多相关文章

  1. sencha touch 调用android主函数里的方法(可用与phoneGap开发第三
  2. Android知识点记录: 使用代码设置 android 上listView的条目的点
  3. Android 4.1源代码今日将发布
  4. Android的源代码结构(转)
  5. Android 代码混淆
  6. 使用android studio 查看 android 的源代码
  7. ANDROID源代码结构

随机推荐

  1. Android(安卓)xUtils框架(一) DbUtils
  2. Android 配置环境
  3. 根据百度地图API得到坐标和地址并在地图
  4. android 4.2 修改默锁屏为无
  5. android实现猜扑克牌小游戏(改进:每次只可
  6. Android trouble shooting 整理
  7. Android(安卓)GPS架构分析-preview
  8. Glide使用方法汇总
  9. 【ClassNotFoundExcept】Android应用程序
  10. Android之反编译