现在的位置: 首页 > 综合 > 正文

Android添加鼠标支持研究

2014年02月26日 ⁄ 综合 ⁄ 共 7700字 ⁄ 字号 评论关闭


 

Android默认是没有鼠标支持的,但在Android系统会应用到许多其他的地方,如平板电脑、电视中,许多时候就需要鼠标的支持。

支持原理:Android中有原生的Touch事件,鼠标的各种事件都可以转换为各种Touch事件,将鼠标事件走与Touch事件相关的路径就可以实现。需要注意的是,在屏幕旋转后,鼠标的坐标等信息需要程序处理才能正确。

修改文件概览:
C++文件:
 

             frameworks\base\include\ui\EventHub.h
              frameworks\base\libs\ui\EventHub.cpp
java文件:
               frameworks\base\core\java\android\view\RawInputEvent.java
               frameworks\base\services\java\com\android\server\InputDevice.java
               frameworks\base\services\java\com\android\server\KeyInputQueue.java
               frameworks\base\services\java\com\android\server\WindowManagerService.java

文件功能描述
              EventHub.h                          增加鼠标设备的定义
              EventHub.cpp                   函数open_device(const char *deviceName)中增加鼠标类型
              RawInputEvent.java             增加鼠标设备
              InputDevice.java                  增加鼠标连接状态标志
                                                MotionState中增加方法 generateMouseMotion()将原始鼠标事件转化为
                                                    MotionEvent事件
              KeyInputQueue.java     在事件RawInputEvent.EV_DEVICE_ADDED中判断鼠标设备,动态增加
                                                在事件RawInputEvent.EV_DEVICE_REMOVED中,动态判断鼠标删除
                                                在ev.type == RawInputEvent.EV_KEY中增加鼠标左中右键处理
                                                在ev.type == RawInputEvent.EV_REL中增加鼠标坐标变动和滚轮的处理
                                                  recycleEvent()中增加鼠标相关的清理工作
             WindowManagerService.java    实现在界面上的画鼠标及移动鼠标的工作。

如果你的Android设备支持鼠标,你将会发现默认的光标为灰色半透明的三角形,系统的默认主题是黑色的,造成很难发现鼠标的位置。所以本文介绍怎样定制Android系统的鼠标光标。

     Android系统对鼠标的支持并不好,因为Android系统原本是为手机量身定做的,手机系统基本上是不需要鼠标的。但是随着Android系统移植到其他领域,对鼠标的支持也越来越有意义。现在Android已经支持鼠标了,但是有一个完善的过程。本文后面会介绍到Android对鼠标支持的一些不足。

     原来我以为Android系统的光标会和Windows差不多,是一个图片资源呢。这样的话,我只需要替换掉这个图片就可以搞定了。找了好久都没有找到图片资源的位置,最终反过来思考,Android系统鼠标光标非常简单,手动绘制也不是很难的事情。会不会是代码中绘制的呢?

     沿着这个思路,终于在WindowManagerService.java中,找到了相关的代码:

frameworks/base/services/java/com/android/server/WindowManagerService.java

相关的代码位于performLayoutAndPlaceSurfacesLockedInner方法中:

				mMouseSurface =
					new Surface(mFxSession,
								0,-1,mMw,mMh,
								PixelFormat.TRANSPARENT,
								Surface.FX_SURFACE_NORMAL);
				mCanvas = mMouseSurface.lockCanvas(null);
				mCanvas.drawColor(0x0);

				mPath.moveTo(0.0f,   0.0f);
				mPath.lineTo(16.0f, 0.0f);
				mPath.lineTo(0.0f, 16.0f);
				mPath.close();
				mCanvas.clipPath(mPath);
				mCanvas.drawColor(0x66666666);

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

     可以看出默认情况下Android系统用颜色值0×66666666绘制了一个三角形,这个颜色值为32bit——A8R8G8R8,A表示透明度,0表示全部透明,0xff为不透明,0×66表示半透明。

     你可以修改其中代码来修改鼠标光标的形状,需要学习一下Android绘图系统,熟悉Paint,Canvas等概念,不过挺简单的。下面是我的光标绘制的代码:

				mMouseSurface =
					new Surface(mFxSession,
								0,-1,mMw,mMh,
								PixelFormat.TRANSPARENT,
								Surface.FX_SURFACE_NORMAL);
				mCanvas = mMouseSurface.lockCanvas(null);
				mCanvas.drawColor(0x0);

				mPath.moveTo(0.0f,   0.0f);
				mPath.lineTo(0.0f, 19.0f);
				mPath.lineTo(14.0f, 14.0f);
				mPath.close();
				mCanvas.clipPath(mPath);
				mCanvas.drawColor(0xFFFFFFFF);
				Paint paint = new Paint();
				paint.setStyle(Paint.Style.STROKE);
				paint.setColor(0xFF000000);
				mCanvas.drawPath(mPath, paint);

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

绘制的光标为一个瘦一点儿的不透明的白色填充的三角形,然后用黑色给白色三角形描边。主要是模仿Windows的光标风格,对于各种颜色基调的主题这个光标都可以很清晰。

     可以看出Android系统鼠标光标的定制不是非常容易,需要修改代码,相信Android后续版本会对鼠标的支持有改进。以上代码仅供参考,如有错误敬请指正。

