本文主要介绍minigui中添加键盘支持功能
一、介绍
由于项目需求,要在minigui中添加键盘处理。
不清楚minigui默认是否支持键盘,作者拿到的代码是改动过的,没有实现键盘功能。键盘的整个流程涉及到libminigui部分和minigui主应用部分,作者的理解中,libminigui类似于HAL的功能,minigui主应用则主要是调用libminigui库提供的功能,所以改动部分主要在libminigui中。
二、libminigui库
1.libminigui库中的主要流程分析
InitGUI() 函数入口
mg_InitLWEvent() -> mg_InitIAL() 注册键盘和光标处理函数
SystemThreads() -> pthread_create (&__mg_parsor, NULL, EventLoop, &wait);
EventLoop() 线程中循环查询键盘消息和光标消息
EventLoop:
kernel_GetLWEvent()
-> kernel_RefreshCursor() -> IAL_GetMouseButton() -> __mg_cur_input->get_mouse_button 获取光标消息
-> IAL_UpdateKeyboard() -> IAL_GetKeyboardState() 获取键盘消息
ParseEvent() -> QueueDeskMessage() 发送键盘和光标消息
以上只是简单分析库的流程,关于查询键盘消息和光标消息的流程不做深入讨论,这里主要是介绍注册函数的实现。
2.mg_InitIAL函数定义如下:
int mg_InitIAL (void)
{
...
for (i = 0; i < NR_INPUTS; i++) {
//printf("====================input test===================\n");
if (strncmp (engine, inputs[i].id, LEN_ENGINE_NAME) == 0) {
//printf("inputs[i].id: %s\n",inputs[i].id);
__mg_cur_input = inputs + i;
break;
}
}
...
}
在mg_InitIAL中,主要是检测输入引擎是否存在,并将存在inputs赋值给__mg_cur_input。
3.inputs定义如下:
static INPUT inputs [] =
{
...
#ifdef _MGIAL_TSLIB
{"tslib", InitTSLibInput, TermTSLibInput},
#endif
...
};
其中InitTSLibInput是输入引擎的初始化,TermTSLibInput是销毁函数。
4.InitTSLibInput
#define KBD_DEVICE "/dev/input/event1"
static int keykoard_fd = -1;
static XVFBKEYDATA kbd_data;
static unsigned char kbd_state [NR_KEYS];
static struct input_event kb_event;
BOOL InitTSLibInput(INPUT* input, const char* mdev, const char* mtype)
{
const char* tsdevice;
if ((tsdevice = getenv ("TSLIB_TSDEVICE")) == NULL) {
tsdevice = mdev;
}
//printf("[kevin]: tsdevice:%s\n",tsdevice);
if (tsdevice == NULL) {
_MG_PRINTF ("IAL>TSLib: Please specify the ts device\n");
return FALSE;
}
//printf("start InitTSLibInput!\n");
ts = ts_open (tsdevice, 0);
if (!ts) {
_MG_PRINTF ("IAL>TSLib: can not open ts device\n");
return FALSE;
}
if (ts_config (ts)) {
_MG_PRINTF ("IAL>TSLib: can not config ts device\n");
return FALSE;
}
keykoard_fd = open (KBD_DEVICE, O_RDONLY);
if (keykoard_fd < 0 ) {
_MG_PRINTF ("IAL>%s: Can not open button key!\n", __FILE__);
return FALSE;
}
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_get_state;
input->set_leds = NULL;
input->wait_event = wait_event;
return TRUE;
}
ts是触摸屏相关的文件指针(即光标函数mouse相关部分),keykoard_fd是键盘的文件指针。与键盘有关的部分是后添加的内容,其余为之前就有的部分。
其中主要添加了keyboard_update和keyboard_get_state的实现,以及在wait_event中加入键盘事件检测。
5.keyboard_update和keyboard_get_state
static int keyboard_update(void)
{
unsigned char scan_code;
unsigned char nr_changed_keys = 0;
scan_code = kbd_data.key_code;
kbd_state [scan_code] = kbd_data.key_state ? 1 : 0;
nr_changed_keys = scan_code + 1;
//printf("scan_code:%d, kbd_state:%d, nr_changed_keys:%d\n", scan_code, kbd_state[scan_code], nr_changed_keys);
return nr_changed_keys;
}
static const char * keyboard_get_state (void)
{
return (char*)kbd_state;
}
主要功能是上报键值和键盘的按键状态。
6.wait_event
static int wait_event (int which, int maxfd, fd_set *in, fd_set *out, fd_set *except, struct timeval *timeout)
{
...
if((which & IAL_KEYEVENT) && keykoard_fd >= 0)
{
FD_SET (keykoard_fd, in);
}
#ifndef _MGRM_THREADS
e = select (maxfd + 1, in, out, except, timeout);
#else
e = select (FD_SETSIZE, in, out, except, timeout);
#endif
if (e > 0) {
if (fd > 0 && FD_ISSET (fd, in)) {
return IAL_MOUSEEVENT;
}
else if(keykoard_fd >= 0 && FD_ISSET (keykoard_fd, in) )
{
FD_CLR (keykoard_fd, in);
if(read (keykoard_fd, &kb_event, sizeof (struct input_event))>0)
{
if(kb_event.type==EV_KEY)
if(kb_event.value==0 || kb_event.value==1)
{
kbd_data.key_code = kb_event.code;
kbd_data.key_state = kb_event.value;
ret |= IAL_KEYEVENT;
//printf("wait_event, key_code:%d, key_state:%d\n", kbd_data.key_code, kbd_data.key_state);
}
}
}
}
...
}
对键盘的相应操作主要是,read键值和状态,并把键值和状态赋值给全局变量,并由上面提到的keyboard_update和keyboard_get_state上报给处理函数。
7.最后是TermTSLibInput
void TermTSLibInput(void)
{
if (ts) {
ts_close(ts);
ts = NULL;
}
if (keykoard_fd < 0) {
close(keykoard_fd);
keykoard_fd = -1;
}
}
作用是销毁文件指针。
三、minigui主应用中
static int DesktopPanelProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam)
{
...
switch (message)
{
case MSG_KEYDOWN:
printf ("MGS_KEYDOWN: key %d\n", LOWORD(wParam));
break;
case MSG_CHAR:
printf ("MGS_CHAR: char %d\n", wParam);
break;
...
}
return DefaultMainWinProc(hWnd, message, wParam, lParam);
}
在窗口的MainWindowProc中对MSG_KEYDOWN和MSG_CHAR消息进行相应的处理即可。
四、总结
值得注意的是,当插入键盘开机之后,键盘的结点是event0和event1,触摸屏的结点是event2,此时无论是键盘还是触摸屏都无效了(触摸屏open的结点是event0)。当先开机后插入键盘时,键盘的结点是event1和event2,触摸屏的结点是event0,此时键盘和触摸屏都能正常工作。
关于event结点的自动挂载功能实现,暂时还没有思路,如果后面能够解决,作者会将实现方法记录下来供大家参考。