Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1630502
  • 博文数量: 584
  • 博客积分: 13857
  • 博客等级: 上将
  • 技术积分: 11883
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-16 09:34

分类: LINUX

2010-09-01 10:22:05

今天有人问怎样实现在MIniGUI中实现自己的IAL引擎,看了下2.0.3的手册,它上面说已经二三十多种引擎,那如何实现自己的呢?毕竟不同的板子 实现IAL肯定是不同的。不过这东西看看MiniGUI源码src/ial目录下一些.c文件,你就可以比较清楚的了解了。具体你可以参考里面已经支持的 例子,如:s3c2410.c、ipaq.c、eb7211.c,结合这些东西你就可以自己实现自己的IAL了。
       MiniGUI移植的核心所在就是GAL和IAL的移植。在嵌入式linux应用中,内核通常会提供对framebuffer设备的驱动,而在GAL中对 于fb的支持,MiniGUI是默认的。因此,通过简单的MiniGUI.cfg配置ial=fbcon,就可以完成GAL的支持了。

对IAL的支持并不是那么容易。Linux对输入设备目前还没有一个统一的标准,也未形成任何规范。虽然keyboard在桌面领域已占据主导地位,在嵌 入式中不可能使用类似于键盘那么复杂的设备。嵌入式中多使用触摸屏和4×4的小键盘,而这类设备虽然表面雷同,功能键的定义千差万别。移植这类设备的 IAL实现更有意义。 MiniGUI不论是库还是应用程序都不是内核的一部分,因此,MiniGUI没有直接访问设备的权限。为了实现触摸屏和小键盘的支持,内核中必须提供这 二者的驱动程序。当然,这里的驱动程序可以是最底层的实现,更为复杂的通过MiniGUI的IAL驱动扩展实现。
因此在MiniGUI中实现一种新设备的IAL支持,通常提供如下步骤:
1.内核提供该设备(触摸屏或者小键盘)的驱动程序。
2.在libminigui的src/ial/目录建立需要的.c和.h文件,编写高层IAL驱动程序。
3.将新的IAL驱动程序编译到MiniGUI的库中,以便为应用程序提供新的IAL支持。
4.修改MiniGUI.cfg的ial配置,使应用程序运行时使用移植好的IAL设备。

       实现一个输入引擎,可以将触摸屏按照鼠标处理,将按键按照键盘处理。
      如何在MiniGUI中添加新的IAL引 擎:(假设新的IAL引擎为_NAME_IAL

1.         ial.c文 件中添加新引擎的入口:

例如:(ial.c文件中)

A)       #ifdef _NAME _IAL
       #include "NAME.h"
   #endif

B)       input 数组中添加

       #ifdef _NAME _IAL
            {"NAME ", InitNAMEInput, TermNAMEInput},
       #endif

2.       把新的 .c 添加到 Makefile.am 文件中即可。

3.       修改配置文件IAL 引擎项,使用这个新的IAL引擎_NAME_IAL.

²        如何编写IAL引 擎:

1.         MiniGUI中 引入了输入抽象层(Input Abstract Layer IAL) 的概念,它大大提高了MiniGUI的可移植性。

2.         IAL是 定义的一组不依赖于任何特殊硬件的抽象接口。而我们这里所说的IAL引 擎则是对IAL定义的抽象接口的实现的底层代码。

3.         IAL接 口对下是IAL引擎,这些引擎使用了输入设备驱动提供的一些函数;对上则是应用程序或是GDI, 上层MiniGUI库中ParseEvent() 函数将通过这些IAL引擎将收集到的鼠标键盘事件转换为MiniGUI中 的消息。

4.         MiniGUI IAL结 构如下:

在代码实现上,MiniGUI通过INPUT数 据结构来表示输入引擎

typedef struct tagINPUT

{

    char*   id;

    // Initialization and termination

    BOOL (*init_input) (struct tagINPUT *input, const char* mdev, const char* mtype);

    void (*term_input) (void);

    // Mouse operations

    int (*update_mouse) (void);

    void (*get_mouse_xy) (int* x, int* y);

    void (*set_mouse_xy) (int x, int y);

    int (*get_mouse_button) (void);

    void (*set_mouse_range) (int minx, int miny, int maxx, int maxy);

    void (*suspend_mouse) (void);

    int (*resume_mouse) (void);

    // Keyboard operations

    int (*update_keyboard) (void);

    const char* (*get_keyboard_state) (void);

    void (*suspend_keyboard) (void);

    int (*resume_keyboard) (void);

    void (*set_leds) (unsigned int leds);

    // Event

#ifdef _LITE_VERSION

    int (*wait_event) (int which, int maxfd, fd_set *in, fd_set *out, fd_set *except,

            struct timeval *timeout);

#else

   int (*wait_event) (int which, fd_set *in, fd_set *out, fd_set *except,

            struct timeval *timeout);

#endif

    char mdev [MAX_PATH + 1];

}INPUT;

