全部博文(584)
分类: LINUX
2010-09-01 10:22:05
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()
{
………………..
}
InitNAMEInput(INPUT* 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的值时,该函数检查在两个文件描述符上是否有可读的数据等待读取,如果是,则分别 从两个文件描述符读取触摸屏和按键数据。
返回值int型retvalue变 量,其中包含了信息:鼠标事件发生、键盘事件发生或者鼠标和键盘事件都发生了(retvalue |= IAL_MOUSEEVENT,retvalue |= IAL_KEYEVENT)。
7. 开发IAL引 擎,实现以上函数:
开发IAL引 擎准备工作:需对输入设备有些了解:
a) 是鼠标、触摸屏还是触摸板? 键盘都有哪些键?
b) 数据包格式怎样?(同样是触摸 屏,不同型号其通过设备文件获得数据结构也不一样,得到的若是A/D转换得来的原始数据处理起来就有些麻烦; 键盘的释放与按下状态是通过判断读得的字符最高位0与1来 判断,还是对同一键其按下和释放对应两个毫无联系的字符)
c) 键盘的编码怎样,和MiniGUI在include/common.h中 定义的一样吗?
d) 在读得的坐标和屏幕显示坐标间 需不需要进行坐标转换?Mouse_getxy中最终返回的坐标为屏幕显示坐标。
e) 输入设备驱动支持select系 统调用吗?
f) 触摸屏(触摸板)驱动中是否 解决了抖动消除的问题,是否需要在IAL引擎中解决触摸屏消抖?
总结代码中几个针对具体系统开发的IAL 引擎:
a) 引擎包含的各个函数所要做的 工作在上面的函数功能说明中已经反应出来,但是具体处理起来,不一定要求有的工作就得在某个函数中完成。比如,从设备文件读取鼠标坐标的信息并对其进行处 理,不一定都在Mouse_getxy中完成,可以在Wait_event或update_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中 定义的),Getlwevent(event,&lwe) 中分析event:
当event是IAL_KEYEVENT时:
调用了引擎IAL_UpdateKeyboard ()和IAL_GetKeyboardState ()
当event是IAL_MOUSEEVENT时:
调用了引擎IAL_UpdateMouse ()和函数RefreshCursor(&me->x, &me->y, &button)(该函数中调用了IAL_GetMouseXY (x, y)和IAL_GetMouseButton )
Getlwevent(event,&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=Msg-KEYDOWN
Msg.wparam=ke->scancode
Msg.iparam=ke->status
Getlwevent(event,&lwe)收 集底层输入事件lwe(利用了IAL引擎)
parseEvent(msg_que,event)将收集到的这些事件 转化为上层能理解的消息。
d) 有关键盘的IAL引 擎就是给state数组赋值。
MiniGUI在include/common.h中 列举了每种按键在state数组中的位置(如#define SCANCODE_Z 44可以知道state数组中第44个 元素表示Z键的状态),我们必须分析从键盘配置文件读取的字符字节的信息,根据这些信息给state数 组中相应元素赋值,这样MiniGUI才能根据state数 组正确处理这些事件(即MiniGUI是通过state数 组中的元素来正确识别哪个键按下的。必须严格根据state数组的规定)。
8. 编写输入引擎可参考ipaq.c, 它是针对了比较普通的触摸屏的写的。
9. 写出触摸屏接口代码,注意:鼠标 获取的数据一般是相对坐标,而典型的触摸屏则是绝对坐标(差劲的驱动是直接返回A/D转换得来的原始数据)。