UCGUI的模拟器UCGUISim详解
From: http://www.cnblogs.com/shellstudio/articles/ucgui.html
?
本文轉自www.ucgui.com感謝原作者(最近發現該網站已經撤銷,不知道作者近況如何.想當初,他對我理解ucgui提供了很多支持和幫助呢!)。
聯系方式: ucgui.com@gmail.com
一、問題的由來-----模擬器完成了什么
在官方發布的UCGUI的源碼包當中,附有很多的示例,源碼與示例都打包成一個VC工程,在這個工程中我們可以編譯和運行UCGUI的示例,進行UCGUI的圖形編程,非常方便,這個工程結構下:
Application-------UCGUI應用程序目錄。
Config-------------UCGUI配制文件目錄。
GUI----------------UCGUI源碼文件。
Simulation--------模擬器庫文件、模擬器頭文件目錄,主要有GUISim.lib這個提供模擬器的庫文件。
System-------------應用程序的接口調用主文件,即調用用戶的MainTask函數的main函數。
在這個官方提供的包中,我們進行UCGUI的圖形編程時, 大多都是將要寫的程序源文件放加到Application目錄中, 其中應用程序中必不可少要提供的一個函數是MainTask(), 好奇的朋友會發覺, 我們程序并沒創建窗口, 為什么一運行就有窗口界面并有一個LCD顯示屏顯示出自己的UCGUI程序的運行效果出來, 其實這些我們看不到的代碼都是寫在GUISim.lib這個庫文件當中的,為了了解模擬器具體做了些什么,我通過反編譯,還原了官方模擬器的源碼,下面詳細介紹模擬器的構成[以下均為官方模擬器采用的方法]。
GUISim.lib主要完成以下幾件事,具體的模塊劃分將在文中后面描述:
1. 創建模擬器主窗口,這個窗體包括一些模擬器控制菜單,如打開LOG記錄/打開調色板顯示窗體/新建LCD模擬器窗體,以及暫停/繼續模擬器。
2. 創建一個LCD模擬顯示窗口并初始化其顯示所需的各種數據結構,LCD窗口的大小由UCGUI中LCDConf.h中配制時指定 (LCD_XSIZE/LCD_YSIZE),及其它的諸如每個象素占用多少位(LCD_BITSPERPIXEL),首先分配一塊足夠大的顯存(4M) 并初始化這塊數據為0,每個象素占用不大于 8位時模擬顯示屏幕需要用到8位圖,還必須初始化要用到的調色板。
3. 提供操作LCD模擬顯示屏幕的幾個基本圖形函數,UCGUI是一個設計層次非常清晰的圖形系統,它將GUI的底層圖形功能作為一層向上層提供最基本的圖形功能,只有這一層才與具體的硬件相關,這一層包括基本的畫點函數/矩形填充函數/調色板初始化函數/顏色索引與RGB的轉換函數。
4. 提供上層的LOG記錄接口的實現,主要完成UCGUI中調試信息的輸出,是否輸出調試信息可以由UCGUI中的一個開關設置。
5. 開啟一個新的線程,在此線程中調用System\Main.c中的main()函數,此函數中再調用MainTask()函數,這個函數即為我們在模擬器中編程必須提供的一個函數,在單任務情形下UCGUI的程序均寫在MainTask函數當中,供模擬器開啟的線程調用。這里必須分清楚:主線程創建模擬器主窗口及LCD模擬窗口;UCGUI圖形應用程序以新開的另外一個線程運行,這個線程結束時則UCGUI圖形應用程序結束。
6. 從LCD模擬器窗口消息函數當中接收KEY消息及MOUSE消息,并通過UCGUI中的KEY及MOUSE接口傳送到UCGUI內部以驅動UCGUI事件消息LOOP。
二、進一步入了解-----模擬器的基本實現原理
-----LCD模擬顯示器的實現原理。
1. 上文中已經提到了UCGUI是一個設計層次分明的圖形系統,具體的圖形功能分為一層;再細化圖形層,還可細分為兩層:層一是最底層的直接實現基本的畫點函數/矩形填充函數/調色板初始化函數/顏色索引與RGB的轉換函數,這一層與直接的硬件及調色板相關,由模擬器中的LCDSIM.c文件實現;層二是位于上述 層一之上,提供更多更強圖形功能的函數,如位圖[1位/2位/4位/8位/16位]顯示函數/水平垂直畫線函數/矩形填充函數/畫點函數,這些功能在\LCDDriver\LCDWin.c中完成,這一層當中的畫點函數均以宏的形式提供,具體實現由上述更低的上述層一即模擬器的圖形驅動來實現。
在WIN環境下,實現這個模擬器比較簡單,要做的就是將GUI的結果顯示給用戶看,即做出一個LCD模擬顯示器,將GUI畫圖的結果呈現在上面,
GUI 畫圖的結果在顯存中,所以也就是將顯存中的GUI畫圖數據用位圖顯示出來,處理這個位圖顯示時,可以分兩種情況:第一種情況是單個象素點占8位及8位以下的情況,此時顯示位圖需要用到調色板(所以初始化時必須初始化調色板),每個象素點簡化處理為占用一個字節(8位以下實際情況下并非如此,實際是幾位就占幾位),值表示的是該象素點在調色板中的顏色索引,此時將顯存中的數據以8位位圖來顯示處理;第二種情況是單個象素點占用8位以上的情況,這種情況下,每個象素點簡化處理為占用4個字節(實際情況占幾位就是幾位),其值表示的是實際的該點的RGB顏色值,此時將顯存中的數據以32位位圖來顯示處理。
2. 在LCD窗口中,將GUI畫圖的結果以上述位圖形式畫到LCD窗體當中并隔一定時間刷新顯示,雖然這樣做不一定在速度上非常準確實時,但基本上可以滿足要求了,只要我們設定一個重畫定時器,定時檢測在顯示中數據是否發生變化,有變化則刷新一次LCD窗口中顯示的內容,可以滿足要求。
3. 在解決了模擬LCD顯示的問題后,還有要弄清的問題是,要顯示器的一屏象素的存放位置,也即畫圖時所讀寫象素的內存,其實只需開一塊足夠大的內存來存放一屏LCD的象素,讀寫象素均在此塊內存中,我們可以稱此塊內存為顯存。如LCD寬XSize,高YSize, 顯存起始地址為pFix,單個象素點占用8位或8位以下(此時一個象素占1字節),則象素點(x,y)的在顯存中的地址即為 x + y * YSize + pFix;如果是單個象素點占8位以上(此時一個象素占四字節),則為(x + y * YSize)*4 + pFix。顯存中象素是按行存放的,如果為了查看器(ucguiview)可以同樣顯示出獨立運的模擬器程序的GUI畫圖結果,那么這個顯存必須以內存映象文件的方式來實現多個進程之間內存共享訪問支持。
4. 關于一個象素用多少位來表示的問題,其實這個問題與幾位位圖是一個意思:位圖中,8位及8位以下的均會使用一個調色板,原因:用調色板[實際為一維組,表項個數由位圖位數決定]可以以顏色索引來表示出一個象素點的RGB顏色,調色板中每一個表項存的是該表項索引對應的RGB顏色值,在位圖存儲時只須要將該位圖對應的調色板數組存起來,那么存單個象素點時僅須要存其對應索引而不需要存4個字節的RGB顏色值,這樣節約空間。位圖中的數據為調色板中顏色的索引值,沒有調色板是無法解析顯示此位圖的,所以8位及位以下位圖對應的BMP文件會多出一個調色板內容;8位以上的位圖,其位圖數據即為RGB值或索引值 (16位時),16位/24位/32位單象素分別占用2/3/4個字節,這里必須注意區別的是,我們這里所說的位圖一個象素所占用情況分析,是指位圖存儲為文件時的占用情況,其中也并沒有提到具體一個象素點中R/G/B分別占用多少位,特別對于16位的情況下,RGB占用情況一般分5/6/5或5/5 /5,此時R/G/B中可以表示的最大值索引值為64,此時無法表示出0x0~0xff之間255種顏色,所以16位位圖中的象素點數據還是直接的顏色索引值,并非直接RGB顏色值,但此時并不須要用調色板來輔助轉化此索引值為RGB顏色值,而是通過一個轉換算法,不過這樣會對速度產生影響,沒有使用調色板快,不采用調色板是因為需要太多調色板表項。
[注意:關于位圖文件,這時就不多介紹了,介紹大家下載這篇文章看一下,"BMP檔案結構及平滑縮放.doc",也可以自己通過WIN下面自帶的畫板來分析不同位數的位圖,總之只要記住一點,要處理顯示一個位圖文件,必須知道位圖文件大小及單個象素占用位數(即位圖位數),然后顯示時就是取得每個象素點的RGB值,這個RGB顏色值是根據調色板來取得或者由索引根據一定的轉換算法取得或者象素點數據本身就表示RGB值]。
5. LCD_BITSPERPIXEL是UCGUI中定義的一個象素用多少位來表示的宏定義,則可以表示的顏色總數為 1L<<LCD_BITSPERPIXEL種,但是RGB分別占多少位,則其可表示的具體哪些顏色是不同的,模擬器中以 LCD_FIXEDPALETTE表示R/G/B(正常情況下沒有進行R/B交換時)分別所占位數,主要有444(12)、555(15)、 565(16)等,一個象素是由RGB三值來描述,RGB三值范圍都是0x00-0xf;所以除非每種顏色都用(r|g|b)8位表示,否則不可能把 0x00-0xf的值均表示到;另外,對于每一種可顯示的顏色模擬器中均以索引值來表示,最基本的畫象素的 LCDSIM_SetPixelIndex(int x, int y, int Index)中用的是索引值,這個索引值可以通過一種轉換轉為RGB值。
6. 顏色索引值到RGB值的轉換,索引轉換成RGB的基本原理,這里我們不講含調色板的情況------首先,對于RGB三值,由FixedPalette指定其每個位所占的位數,如為444則各4位. FixedPalette中指定能表示的RGB的范圍分別為(R,G,B)1111/1111/1111,即16(R)/16(G)/16(B). 則當索引值Index為444時,則是RGB各值索引最大的時候,由此即可分析,R/G/B三值要表示的顏色范圍是0x00-0xff,為了讓有限的 0-16的索引來表示0x00-0xff這些顏色值, 那么當然只能是跳隔著來表示,拿R來說,最好是取值為(17*0, 17*1,17*2,17*3,...17*15=248),如此的話,才能差不多在有限的16個索引值下將0xff種顏色最大程度的涵蓋到(比較平均),但實際你可以自己控制索引到RGB顏色值的轉換算法,但一定要合理,盡可能涵蓋全面。
同理,對于FixedPalette為555時,則R取值最好為(8*0,8*1,8*2,
8*3,...8*31=243)...
同理,對于FixedPalette為565時,則B取值最好為(4*0,4*1,4*2,
4*3,...4*63=252)知道這一點,則對于以下函數的理解就非常容易...
7. 在LCD_BITSPERPIXEL小于等于8時,顏色索引值則無須通過運算來轉換,因為它所能表示的顏色數不多于256種,此時我們就會用一個調色板來表示這不多于256種的顏色,取用也非常方便,通過調色板數組就可以取得索引對應的RGB值。對FixedPalette為111時,調色板中只有八種顏色,不須要256個選項, 8種為(0x000000[0],0x0000ff[1],0x00ff00[2],0x00ffff[3], 0xff0000[4],0xff00ff[5],0xffff00[6],0xffffff[7]),即調色板索引為(0-7)其余對于 FixedPalette為111時并未用于;初始化調色板時,要先調用LCD_L0_Index2Color(i)將Index轉為RGB表示的顏色,再與黑白成比例綜合. 這樣了就可適應所有實際使用調色板為2項,4項,8項,16項,256項的所有用到調色板的情況。
另外還要提到的是在8位以下的灰度問題,灰度時,R/G/G三值相等,所以最多可以有256級灰度,其中二級灰度/四級灰度/十六級等,都是間隔著取256級灰度中的顏色值,取的方法是平均涵蓋。
以上六點是LCD模擬顯示器中用到的幾點核心要點,要理解LCD模擬顯示器,就必然先理解以上幾點。
-----實現模擬LCD的內存布局。
[1]、首先是創建一個名為“emWinLCDMap”的大小為0x00400000(4M)的可讀可寫及其它所有權限的內存映象文件,如果已存在則是打開該內存映象文件, 設其分配所得初始地址為pSMemFix,類型字節。
[2]、 pSMemFix+0x20開始,分別存放XSize、YSize、VXSize、VYSize、FixedPalette、BPP、 NumColors(分別為LCD水平寬度/豎直高度、LCD虛擬屏水平及豎直大小、調色板模式、單個象素點倍數、可用顏色總數),其計28個字節,這里存入這些信息是為ucguiview查看器使用的,所有的對于查看器要使用的信息均可以在這里存放。
[3]、pSMemFix + 0x100開始,用于存放位圖結構信息40(0x28)個字節及1000個字節(256*4)的調色板(最多可用表項為256項)信息,即如下結構:
[4]、pSMemFix + 0x1000開始,用作LCD的顯存,存放LCD屏幕的象素點,大小總計為4M。
-----實現LCD功能的幾個基本函數。
[1]、LCDSIM_SetPixelIndex--------畫點.
/// // // 函數名 : LCDSIM_SetPixelIndex // 功能描述 : 最基本的畫點函數... // 參數 : int x[點x坐標] // 參數 : int y[點y坐標] // 參數 : int Index[顏色索引值] // 返回值 : void // /// void LCDSIM_SetPixelIndex(int x, int y, int Index){static int preIndex = 0, preLUT = 0, curLUT = 0, curColor = 0;int pixPos = 0;char* lptemp = 0;if(paaPixel == 0) return;if(BPP <= 8){pixPos = y * BytesPerLine + x;lptemp = (char*)paaPixel + pixPos;*lptemp = Index;}else{// 2005-8-27 13:04:52lptemp = (char*)pFix + 0x40;curLUT = *((int*)lptemp);if(curLUT != preLUT){//改變了調色板時,一定要重新根據索引轉顏色...preLUT = curLUT;preIndex = -1;}if(preIndex != Index){//轉索引為RGB顏色值..curColor = Convert_Index16IntoIndex32(Index);}pixPos = y * BytesPerLine + x * 4;lptemp = (char*)paaPixel + pixPos;*(int*)lptemp = curColor;preIndex = Index;}//表明LCD顯存數據已有變化,在LCD窗口中的定時器會檢測此值以決定是//否重畫窗口,即更新顯示LCD屏幕...ModifyCnt++;if(pFix != 0){lptemp = (char*)((char*)pFix + 0x3c);*((int*)lptemp) = ModifyCnt;} }
這個函數是最基本的畫點函數,是LCD模擬顯示器的最基本與最核心的函數,其余畫線、畫矩形、畫位圖等等功能均由以此為基礎,畫點時指定顏色時是以索引指定的,具體這個索引到RGB顏色的轉換分兩種情況,前面已經反復的講過索引到RGB顏色的轉換,這里再重復一下 Convert_Index16IntoIndex32這個8位以上象素點的索引轉顏色,其實在UCGUI中有一個專門的文件中存放的文件都是用于各種情況下的索引轉顏色,無論一個象素點占幾位,只要用到顏色索引的都必須提供一個索引到顏色之間互轉的兩個函數,調色板模式下在畫點函數中不用再轉換,直接從根據索引從調色板中取,但是在實始化調色板時還是用到了索引到RGB的轉換來初始化調色板;UCGUI提供的顏色索引到RGB顏色的互轉算法只是一種比較適合的算法但并非必須如此,只是一種轉換約定方法而已。
這個函數當中有一個小的優化,那就是當與上一次顏色相同時,則不必再進行索引到顏色之間的轉換,這一點對于區域性畫圖很有優勢,不過要記住調色板改變后就必須重新進行索引與顏色間的轉換。
[paaPixel]-------------LCD顯存起始地址。
[BytesPerLine]---------LCD顯示屏一行象素之字節數。
[ModifyCnt]------------表示LCD顯示是否有更新,每畫一個點加1。
[2]、LCDSIM_FillRect--------矩形填充.
//填充一個矩形... //#define FASTTING 1 //定義是否加速,使用串傳送,注意移值性問題... void LCDSIM_FillRect(int x0, int y0, int x1, int y1, int Index) {int step = 1, color = 0;int line = 0, comlum = 0;char* lptemp = 0;if(BPP == 0) return;if(x1 > XSize) x1 = XSize - 1;if(y1 > YSize) y1 = YSize - 1;if(x0 < 0) x1 = 1;if(y1 < 0) y1 = 1;if(paaPixel == 0) return;if(BPP > 8){step = 4;color = Convert_Index16IntoIndex32(Index);}else{color = Index;}comlum = (x1 - x0);lptemp = (char*)paaPixel + BytesPerLine * y0 + x0 * step;//矩形寬度是否為整行... #ifdef FASTTINGif(comlum == XSize){comlum = comlum*(y1-y0);_asm{mov eax, colormov ecx, comlummov edi, lptemp}if(step == 1) __asm rep stosbelse __asm rep stosdreturn;} #endif// 2005-8-27 14:35:38 使用串傳送指令提高速度...for(line = y0; line < (y1 - y0); line++){ #ifdef FASTTING_asm{mov eax, colormov ecx, comlummov edi, lptemp}if(step == 1) __asm rep stosbelse __asm rep stosdlptemp += BytesPerLine; #else// 2005-8-27 14:54:02for(comlum = x0; comlum < (x1 - x0); comlum++){lptemp = (char*)paaPixel + BytesPerLine * line + comlum * step;if(step == 4) *((int*)lptemp) = color;else *lptemp = color;} #endif} }
這個函數進行了優化處理,在畫矩形時因為是塊填充,把以只須進行一次索引到顏色的轉換,而且在行填充當中,也是采用串傳送,一次填充四字節,如果是全屏填充,那么可以采用一串傳送完成任務,傳送數據時是直接傳送到顯存中,矩形填充的效率很重要,調用頻率比較高,一定要注意優化,而且在真正的硬件應用當中,也必須進行類似于此的專門的優化處理,這樣會大大提高效率。
[3]、Convert_Index16IntoIndex32----轉換象素位數大于8位時的顏色索引為RGB顏色值。
當單個象素位數 LCD_BITSPERPIXEL 不大于8位時,直接寫索引值到顯存中(因為后面采用的位圖顯示函數會根據指定調色板來顯示這些象素點,內部會包含索引到RGB顏色的轉換);大于8位時,必須將索引值轉換為RGB顏色值后再寫入。 其實在我們這個模擬LCD顯示屏當中,我們往其中畫點的過程就是構造位圖數據的過程,但沒有BMP文件頭、位圖信息頭,在BMP位圖文件中,這些都輔助用于解析顯示位圖用的,我們這里的LCD調色板是放在另外一塊內存中,并已經初始化; 當構造好位圖數據后,我們調用WIN的API SetDIBitsToDevice或StretchDIBits來將位圖畫到LCD窗口中,下面說明一下這兩個API:
[SetDIBitsToDevice]----是將設備無關位圖中的顏色數據畫到與指定的設備場景相關的設備上的指定矩形中,這個函數不會進行縮放,即原矩形與目標矩形大小相同,它有一個參數為位圖數據,還有一個參數為位圖信息結構及調色板(BITMAPINFO),8位及其以下位圖必須指定調色板,其余為指定源矩形與目標矩形及設備場景句柄。
[StretchDIBits]--------除完成以上功能還會對位圖進行縮放顯示,此種情況即為模擬器中LCD_YMAG、LCD_XMAG不為1的情況,即放大顯示。
調用這兩個函數之前必須先調用SetStretchBltMode位圖映射模式。
[4]、LCDSIM_GetPixelColor----取點RGB顏色值
int LCDSIM_GetPixelColor(int x, int y) {int Color = 0;if(paaPixel == 0) return Color;if(BPP > 8){//直接在顯示內存中取,其值即為該點RGB值.Color = *((int*)paaPixel + y * BytesPerLine + x * 4);}else if(BPP <= 8){Color = *((char*)paaPixel + BytesPerLine * y + x * 4);Color = LCDSIM_Index2Color(LCDSIM_GetPixelIndex(x,y));}return Color; }
獲取指定象素點的RGB顏色值,當LCD_BITSPERPIXEL大于8時,此點RGB直接在LCD顯存中取即是;當不大于8時,則須根據從LCD顯存中取回的索引值再取調色板中RGB值,即下面的函數:轉換索引為顏色值。
[5]、LCDSIM_Index2Color------根據索引轉換成RGB值。
int LCDSIM_Index2Color(int Index) {int getColor = 0;if(BPP == 0) return getColor;else if(BPP > 8){getColor = Convert_Index16IntoIndex32(Index);}else if(BPP <= 8){getColor = *((char*)pBitmapInfo + 0x28 + Index*4) << 16 | *((char*)pBitmapInfo + 0x29 + Index*4) << 8 | *((char*)pBitmapInfo + 0x2a + Index*4);}return getColor; }
[pBitmapInfo]-----------位圖信息起始地址,其中位圖結構大小0x28.
[pBitmapInfo+0x28]---調色板起始址址。
[6]、Convert_Index16IntoIndex32----轉換LCD_BITSPERPIXEL大于8時的顏色索引值為RGB顏色值
LCD_COLOR Convert_Index16IntoIndex32(int Index) {// 2005-6-4 12:33:06//此一句可以底上下面的switch N句,編譯器將由FixedPalette預定義值來選定//具體的RGB顏色與顏色索引間的轉換函數。return INDEX2COLOR(Index);/* LCD_COLOR convertColor = 0;switch(FixedPalette){case 444:convertColor = LCD_Index2Color_444(Index);break;case 555:convertColor = LCD_Index2Color_555(Index);break;case -555:convertColor = LCD_Index2Color_M555(Index);break;case 565:convertColor = LCD_Index2Color_565(Index);break;case -565:convertColor = LCD_Index2Color_M555(Index);break;case -444: //無此項轉換...break;}return convertColor;*/ }
在這個函數中,具體的轉換的功能是由GUI\ConvertColor目錄下的幾個文件中提供的,具體參看UCGUI源碼。
[7]、LCDSIM_SetLUTEntry------設置調色板信息。
void LCDSIM_SetLUTEntry(U8 Pos, LCD_COLOR color) {char* lptemp = 0;if(BPP == 0) return;color=FilterColor(color,LCDSIM_aLCDColorBlack[0],LCDSIM_aLCDColorWhite[0]);lptemp = (char*)pBitmapInfo + 0x28 + Pos * 4;*(char*)lptemp++ = (color & 0xff0000) >> 16;*(char*)lptemp++ = (color & 0xff00) >> 8;*(char*)lptemp = color & 0xff;ModifyCnt++;LUT_ModifyCnt++;if(pFix != 0){lptemp = (char*)pFix + 0x3c;*lptemp = ModifyCnt;lptemp = (char*)pFix + 0x40;*((int*)lptemp) = LUT_ModifyCnt;} }
[LUT_ModifyCnt]----記錄調色信息的更改次數。
[pBitmapInfo]---------位圖信息起始地址。
[FilterColor]-----------此函數負責將指定顏色值轉換為在背景色與前景色之間的值。轉換的方法是(colorWhite & 0xff - colorBlack &0xff) * (color & 0xff) / 0xff; colorWhite為前景色,colorBlack為背景色,取相應的R/G/B位,用前景色減去背景色之值再乘以color的對應R/G/B的值, 所得值再除以255得商即為調整后顏色值,這樣做目的是將指定顏色值調整為前景色與背景色之間。
-----模擬器的輸入模擬在UCGUI當中有專門的接收輸入的接口,有MOUSE、KEY、TOUCH的,分別為GUI_MOUSE_StoreState、GUI_StoreKeyMsg、 GUI_TOUCH_StoreState這三個函數,三UCGUI中關于這些消息的處理都比較簡易,并沒有什么隊列,都是接收一個處理一個,這對于簡單的嵌入式應用來說已經足夠,可以減少內存占用,但有可能造成消息的丟失,MOUSE及KEY消息均來自于LCD窗口的窗口消息處理函數中。
[MOUSE]
[1]、LCDSIM_SetMouseState--------傳送MOUSE及TOUCH(觸摸屏)消息到UCGUI。
void NotifyMouseState(LCD_tMouseState mouseState) {if(mouseState.KeyStat == 0){GUI_TOUCH_StoreState(-1, -1);}else{GUI_TOUCH_StoreState(mouseState.x, mouseState.y);}GUI_MOUSE_StoreState((const GUI_PID_STATE*)&mouseState); }
MOUSE消息處理中,包括WM_MOUSEMOVE、WM_LBUTTONDOWN、WM_LBUTTONUP這三種,NotifyMouseState的功能就是內存消息至ucgui.
[3]、LCDSIM_GetMouseState--------獲取MOUSE消息。
[KEY]
[1]、HandleKeyEvents-------------傳送KEY消息到UCGUI。
void HandleKeyEvents(UINT message, WPARAM wParam) {int key = 0, keyCount = 0;switch(message){case WM_KEYDOWN:key = VirtKey2Key(wParam);if(key == 0) key = Keydown2ASCII(wParam);keyCount = 1;break;case WM_KEYUP:key = VirtKey2Key(wParam);keyCount = 0;break;}if(key != 0) GUI_StoreKeyMsg(key, keyCount); }
[VirtKey2Key]----主要處理一些特殊鍵,如SHIFT、DELTE、BACKSPACE、INSERT、CRTL、ENTER、方向鍵等。
[Keydown2ASCII]--將鍵盤虛擬碼轉換為ASCII碼,大小寫區別的,在鍵盤處理當中,如上所說的特殊鍵是有特別用途的,UCGUI中已重定義這些特殊鍵所對應的KEY值,可以在GUI.h當中查找GUI_KEY_UP來找到這些特殊鍵在UCGUI中的KEY值。在傳送鍵盤消息時,這里只在 WM_KEYDOWN時處理普通鍵,WM_KEYUP中并未處理,WM_KEYUP只處理了特殊鍵。其它人可以根據自己人須求要改寫這個傳送鍵盤消息到 UCGUI的函數。
HandleKeyEvents在LCD的窗口消息函數中,當LCD窗口有鍵盤消息時,即傳送至UCGUI內部,以驅動UCGUI的鍵盤處理。
三、拔去見日-----UCGUISim模擬器的模塊劃分。
在上面介如了模擬器的基本原理,差不多將核心的東西都說出來了,這時簡要的說明一下模擬器的幾個構成模塊。
emWin.c----------創建UCGUISim模器主窗口及LCD顯示窗口,處理KEY、MOUSE消息傳送,開啟、暫停UCGUI程序,輸出LOG等。
LCDSIM.c--------實現模擬LCD顯示屏。
Branding.c--------顯示版權。
GUI_X_SIM.c---實現UCGUI的臨界代碼鎖及實際的LOG輸出及延時功能。
具體可以能見源碼,這里就不就代碼作詳細解說了。
?
總結
以上是生活随笔為你收集整理的UCGUI的模拟器UCGUISim详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 畅想动画制作的乐趣
- 下一篇: 通过windows的超级终端连接华为交换