extern INPUT* cur_input;

系统启动后,将根据配置文件寻找特定的输入引擎作为当前的输入引擎,并对全局变量cur_input(表 当前使用的输入引擎)赋值。

为书写方便,定义了当前引擎的C语 言宏

#define IAL_InitInput           (*cur_input->init_input)

#define IAL_TermInput           (*cur_input->term_input)

#define IAL_UpdateMouse         (*cur_input->update_mouse)

#define IAL_GetMouseXY          (*cur_input->get_mouse_xy)

#define IAL_GetMouseButton      (*cur_input->get_mouse_button)

#define IAL_SetMouseXY          if (cur_input->set_mouse_xy) (*cur_input->set_mouse_xy)

#define IAL_SetMouseRange       if (cur_input->set_mouse_range) (*cur_input->set_mouse_range)

#define IAL_SuspendMouse        if (cur_input->suspend_mouse) (*cur_input->suspend_mouse)

#define IAL_UpdateKeyboard      (*cur_input->update_keyboard)

#define IAL_GetKeyboardState    (*cur_input->get_keyboard_state)

#define IAL_SuspendKeyboard     if (cur_input->suspend_keyboard) (*cur_input->suspend_keyboard)

#define IAL_SetLeds(leds)       if (cur_input->set_leds) (*cur_input->set_leds) (leds)

5.         我们编写IAL引 擎要做的就是在_NAME_IAL.c中实现输入引擎结构中定义的这些函数。如:_NAME_IAL.c:

#include ………

…………..变量定义

/************************ Low Level Input Operations **********************/

mouse_update()

{

……………

}

mouse_getxy()

{

………………..

}

mouse_getbutton()

{

………………..

}

………….IAL引擎结构中定义的其它有关mouse的 函数一般无需实现。

Keyboard_update()

{

……………..

}

   keyboard_getstate()

{

………

}

……………..同样结构中定义的其它有关keyboard的 函数一般无需实现。

Wait_event()

{

………………..

}

InitNAMEInputINPUT* input, const char* mdev, const char* mtype

{

…………

input->update_mouse = mouse_update;

    input->get_mouse_xy = mouse_getxy;

    input->set_mouse_xy = NULL;

    input->get_mouse_button = mouse_getbutton;

    input->set_mouse_range = NULL;

    input->update_keyboard = keyboard_update;

    input->get_keyboard_state = keyboard_getstate;

    input->set_leds = NULL;

    input->wait_event = wait_event;

………………..

}

void TermNAMEInput (void)

{

   …………….

}

6.         各函数功能说明:开发一输入 引擎一般也就是实现以下几个函数。

         InitNAMEInput函 数就是在src/ial/ial.c中定义的NAME输 入引擎的初始化函数,它打开触摸屏(鼠标)和键盘设备文件。在成功打开这两个设备文件后,该函数设置了INPUT结 构的其它一些成员。其中一些成员被赋值为NULL

        Mouse_update函 数始终返回1,表明更新鼠标状态成功。

         Mouse_getxy函 数返回由其它函数准备好的鼠标位置,有可能做了适当的边界检查和支持屏幕显示旋转时对坐标的转换。函数的参数是两个指针变量。

         Mouse_getbutton函 数返回了触摸屏状态,即用户是否触摸了屏幕,相当于是否按下了左键。(或者鼠标哪个键按下,左键、右键还是当中的那个?)

返回值为触摸屏(鼠标)状态。

         Keyboard_update函 数根据其它函数准备好的键盘消息,适当填充了state数组。返回值是NR_KEYS

        Keyboard_state函 数直接返回了state数组的地址:“return state”。

        Wait_event函 数是输入引擎的核心函数。这个函数首先将先前打开的两个设备的文件描述符与传入的in文件描述符集 合并在了一起,然后调用了select系统调用。当select系 统调用返回大于0的值时,该函数检查在两个文件描述符上是否有可读的数据等待读取,如果是,则分别 从两个文件描述符读取触摸屏和按键数据。

返回值intretvalue变 量,其中包含了信息:鼠标事件发生、键盘事件发生或者鼠标和键盘事件都发生了(retvalue |= IAL_MOUSEEVENTretvalue |= IAL_KEYEVENT)。

