MiniGUI中IAL引擎的實現

admin @ 2014-03-25 , reply:0

一、如何在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()
{
………………..
}

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轉換得來的原始數據)。




[admin via 研發互助社區 ] MiniGUI中IAL引擎的實現已經有2033次圍觀

http://cocdig.com/docs/show-post-42409.html