網(wǎng)上有很多關(guān)于pos機(jī)交互過程,CodeBlock下的人機(jī)交互界面設(shè)計(jì)的知識(shí),也有很多人為大家解答關(guān)于pos機(jī)交互過程的問題,今天pos機(jī)之家(www.dsth100338.com)為大家整理了關(guān)于這方面的知識(shí),讓我們一起來看下吧!
本文目錄一覽:
pos機(jī)交互過程
人機(jī)交互界面指的是計(jì)算機(jī)系統(tǒng)與用戶之間的接口。通過該接口,一方面,計(jì)算機(jī)系統(tǒng)向用戶輸出系統(tǒng)的運(yùn)行狀態(tài)、運(yùn)行控制和運(yùn)行結(jié)果等方面信息;另一方面,用戶根據(jù)輸出信息向系統(tǒng)輸入相應(yīng)的指令和數(shù)據(jù)等信息。
3.4.1 控制臺(tái)窗口和屏幕緩沖區(qū)
控制臺(tái)窗口是個(gè)二維平面空間,其坐標(biāo)系統(tǒng)的原點(diǎn)(0, 0)設(shè)在窗口左上角,即窗口第一行第一列字符單元的位置。橫軸(X軸)的正向沿原點(diǎn)向右,與窗口的第一行重合,每刻度為一個(gè)字符寬度;縱軸(Y軸)的正向沿原點(diǎn)向下,與窗口的第一列重合,每刻度為一個(gè)字符高度。窗口中每個(gè)字符單元對(duì)應(yīng)一個(gè)二維坐標(biāo)。比如,第5行第32列字符單元的坐標(biāo)為(31, 4)。如圖3.8所示。
圖3.8 控制臺(tái)窗口和屏幕緩沖區(qū)關(guān)系示意圖
屏幕緩沖區(qū)是個(gè)二維數(shù)組,邏輯上可看作一個(gè)二維平面空間。數(shù)組第一個(gè)元素的下標(biāo)[0][0]對(duì)應(yīng)此平面空間坐標(biāo)系統(tǒng)的原點(diǎn)(0, 0),數(shù)組第1維的下標(biāo)對(duì)應(yīng)坐標(biāo)系統(tǒng)的縱坐標(biāo)(Y坐標(biāo)),第2維下標(biāo)對(duì)應(yīng)坐標(biāo)系統(tǒng)的橫坐標(biāo)(X坐標(biāo))。屏幕緩沖區(qū)存放著M行N列字符單元的信息,M和N的大小由系統(tǒng)設(shè)置,并可以進(jìn)行修改。
每個(gè)字符單元信息用一個(gè)Char_INFO結(jié)構(gòu)類型的數(shù)據(jù)來表示,結(jié)構(gòu)成員CHAR存放字符的碼值(Unicode碼或ASCII碼,取決于系統(tǒng)所采用的字符集),結(jié)構(gòu)成員Attributes存放字符的屬性(字符顯示所用的前景色和背景色)。
操作系統(tǒng)以一定的頻率從屏幕緩沖區(qū)讀取字符單元信息,并顯示在控制臺(tái)窗口中。應(yīng)用程序的輸出信息實(shí)際上輸出到了屏幕緩沖區(qū),由此改變了控制臺(tái)窗口所顯示的內(nèi)容。初始狀態(tài)下,屏幕緩沖區(qū)坐標(biāo)系統(tǒng)與控制臺(tái)窗口坐標(biāo)系統(tǒng)重合,窗口中第m行第n列字符的碼值和顏色值存放在屏幕緩沖區(qū)二維數(shù)組中下標(biāo)為[m-1][n-1]的元素中。利用控制臺(tái)函數(shù)可以改變這兩個(gè)坐標(biāo)系統(tǒng)的對(duì)應(yīng)關(guān)系,實(shí)現(xiàn)特殊的顯示效果。圖3.8表示了控制臺(tái)窗口和屏幕緩沖區(qū)的相互關(guān)系。
一個(gè)控制臺(tái)可擁有多個(gè)屏幕緩沖區(qū),但只有處于激活狀態(tài)的屏幕緩沖區(qū)內(nèi)容顯示在控制臺(tái)窗口中。操作系統(tǒng)在為進(jìn)程創(chuàng)建控制臺(tái)的同時(shí)會(huì)創(chuàng)建一個(gè)屏幕緩沖區(qū)。
進(jìn)程可調(diào)用函數(shù)CreateConsoleScreenBuffer為其控制臺(tái)創(chuàng)建另外的屏幕緩沖區(qū)。
調(diào)用函數(shù)SetConsoleActiveScreenBuffer可以將某個(gè)已有的屏幕緩沖區(qū)置為激活狀態(tài),使其內(nèi)容顯示在屏幕窗口中。
不管是否處于激活狀態(tài),屏幕緩沖區(qū)都可以通過句柄來進(jìn)行讀寫操作,只不過激活狀態(tài)下屏幕緩沖區(qū)的內(nèi)容可以看到,非激活狀態(tài)下看不到而已。
屏幕緩沖區(qū)相關(guān)的多個(gè)屬性可以獨(dú)立進(jìn)行設(shè)置。激活的屏幕緩沖區(qū)屬性值的變化能在控制臺(tái)窗口中產(chǎn)生奇妙的外觀效果。屏幕緩沖區(qū)相關(guān)的屬性包括:
l 屏幕緩沖區(qū)大小,以字符行和列為單位;
l 文本屬性(文本信息顯示的前景色和背景色);
l 窗口大小和定位(控制臺(tái)屏幕緩沖區(qū)在控制臺(tái)窗口中顯示時(shí)所處的矩形區(qū)域);
l 光標(biāo)位置、外觀和是否可見;
l 輸出模式(控制字符的輸出處理和行末換行處理)。
屏幕緩沖區(qū)在創(chuàng)建時(shí),它所包含的字符內(nèi)容初始化為空格,光標(biāo)設(shè)為可見并定位在緩沖區(qū)原點(diǎn)(0, 0),而窗口的原點(diǎn)(左上角)與緩沖區(qū)原點(diǎn)置為重合??刂婆_(tái)屏幕緩沖區(qū)的大小、窗口的大小、文本屬性和光標(biāo)的外觀取決于用戶或系統(tǒng)的缺省設(shè)置。
為獲取控制臺(tái)屏幕緩沖區(qū)各種相關(guān)屬性的當(dāng)前值,可分別調(diào)用函數(shù):
GetConsoleScreenBufferInfo;
GetConsoleCursorInfo;
GetConsoleMode。
屏幕緩沖區(qū)光標(biāo)信息用CONSOLE_CURSOR_INFO結(jié)構(gòu)類型的數(shù)據(jù)表示,成員bVisible表示光標(biāo)是否可見,成員dwSize表示光標(biāo)外觀大小,取值范圍為1~100。光標(biāo)可見時(shí),dwSize的取值從100變?yōu)?,光標(biāo)外觀大小從充滿整個(gè)字符單元變?yōu)槌霈F(xiàn)在單元底部的一條水平線。調(diào)用函數(shù)GetConsoleCursorInfo和SetConsoleCursorInfo分別可以獲得和設(shè)置光標(biāo)屬性值。
由高級(jí)控制臺(tái)I/O函數(shù)(如getchar,putchar,printf,scanf等)輸出的字符將輸出在光標(biāo)當(dāng)前位置,同時(shí)光標(biāo)移動(dòng)到下一個(gè)字符輸出位置。
調(diào)用函數(shù):
GetConsoleScreenBufferInfo和SetConsoleCursorPosition,
分別可以獲得和設(shè)置光標(biāo)在屏幕緩沖區(qū)坐標(biāo)系統(tǒng)中的當(dāng)前位置,由此可以控制高級(jí)I/O函數(shù)輸出或回顯字符的位置。
字符屬性分為兩類:顏色屬性和DBCS(Double-Byte Character Set,雙字節(jié)字符集)屬性。表3.14中的符號(hào)常量在wincon.h頭文件中進(jìn)行定義。
表3.14 字符屬性符號(hào)常量表
屬性
含義
FOREGROUND_BLUE
文本顏色包含藍(lán)色
FOREGROUND_GREEN
文本顏色包含綠色
FOREGROUND_RED
文本顏色包含紅色
FOREGROUND_INTENSITY
文本顏色加亮
BACKGROUND_BLUE
背景含藍(lán)色
BACKGROUND_GREEN
背景含綠色
BACKGROUND_RED
背景含紅色
BACKGROUND_INTENSITY
背景加亮
COMMON_LVB_LEADING_BYTE
首字節(jié)
COMMON_LVB_TRAILING_BYTE
末字節(jié)
COMMON_LVB_GRID_HORIZONTAL
首行
COMMON_LVB_GRID_LVERTICAL
左列
COMMON_LVB_GRID_RVERTICAL
右列
COMMON_LVB_REVERSE_VIDEO
翻轉(zhuǎn)前景及背景屬性
COMMON_LVB_UNDERSCORE
下劃線
前綴為FOREGROUND的常量值指定文本顏色(文本的前景色)。前綴為BACKGROUND的常量值指定用于填充字符單元背景的顏色。其他常量值用于DBCS屬性。
應(yīng)用程序可以將前景色和背景色常量值組合起來,獲得不同顏色。例如,下面顏色組合的效果為藍(lán)色背景上的亮青色文本。
FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_BLUE
配色問題可以由實(shí)驗(yàn)的輸出試驗(yàn)確定!
如果不指定背景顏色值,那么背景為黑色,而不指定前景顏色值,文本為黑色。例如,下面顏色組合將產(chǎn)生白色背景上的黑色文本效果。
BACKGROUND_BLUE | BACKGROUND_GREEN | BACKGROUND_RED
每個(gè)屏幕緩沖區(qū)字符單元儲(chǔ)存了在“畫”該單元的文本(前景)和背景時(shí)所使用的顏色屬性值。應(yīng)用程序可以分別設(shè)置每個(gè)字符單元的顏色值,并將顏色值存儲(chǔ)在每個(gè)單元CHAR_INFO結(jié)構(gòu)類型數(shù)據(jù)的Attributes成員中。
3.4.2 在屏幕上指定位置輸出信息
有多種方法在屏幕指定位置輸出帶屬性的字符串信息,這里介紹其中四種基本方法。
(1) 用標(biāo)準(zhǔn)輸出函數(shù)(putchar, printf, puts等)輸出字符串信息;
//設(shè)置光標(biāo)位置
SetConsoleCursorPosition(output_handle, new_pos);
//輸出字符串string
printf(“%s”, string);
//在字符串輸出位置填充指定的文本屬性
FillConsoleOutputAttribute(output_handle, new_attributes, strlen(string), new_pos, NULL);
其中output_handle是屏幕緩沖區(qū)句柄,new_pos為COORD類型的變量,存放指定的光標(biāo)位置坐標(biāo),new_attributes為WORD類型的變量,存放指定的文本屬性值,string是字符數(shù)組,存放被輸出的字符串。
(2) 用函數(shù)WriteConsole輸出字符串信息;
//設(shè)置光標(biāo)位置
SetConsoleCursorPosition (output_handle, new_pos);
//設(shè)置文本屬性
SetConsoleTextAttribute(output_handle, new_attributes);
//輸出字符串
WriteConsole(output_handle, string, strlen(string), NULL, NULL);
變量的含義同上。
(3) 用函數(shù)WriteConsoleOutputCharacter輸出字符串信息;
//在指定位置填充與所輸出字符串等長的文本屬性值
FillConsoleOutputAttribute(output_handle, new_attributes, strlen(string), new_pos, NULL);
//在該指定位置輸出字符串
WriteConsoleOutputCharacter(output_handle, string, strlen(string), new_pos, NULL);
(4) 用函數(shù)WriteConsoleOutput輸出字符串信息;
CHAR_INFO * lpBuffer;
COORD pos = {0, 0};
COORD size = { strlen(string), 1};
SMALL_RECT area = {new_pos.X, new_pos.Y, new_pos.X+strlen(string)-1, new_pos.Y};
lpBuffer = (CHAR_INFO *)malloc(size.X * size.Y * sizeof(CHAR_INFO));
for(i=0; i<strlen(string); i++) {
lpBuffer->Char.AsciiChar = string[i];
lpBuffer->Attributes = new_attributes;
}
WriteConsoleOutput(output_handle, lpBuffer, size, pos, &area);
free(&area);
演示并解釋例3.1 menu_ex3_1
這種方法使用起來相對(duì)復(fù)雜一些。基本思想是將輸出信息當(dāng)作一個(gè)矩形字符信息塊,設(shè)置矩形塊的大小size,矩形塊在窗口中的輸出位置area,將矩形塊內(nèi)字符信息存放在一個(gè)動(dòng)態(tài)存儲(chǔ)緩沖區(qū)lpBuffer內(nèi),字符信息包含了字符的碼值和顏色屬性,最后調(diào)用函數(shù)WriteConsoleOutput將lpBuffer中字符塊信息寫到控制臺(tái)屏幕緩沖區(qū)指定位置。
3.4.3 彈出窗口的設(shè)計(jì)
屏幕窗口是個(gè)有限的信息顯示區(qū)域。在文本字符界面下,控制臺(tái)窗口的大小通常設(shè)為80個(gè)字符的寬度和25行字符的高度,即每屏可以顯示2000個(gè)字符。
彈出窗口設(shè)計(jì)的基本思路是:
1、確定輸出信息的屏幕位置和大?。?/p>
2、將新窗口彈出后所要覆蓋的屏幕區(qū)域字符信息讀入到一塊內(nèi)存緩沖區(qū);
3、在新窗口內(nèi)輸出信息,模擬“彈出”效果。
4、彈出窗口內(nèi)的操作完成后,把保存在內(nèi)存緩沖區(qū)的字符信息寫到其原來所在的屏幕位置,彈出窗口消失,屏幕恢復(fù)為窗口彈出之前的外觀。
演示并解釋例3.1 menu_ex3_2
多層彈出窗口自學(xué)
按照這一思路,可以實(shí)現(xiàn)多層彈出窗口。窗口的多層彈出和逐層關(guān)閉,給屏幕信息的維護(hù)帶來了復(fù)雜性。為了便于處理,我們用鏈表來模擬堆棧,實(shí)現(xiàn)彈出窗口的棧式管理。
彈出窗口棧式管理用到以下結(jié)構(gòu)類型。
typedef struct layer_node {
char LayerNo; //彈出窗口層數(shù)
SMALL_RECT rcArea; //彈出窗口區(qū)域坐標(biāo)
CHAR_INFO *pContent; //彈出窗口區(qū)域字符單元原信息存儲(chǔ)緩沖區(qū)
char *pScrAtt; //彈出窗口區(qū)域字符單元原屬性值存儲(chǔ)緩沖區(qū)
struct layer_node *next; //下一結(jié)點(diǎn)的地址
} LAYER_NODE;
利用這種結(jié)構(gòu)類型的數(shù)據(jù)可以模擬出如圖3.10所示的堆棧,對(duì)彈出窗口信息進(jìn)行管理。
圖3.10 彈出窗口信息堆棧
LAYER_NODE結(jié)構(gòu)的5個(gè)成員分別表示了彈出窗口相關(guān)信息。LayerNo表示當(dāng)前彈出窗口的層數(shù);rcArea表示當(dāng)前彈出窗口矩形區(qū)域的位置和大小;pContent指向的動(dòng)態(tài)存儲(chǔ)區(qū)存放被彈出窗口所覆蓋區(qū)域的原字符單元信息,用于當(dāng)前彈出窗口關(guān)閉后恢復(fù)原屏幕窗口信息;pScrAtt指向的動(dòng)態(tài)存儲(chǔ)區(qū)存放內(nèi)容的用途與輸入處理相關(guān),將在下面的輸入處理中進(jìn)行介紹;next存放下層彈出窗口相關(guān)信息的地址。
堆棧棧頂由LAYER_NODE結(jié)構(gòu)指針TopLayer來指示,初值為NULL。系統(tǒng)界面初始化完成之后,屏幕窗口看作第一層彈出窗口,窗口相關(guān)信息用LAYER_NODE結(jié)構(gòu)類型的動(dòng)態(tài)存儲(chǔ)區(qū)存放后入棧,結(jié)構(gòu)指針TopLayer指向棧頂;以后每彈出一層窗口,就執(zhí)行一次入棧操作。關(guān)閉彈出窗口時(shí),用TopLayer指向的LAYER_NODE結(jié)構(gòu)類型數(shù)據(jù)恢復(fù)被覆蓋的屏幕區(qū)域,將TopLayer指向下一層結(jié)點(diǎn),釋放用過的動(dòng)態(tài)存儲(chǔ)區(qū),完成出棧操作。
3.4.4 鍵盤和鼠標(biāo)輸入信息的獲取
ReadConsoleInput函數(shù)原型為:
BOOL WINAPI ReadConsoleINPUT(HANDLE hConsoleInput, PINPUT_RECORD
lpBuffer, DWORD nLength, LPDWORD lpNumberOfEventsRead);
功能:用來從控制臺(tái)輸入緩沖區(qū)讀取輸入數(shù)據(jù),并將讀出數(shù)據(jù)從輸入緩沖區(qū)刪除掉。
函數(shù)ReadConsoleInput被調(diào)用時(shí),如果緩沖區(qū)中沒有輸入數(shù)據(jù),函數(shù)將等待下去,直到讀到至少一條記錄后返回。讀到的記錄存放在參數(shù)lpBuffer所指向的內(nèi)存單元。
記錄用INPUT_RECORD結(jié)構(gòu)類型的數(shù)據(jù)來表示;
成員EventType表示事件的類型;
成員Event是聯(lián)合類型,存放事件的具體內(nèi)容。
編程時(shí),需要對(duì)EventType的值為KEY_EVENT(鍵盤輸入)或MOUSE_EVENT(鼠標(biāo)輸入)的兩類事件進(jìn)行處理。
當(dāng)EventType的值為KEY_EVENT時(shí),Event的聯(lián)合成員KeyEvent存放了按鍵相關(guān)信息。KeyEvent是KEY_EVENT_RECORD結(jié)構(gòu)類型,其成員bKeyDown表明鍵是被按下(TRUE)還是被釋放(FALSE),成員wRepeatCount表明按鍵重復(fù)的次數(shù),成員wVirtualKeyCode存放按鍵的虛擬鍵碼,成員wVirtualScanCode存放按鍵的虛擬掃描碼,成員uChar存放按鍵的ASCII碼或Unicode碼(取決于系統(tǒng)所采用的字符集),成員dwControlKeyState表示有哪些控制鍵被同時(shí)按下。我們每按一次鍵會(huì)產(chǎn)生兩個(gè)事件記錄,一個(gè)記錄表示鍵被按下,另一條記錄表示鍵被釋放。常用鍵的各種碼值參見附錄。
當(dāng)EventType的值為MOUSE_EVENT時(shí),Event的聯(lián)合成員MouseEvent存放了鼠標(biāo)操作相關(guān)信息。MOUSEEvent是MOUSE_EVENT_RECORD結(jié)構(gòu)類型,其成員dwMousePosition存放了鼠標(biāo)操作時(shí)的坐標(biāo)位置,表明鼠標(biāo)處于窗口中的某行和某列的字符單元位置上,成員dwButtonState表明鼠標(biāo)哪些按鈕被按下,取值可為下面符號(hào)常量之一或多個(gè)符號(hào)常量的組合值:
FROM_LEFT_1ST_BUTTON_PRESSED值為1,表示按下了鼠標(biāo)最左邊按鈕;
RIGHTMOST_BUTTON_PRESSED值為2,表示按下了鼠標(biāo)最右邊按鈕;
FROM_LEFT_2ND_BUTTON_PRESSED值為4,表示按下了鼠標(biāo)左起第二個(gè)按鈕;
FROM_LEFT_3RD_BUTTON_PRESSED值為8,表示按下了鼠標(biāo)左起第三個(gè)按鈕;
FROM_LEFT_4TH_BUTTON_PRESSED值為16,表示按下了鼠標(biāo)左起第四個(gè)按鈕。
成員dwControlKeyState表示在鼠標(biāo)事件發(fā)生時(shí)有哪些控制鍵被同時(shí)按下,成員dwEventFlags表示鼠標(biāo)事件的具體類型,取值為以下符號(hào)常量:
MOUSE_MOVED值為1,表示鼠標(biāo)移動(dòng)事件;
DOUBLE_CLICK值為2,表示鼠標(biāo)雙擊事件;
MOUSE_WHEELED值為4,表示鼠標(biāo)滾輪滾動(dòng)事件。
3.4.5 輸入處理(略)
(1) 鍵盤輸入處理
按照表3.15進(jìn)行處理,對(duì)其他按鍵不予響應(yīng)。
表3.15 主界面下的鍵盤輸入處理設(shè)計(jì)
按鍵
系統(tǒng)響應(yīng)
F1
執(zhí)行幫助菜單下的幫助主題子菜單對(duì)應(yīng)功能模塊
Alt+X
執(zhí)行文件菜單下的退出系統(tǒng)子菜單對(duì)應(yīng)功能模塊
Alt+F
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記文件菜單項(xiàng)并彈出文件菜單的子菜單
Alt+M
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)維護(hù)菜單項(xiàng)并彈出數(shù)據(jù)維護(hù)菜單的子菜單
Alt+Q
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)查詢菜單項(xiàng)并彈出數(shù)據(jù)查詢菜單的子菜單
Alt+S
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)統(tǒng)計(jì)菜單項(xiàng)并彈出數(shù)據(jù)統(tǒng)計(jì)菜單的子菜單
Alt+H
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記幫助菜單項(xiàng)并彈出幫助菜單的子菜單
向左←
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記左側(cè)菜單項(xiàng)
向右→
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記右側(cè)菜單項(xiàng)
向下↓
彈出當(dāng)前菜單項(xiàng)的子菜單
f或F
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記文件菜單項(xiàng)并彈出文件菜單的子菜單
m或M
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)維護(hù)菜單項(xiàng)并彈出數(shù)據(jù)維護(hù)菜單的子菜單
q或Q
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)查詢菜單項(xiàng)并彈出數(shù)據(jù)查詢菜單的子菜單
s或S
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記數(shù)據(jù)統(tǒng)計(jì)菜單項(xiàng)并彈出數(shù)據(jù)統(tǒng)計(jì)菜單的子菜單
h或H
清除當(dāng)前選中菜單項(xiàng)標(biāo)記,標(biāo)記幫助菜單項(xiàng)并彈出幫助菜單的子菜單
回車
彈出當(dāng)前菜單項(xiàng)的子菜單
鍵盤輸入處理時(shí),要考慮輸入處理的優(yōu)先級(jí),應(yīng)先響應(yīng)快捷鍵,再響應(yīng)組合鍵,最后響應(yīng)單鍵。以Alt組合鍵為例,判斷組合鍵的方法為:
ReadConsoleInput(hIn, &inRec, 1, &res); //從輸入緩沖區(qū)讀取一條輸入記錄
if (inRec.EventType == KEY_EVENT && inRec.Event.KeyEvent.bKeyDown) {
//輸入事件類別為KEY_EVENT,且事件由鍵被按下所觸發(fā)
vkc = inRec.Event.KeyEvent.wVirtualKeyCode; //提取虛擬鍵碼
asc = inRec.Event.KeyEvent.uChar.AsciiChar; //提取ASCII碼
if (inRec.Event.KeyEvent.dwControlKeyState //如果左或右Alt鍵被按下
& (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
…… //進(jìn)一步判斷與Alt組合的另一個(gè)鍵,并做響應(yīng)處理
}
…… //非Alt組合鍵的響應(yīng)處理
}
常用控制鍵所對(duì)應(yīng)的符號(hào)常量在wincon.h頭文件中進(jìn)行了定義,如表3.16所示。
表3.16 控制鍵對(duì)應(yīng)符號(hào)常量表
鍵名
符號(hào)常量
值
鍵名
符號(hào)常量
值
右Alt
RIGHT_ALT_PRESSED
1
左Alt
LEFT_ALT_PRESSED
2
右Ctrl
RIGHT_CTRL_PRESSED
4
左Ctrl
LEFT_CTRL_PRESSED
8
左右Shift
SHIFT_PRESSED
16
數(shù)字鎖定
NUMLOCK_ON
32
屏幕鎖定
SCROLLLOCK_ON
64
大寫鎖定
CAPSLOCK_ON
128
(2) 鼠標(biāo)輸入處理
熱區(qū)本是網(wǎng)頁設(shè)計(jì)中用到的一個(gè)概念,是指網(wǎng)頁上建有鏈接的區(qū)域。我們將熱區(qū)這個(gè)概念借用到程序設(shè)計(jì)中人機(jī)交互界面的設(shè)計(jì)上來,用來指界面上需要對(duì)鼠標(biāo)事件(包括鼠標(biāo)移動(dòng)、滾輪轉(zhuǎn)動(dòng)、雙擊和任意一到多個(gè)鍵的按下)產(chǎn)生反應(yīng)的區(qū)域。
基于這一思想,可用一個(gè)字符(8個(gè)二進(jìn)制位)來表示窗口中某個(gè)字符單元的屬性。如圖3.12所示,這8個(gè)二進(jìn)制位分為三段:0~1比特為A1,2~5比特為A2,6~7比特為A3。A1的取值范圍為0~3,用來表示字符單元的“高度”,即該字符單元上彈出窗口的層數(shù),0表示字符單元處于系統(tǒng)主界面層,沒有彈出窗口覆蓋該字符單元,這樣彈出窗口的層數(shù)最多可到3層;A2取值范圍為0~15,用來表示字符單元的熱區(qū)編號(hào),0表示字符單元不屬于熱區(qū),這樣同一層上的熱區(qū)最多可為15個(gè);A3取值范圍為0~3,在A2取值不為0時(shí)用來表示字符單元的熱區(qū)類型,0代表按鈕類型,1代表輸入框類型,2代表下拉選框類型,3保留備用。不同類型的熱區(qū)被鼠標(biāo)擊中時(shí),系統(tǒng)可以分別進(jìn)行處理。本課程設(shè)計(jì)中,字符單元的屬性用8個(gè)二進(jìn)制位來存放,剛好夠用。在其他應(yīng)用程序開發(fā)中,如果彈出菜單超過3層,或某層窗口中熱區(qū)超過15個(gè),或熱區(qū)類型超過4類,可以考慮用16個(gè)二進(jìn)制位來存放字符單元屬性。
7
6
5
4
3
2
1
0
A3
A2
A1
圖3.12 字符單元屬性的表示
前面在介紹彈出窗口設(shè)計(jì)時(shí),彈出窗口的棧式管理用到以下結(jié)構(gòu)類型:
typedef struct layer_node {
char LayerNo; //彈出窗口層數(shù)
SMALL_RECT rcArea; //彈出窗口區(qū)域坐標(biāo)
CHAR_INFO *pContent; //彈出窗口區(qū)域字符單元原信息存儲(chǔ)緩沖區(qū)
char *pScrAtt; //彈出窗口區(qū)域字符單元原屬性值存儲(chǔ)緩沖區(qū)
struct layer_node *next; //下一結(jié)點(diǎn)的地址
} LAYER_NODE;
其中,結(jié)構(gòu)成員pScrAtt用來指向一個(gè)動(dòng)態(tài)存儲(chǔ)區(qū),該存儲(chǔ)區(qū)存放被彈出窗口所覆蓋字符單元的原先屬性值,在彈出窗口關(guān)閉時(shí)用于恢復(fù)窗口彈出前屏幕字符單元的屬性。
系統(tǒng)界面初始化完成之后,屏幕顯示系統(tǒng)的主界面(如圖3.9所示)。用一個(gè)字符數(shù)組ScrAtt存放屏幕上所有字符單元的屬性值,字符單元的坐標(biāo)X和Y與存放其屬性值的數(shù)組元素下標(biāo)n的關(guān)系為:
n = Y × 屏幕緩沖區(qū)的寬度 + X
主界面中只有5個(gè)主菜單項(xiàng)顯示區(qū)域?yàn)闊釁^(qū),依次編號(hào)1~5,熱區(qū)類型為按鈕型。此后,如果有窗口彈出(彈出菜單也是彈出窗口),則將窗口所覆蓋區(qū)域字符單元的信息和屬性分別保存起來,執(zhí)行彈出窗口信息入棧操作,然后在彈出窗口區(qū)域輸出提示信息,將彈出窗口字符單元的屬性值寫入數(shù)組ScrAtt對(duì)應(yīng)元素以設(shè)置熱區(qū)。鼠標(biāo)輸入處理時(shí),取鼠標(biāo)所在字符單元的屬性值,根據(jù)字符單元的層數(shù)、熱區(qū)編號(hào)和熱區(qū)類型,結(jié)合鼠標(biāo)事件類型做出相應(yīng)處理。當(dāng)彈出窗口關(guān)閉時(shí),用所保存的彈出窗口區(qū)域字符單元原先的屬性值修改數(shù)組ScrAtt對(duì)應(yīng)元素值,恢復(fù)窗口彈出前屏幕字符單元的屬性,最后執(zhí)行彈出窗口信息出棧操作。
3.4.6 菜單操作與系統(tǒng)功能函數(shù)的調(diào)用
按照概要設(shè)計(jì),系統(tǒng)功能分為五個(gè)模塊,各模塊所包含的子模塊共有22個(gè),分別用22個(gè)函數(shù)實(shí)現(xiàn)相應(yīng)功能。其中,數(shù)據(jù)加載函數(shù)和界面初始化函數(shù)只在系統(tǒng)啟動(dòng)時(shí)執(zhí)行一次,以后不再執(zhí)行。其余20個(gè)函數(shù)可以通過菜單操作或快捷鍵執(zhí)行相應(yīng)功能。
例3.3 在圖3.9所示的主界面下,實(shí)現(xiàn)菜單操作與系統(tǒng)功能函數(shù)的調(diào)用。本例中給出了函數(shù)SysRun和函數(shù)ExeFunction的定義,分別用于菜單操作和系統(tǒng)功能函數(shù)的調(diào)用。例子中調(diào)用了例3.1和例3.2中的函數(shù),而其余函數(shù)的定義沒有給出。
#include "dorm.h"
void SysRun( )
{
INPUT_RECORD inRec;
DWORD res;
COORD pos = {0, 0};
BOOL bRet = TRUE;
int i, loc, num;
int cNo, cAtt; //cNo:字符單元層號(hào), cAtt:字符單元屬性
char vkc, asc; //vkc:虛擬鍵代碼, asc:字符的ASCII碼值
while (bRet) { // 循環(huán)
ReadConsoleInput(hIn, &inRec, 1, &res);
if (inRec.EventType == MOUSE_EVENT) {
pos = inRec.Event.MouseEvent.dwMousePosition; /* pos 是坐標(biāo) */
cNo = ScrAtt[pos.Y * ScrCol + pos.X] & 3;
cAtt = ScrAtt[pos.Y * ScrCol + pos.X] >> 2;
if (cNo == 0) {
if (cAtt > 0 && cAtt != SelMenu && TopLayer->LayerNo > 0) {
PopOff();
SelSMenu = 0;
PopMenu(cAtt);
}
}
else if (cAtt > 0) {
TagSMenu(cAtt);
}
if (inRec.Event.MouseEvent.dwButtonState
== FROM_LEFT_1ST_BUTTON_PRESSED) {
if (cNo == 0) {
if (cAtt > 0) {
PopMenu(cAtt);
}
else if (TopLayer->LayerNo > 0) {
PopOff();
SelSMenu = 0;
}
}
else {
if (cAtt > 0) {
PopOff();
SelSMenu = 0;
bRet = ExeFunction(SelMenu, cAtt);
}
}
}
else if (inRec.Event.MouseEvent.dwButtonState
== RIGHTMOST_BUTTON_PRESSED) {
if (cNo == 0) {
PopOff();
SelSMenu = 0;
}
}
}
else if (inRec.EventType == KEY_EVENT
&& inRec.Event.KeyEvent.bKeyDown) {
vkc = inRec.Event.KeyEvent.wVirtualKeyCode;
asc = inRec.Event.KeyEvent.uChar.AsciiChar;
//系統(tǒng)快捷鍵的處理
if (vkc == 112) { //F1鍵
if (TopLayer->LayerNo != 0) {
PopOff();
SelSMenu = 0;
}
bRet = ExeFunction(5, 1); //F1幫助主題
}
else if (inRec.Event.KeyEvent.dwControlKeyState
& (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) {
switch (vkc) { //組合鍵Alt+字母
case 88: if (TopLayer->LayerNo != 0) {
PopOff();
SelSMenu = 0;
}
bRet = ExeFunction(1,4); break; //Alt+X 退出
case 70: PopMenu(1); break; //Alt+F
case 77: PopMenu(2); break; //Alt+M
case 81: PopMenu(3); break; //Alt+Q
case 83: PopMenu(4); break; //Alt+S
case 72: PopMenu(5); break; //Alt+H
}
}
else if (asc == 0) { //方向鍵的處理
if (TopLayer->LayerNo == 0) { //未彈出子菜單時(shí)
switch (vkc) { //方向鍵(左、右、下)的處理
case 37: SelMenu--;
if (SelMenu == 0) {
SelMenu = 5;
}
TagMenu(SelMenu); break;
case 39: SelMenu++;
if (SelMenu == 6) {
SelMenu = 1;
}
TagMenu(SelMenu); break;
case 40: PopMenu(SelMenu);
TagSMenu(1); break;
}
}
else { //已彈出子菜單時(shí)
for (loc=0,i=1; i<SelMenu; i++) {
loc += cSMenu[i-1];
} //找到子菜單第一項(xiàng)在子菜單數(shù)組中的位置(下標(biāo))
switch (vkc) { //方向鍵(左、右、上、下)的處理
case 37: SelMenu--;
if (SelMenu < 1) {
SelMenu = 5;
}
TagMenu(SelMenu); PopOff();
PopMenu(SelMenu); TagSMenu(1);
break;
case 38: num = SelSMenu - 1;
if (num < 1) {
num = cSMenu[SelMenu-1];
}
if (strlen(SMenu[loc+num-1]) == 0) {
num--;
}
TagSMenu(num); break;
case 39: SelMenu++;
if (SelMenu > 5) {
SelMenu = 1;
}
TagMenu(SelMenu); PopOff();
PopMenu(SelMenu); TagSMenu(1);
break;
case 40: num = SelSMenu + 1;
if (num > cSMenu[SelMenu-1]) {
num = 1;
}
if (strlen(SMenu[loc+num-1]) == 0) {
num++;
}
TagSMenu(num); break;
}
}
}
else if ((asc-vkc == 0) || (asc-vkc == 32)){ //按下普通鍵
if (TopLayer->LayerNo == 0) { //未彈出子菜單時(shí)
switch (vkc) {
case 70: PopMenu(1); break; //f或F
case 77: PopMenu(2); break; //m或M
case 81: PopMenu(3); break; //q或Q
case 83: PopMenu(4); break; //s或S
case 72: PopMenu(5); break; //h或H
case 13: PopMenu(SelMenu); //回車
TagSMenu(1); break;
}
}
else { //已彈出子菜單時(shí)的鍵盤輸入處理
if (vkc == 27) { //按下ESC鍵時(shí), 關(guān)閉子菜單
PopOff();
SelSMenu = 0;
}
else if(vkc == 13) { //|| vkc == 32
num = SelSMenu;
PopOff();
SelSMenu = 0;
bRet = ExeFunction(SelMenu, num);
}
else {
for (loc=0,i=1; i<SelMenu; i++) {
loc += cSMenu[i-1];
}
for (i=loc; i<loc+cSMenu[SelMenu-1]; i++) {
if (strlen(SMenu[i])>0 && vkc==SMenu[i][1]) {
PopOff();
SelSMenu = 0;
bRet = ExeFunction(SelMenu, i-loc+1);
}
}
}
}
}
}
}
}
BOOL ExeFunction(int m, int s)
{
BOOL bRet = TRUE;
BOOL (*pFunction[cSMenu[0]+cSMenu[1]+cSMenu[2]+cSMenu[3]+cSMenu[4]])(void);
int i, loc;
//pFunction
pFunction[0] = DataSave;
pFunction[1] = DataBackup;
pFunction[2] = DataRestore;
pFunction[3] = SySexit;
pFunction[4] = MaintainSex;
pFunction[5] = MaintainType;
pFunction[6] = NULL;
pFunction[7] = MaintainDorm;
pFunction[8] = MaintainStu;
pFunction[9] = MaintainCharge;
pFunction[10] = QuerySex;
pFunction[11] = QueryType;
pFunction[12] = NULL;
pFunction[13] = QueryDorm;
pFunction[14] = QueryStu;
pFunction[15] = QueryCharge;
pFunction[16] = StatIn;
pFunction[17] = StatType;
pFunction[18] = StatCharge;
pFunction[19] = StatUncharge;
pFunction[20] = HelpTopic;
pFunction[21] = NULL;
pFunction[22] = AboutDorm;
for (i=1,loc=0; i<m; i++) {
loc += cSMenu[i-1];
}
loc += s - 1;
if (pFunction[loc] != NULL) {
bRet = (*pFunction[loc])();
}
return bRet;
}
演示并解釋例3.1 menu_ex3_2
作者:liaojiaohong https://www.bilibili.com/read/cv12993546 出處:bilibili
以上就是關(guān)于pos機(jī)交互過程,CodeBlock下的人機(jī)交互界面設(shè)計(jì)的知識(shí),后面我們會(huì)繼續(xù)為大家整理關(guān)于pos機(jī)交互過程的知識(shí),希望能夠幫助到大家!