SDL for Embedded Systems

    SDL stands for "Simple DirectMedia Layer". It is simple, small and can access multimedia hardware directly. Therefore, it is particularly useful in developing applications for Embedded Linux systems as such systems usually have highly constrained resources.
    However, from time to time you may need to make modifications to the SDL libraries in order that they fully function in the embedded environment. In general, an Embedded Linux system does not support X-Window as it requires tremendous amount of resources to
    run; this may render the mouse useless. In order to use the mouse in a non-X environment, we need to make some minor modifications to the SDL libraries as of to date ( version 1.2.11 ). Very often, an embedded Linux development board provides one or more USB
    ports for I/O interface; the USB ports can be used to interface to a mouse, a keyboard or some other USB devices. In this chapter, we discuss how to modify SDL-1.2.11 to support USB I/O devices for Embedded Linux.

  1. USB Mouse and Touch Screen ( TS ) Input

    Mouse and TS have similar input mechanisms. For latest Linux versions, the devices in general can be accessed via

      /dev/input/event0   or   /dev/input/event1

    For backward compatibility, the mouse may also be accessed via /dev/input/mice/dev/input/mouse0, or/dev/input/mouse1, etc

    You could test if the mouse works by the executing the command,

      #cat /dev/input/event1

    Moving the mouse around will display some random characters, mostly unprintable on the screen.

    In an ARM-9 board, most likely you can only see

  2. /dev/input/event0
  3. /dev/input/event1

  4. In this case, event0 is for ts ( touch screen ) and event1 is for mouse or keyboard, depending on what you have plugged in the USB port. Again, you can use the command "cat /dev/input/eventn" to test if you could open the device.

    SDL mouse support 


    SDL does not support USB mouse directly ( in a PC, SDL utilizes X-window routine to handle the mouse but in our ARM board, we use the frame buffer routine directly ). To support USB mouse and touch screen, we may modify some of the source files of the SDL-1.2.11
    library as follows.

    You need to modify the following three files located at src/video/fbcon of the SDL source code tree:

    • SDL_fbevents.c
    • SDL_fbevents_c.h
    • SDL_fbvideo.c
  5. First, add functions in SDL_fbvideo.c to handle mouse/ts I/Os ( note that we use SELECT to handle I/O ):
      static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
      ...
      #ifdef __ARM__
        if ( FB_OpenEventX(this) == 0 ) {
          SDL_SetError("Unable to open /dev/input/eventX");
          FB_VideoQuit(this);
          return(-1);
        }
      #else
        //PC original code
      #endif
      
  6. Second, add function prototypes to header file SDL_fbevents_c.h:
    static int FB_VideoInit(_THIS, SDL_PixelFormat *vformat)
    extern int FB_OpenEventX(_THIS);
    extern void FB_CloseEventX(_THIS);
    extern void FB_vgamousecallback(int button, int relative, int dx, int dy);
      
  7. Third, add the following to SDL_fbevents.c:
    #include <linux/input.h>
    ....
    static int event0_fd = -1;
    static int event1_fd = -1;
    struct input_event ev0[64];
    struct input_event ev1[64];
    
    //for handling TS
    static void handle_event0(_THIS)
    {
      int button=0, x=0, y=0, realx=0, realy=0, i, rd;
    
      rd = read(event0_fd, ev0, sizeof(struct input_event) * 64);
      if( rd < sizeof(struct input_event) ) return;
    
      for (i = 0; i < rd / sizeof(struct input_event); i++)
      {
        if(ev0[i].type == 3 && ev0[i].code == 0) x = ev0[i].value;
        else if(ev0[i].type == 3 && ev0[i].code == 1) y = ev0[i].value;
        else if(ev0[i].type == 1 && ev0[i].code == 330) button = ev0[i].value << 2;
        else if(ev0[i].type == 0 && ev0[i].code == 0 && ev0[i].value == 0)
        {
        //need to define numbers in header for flexibility
    	realx = (950-y)*240/(950-70);
    	realy = (x-70)*320/(950-70);
    
    	if( realx < 0  ) realx = 0; 
    	if( realx > 240  ) realx = 240;
    	if( realy < 0  ) realy = 0; 
    	if( realy > 320  )realx = 320;
    	FB_vgamousecallback(button, 0, realx, realy);
        }		
      }
      return;
    }
    
    //for handling mouse
    static void handle_event1(_THIS)
    {
      int button=0, x=0, y=0, i, rd;
      rd = read(event1_fd, ev1, sizeof(struct input_event) * 64);
      if( rd < sizeof(struct input_event) ) return;
    
      for (i = 0; i < rd / sizeof(struct input_event); i++)
      {
        if(ev1[i].type == 2 && ev1[i].code == 0) x = ev1[i].value;
        else if(ev1[i].type == 2 && ev1[i].code == 1) y = ev1[i].value;
        else if(ev1[i].type == 1) {
    	if(ev1[i].code == 272) { 
    	  button &= ~0x4; 
    	  button |= ev1[i].value << 2; 
    	} else if(ev1[i].code == 273) {
    	  button &= ~0x1; 
    	  button |= ev1[i].value; 
            } else if(ev1[i].code == 274) { 
    	  button &= ~0x2; 
    	  button |= ev1[i].value << 1; 
            }
        } else if(ev1[i].type == 0 && ev1[i].code == 0 && ev1[i].value == 0) {
    	FB_vgamousecallback(button, 1, x, y);
    	x=0, y=0;
        }	
      }
    	
      return;
    }
    
    int FB_OpenEventX(_THIS)
    {
      event0_fd = open("/dev/input/event0", O_RDWR);
      event1_fd = open("/dev/input/event1", O_RDWR);
    
      if(event0_fd < 0 && event1_fd < 0)
        return 0;
    	
      return 1;
    }
    
    void FB_CloseEventX(_THIS)
    {
      if ( event0_fd > 0 ) {
        close(event0_fd);
      }
    
      if ( event1_fd > 0 ) {
        close(event1_fd);
      }
    
      event0_fd = -1;
      event1_fd = -1;
    }
    ....
    
  8. After you've made the above modifications, recompile the SDL library as discussed in the previous chapters. The new library will support both USB mouse and touch screen.

抱歉!评论已关闭.