『壹』 c語言怎樣實現鍵盤操作
1.在Microsoft Windows 中,鍵盤和滑鼠是兩個標準的用戶輸入源,在一些交疊的操作中通常相互補充使用。當然,滑鼠在今天的應用程序中比10年前使用得更為廣泛。甚至在一些應用程序中,我們更習慣於使用滑鼠,例如在游戲、畫圖程序、音樂程序,以及Web創覽器等程序中就是這樣。然而,我們可以不使用滑鼠,但絕對不能從一般的PC中拆掉鍵盤。
Windows程序獲得鍵盤輸入的方式:鍵盤輸入以消息的形式傳遞給程序的窗口過程。實際上,第一次學習消息時,鍵盤就是一個明顯的例子:消息應該傳遞給應用程序的信息類型。
Windows用8種不同的消息來傳遞不同的鍵盤事件。這好像太多了,但是(就像我們所看到的一樣)程序可以忽略其中至少一半的消息而不會有任何問題。並且,在大多數情況下,這些消息中包含的鍵盤信息會多於程序所需要的。處理鍵盤的部分工作就是識別出哪些消息是重要的,哪些是不重要的。
2.鍵盤基礎知識
雖然應用程序在很多情況下可以通過滑鼠實現信息的輸入,但到現在為止鍵盤仍然是PC機中不可替代的重要輸入設備。
用鍵盤當作輸入設備,每當用戶按下或釋放某一個鍵時,會產生一個中斷,該中斷激活鍵盤驅動程序KEYBOARD.DRV來對鍵盤中斷進行處理。 KEYBOARD.DRV程序會根據用戶的不同操作進行編碼,然後調用Windows用戶模塊USER.EXE生成鍵盤消息,並將該消息發送到消息隊列中等候處理。
1.掃描碼和虛擬碼
掃描碼對應著鍵盤上的不同鍵,每一個鍵被按下或釋放時,都會產生一個唯一的掃描碼作為本身的標識。掃描碼依賴於具體的硬體設備,即當相同的鍵被按下或釋放時,在不同的機器上可能產生不同的掃描碼。在程序中通常使用由Windows系統定義的與具體設備無關的虛擬碼。在擊鍵產生掃描碼的同時,鍵盤驅動程序KEYBOARD.DRV截取鍵的掃描碼,然後將其翻譯成對應的虛擬碼,再將掃描碼和虛擬碼一齊編碼形成鍵盤消息。所以,最後發送到消息隊列的鍵盤消息中,既包含了掃描碼又包含了虛擬碼。
經常使用的虛擬碼在WINDOWS.H文件中定義,常用虛擬碼的數值、常量符號和含義如表所示。
取值(16進制) 常量符號 含義
01 VK_LBUTTON 滑鼠左鍵
02 VK_RBUTTON 滑鼠右鍵
03 VK_CANCEL Break中斷鍵
04 VK_MBUTTON 滑鼠中鍵
05-07 -- 未定義
08 VK_BACK (BackSpace)鍵
09 VK_TAB Tab鍵
0A-0B -- 未定義
0C VK_CLEAR Clear鍵
0D VK_RETURN Enter鍵
0E-0F -- 未定義
10 VK_SHIFT Shift鍵
11 VK_CONTROL Ctrl鍵
12 VK_MENU Alt鍵
13 VK_PAUSE Pause鍵
14 VK_CAPTIAL CapsLock鍵
15-19 -- 漢字系統保留
1A -- 未定義
1B VK_ESCAPE Esc鍵
1C-1F -- 漢字系統保留
20 VK_SPACE 空格鍵
21 VK_PRIOR PageUp鍵
22 VK_NEXT PageDown鍵
23 VK_END End鍵
24 VK_HOME Home鍵
25 VK_LEFT ←(Left Arrow)鍵
26 VK_UP ↑(Up Arrow)鍵
27 VK_RIGHT →(Right Arrow)鍵
28 VK_DOWN ↓(Down Arrow)鍵
29 VK_SELECT Select鍵
2A -- OEM保留
2B VK_EXECUTE Execute鍵
2C VK_SNAPSHOT Print Screen鍵
2D VK_INSERT Insert鍵
2E VK_DELETE Delete鍵
2F VK_HELP Help鍵
30-39 VK_0-VK_9 數字鍵0-9
3A-40 -- 未定義
41-5A VK_A-VK_Z 字母鍵A-Z
5B-5F -- 未定義
60-69 VK_NUMPAD0-VK_NUMPAD9 小鍵盤數字鍵0-9
6A VK_MULTIPLY *(乘號)鍵
6B VK_ADD +(加號)鍵
6C VK_SEPAPATOR 分隔符鍵
6E VK_SUBTRACT -(減號)鍵
6F VK_DECIMAL .(小數點)鍵
70-87 VK_DIVIDE /(除號)鍵
88-8F VK_F1-VK_F24 F1-F24功能鍵
90 VK_NUMBERLOCK Number lock鍵
91 VK_SCROLL Scroll lock鍵
92-B9 -- 未定義
BA-C0 -- OEM保留
C1-DA -- 未定義
DB_E4 -- OEM保留
E5 -- 未定義
E6 -- OEM保留
E7-E8 -- 未定義
E9-F5 -- OEM保留
F6-FE -- 未定義
2.輸入焦點
同一時刻,Windows中可能有多個不同的程序在運行,也就是說有多個窗口同時存在。這時,鍵盤由多個窗口共享,但只有一個窗口能夠接收到鍵盤消息,這個能夠接收鍵盤消息的窗口被稱為擁有輸入焦點的窗口。
擁有輸入焦點的窗口應該是當前的活動窗口,或者是活動窗口的子窗口,其標題和邊框會以高亮度顯示,以區別於其他窗口。擁有輸入焦點的也可以是圖標而不是窗口,此時,Windows也將消息發送給圖標,只是消息的格式略有不同。
窗口過程可以通過發送WM_SETFOCUS和 WM_KILLFOCUS消息使窗體獲得或失去輸入焦點。程序也可以通過捕獲WM_SETFOCUS和WM_KILLFOCUS消息來判斷窗體何時獲得或失去輸入焦點。其中WM_SETFOCUS消息表示窗口正獲得輸入焦點,WM_ KILLFOCUS消息表示窗口正失去輸入焦點。
3.鍵盤消息
鍵盤消息分為系統鍵消息和非系統鍵消息。系統鍵消息是指由Aft鍵和其他鍵組合而產生的按鍵消息。當系統鍵被按下時產生WM_ SYSKEYDOWN消息,當系統鍵被釋放時產生WM_SYSKEYUP消息。 Aft鍵與其他鍵形成的組合鍵通常用於對程序菜單和系統菜單進行選擇,或用於在不同的程序之間進行切換。因此,系統鍵消息應該交由Windows進行處理,用戶所編制的程序一般不處理系統鍵消息,而是將這些消息交由DefWindowProc函數進行處理。如果用戶想對系統鍵消息進行處理,應該在處理完這些消息後,再將其發送給DefWindowProc函數,使得Windows系統能夠正常工作。
某些擊鍵消息可以被轉換成字元消息,例如字母鍵、數字鍵等。而有些鍵只能產生按鍵消息而沒有字元消息,例如 Shift鍵、Insert鍵等。消息循環中的 TranslateMessage函數可以實現從擊鍵消息向字元消息的轉化。當GetMessage函數捕獲一個WM_SYSKEYDOWN消息或 WM_KEYDOWN消息後,TranslateMessage函數判斷產生該消息的鍵是否能夠被轉換成字元消息,如果能,就將該消息轉換成字元消息,再通過DispatchMessape函數將轉換後的字元消息發送到消息隊列中去。字元消息共有以下四種,如表所示。
字元 系統字元 非系統字元
普通字元 WM_SYSCHAR WM_CHAR
死字元 WM_SYSDEADCHAR WM_DEADCHAR
其中死字元是由某些特殊鍵盤上的按鍵所造成的,Windows一般忽略死字元所產生的消息。
Windows的消息一般是通過一個MSG結構體變數傳送給消息處理函數的。對於鍵盤消息, MSG結構體變數的各個域中較重要的是lParam域和 wParam域。wParam域用於保存按鍵的虛擬鍵代碼或字元的ASCII碼。對於非字元消息,wParam域保存按鍵的虛擬健代碼;對於字元消息, wParam域不保存字元的ASCII碼。lParam域則用於保存擊鍵時產生的附加信息,實際上一個32位的lParam變數被分為六部分,記錄了以下相關信息:重復次數、OEM掃描碼、擴展鍵標志、關聯鍵標志、前一擊鍵狀態和轉換狀態。lParam域各位的含義如表所示。
位數 含義
0-15 擊鍵重復次數累加
16-23 OEM掃描碼
24 是否為擴展鍵
25-28 未定義
29 是否便用關聯鍵,及Alt鍵是否同時按下。
30 前一次擊鍵狀態,0表示該鍵前一次狀態為抬起,1表示前一次狀態為按下
31 轉換狀態
按鍵的次序不同,產生的消息也不相同。例如,按下並釋放1鍵,讀過程依次產生如表所示三條消息。按下1鍵所產生的消息和wParam的取值
消息 wParam變數取值
WM_KEYDOWN 虛擬碼1
WM_CHAR ASCII碼「1」
WM_KEYUP 虛擬碼1
如果按下Shift鍵後再按下1鍵並釋放,則依次產生如表所示的消息。按下 Shift鍵後按 1健所產生的消息和 wParam的取值
消息 wParam變數取值
WM_KEYDOWN 虛擬碼 VK_SHIFT
WM_KEYDOWN 虛擬碼 VK_1
WM_CHAR ASCII碼「1」
WM_KEYUP 虛擬碼 VK_1
WM_KEYUP 虛擬碼 VK_SHIF
鍵盤應用實例
下面通過一個應用程序實例來說明在實際編程中如何處理鍵盤消息。
#include <windows.h>
#include <stdio.h>
// 全局變數
RECT rc; //記錄滾屏的矩形區域
int xChar, yChar; //文本輸入點坐標
WNDCLASSEX wnd; //窗口類結構變數
char szAppName[] = "鍵盤消息監視程序"; //窗口類名
//函數聲明
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
BOOL MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE hInstance,int iCmdShow);
//函數:WinMain
//作用:入口函數
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR szCmdLine,int iCmdShow)
{
MSG msg;
if(!MyRegisterClass(hInstance))
{
return FALSE;
}
if(!InitInstance(hInstance,iCmdShow))
{
return FALSE;
}
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
return msg.wParam;
}
//函數:ShowKey
//作用:實現在窗口中顯示按鍵信息
void ShowKey (HWND hwnd, int iType,char *szMessage,WPARAM wParam,LPARAM lParam)
{
static char *szFormat[2] ={"%-14s %3d %c %6u %4d %5s %5s %6s %6s",
"%-14s %3d %c %6u %4d %5s %5s %6s %6s" };
char szBuffer[80];
HDC hdc;
ScrollWindowEx(hwnd, 0, -yChar, &rc,&rc,NULL,NULL,SW_INVALIDATE);
hdc = GetDC (hwnd);
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT));
TextOut (hdc,
xChar,
rc.bottom - yChar,
szBuffer,
wsprintf szBuffer,
szFormat[iType],
szMessage, //消息
wParam, //虛擬鍵代碼
(BYTE) (iType ? wParam :『 』),//顯示字元值
LOWORD (lParam), // 重復次數
HIWORD (lParam) & 0xFF, // OEM鍵盤掃描碼
//判斷是否為增強鍵盤的擴展鍵
(PSTR) (0x01000000 & lParam ? 「是」 : 「否」),
//判斷是否同時使用了ALT鍵
(PSTR) (0x20000000 & lParam ? 「是」 : 「否」),
(PSTR) (0x40000000 & lParam ? 「按下」 : 「抬」),
//判斷前一次擊鍵狀
(PSTR)(0x80000000 & lParam ? 「按下」 : 「抬起」))
//判斷轉換狀態?
);
ReleaseDC (hwnd, hdc); ?
ValidateRect (hwnd, NULL); ?
}
//函數:WndProc
//作用:處理主窗口的消息
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
static char szTop[] ="消息鍵 字元 重復數 掃描碼 擴展碼 ALT 前一狀態 轉換狀態";
static char szUnd[] ="_______ __ ____ _____ ______ ______ ___ _______ ______";
//在窗口中輸出文字作為信息標題
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
switch (iMsg)
{
case WM_CREATE://處理窗口創建的消息
hdc = GetDC (hwnd); //設定字體
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)); //檢取當前字體的度量數據
GetTextMetrics (hdc, &tm);
xChar = tm.tmAveCharWidth;//保存字體平均寬度
yChar = tm.tmHeight; //保存字體高度
ReleaseDC (hwnd, hdc);
rc.top = 3 * yChar / 2;
return 0;
case WM_SIZE://處理窗口大小改變的消息
//窗體改變後保存新的滾屏區域右下角坐標
rc.right = LOWORD (lParam);
rc.bottom = HIWORD (lParam);
UpdateWindow (hwnd);
return 0;
case WM_PAINT: //處理窗口重繪消息
InvalidateRect (hwnd, NULL, TRUE);
hdc = BeginPaint (hwnd, &ps);
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT)) ;
SetBkMode (hdc, TRANSPARENT) ;
TextOut (hdc, xChar, yChar / 2, szTop, (sizeof szTop) - 1) ;
TextOut (hdc, xChar, yChar / 2, szUnd, (sizeof szUnd) - 1) ;
EndPaint (hwnd, &ps);
return 0;
case WM_KEYDOWN:
//處理鍵盤上某一鍵按下的消息
ShowKey (hwnd, 0, "WM_KEYDOWN",wParam, lParam);
return 0;
case WM_KEYUP:
//處理鍵盤上某一按下鍵被釋放的消息
ShowKey (hwnd, 0, "WM_KEYUP", wParam, lParam);
return 0;
case WM_CHAR:
//處理擊鍵過程中產生的非系統鍵的可見字元消息
howKey (hwnd, 1, "WM_CHAR", wParam, lParam);
return 0;
case WM_DEADCHAR:
//處理擊鍵過程中產生的非系統鍵"死字元"消息
ShowKey (hwnd, 1, "WM_DEADCHAR", wParam, lParam);
return 0;
case WM_SYSKEYDOWN:
//處理系統鍵按下的消息
ShowKey (hwnd, 0, "WM_SYSKEYDOWN",wParam, lParam);
break;
case WM_SYSKEYUP:
//處理系統鍵抬起的消息
ShowKey (hwnd, 0, "WM_SYSKEYUP", wParam, lParam);
break;
case WM_SYSCHAR://處理系統鍵可見字元消息
ShowKey (hwnd, 1, "WM_SYSCHAR", wParam, lParam);
break;
case WM_SYSDEADCHAR://處理系統鍵"死字元"消息
ShowKey (hwnd, 1, "WM_SYSDEADCHAR", wParam, lParam);
break;
case WM_DESTROY:
//處理結束應用程序的消息
PostQuitMessage (0);
return 0;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam);
}
//函數:MyRegisterClass
//作用:注冊窗口類
BOOL MyRegisterClass(HINSTANCE hInstance)
{
wnd.cbSize= sizeof (wnd);
wnd.style = CS_HREDRAW | CS_VREDRAW;
wnd.lpfnWndProc = WndProc;
wnd.cbClsExtra = 0;
wnd.cbWndExtra = 0;
wnd.hInstance = hInstance;
wnd.hIcon = LoadIcon (NULL, IDI_APPLICATION);?
wnd.hCursor = LoadCursor (NULL, IDC_ARROW);
wnd.hbrBackground = (HBRUSH)
GetStockObject (WHITE_BRUSH);
wnd.lpszMenuName = NULL;
wnd.lpszClassName = szAppName;
wnd.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
return RegisterClassEx (&wnd);
}
//函數:InitInstance
//作用:創建主窗口
BOOL InitInstance(HINSTANCE hInstance,int iCmdShow)
{
HWND hwnd;
hwnd = CreateWindow (szAppName,
"鍵盤消息監視程序",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL
);
if(!hwnd)
{
return FALSE;
}
ShowWindow (hwnd, iCmdShow);
UpdateWindow (hwnd);
return TRUE;
}
『貳』 c語言怎樣判斷鍵盤按鍵的按下、釋放
C語言判斷鍵盤按下和釋放,是通過檢測該鍵的狀態來實現的。如果是單一的一個按鍵,那麼直接檢測該鍵是「1」還是「0」,就可以確定是按下還是釋放。如果是矩陣鍵盤,那麼需要發送掃描碼,再檢測輸入值,來判斷鍵盤中鍵的狀態。以下舉例說明:
bitkeychk()//單一按鍵檢測
{
if(P1.0==0)//如果鍵按下
{
delay();//延時去抖
if(P1.0==0)return(1);//返回鍵狀態
}
return(0);
}
unsignedcharkbscan(void)//矩陣掃描按鍵檢測
{
unsignedcharsccode,recode;
P1=0x0f;//發0掃描,列線輸入
if((P2&0x0f)!=0x0f)//有鍵按下
{
delay(20);//延時去抖動
if((P1&0x0f)!=0x0f)
{
sccode=0xef;//逐行掃描初值
while((sccode&0x01)!=0)
{
P1=sccode;
if((P1&0x0f)!=0x0f)
{
recode=(P1&0x0f)|0xf0;
while((P1&0x0f)!=0x0f);//等待鍵抬起
return((~sccode)+(~recode));
}
else
sccode=(sccode<<1)|0x01;
}
}
}
return0;//無鍵按下,返回0
}
『叄』 求C語言中各鍵值
鍵盤掃描碼
[編輯本段]定義
鍵盤上的每一個鍵都有兩個唯一的數值進行標志。為什麼要用兩個數值而不是一個數值呢?這是因為一個鍵可以被按下,也可以被釋放。當一個鍵按下時,它們產生一個唯一的數值,當一個鍵被釋放時,它也會產生一個唯一的數值,我們把這些數值都保存在一張表裡面,到時候通過查表就可以知道是哪一個鍵被敲擊,並且可以知道是它是被按下還是被釋放了。這些數值在系統中被稱為鍵盤掃描碼
[編輯本段]掃描碼大全
掃描碼 鍵
0x011b ESC
0x3b00 F1
0x3c00 F2
0x3d00 F3
0x3e00 F4
0x3f00 F5
0x4000 F6
0x4100 F7
0x4200 F8
0x4300 F9
0x4400 F10
主鍵盤區:
0x2960 ~
0x0231 1
0x0332 2
0x0433 3
0x0534 4
0x0635 5
0x0736 6
0x0837 7
0x0938 8
0x0a39 9
0x0b30 0
0x0c2d -
0x0d3d =
0x2b5c \
0x0e08 退格鍵
0x0f09 Tab
0x1071 q
0x1177 w
0x1265 e
0x1372 r
0x1474 t
0x1579 y
0x1675 u
0x1769 i
0x186f o
0x1970 p
0x1a5b [
0x1b5d ]
0x1e61 a
0x1f73 s
0x2064 d
0x2166 f
0x2267 g
0x2368 h
0x246a j
0x256b k
0x266c l
0x273b ;
0x2827 '
0x1c0d 回車
0x2c7a z
0x2d78 x
0x2e63 c
0x2f76 v
0x3062 b
0x316e n
0x326d m
0x332c ,
0x342e .
0x352f /
0x3920 空格鍵
0xe05b 左Win
0xe05c 右Win
0xe05d Menu
右邊數字鍵盤:
0x5200 Insert
0x4700 Home
0x4900 Page UP
0x5300 Delete
0x4f00 End
0x5100 PageDown
0x4800 上箭頭
0x4b00 左箭頭
0x5000 下箭頭
0x4d00 右箭頭
0x352f /
0x372a *
0x4a2d - (注意,這是數字鍵盤的)
0x4737 7
0x4838 8
0x4939 9
0x4b34 4
0x4c35 5
0x4d36 6
0x4e2b +
0x4f31 1
0x5032 2
0x5133 3
0x5230 0
0x532e Del
『肆』 C語言怎麼捕捉按鍵
通過鍵盤對應鍵的ASCII碼值進行獲取所按下的鍵值,從而確定所按下的具體按鍵。具體實現代碼如下:
#include<stdio.h>
#include<conio.h>
intmain()
{
intkey;
while(1)
{
key=getch();
if(key==27)break;
if(key>31&&key<127)/*如果不是特殊鍵*/
{
printf("按了%c鍵按ESC退出! ",key);
continue;
}
key=getch();
if(key==72)printf("按了上鍵按ESC退出! ");
if(key==80)printf("按了下鍵按ESC退出! ");
if(key==75)printf("按了左鍵按ESC退出! ");
if(key==77)printf("按了右鍵按ESC退出! ");
}
return0;
}
『伍』 C語言獲取按鍵信息函數
這個程序應該滿足你的要求吧。
#include <stdio.h>
#include <conio.h>
int main(void)
{
while (1)
{
if (!kbhit())
printf("1");
else
{
char c = getch();
if (c == 'a')
{
putchar('2');
getch();
}
}
}
return 0;
}
『陸』 C語言接收鍵盤的按鍵值
我來給你打出來,稍等,先佔位。
『柒』 c語言鍵盤按鍵觸發怎麼表示
可以用FlexibleButton表示。
FlexibleButton 是一個基於標准 C 語言的小巧靈活的按鍵處理庫,支持單擊、連擊、短按、長按、自動消抖,可以自由設置組合按鍵,可用於中斷和低功耗場景。
該按鍵庫解耦了具體的按鍵硬體結構,理論上支持輕觸按鍵與自鎖按鍵,並可以無限擴展按鍵數量。另外,FlexibleButton 使用掃描的方式一次性讀取所有所有的按鍵狀態,然後通過事件回調機制上報按鍵事件。
核心的按鍵掃描代碼僅有三行,沒錯,就是經典的 三行按鍵掃描演算法。使用 C 語言標准庫 API 編寫,也使得該按鍵庫可以無縫兼容任意的處理器平台,並且支持任意 OS 和 non-OS(裸機編程)。
快速體驗:
FlexibleButton 庫中提供了一個測試常式 ./examples/demo_rtt_iotboard.c,該常式基於 RT-Thread OS 進行測試,硬體平台選擇了 RT-Thread IoT Board Pandora v2.51 開發板。
當然你可以選擇使用其他的 OS,或者使用裸機測試,只需要移除 OS 相關的特性即可。
如果你使用自己的硬體平台,只需要將 FlexibleButton 庫源碼和常式加入你既有的工程下即可。
DEMO 程序說明:
該示常式序可以直接在 RT-Thread stm32l475-atk-pandora BSP 中運行,可以在該 BSP 目錄下,使用 menuconfig 獲取本軟體包。
『捌』 C語言中鍵盤每個按鍵對應的值分別是多少,例如上下左右分別是0x4800 0x5000 0x4b00 0x4d00。謝謝啦!
看一下ASCII表吧
http://ke..com/view/15482.htm
『玖』 請問下c語言從鍵盤讀入控制鍵鍵值如何實現
用bioskey()函數;在dos.h頭文件中!
函數原型:int bioskey (int cmd)
說明:bioskey()的函數原型在bios.h中
bioskey()完成直接鍵盤操作,cmd的值決定執行什麼操作。
cmd = 0:
當cmd是0,bioskey()返回下一個在鍵盤鍵入的值(它將等待到按下一個鍵)。它返回一個16位的二進制數,包括兩個不同的值。當按下一個普通鍵時,它的低8位數存放該字元的ASCII碼;對於特殊鍵(如方向鍵、F1~F12等等),低8位為0,高8位位元組存放該鍵的掃描碼。
cmd = 1:
當cmd是1,bioskey()查詢是否按下一個鍵,若按下一個鍵則返回非零值,否則返回0。
cmd = 2:
當cmd是2,bioskey()返回Shift、Ctrl、Alt、ScrollLock、NumLock、CapsLock、Insert鍵的狀態。各鍵狀態存放在返回值的低8位位元組中。
位元組位 含義
0 右邊Shift鍵狀態
1 左邊Shift鍵狀態
3 Ctrl鍵狀態
4 Alt鍵狀態
5 ScrollLock鍵狀態
6 NumLock鍵狀態
7 CapsLock鍵狀態
8 Insert鍵狀態
方向鍵可以用下面的程序啊!
#define Key_Up 0x4800/*up*/
#define Key_Down 0x5000/*down*/
#define Key_Right 0x4d00/*right*/
#define Key_Left 0x4b00/*left*/
int key=bioskey(0);
switch(key)
{
case Key_Up:/*code*/
case Key_Down:/*code*/
case Key_Left:/*code*/
case Key_Right:/*code*/
}
『拾』 c語言怎麼監聽鍵盤按鍵
在Microsoft Windows 中,鍵盤和滑鼠是兩個標準的用戶輸入源,在一些交疊的操作中通常相互補充使用。當然,滑鼠在今天的應用程序中比10年前使用得更為廣泛。甚至在一些應用程序中,我們更習慣於使用滑鼠,例如在游戲、畫圖程序、音樂程序,以及Web創覽器等程序中就是這樣。然而,我們可以不使用滑鼠,但絕對不能從一般的PC中拆掉鍵盤。
Windows程序獲得鍵盤輸入的方式:鍵盤輸入以消息的形式傳遞給程序的窗口過程。實際上,第一次學習消息時,鍵盤就是一個明顯的例子:消息應該傳遞給應用程序的信息類型。
Windows用8種不同的消息來傳遞不同的鍵盤事件。這好像太多了,但是(就像我們所看到的一樣)程序可以忽略其中至少一半的消息而不會有任何問題。並且,在大多數情況下,這些消息中包含的鍵盤信息會多於程序所需要的。處理鍵盤的部分工作就是識別出哪些消息是重要的,哪些是不重要的。
鍵盤基礎知識
雖然應用程序在很多情況下可以通過滑鼠實現信息的輸入,但到現在為止鍵盤仍然是PC機中不可替代的重要輸入設備。
用鍵盤當作輸入設備,每當用戶按下或釋放某一個鍵時,會產生一個中斷,該中斷激活鍵盤驅動程序KEYBOARD.DRV來對鍵盤中斷進行處理。 KEYBOARD.DRV程序會根據用戶的不同操作進行編碼,然後調用Windows用戶模塊USER.EXE生成鍵盤消息,並將該消息發送到消息隊列中等候處理。
1.掃描碼和虛擬碼
掃描碼對應著鍵盤上的不同鍵,每一個鍵被按下或釋放時,都會產生一個唯一的掃描碼作為本身的標識。掃描碼依賴於具體的硬體設備,即當相同的鍵被按下或釋放時,在不同的機器上可能產生不同的掃描碼。在程序中通常使用由Windows系統定義的與具體設備無關的虛擬碼。在擊鍵產生掃描碼的同時,鍵盤驅動程序KEYBOARD.DRV截取鍵的掃描碼,然後將其翻譯成對應的虛擬碼,再將掃描碼和虛擬碼一齊編碼形成鍵盤消息。所以,最後發送到消息隊列的鍵盤消息中,既包含了掃描碼又包含了虛擬碼。
經常使用的虛擬碼在WINDOWS.H文件中定義,常用虛擬碼的數值、常量符號和含義如表所示。
取值(16進制) 常量符號 含義
01 VK_LBUTTON 滑鼠左鍵
02 VK_RBUTTON 滑鼠右鍵
03 VK_CANCEL Break中斷鍵
04 VK_MBUTTON 滑鼠中鍵
05-07 -- 未定義
08 VK_BACK (BackSpace)鍵
09 VK_TAB Tab鍵
0A-0B -- 未定義
0C VK_CLEAR Clear鍵
0D VK_RETURN Enter鍵
0E-0F -- 未定義
10 VK_SHIFT Shift鍵
11 VK_CONTROL Ctrl鍵
12 VK_MENU Alt鍵
13 VK_PAUSE Pause鍵
14 VK_CAPTIAL CapsLock鍵
15-19 -- 漢字系統保留
1A -- 未定義
1B VK_ESCAPE Esc鍵
1C-1F -- 漢字系統保留
20 VK_SPACE 空格鍵
21 VK_PRIOR PageUp鍵
22 VK_NEXT PageDown鍵
23 VK_END End鍵
24 VK_HOME Home鍵
25 VK_LEFT ←(Left Arrow)鍵
26 VK_UP ↑(Up Arrow)鍵
27 VK_RIGHT →(Right Arrow)鍵
28 VK_DOWN ↓(Down Arrow)鍵
29 VK_SELECT Select鍵
2A -- OEM保留
2B VK_EXECUTE Execute鍵
2C VK_SNAPSHOT Print Screen鍵
2D VK_INSERT Insert鍵
2E VK_DELETE Delete鍵
2F VK_HELP Help鍵
30-39 VK_0-VK_9 數字鍵0-9
3A-40 -- 未定義
41-5A VK_A-VK_Z 字母鍵A-Z
5B-5F -- 未定義
60-69 VK_NUMPAD0-VK_NUMPAD9 小鍵盤數字鍵0-9
6A VK_MULTIPLY *(乘號)鍵
6B VK_ADD +(加號)鍵
6C VK_SEPAPATOR 分隔符鍵
6E VK_SUBTRACT -(減號)鍵
6F VK_DECIMAL .(小數點)鍵
70-87 VK_DIVIDE /(除號)鍵
88-8F VK_F1-VK_F24 F1-F24功能鍵
90 VK_NUMBERLOCK Number lock鍵
91 VK_SCROLL Scroll lock鍵
92-B9 -- 未定義
BA-C0 -- OEM保留
C1-DA -- 未定義
DB_E4 -- OEM保留
E5 -- 未定義
E6 -- OEM保留
E7-E8 -- 未定義
E9-F5 -- OEM保留
F6-FE -- 未定義
2.輸入焦點
同一時刻,Windows中可能有多個不同的程序在運行,也就是說有多個窗口同時存在。這時,鍵盤由多個窗口共享,但只有一個窗口能夠接收到鍵盤消息,這個能夠接收鍵盤消息的窗口被稱為擁有輸入焦點的窗口。
擁有輸入焦點的窗口應該是當前的活動窗口,或者是活動窗口的子窗口,其標題和邊框會以高亮度顯示,以區別於其他窗口。擁有輸入焦點的也可以是圖標而不是窗口,此時,Windows也將消息發送給圖標,只是消息的格式略有不同。
窗口過程可以通過發送WM_SETFOCUS和 WM_KILLFOCUS消息使窗體獲得或失去輸入焦點。程序也可以通過捕獲WM_SETFOCUS和WM_KILLFOCUS消息來判斷窗體何時獲得或失去輸入焦點。其中WM_SETFOCUS消息表示窗口正獲得輸入焦點,WM_ KILLFOCUS消息表示窗口正失去輸入焦點。
3.鍵盤消息
鍵盤消息分為系統鍵消息和非系統鍵消息。系統鍵消息是指由Aft鍵和其他鍵組合而產生的按鍵消息。當系統鍵被按下時產生WM_ SYSKEYDOWN消息,當系統鍵被釋放時產生WM_SYSKEYUP消息。 Aft鍵與其他鍵形成的組合鍵通常用於對程序菜單和系統菜單進行選擇,或用於在不同的程序之間進行切換。因此,系統鍵消息應該交由Windows進行處理,用戶所編制的程序一般不處理系統鍵消息,而是將這些消息交由DefWindowProc函數進行處理。如果用戶想對系統鍵消息進行處理,應該在處理完這些消息後,再將其發送給DefWindowProc函數,使得Windows系統能夠正常工作。
某些擊鍵消息可以被轉換成字元消息,例如字母鍵、數字鍵等。而有些鍵只能產生按鍵消息而沒有字元消息,例如 Shift鍵、Insert鍵等。消息循環中的 TranslateMessage函數可以實現從擊鍵消息向字元消息的轉化。當GetMessage函數捕獲一個WM_SYSKEYDOWN消息或 WM_KEYDOWN消息後,TranslateMessage函數判斷產生該消息的鍵是否能夠被轉換成字元消息,如果能,就將該消息轉換成字元消息,再通過DispatchMessape函數將轉換後的字元消息發送到消息隊列中去。字元消息共有以下四種,如表所示。
字元 系統字元 非系統字元
普通字元 WM_SYSCHAR WM_CHAR
死字元 WM_SYSDEADCHAR WM_DEADCHAR
其中死字元是由某些特殊鍵盤上的按鍵所造成的,Windows一般忽略死字元所產生的消息。
Windows的消息一般是通過一個MSG結構體變數傳送給消息處理函數的。對於鍵盤消息, MSG結構體變數的各個域中較重要的是lParam域和 wParam域。wParam域用於保存按鍵的虛擬鍵代碼或字元的ASCII碼。對於非字元消息,wParam域保存按鍵的虛擬健代碼;對於字元消息, wParam域不保存字元的ASCII碼。lParam域則用於保存擊鍵時產生的附加信息,實際上一個32位的lParam變數被分為六部分,記錄了以下相關信息:重復次數、OEM掃描碼、擴展鍵標志、關聯鍵標志、前一擊鍵狀態和轉換狀態。lParam域各位的含義如表所示。
位數 含義
0-15 擊鍵重復次數累加
16-23 OEM掃描碼
24 是否為擴展鍵
25-28 未定義
29 是否便用關聯鍵,及Alt鍵是否同時按下。
30 前一次擊鍵狀態,0表示該鍵前一次狀態為抬起,1表示前一次狀態為按下
31 轉換狀態
按鍵的次序不同,產生的消息也不相同。例如,按下並釋放1鍵,讀過程依次產生如表所示三條消息。按下1鍵所產生的消息和wParam的取值
消息 wParam變數取值
WM_KEYDOWN 虛擬碼1
WM_CHAR ASCII碼「1」
WM_KEYUP 虛擬碼1
如果按下Shift鍵後再按下1鍵並釋放,則依次產生如表所示的消息。按下 Shift鍵後按 1健所產生的消息和 wParam的取值
消息 wParam變數取值
WM_KEYDOWN 虛擬碼 VK_SHIFT
WM_KEYDOWN 虛擬碼 VK_1
WM_CHAR ASCII碼「1」
WM_KEYUP 虛擬碼 VK_1
WM_KEYUP 虛擬碼 VK_SHIF鍵盤應用實例
下面通過一個應用程序實例來說明在實際編程中如何處理鍵盤消息。#include<windows.h>
#include<stdio.h>
//全局變數
RECTrc;//記錄滾屏的矩形區域
?
intxChar,yChar;//文本輸入點坐標
WNDCLASSEXwnd;//窗口類結構變數
charszAppName[]="鍵盤消息監視程序";//窗口類名
//函數聲明
LRESULTCALLBACKWndProc(HWND,UINT,WPARAM,LPARAM);
BOOLMyRegisterClass(HINSTANCEhInstance);
BOOLInitInstance(HINSTANCEhInstance,intiCmdShow);
//函數:WinMain
//作用:入口函數
intWINAPIWinMain(HINSTANCEhInstance,HINSTANCEhPrevInstance,LPSTRszCmdLine,intiCmdShow)
{
MSGmsg;
if(!MyRegisterClass(hInstance))
{
returnFALSE;
}
if(!InitInstance(hInstance,iCmdShow))
{
returnFALSE;
}
while(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
returnmsg.wParam;
}
//函數:ShowKey
//作用:實現在窗口中顯示按鍵信息
voidShowKey(HWNDhwnd,intiType,char*szMessage,WPARAMwParam,LPARAMlParam)
{
staticchar*szFormat[2]={"%-14s%3d%c%6u%4d%5s%5s%6s%6s",
"%-14s%3d%c%6u%4d%5s%5s%6s%6s"};
charszBuffer[80];
HDChdc;
ScrollWindowEx(hwnd,0,-yChar,&rc,&rc,NULL,NULL,SW_INVALIDATE);
hdc=GetDC(hwnd);
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
TextOut(hdc,
xChar,
rc.bottom-yChar,
szBuffer,
wsprintfszBuffer,
szFormat[iType],
szMessage,//消息
wParam,//虛擬鍵代碼
(BYTE)(iType?wParam:『』),//顯示字元值
LOWORD(lParam),//重復次數
HIWORD(lParam)&0xFF,//OEM鍵盤掃描碼
//判斷是否為增強鍵盤的擴展鍵
(PSTR)(0x01000000&lParam?「是」:「否」),
//判斷是否同時使用了ALT鍵
(PSTR)(0x20000000&lParam?「是」:「否」),
(PSTR)(0x40000000&lParam?「按下」:「抬」),
//判斷前一次擊鍵狀
(PSTR)(0x80000000&lParam?「按下」:「抬起」))
//判斷轉換狀態?
);
ReleaseDC(hwnd,hdc);?
ValidateRect(hwnd,NULL);?
}
//函數:WndProc
//作用:處理主窗口的消息
LRESULTCALLBACKWndProc(HWNDhwnd,UINTiMsg,WPARAMwParam,LPARAMlParam)
{
staticcharszTop[]="消息鍵字元重復數掃描碼擴展碼ALT前一狀態轉換狀態";
staticcharszUnd[]="______________________________________________";
//在窗口中輸出文字作為信息標題
HDChdc;
PAINTSTRUCTps;
TEXTMETRICtm;
switch(iMsg)
{
caseWM_CREATE://處理窗口創建的消息
hdc=GetDC(hwnd);//設定字體
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));//檢取當前字體的度量數據
GetTextMetrics(hdc,&tm);
xChar=tm.tmAveCharWidth;//保存字體平均寬度
yChar=tm.tmHeight;//保存字體高度
ReleaseDC(hwnd,hdc);
rc.top=3*yChar/2;
return0;
caseWM_SIZE://處理窗口大小改變的消息
//窗體改變後保存新的滾屏區域右下角坐標
rc.right=LOWORD(lParam);
rc.bottom=HIWORD(lParam);
UpdateWindow(hwnd);
return0;
caseWM_PAINT://處理窗口重繪消息
InvalidateRect(hwnd,NULL,TRUE);
hdc=BeginPaint(hwnd,&ps);
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
SetBkMode(hdc,TRANSPARENT);
TextOut(hdc,xChar,yChar/2,szTop,(sizeofszTop)-1);
TextOut(hdc,xChar,yChar/2,szUnd,(sizeofszUnd)-1);
EndPaint(hwnd,&ps);
return0;
caseWM_KEYDOWN:
//處理鍵盤上某一鍵按下的消息
ShowKey(hwnd,0,"WM_KEYDOWN",wParam,lParam);
return0;
caseWM_KEYUP:
//處理鍵盤上某一按下鍵被釋放的消息
ShowKey(hwnd,0,"WM_KEYUP",wParam,lParam);
return0;
caseWM_CHAR:
//處理擊鍵過程中產生的非系統鍵的可見字元消息
howKey(hwnd,1,"WM_CHAR",wParam,lParam);
return0;
caseWM_DEADCHAR:
//處理擊鍵過程中產生的非系統鍵"死字元"消息
ShowKey(hwnd,1,"WM_DEADCHAR",wParam,lParam);
return0;
caseWM_SYSKEYDOWN:
//處理系統鍵按下的消息
ShowKey(hwnd,0,"WM_SYSKEYDOWN",wParam,lParam);
break;
caseWM_SYSKEYUP:
//處理系統鍵抬起的消息
ShowKey(hwnd,0,"WM_SYSKEYUP",wParam,lParam);
break;
caseWM_SYSCHAR://處理系統鍵可見字元消息
ShowKey(hwnd,1,"WM_SYSCHAR",wParam,lParam);
break;
caseWM_SYSDEADCHAR://處理系統鍵"死字元"消息
ShowKey(hwnd,1,"WM_SYSDEADCHAR",wParam,lParam);
break;
caseWM_DESTROY:
//處理結束應用程序的消息
PostQuitMessage(0);
return0;
}
returnDefWindowProc(hwnd,iMsg,wParam,lParam);
}
//函數:MyRegisterClass
//作用:注冊窗口類
BOOLMyRegisterClass(HINSTANCEhInstance)
{
wnd.cbSize=sizeof(wnd);
wnd.style=CS_HREDRAW|CS_VREDRAW;
wnd.lpfnWndProc=WndProc;
wnd.cbClsExtra=0;
wnd.cbWndExtra=0;
wnd.hInstance=hInstance;
wnd.hIcon=LoadIcon(NULL,IDI_APPLICATION);?
wnd.hCursor=LoadCursor(NULL,IDC_ARROW);
wnd.hbrBackground=(HBRUSH)
GetStockObject(WHITE_BRUSH);
wnd.lpszMenuName=NULL;
wnd.lpszClassName=szAppName;
wnd.hIconSm=LoadIcon(NULL,IDI_APPLICATION);
returnRegisterClassEx(&wnd);
}
//函數:InitInstance
//作用:創建主窗口
BOOLInitInstance(HINSTANCEhInstance,intiCmdShow)
{
HWNDhwnd;
hwnd=CreateWindow(szAppName,
"鍵盤消息監視程序",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL
);
if(!hwnd)
{
returnFALSE;
}
ShowWindow(hwnd,iCmdShow);
UpdateWindow(hwnd);
returnTRUE;
}