嵌入式裝置無滑鼠、觸控,鍵盤是唯一輸入。功能鍵切換畫面、數字鍵輸入參數,邏輯交織複雜。本文提出結構化處理架構,借鑑 Windows 訊息機制,實現清晰、可擴展的按鍵處理。
主畫面按 Enter 進入「設定 XX」子畫面,同一顆鍵在不同畫面觸發完全不同動作。傳統巨大 switch-case 難以維護。
#define ELEMENT_NUM 10
typedef struct {
BYTE ID;
void (*OnOk)(void);
void (*OnCancel)(void);
// ... 其他事件處理函數指標
} ELEMENT;
typedef struct {
BYTE currentFocus; // 當前焦點元素 ID
ELEMENT element[ELEMENT_NUM]; // 畫面元素陣列
void (*messageFun)(BYTE keyValue); // 訊息處理函數
} WINDOW;
void MessageFunction(BYTE keyValue) {
BYTE i = 0;
// 尋找焦點元素
while (i < ELEMENT_NUM && element[i].ID != currentFocus)
i++;
if (i < ELEMENT_NUM) { // 找到焦點元素
switch (keyValue) {
case KEY_OK:
if (element[i].OnOk) element[i].OnOk();
break;
case KEY_CANCEL:
if (element[i].OnCancel) element[i].OnCancel();
break;
// ... 其他鍵值
}
}
}
此即「訊息映射」機制。進階可參考 MFC MESSAGE_MAP 巨集實現編譯期綁定。
使用者逐位輸入,每位對應螢幕特定座標,程式需記錄座標與數值,傳統分離變數管理極易出錯。
typedef struct {
BYTE byNum; // 輸入數值
BYTE xPos; // 顯示 X 座標
BYTE yPos; // 顯示 Y 座標
} InputNum, *LPInputNum;
InputNum inputElement[NUM_LENGTH]; // 輸入緩衝區
BYTE currentElementInputPlace = 0; // 當前輸入位置
extern void OnNumKey(BYTE num) {
if (num == 0 || num == 1) { // 僅接受二進位
// 1. 顯示輸入
DrawText(inputElement[currentElementInputPlace].xPos,
inputElement[currentElementInputPlace].yPos,
"%1d", num);
// 2. 記錄數值
inputElement[currentElementInputPlace].byNum = num;
// 3. 焦點右移
MoveToRight();
}
}
座標與數值綁定,處理邏輯緊湊清晰。
void ConvertToXXX() {
XXX = 0;
for (BYTE i = 0; i < NUM_LENGTH; i++)
XXX += inputElement[i].byNum * POWER(2, NUM_LENGTH - i - 1);
}
void ConvertFromXXX() {
for (BYTE i = 0; i < NUM_LENGTH; i++)
inputElement[i].byNum = (XXX / POWER(2, NUM_LENGTH - i - 1)) % 2;
}
註:二進位建議用位移 <</>> 取代 POWER,十進位則需冪運算。
| 傳統寫法 | 本架構 |
|---|---|
| 巨大 switch-case 處理所有畫面按鍵 | 每畫面獨立訊息函數,職責分離 |
| 焦點邏輯分散 | 焦點屬於畫面,封裝於 WINDOW |
| 數字輸入座標、數值分離管理 | InputNum 結構體綁定,原子化操作 |
| 新增畫面需修改核心邏輯 | 新增 WINDOW 實例,註冊訊息函數即可 |
計算機科學知識具有普遍相通性。Windows 訊息機制、MFC 訊息映射、瀏覽器事件冒泡,本質相同。精通組合語言、C、C++(或 Java)三大核心語言,觸類旁通,新技術不過是舊概念的新包裝。夯實基本功,勝過追逐潮流。