BOOL ReadConsoleInput(
HANDLE hConsoleInput, // 標準輸入控制代碼
PINPUT_RECORD lpBuffer, // 輸入事件緩衝區
DWORD nLength, // 讀取記錄數
LPDWORD lpNumberOfEventsRead // 實際讀取數
);
從標準輸入讀取鍵盤、滑鼠、視窗縮放等事件。鍵盤事件包含字符事件(產生字符)與按鍵事件(按下/釋放),統一通過 `INPUT_RECORD` 結構體傳遞。
typedef struct _INPUT_RECORD {
WORD EventType; // 事件類型
union {
KEY_EVENT_RECORD KeyEvent;
MOUSE_EVENT_RECORD MouseEvent;
WINDOW_BUFFER_SIZE_RECORD WindowBufferSizeEvent;
MENU_EVENT_RECORD MenuEvent;
FOCUS_EVENT_RECORD FocusEvent;
} Event;
} INPUT_RECORD;
鍵盤事件對應 `EventType == KEY_EVENT`,具體資訊在 `Event.KeyEvent`。
typedef struct _KEY_EVENT_RECORD {
BOOL bKeyDown; // TRUE=按下, FALSE=釋放
WORD wRepeatCount; // 重複次數
WORD wVirtualKeyCode; // 虛擬鍵碼
WORD wVirtualScanCode; // 掃描碼
union {
WCHAR UnicodeChar; // Unicode 字符
CHAR AsciiChar; // ASCII 字符
} uChar;
DWORD dwControlKeyState; // 控制鍵狀態位掩碼
} KEY_EVENT_RECORD;
| 常數 | 值 | 按鍵 |
|---|---|---|
| VK_ESCAPE | 0x1B | Esc |
| VK_RETURN | 0x0D | Enter |
| VK_SHIFT | 0x10 | Shift |
| VK_CONTROL | 0x11 | Ctrl |
| VK_MENU | 0x12 | Alt |
| VK_LEFT | 0x25 | ← |
| VK_UP | 0x26 | ↑ |
| VK_RIGHT | 0x27 | → |
| VK_DOWN | 0x28 | ↓ |
| 'A'~'Z' | 0x41~0x5A | 字母鍵 |
| '0'~'9' | 0x30~0x39 | 數字鍵(主鍵盤) |
| VK_F1~VK_F12 | 0x70~0x7B | 功能鍵 |
ENHANCED_KEY // 擴展鍵
LEFT_ALT_PRESSED // 左 Alt
RIGHT_CTRL_PRESSED // 右 Ctrl
SHIFT_PRESSED // Shift
CAPSLOCK_ON // Caps Lock 開啟
NUMLOCK_ON // Num Lock 開啟
SCROLLLOCK_ON // Scroll Lock 開啟
#include <stdio.h>
#include <windows.h>
int main() {
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD rec; DWORD cnt;
for (;;) {
ReadConsoleInput(hIn, &rec, 1, &cnt);
if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) {
if (rec.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE) {
printf("Esc pressed, exit.\n");
break;
}
}
}
return 0;
}
關鍵:必須檢查 `bKeyDown`,否則按下與釋放各觸發一次,導致雙重處理。
#include <stdio.h>
#include <windows.h>
int main() {
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
INPUT_RECORD rec; DWORD cnt;
for (;;) {
ReadConsoleInput(hIn, &rec, 1, &cnt);
if (rec.EventType == KEY_EVENT && rec.Event.KeyEvent.bKeyDown) {
if (rec.Event.KeyEvent.wVirtualKeyCode == 'A') {
DWORD state = rec.Event.KeyEvent.dwControlKeyState;
if (state & SHIFT_PRESSED) printf("Shift+");
if (state & CAPSLOCK_ON) printf("A "); else printf("a ");
}
}
}
return 0;
}
技巧:控制鍵狀態使用位元 AND (`&`)而非相等比較,因多個控制鍵可能同時按下(如 Shift + CapsLock)。
Windows 控制台鍵盤事件處理的核心是 `ReadConsoleInput` + `KEY_EVENT_RECORD`。掌握虛擬鍵碼、掃描碼、字符碼三者關係,善用位元運算檢查控制鍵狀態,即可構建健壯的互動式控制台應用。