7.         开发IAL引 擎,实现以上函数:

        开发IAL引 擎准备工作:需对输入设备有些了解:

a)         是鼠标、触摸屏还是触摸板? 键盘都有哪些键?

b)        数据包格式怎样?(同样是触摸 屏,不同型号其通过设备文件获得数据结构也不一样,得到的若是A/D转换得来的原始数据处理起来就有些麻烦; 键盘的释放与按下状态是通过判断读得的字符最高位01来 判断,还是对同一键其按下和释放对应两个毫无联系的字符)

c)        键盘的编码怎样,和MiniGUIinclude/common.h中 定义的一样吗?

d)        在读得的坐标和屏幕显示坐标间 需不需要进行坐标转换?Mouse_getxy中最终返回的坐标为屏幕显示坐标。

e)         输入设备驱动支持select系 统调用吗?

f)         触摸屏(触摸板)驱动中是否 解决了抖动消除的问题,是否需要在IAL引擎中解决触摸屏消抖?

        总结代码中几个针对具体系统开发的IAL 引擎:

a)         引擎包含的各个函数所要做的 工作在上面的函数功能说明中已经反应出来,但是具体处理起来,不一定要求有的工作就得在某个函数中完成。比如,从设备文件读取鼠标坐标的信息并对其进行处 理,不一定都在Mouse_getxy中完成,可以在Wait_eventupdate_mouse中 完成,在mouse_getxy中只是将最终的显示屏幕坐标赋给mouse_getxy函 数的两个参数。

b)        IAL引 擎的作用是正确分析从设备文件读得的数据,获得鼠标(触摸屏、触摸板)坐标和状态及键盘按键情况(哪个键按下?该键是不是释放了?).这 也是我们开发IAL引擎的指南。

c)        IAL引 擎在MiniGUI的使用(位置):

        \src\sever\server.c L396 函数IdleHandler4Server()中用了输入 引擎中的IAL_WaitEvent检查是否有底层输入事件发生,

         当有事件发生时检查是鼠标(触摸 屏、触摸板)事件发生还是键盘事件发生,并分别用parseEvent(msg_que,event)函 数(\src\sever\server.c)处理这些事件

ParseEvent (msg_queue, IAL_MOUSEEVENT)

ParseEvent (msg_queue, IAL_KEYEVENT)

ParseEvent (msg_queue, 0)

        parseEvent(msg_que,event)函 数中首先调用了Getlwevent(event,&lwe) (lwe是在parseEvent中 定义的)Getlweventevent,&lwe) 中分析event:

eventIAL_KEYEVENT时:

调用了引擎IAL_UpdateKeyboard ()IAL_GetKeyboardState ()

eventIAL_MOUSEEVENT时:

调用了引擎IAL_UpdateMouse ()和函数RefreshCursor(&me->x, &me->y, &button)(该函数中调用了IAL_GetMouseXY (x, y)IAL_GetMouseButton

Getlweventevent,&lwe) 最终得到了鼠标键盘的坐标状态等具体信息,这些信息由lwe变量带回。

变量Lwe数据结构:

typedef struct _LWEVENT

{

    int type;

    int count;

    DWORD status;

    LWEVENTDATA data;

}LWEVENT;

typedef union _LWEVENTDATA {

    MOUSEEVENT me;

    KEYEVENT ke;

}LWEVENTDATA;

        parseEvent(msg_que,event)中 利用了获得的lwe,将其转化为消息,放到消息队列中。如对键盘:

Msg.message=MsgKEYDOWN

Msg.wparam=ke->scancode

Msg.iparam=ke->status

         Getlwevent(event,&lwe)收 集底层输入事件lwe(利用了IAL引擎)

   parseEvent(msg_que,event)将收集到的这些事件 转化为上层能理解的消息。

d)        有关键盘的IAL引 擎就是给state数组赋值。

    MiniGUIinclude/common.h中 列举了每种按键在state数组中的位置(如#define SCANCODE_Z 44可以知道state数组中第44个 元素表示Z键的状态),我们必须分析从键盘配置文件读取的字符字节的信息,根据这些信息给state数 组中相应元素赋值,这样MiniGUI才能根据state数 组正确处理这些事件(即MiniGUI是通过state数 组中的元素来正确识别哪个键按下的。必须严格根据state数组的规定)。

8.         编写输入引擎可参考ipaq.c, 它是针对了比较普通的触摸屏的写的。

9.       写出触摸屏接口代码,注意:鼠标 获取的数据一般是相对坐标,而典型的触摸屏则是绝对坐标(差劲的驱动是直接返回A/D转换得来的原始数据)。

阅读(954) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~