MiniGUI 体系结构之四 图形抽象层和输入抽象层及 Native Engine 的实现(一)
本文是 MiniGUI 体系结构系列文章的第四篇。图形抽象层(GAL)和输入抽象层(IAL)大大提高了 MiniGUI 的可移植性,并将底层图形设备和上层接口分离开来。这里将重点介绍 MiniGUI 的 GAL 和 IAL 接口,并以最新的 MiniGUI-Lite 版本为例,介绍基于 Linux FrameBuffer 的 Native 图形引擎的实现,以及特定嵌入式系统上输入引擎的实现。
1 引言
在 MiniGUI 0.3.xx 的开发中,我们引入了图形和输入抽象层(Graphics and Input Abstract Layer,GAL 和 IAL)的概念。抽象层的概念类似 Linux 内核虚拟文件系统的概念。它定义了一组不依赖于任何特殊硬件的抽象接口,所有顶层的图形操作和输入处理都建立在抽象接口之上。而用于实现这一抽象接口的底层代码称为“图形引擎”或“输入引擎”,类似操作系统中的驱动程序。这实际是一种面向对象的程序结构。利用 GAL 和 IAL,MiniGUI 可以在许多已有的图形函数库上运行,比如 SVGALib 和 LibGGI。并且可以非常方便地将 MiniGUI 移植到其他 POSIX 系统上,只需要根据我们的抽象层接口实现新的图形引擎即可。比如,在基于 Linux 的系统上,我们可以在 Linux FrameBuffer 驱动程序的基础上建立通用的 MiniGUI 图形引擎。实际上,包含在 MiniGUI 1.0.00 版本中的私有图形引擎(Native Engine)就是建立在 FrameBuffer 之上的图形引擎。一般而言,基于 Linux 的嵌入式系统均会提供 FrameBuffer 支持,这样私有图形引擎可以运行在一般的 PC 上,也可以运行在特定的嵌入式系统上。
相比图形来讲,将 MiniGUI 的底层输入与上层相隔显得更为重要。在基于 Linux 的嵌入式系统中,图形引擎可以通过 FrameBuffer 而获得,而输入设备的处理却没有统一的接口。在 PC 上,我们通常使用键盘和鼠标,而在嵌入式系统上,可能只有触摸屏和为数不多的几个键。在这种情况下,提供一个抽象的输入层,就显得格外重要。
本文将介绍 MiniGUI 的 GAL 和 IAL 接口,并介绍私有图形引擎和特定嵌入式系统下的输入引擎实现。
2 MiniGUI 的 GAL 和 IAL 定义
GAL 和 IAL 的结构是类似的,我们以 GAL 为例说明 MiniGUI GAL 和 IAL 抽象层的结构。
2.1 GAL 和图形引擎
参见图 1。系统维护一个已注册图形引擎数组,保存每个图形引擎数据结构的指针。系统利用一个指针保存当前使用的图形引擎。一般而言,系统中至少有两个图形引擎,一个是“哑”图形引擎,不进行任何实际的图形输出;一个是实际要使用的图形引擎,比如 LibGGI 或者 SVGALib,或者 Native Engine。每个图形引擎的数据结构定义了该图形引擎的一些信息,比如标识符、属性等,更重要的是,它实现了 GAL 所定义的各个接口,包括初始化和终止、图形上下文管理、画点处理函数、画线处理函数、矩形框填充函数、调色板函数等等。
图1 GAL 和图形引擎
如果在某个实际项目中所使用的图形硬件比较特殊,现有的图形引擎均不支持。这时,我们就可以安照 GAL 所定义的接口实现自己的图形引擎,并指定 MiniGUI 使用这种私有的图形引擎即可。这种软件技术实际就是面向对象多态性的具体体现。
利用 GAL 和 IAL,大大提高了 MiniGUI 的可移植性,并且使得程序的开发和调试变得更加容易。我们可以在 X Window 上开发和调试自己的 MiniGUI 程序,通过重新编译就可以让 MiniGUI 应用程序运行在特殊的嵌入式硬件平台上。
在代码实现上,MiniGUI 通过 GFX 数据结构来表示图形引擎,见清单 1。
清单 1 MiniGUI 中的图形引擎结构(src/include/gal.h) 55 typedef struct tagGFX 56 { 57 char* id; 58 59 // Initialization and termination 60 BOOL (*initgfx) (struct tagGFX* gfx); 61 void (*termgfx) (struct tagGFX* gfx); 62 63 // Phisical graphics context 64 GAL_GC phygc; 65 int bytes_per_phypixel; 66 int bits_per_phypixel; 67 int width_phygc; 68 int height_phygc; 69 int colors_phygc; 70 BOOL grayscale_screen; 71 72 // GC properties 73 int (*bytesperpixel) (GAL_GC gc); 74 int (*bitsperpixel) (GAL_GC gc); 75 int (*width) (GAL_GC gc); 76 int (*height) (GAL_GC gc); 77 int (*colors) (GAL_GC gc); 78 79 // Allocation and release of graphics context 80 int (*allocategc) (GAL_GC gc, int width, int height, int depth, 81 GAL_GC* newgc); 82 void (*freegc) (GAL_GC gc); 83 void (*setgc) (GAL_GC gc); 84 85 // Clipping of graphics context 86 void (*enableclipping) (GAL_GC gc); 87 void (*disableclipping) (GAL_GC gc); 88 int (*setclipping) (GAL_GC gc, int x1, int y1, int x2, int y2); 89 int (*getclipping) (GAL_GC gc, int* x1, int* y1, int* x2, int* y2); 90 91 // Background and foreground colors 92 int (*getbgcolor) (GAL_GC gc, gal_pixel* color); 93 int (*setbgcolor) (GAL_GC gc, gal_pixel color); 94 int (*getfgcolor) (GAL_GC gc, gal_pixel* color); 95 int (*setfgcolor) (GAL_GC gc, gal_pixel color); 96 97 // Convertion between gal_color and gal_pixel 98 gal_pixel (*mapcolor) (GAL_GC gc, gal_color *color); 99 int (*unmappixel) (GAL_GC gc, gal_pixel pixel, gal_color* color); 100 int (*packcolors) (GAL_GC gc, void* buf, gal_color* colors, int len); 101 int (*unpackpixels) (GAL_GC gc, void* buf, gal_color* colors, int len); 102 103 // Palette operations 104 int (*getpalette) (GAL_GC gc, int s, int len, gal_color* cmap); 105 int (*setpalette) (GAL_GC gc, int s, int len, gal_color* cmap); 106 int (*setcolorfulpalette) (GAL_GC gc); 107 108 // Box operations 109 size_t (*boxsize) (GAL_GC gc, int w, int h); 110 int (*fillbox) (GAL_GC gc, int x, int y, int w, int h, 111 gal_pixel pixel); 112 int (*putbox) (GAL_GC gc, int x, int y, int w, int h, void* buf); 113 int (*getbox) (GAL_GC gc, int x, int y, int w, int h, void* buf); 114 int (*putboxmask) (GAL_GC gc, int x, int y, int w, int h, void* buf, gal_pixel cxx); 115 int (*putboxpart) (GAL_GC gc, int x, int y, int w, int h, int bw, 116 int bh, void* buf, int xo, int yo); 117 int (*putboxwithop) (GAL_GC gc, int x, int y, int w, int h, 118 void* buf, int raster_op); 119 int (*scalebox) (GAL_GC gc, int sw, int sh, void* srcbuf, 120 int dw, int dh, void* dstbuf); 121 122 int (*copybox) (GAL_GC gc, int x, int y, int w, int h, int nx, int ny); 123 int (*crossblit) (GAL_GC src, int sx, int sy, int sw, int sh, 124 GAL_GC dst, int dx, int dy); 125 126 // Horizontal line operaions 127 int (*drawhline) (GAL_GC gc, int x, int y, int w, gal_pixel pixel); 128 int (*puthline) (GAL_GC gc, int x, int y, int w, void* buf); 129 int (*gethline) (GAL_GC gc, int x, int y, int w, void* buf); 130 131 // Vertical line operations 132 int (*drawvline) (GAL_GC gc, int x, int y, int h, gal_pixel pixel); 133 int (*putvline) (GAL_GC gc, int x, int y, int h, void* buf); 134 int (*getvline) (GAL_GC gc, int x, int y, int h, void* buf); 135 136 // Pixel operations 137 int (*drawpixel) (GAL_GC gc, int x, int y, gal_pixel pixel); 138 int (*putpixel) (GAL_GC gc, int x, int y, gal_pixel color); 139 int (*getpixel) (GAL_GC gc, int x, int y, gal_pixel* color); 140 141 // Other drawing 142 int (*circle) (GAL_GC gc, int x, int y, int r, gal_pixel pixel); 143 int (*line) (GAL_GC gc, int x1, int y1, int x2, int y2, 144 gal_pixel pixel); 145 int (*rectangle) (GAL_GC gc, int l, int t, int r, int b, 146 gal_pixel pixel); 147 148 // Simple Character output 149 int (*putchar) (GAL_GC gc, int x, int y, char c); 150 int (*putstr) (GAL_GC gc, int x, int y, const char* str); 151 int (*getcharsize) (GAL_GC gc, int* width, int* height); 152 int (*setputcharmode) (GAL_GC gc, int bkmode); 153 int (*setfontcolors) (GAL_GC gc, 154 gal_pixel fg, gal_pixel bg); 155 156 // Asynchronous mode support 157 void (*flush) (GAL_GC gc); 158 void (*flushregion) (GAL_GC gc, int x, int y, int w, int h); 159 160 // Panic 161 void (*panic) (int exitcode); 162 163 } GFX; 164 165 extern GFX* cur_gfx; |
系统启动之后,将根据配置寻找特定的图形引擎作为当前的图形引擎,并且对全局变量 cur_gfx 赋值。之后,当 MiniGUI 需要在屏幕上进行绘制之后,调用当前图形引擎的相应功能函数。比如,在画水平线时如下调用:
(*cur_gfx->drawhline) (gc, x, y, w, pixel); |
为方便程序书写,我们还定义了如下 C 语言宏:
167 #define PHYSICALGC (cur_gfx->phygc) 168 #define BYTESPERPHYPIXEL (cur_gfx->bytes_per_phypixel) 169 #define BITSPERPHYPIXEL (cur_gfx->bits_per_phypixel) 170 #define WIDTHOFPHYGC (cur_gfx->width_phygc) 171 #define HEIGHTOFPHYGC (cur_gfx->height_phygc) 172 #define COLORSOFPHYGC (cur_gfx->colors_phygc) 173 #define GRAYSCALESCREEN (cur_gfx->grayscale_screen) 174 175 #define GAL_BytesPerPixel (*cur_gfx->bytesperpixel) 176 #define GAL_BitsPerPixel (*cur_gfx->bitsperpixel) 177 #define GAL_Width (*cur_gfx->width) 178 #define GAL_Height (*cur_gfx->height) 179 #define GAL_Colors (*cur_gfx->colors) 180 181 #define GAL_InitGfx (*cur_gfx->initgfx) 182 #define GAL_TermGfx (*cur_gfx->termgfx) 183 184 #define GAL_AllocateGC (*cur_gfx->allocategc) 185 #define GAL_FreeGC (*cur_gfx->freegc) 186 ... 198 199 #define GAL_MapColor (*cur_gfx->mapcolor) 200 #define GAL_UnmapPixel (*cur_gfx->unmappixel) 201 #define GAL_PackColors (*cur_gfx->packcolors) 202 #define GAL_UnpackPixels (*cur_gfx->unpackpixels) 203 ... 208 #define GAL_BoxSize (*cur_gfx->boxsize) 209 #define GAL_FillBox (*cur_gfx->fillbox) 210 #define GAL_PutBox (*cur_gfx->putbox) 211 #define GAL_GetBox (*cur_gfx->getbox) 212 #define GAL_PutBoxMask (*cur_gfx->putboxmask) 213 #define GAL_PutBoxPart (*cur_gfx->putboxpart) 214 #define GAL_PubBoxWithOp (*cur_gfx->putboxwithop) 215 #define GAL_ScaleBox (*cur_gfx->scalebox) ... 224 #define GAL_DrawVLine (*cur_gfx->drawvline) 225 #define GAL_PutVLine (*cur_gfx->putvline) 226 #define GAL_GetVLine (*cur_gfx->getvline) |
这样,上述画线函数可以如下书写:
GAL_DrawVLine (gc, x, y, w, pixel); |
显然,只要在系统初始化时能够根据设定对 cur_gfx 进行适当的赋值,MiniGUI 就能够在相应的图形引擎之上进行绘制。
对底层图形引擎的调用,主要集中在 MiniGUI 的 GDI 函数中。比如,要绘制一条直线,MiniGUI 的 LineTo 函数定义如清单 2 所示:
清单 2 LineTo 函数(src/gdi/draw-lite.c) 255 void GUIAPI LineTo (HDC hdc, int x, int y) 256 { 257 PCLIPRECT pClipRect; 258 PDC pdc; 259 RECT rcOutput; 260 int startx, starty; 261 262 pdc = dc_HDC2PDC(hdc); 263 264 if (dc_IsGeneralHDC(hdc)) { 265 if (!dc_GenerateECRgn (pdc, FALSE)) { 266 return; 267 } 268 } 269 270 // Transfer logical to device to screen here. 271 startx = pdc->CurPenPos.x; 272 starty = pdc->CurPenPos.y; 273 274 // Move the current pen pos. 275 pdc->CurPenPos.x = x; 276 pdc->CurPenPos.y = y; 277 278 coor_LP2SP(pdc, &x, &y); 279 coor_LP2SP(pdc, &startx, &starty); 280 rcOutput.left = startx - 1; 281 rcOutput.top = starty - 1; 282 rcOutput.right = x + 1; 283 rcOutput.bottom = y + 1; 284 NormalizeRect(&rcOutput); 285 286 IntersectRect (&rcOutput, &rcOutput, &pdc->ecrgn.rcBound); 287 if( !dc_IsMemHDC(hdc) ) ShowCursorForGDI(FALSE, &rcOutput); 288 289 // set graphics context. 290 GAL_SetGC (pdc->gc); 291 GAL_SetFgColor (pdc->gc, pdc->pencolor); 292 293 pClipRect = pdc->ecrgn.head; 294 while(pClipRect) 295 { 296 if (DoesIntersect (&rcOutput, &pClipRect->rc)) { 297 GAL_SetClipping (pdc->gc, pClipRect->rc.left, pClipRect->rc.top, 298 pClipRect->rc.right - 1, pClipRect->rc.bottom - 1); 299 300 if(starty == y) { 301 if (startx > x) 302 GAL_DrawHLine (pdc->gc, x, y, startx - x, pdc->pencolor); 303 else 304 GAL_DrawHLine (pdc->gc, startx, y, x - startx, pdc->pencolor); 305 } 306 else 307 GAL_Line (pdc->gc, startx, starty, x, y, pdc->pencolor); 308 } 309 310 pClipRect = pClipRect->next; 311 } 312 313 if (!dc_IsMemHDC (hdc)) ShowCursorForGDI (TRUE, &rcOutput); 314 } |
在 MiniGUI 的所有绘图函数中,要依次做如下几件事:
- 进行逻辑坐标到设备坐标的转换;
- 检查是否应该重新生成有效剪切域;
- 计算输出矩形,并判断是否隐藏鼠标;
- 由于底层引擎尚不支持剪切域,因此,对剪切域中的每个剪切矩形,调用底层绘图函数输出一次。
在上面的四个步骤当中,第 3 步和第 4 步实际可以放到底层引擎当中,从而能够大大提高 MiniGUI 的绘图效率。不过,这种性能上的提高,对块输出,比如填充矩形、输出位图来讲,并不是非常明显。在将来的底层图形引擎当中,我们将针对上述两点,进行较大的优化以提高图形输出效率。
2.2 IAL 和输入引擎
如前所属,MiniGUI IAL 结构和 GAL 结构类似。在代码实现上,MiniGUI 通过 INPUT数据结构来表示输入引擎,见清单 3。
清单 3 MiniGUI 中的输入引擎结构(src/include/ial.h) 34 typedef struct tagINPUT 35 { 36 char* id; 37 38 // Initialization and termination 39 BOOL (*init_input) (struct tagINPUT *input, const char* mdev, const char* mtype); 40 void (*term_input) (void); 41 42 // Mouse operations 43 int (*update_mouse) (void); 44 int (*get_mouse_x) (void); 45 int (*get_mouse_y) (void); 46 void (*set_mouse_xy) (int x, int y); 47 int (*get_mouse_button) (void); 48 void (*set_mouse_range) (int minx, int miny,int maxx,int maxy); 49 50 // Keyboard operations 51 int (*update_keyboard) (void); 52 char* (*get_keyboard_state) (void); 53 void (*suspend_keyboard) (void); 54 void (*resume_keyboard) (void); 55 void (*set_leds) (unsigned int leds); 56 57 // Event 58 #ifdef _LITE_VERSION 59 int (*wait_event) (int which, int maxfd, fd_set *in, fd_set *out, fd_set *except, 60 struct timeval *timeout); 61 #else 62 int (*wait_event) (int which, fd_set *in, fd_set *out, fd_set *except, 63 struct timeval *timeout); 64 #endif 65 }INPUT; 66 67 extern INPUT* cur_input; |
系统启动之后,将根据配置寻找特定的输入引擎作为当前的输入引擎,并且对全局变量 cur_input 赋值。
(*cur_gfx->drawhline) (gc, x, y, w, pixel); |
为方便程序书写,我们还定义了如下 C 语言宏:
69 #define IAL_InitInput (*cur_input->init_input) 70 #define IAL_TermInput (*cur_input->term_input) 71 #define IAL_UpdateMouse (*cur_input->update_mouse) 72 #define IAL_GetMouseX (*cur_input->get_mouse_x) 73 #define IAL_GetMouseY (*cur_input->get_mouse_y) 74 #define IAL_SetMouseXY (*cur_input->set_mouse_xy) 75 #define IAL_GetMouseButton (*cur_input->get_mouse_button) 76 #define IAL_SetMouseRange (*cur_input->set_mouse_range) 77 78 #define IAL_UpdateKeyboard (*cur_input->update_keyboard) 79 #define IAL_GetKeyboardState (*cur_input->get_keyboard_state) 80 #define IAL_SuspendKeyboard (*cur_input->suspend_keyboard) 81 #define IAL_ResumeKeyboard (*cur_input->resume_keyboard) 82 #define IAL_SetLeds(leds) if (cur_input->set_leds) (*cur_input->set_leds) (leds) 83 84 #define IAL_WaitEvent (*cur_input->wait_event) |
在 src/kernel/event.c 中,我们如下调用底层的输入引擎,从而将输入引擎的数据转换为 MiniGUI 上层能够理解的消息(以 MiniGUI-Lite 为例),见清单 4:
清单 4 MiniGUI 对底层输入事件的处理 172 #ifdef _LITE_VERSION 173 BOOL GetLWEvent (int event, PLWEVENT lwe) 174 { 175 static LWEVENT old_lwe = {0, 0}; 176 unsigned int interval; 177 int button; 178 PMOUSEEVENT me = &(lwe->data.me); 179 PKEYEVENT ke = &(lwe->data.ke); 180 unsigned char* keystate; 181 int i; 182 int make; /* 0 = release, 1 = presse */ 183 184 if (event == 0) { 185 if (timer_counter >= timeout_count) { 186 187 timeout_count = timer_counter + repeat_threshold; 188 189 // repeat last event 190 if (old_lwe.type == LWETYPE_KEY 191 && old_lwe.data.ke.event == KE_KEYDOWN) { 192 memcpy (lwe, &old_lwe, sizeof (LWEVENT)); 193 lwe->data.ke.status |= KE_REPEATED; 194 return 1; 195 } 196 197 if (!(old_lwe.type == LWETYPE_MOUSE 198 && (old_lwe.data.me.event == ME_LEFTDOWN || 199 old_lwe.data.me.event == ME_RIGHTDOWN || 200 old_lwe.data.me.event == ME_MIDDLEDOWN))) { 201 // reset delay time 202 timeout_count = timer_counter + timeout_threshold; 203 } 204 205 // reset delay time 206 lwe->type = LWETYPE_TIMEOUT; 207 lwe->count = timer_counter; 208 return 1; 209 } 210 return 0; 211 } 212 213 timeout_count = timer_counter + timeout_threshold; 214 // There was a event occurred. 215 if (event & IAL_MOUSEEVENT) { 216 lwe->type = LWETYPE_MOUSE; 217 if (RefreshCursor(&me->x, &me->y, &button)) { 218 me->event = ME_MOVED; 219 time1 = 0; 220 time2 = 0; 221 222 if (oldbutton == button) 223 return 1; 224 } 225 226 if ( !(oldbutton & IAL_MOUSE_LEFTBUTTON) && 227 (button & IAL_MOUSE_LEFTBUTTON) ) 228 { 229 if (time1) { 230 interval = timer_counter - time1; 231 if (interval <= dblclicktime) 232 me->event = ME_LEFTDBLCLICK; 233 else 234 me->event = ME_LEFTDOWN; 235 time1 = 0; 236 } 237 else { 238 time1 = timer_counter; 239 me->event = ME_LEFTDOWN; 240 } 241 goto mouseret; 242 } 243 244 if ( (oldbutton & IAL_MOUSE_LEFTBUTTON) && 245 !(button & IAL_MOUSE_LEFTBUTTON) ) 246 { 247 me->event = ME_LEFTUP; 248 goto mouseret; 249 } 250 251 if ( !(oldbutton & IAL_MOUSE_RIGHTBUTTON) && 252 (button & IAL_MOUSE_RIGHTBUTTON) ) 253 { 254 if (time2) { 255 interval = timer_counter - time2; 256 if (interval <= dblclicktime) 257 me->event = ME_RIGHTDBLCLICK; 258 else 259 me->event = ME_RIGHTDOWN; 260 time2 = 0; 261 } 262 else { 263 time2 = timer_counter; 264 me->event = ME_RIGHTDOWN; 265 } 266 goto mouseret; 267 } 268 269 if ( (oldbutton & IAL_MOUSE_RIGHTBUTTON) && 270 !(button & IAL_MOUSE_RIGHTBUTTON) ) 271 { 272 me->event = ME_RIGHTUP; 273 goto mouseret; 274 } 275 } 276 277 if(event & IAL_KEYEVENT) { 278 lwe->type = LWETYPE_KEY; 279 keystate = IAL_GetKeyboardState (); 280 for(i = 0; i < NR_KEYS; i++) { 281 if(!oldkeystate[i] && keystate[i]) { 282 ke->event = KE_KEYDOWN; 283 ke->scancode = i; 284 olddownkey = i; 285 break; 286 } 287 if(oldkeystate[i] && !keystate[i]) { 288 ke->event = KE_KEYUP; 289 ke->scancode = i; 290 break; 291 } 292 } 293 if (i == NR_KEYS) { 294 ke->event = KE_KEYDOWN; 295 ke->scancode = olddownkey; 296 } 297 298 make = (ke->event == KE_KEYDOWN)?1:0; 299 300 if (i != NR_KEYS) { 301 unsigned leds; 302 303 switch (ke->scancode) { 304 case SCANCODE_CAPSLOCK: 305 if (make && caps_off) { 306 capslock = 1 - capslock; 307 leds = slock | (numlock << 1) | (capslock << 2); 308 IAL_SetLeds (leds); 309 status = (DWORD)leds << 16; 310 } 311 caps_off = 1 - make; 312 break; 313 314 case SCANCODE_NUMLOCK: 315 if (make && num_off) { 316 numlock = 1 - numlock; 317 leds = slock | (numlock << 1) | (capslock << 2); 318 IAL_SetLeds (leds); 319 status = (DWORD)leds << 16; 320 } 321 num_off = 1 - make; 322 break; 323 324 case SCANCODE_SCROLLLOCK: 325 if (make & slock_off) { 326 slock = 1 - slock; 327 leds = slock | (numlock << 1) | (capslock << 2); 328 IAL_SetLeds (leds); 329 status = (DWORD)leds << 16; 330 } 331 slock_off = 1 - make; 332 break; 333 334 case SCANCODE_LEFTCONTROL: 335 control1 = make; 336 break; 337 338 case SCANCODE_RIGHTCONTROL: 339 control2 = make; 340 break; 341 342 case SCANCODE_LEFTSHIFT: 343 shift1 = make; 344 break; 345 346 case SCANCODE_RIGHTSHIFT: 347 shift2 = make; 348 break; 349 350 case SCANCODE_LEFTALT: 351 alt1 = make; 352 break; 353 354 case SCANCODE_RIGHTALT: 355 alt2 = make; 356 break; 357 358 } 359 360 status &= 0xFFFFF0C0; 361 362 status |= (DWORD)((capslock << 8) | 363 (numlock << 7) | 364 (slock << 6) | 365 (control1 << 5) | 366 (control2 << 4) | 367 (alt1 << 3) | 368 (alt2 << 2) | 369 (shift1 << 1) | 370 (shift2)); 371 372 // Mouse button status 373 if (oldbutton & IAL_MOUSE_LEFTBUTTON) 374 status |= 0x00000100; 375 else if (oldbutton & IAL_MOUSE_RIGHTBUTTON) 376 status |= 0x00000200; 377 } 378 ke->status = status; 379 SHAREDRES_SHIFTSTATUS = status; 380 memcpy (oldkeystate, keystate, NR_KEYS); 381 memcpy (&old_lwe, lwe, sizeof (LWEVENT)); 382 return 1; 383 } 384 385 old_lwe.type = 0; 386 return 0; 387 388 mouseret: 389 status &= 0xFFFFF0FF; 390 oldbutton = button; 391 if (oldbutton & IAL_MOUSE_LEFTBUTTON) 392 status |= 0x00000100; 393 if (oldbutton & IAL_MOUSE_RIGHTBUTTON) 394 status |= 0x00000200; 395 me->status = status; 396 SHAREDRES_SHIFTSTATUS = status; 397 memcpy (&old_lwe, lwe, sizeof (LWEVENT)); 398 return 1; 399 } #endif |
从这段代码中可以看出,对定点设备来讲,比如鼠标或者触摸屏,MiniGUI 能够自动识别移动信息,也能够自动识别用户的单击和双击事件。这样,底层引擎只需提供位置信息和当前的按键状态信息就可以了。对类似键盘的东西,MiniGUI 也能够自动进行重复处理。当一个按键按下一段时间之后,MiniGUI 将连续发送该按键的消息给上层处理。对特定的嵌入式系统来讲,可以将某些按键映射为 PC 的某些键盘键,上层只需处理这些键盘键消息的按下和释放即可。这样,嵌入式系统上的某些键的功能就可以在 PC 上进行模拟了。