前言
之前看了一篇介绍MiniGUI事件分发的文章MiniGUI事件分发机制,但是最近项目中遇到问题需要排查下事件分发的细节,周六看了下,这里做个记录.
1. 关于EventLoop
文件路径: ./src/kernel/init.c
static void* EventLoop (void* data)
{
LWEVENT lwe;
int event;
lwe.data.me.x = 0; lwe.data.me.y = 0;
sem_post ((sem_t*)data);
while (__mg_quiting_stage > _MG_QUITING_STAGE_EVENT) {
event = IAL_WaitEvent (IAL_MOUSEEVENT | IAL_KEYEVENT, 0,
NULL, NULL, NULL, (void*)&__mg_event_timeout);
if (event < 0) {
usleep(10*1000); /*reduce the CPU usage frequency*/
continue;
}
lwe.status = 0L;
lwe.data.me.status = 0;
// 鼠标事件
if (event & IAL_MOUSEEVENT && kernel_GetLWEvent (IAL_MOUSEEVENT, &lwe))
ParseEvent (&lwe);
lwe.status = 0L;
lwe.data.ke.status = 0;
// 按键事件
if (event & IAL_KEYEVENT && kernel_GetLWEvent (IAL_KEYEVENT, &lwe))
ParseEvent (&lwe);
if (event == 0 && kernel_GetLWEvent (0, &lwe))
ParseEvent (&lwe);
}
/* printf("Quit from EventLoop()\n"); */
return NULL;
}
- while循环一开始会调用IAL_WaitEvent函数获取事件,获取到事件的话会实时处理, 没有事件的话会延时10毫秒等待(防止CPU过度使用),IAL_WaitEvent函数会调用对应输入引擎的实现,tslib中是使用select监听输入事件。
- 接下来,会根据事件类型对事件进行加工,事件类型这里分为鼠标事件和按键事件,TFT屏幕设备的话主要关心的可能还是鼠标事件,因为这里面有按下,抬起,滑动事件。
- kernel_GetLWEvent 函数会对事件进行加工处理,需要保留的事件就会交给parseEvent函数进行解析,不需要保留的函数就会丢弃。
2. kernel_GetLWEvent
BOOL kernel_GetLWEvent (int event, PLWEVENT lwe)
{
/*---省略---*/
timeout_count = 0;
/* There was an event occurred. */
if (event & IAL_MOUSEEVENT) {
lwe->type = LWETYPE_MOUSE;
// 获取button事件
if (kernel_RefreshCursor(&me->x, &me->y, &button)) {
me->event = ME_MOVED;
time1 = 0;
time2 = 0;
//Note:should contains button state in MSG_MOUSEMOVE
if (button == oldbutton)
goto mouseret;
}
// 左键的处理逻辑
if ( !(oldbutton & IAL_MOUSE_LEFTBUTTON) &&
(button & IAL_MOUSE_LEFTBUTTON) )
{
license_on_input();
interval = __mg_timer_counter - time1;
if (interval <= dblclicktime)
me->event = ME_LEFTDBLCLICK;
else
me->event = ME_LEFTDOWN;
time1 = __mg_timer_counter;
goto mouseret;
}
if ( (oldbutton & IAL_MOUSE_LEFTBUTTON) &&
!(button & IAL_MOUSE_LEFTBUTTON) )
{
license_on_input();
me->event = ME_LEFTUP;
goto mouseret;
}
// 下面是右键的button事件--暂不分析
if ( !(oldbutton & IAL_MOUSE_RIGHTBUTTON) &&
(button & IAL_MOUSE_RIGHTBUTTON) )
{
interval = __mg_timer_counter - time2;
if (interval <= dblclicktime)
me->event = ME_RIGHTDBLCLICK;
else
me->event = ME_RIGHTDOWN;
time2 = __mg_timer_counter;
goto mouseret;
}
if ( (oldbutton & IAL_MOUSE_RIGHTBUTTON) &&
!(button & IAL_MOUSE_RIGHTBUTTON) )
{
me->event = ME_RIGHTUP;
goto mouseret;
}
}
/*-------keyevent事件暂不展开------*/
old_lwe.type = 0;
return 0;
mouseret:
status &= ~(MASK_KS_BUTTONS);
oldbutton = button;
if (oldbutton & IAL_MOUSE_LEFTBUTTON)
status |= KS_LEFTBUTTON;
if (oldbutton & IAL_MOUSE_RIGHTBUTTON)
status |= KS_RIGHTBUTTON;
me->status = status;
memcpy (&old_lwe, lwe, sizeof (LWEVENT));
__mg_event_timeout.tv_sec = 0;
__mg_event_timeout.tv_usec = timeoutusec;
return 1;
}
- 该函数包含了对鼠标事件和按键事件的处理逻辑,按键事件此处不进行分析,主要是对鼠标事件进行分析
- 一开始会调用kernel_RefreshCursor函数获取button是按下还是抬起,并获取坐标值。获取button的方法是调用输入引擎的IAL_GetMouseButton函数,该函数获取的button值最终又是由mouse_update函数赋值的,赋值的原理就是,压力值>0认为是按下,反之认为是抬起。
(mouse_update函数中使用的是ts_read函数获取触摸数值,该函数只支持单指,多指的话需要调用ts_read_mt函数获取) - kernel_GetLWEvent 函数接下来会用oldbutton 和 button来判断按下还是抬起逻辑,oldbutton = 0,button = 1是按下,oldbutton = 1,button = 0是抬起,这里没有对oldbutton = 0,button = 0 或者oldbutton = 1,button = 1进行处理,原因是单指操作时,只有这两种逻辑,如果有多指操作的话,这里就需要添加全0或者全1逻辑的处理。
- kernel_GetLWEvent 函数的返回结果会决定接下来是否进入事件解析逻辑,即parseEvent,parseEvent函数对事件进行处理后,决定是否放入消息队列中。