鍵盤和鼠標在
windows
中的重要性不必多說,地球人都知道!鍵盤上每一個有意義的鍵都對應著一個唯一的標識值,稱之為掃描碼。但是這種掃描碼是硬件相關的,為了實現設備無關性的要求,在
windows
應用程序中,使用的往往是與設備無關的虛擬碼。
對鍵盤操作的響應過程基本如下:
用戶按下一個鍵時,與鍵盤驅動程序(
KEYBOARD.DRV
)進行中斷處理并調用
windows
用戶模塊(
USER.EXE
)中的有關程序來生成鍵盤消息,然后消息被發送到系統的消息隊列中由相應的應用應用程序進行處理。鼠標的處理過程與鍵盤類似。但是注意無論是鼠標還是鍵盤的所產生的消息經過操作系統處理后都只會被發送給特定的窗口,即具有“輸入焦點”的窗口來進行處理。
?
???????????
鍵盤消息
鍵盤消息通常可分為按鍵消息和字符消息兩類,用戶按下或松開一個鍵時,就產生一個按鍵消息,當一個按鍵組合產生了一個可以顯示的字條時,就產生了一個字符消息。
按鍵消息一般又可以分為系統按鍵和非系統按鍵。
系統按鍵:是指使用了
Alt
等與相關輸入鍵組成產生的消息,一般這些消息都由操作系統內部直接處理。如果應用程序處理了這些系統鍵消息,就要調用
DefWindowProc
函數,以便不影響
windows
對它們的處理。
非系統按鍵:對應于那些不使用組合鍵的按鍵消息。
?
再對按鍵消息的兩個變量
wParam
和
lParam
做一些解釋:(名堂還真不少
T_T
)
1.????????
wParam
包含了識別按下鍵的虛鍵碼,這些碼是由系統定義的設備無關的。可以在
windows.h
中找到找到相關定義。
2.????????
lParam
32
位的變量
lParam
所表示的含義可以分為以下
7
個部分
(1)?????
重復計數位(
0~15
位)
?????
表示當前消息的重復次數。
(2)?????
OEM
掃描碼(
16~23
位)
OEM
掃描碼是鍵盤發送的碼值,因為是設備相關的幫一般被忽略掉。
(3)?????
擴展鍵標志(
24
位)
在有
Alt
或
Ctrl
鍵按下時為
1,
否則為
0
。
(4)?????
保留位(
25~28
位)
??????????
系統保留,一般不用。
(5)?????
關聯碼(
29
位)
主要用來記錄某鍵與
Alt
等鍵的組合狀態,若按下
Alt
鍵,當
WM_SYSKEYDOWN
消息發送到某個激活窗口時,其值為
1,
否則為
0
。
(6)?????
鍵的先前狀態(
30
位)
用于記錄先前某鍵的狀態。
(7)?????
轉換狀態(
31
位)
用于記錄被始終按下的某鍵所產生的消息。
?
??????
在
WinMain
函數里的消息循環中包含了
TranslateMessage
函數,它的主要功能是把按鍵消息轉化為字符消息,即把按鍵所產生的原始的KEYDOWN/KEYUP消息轉化成WM_CHAR消息。
同樣,字符消息也可以分為系統和非系統消息兩類。
?
Windows
系統支持兩類字符集:
OEM
和
ANSI
。
OEM
是
IBM
的字符集,在
windows
中使用不多,目前大多使用的是
ANSI
字符集。
?
???????????
鼠標消息
1.????????
鼠標操作
簡單的單擊操作包含了按下和松開這一全過程;而雙擊操作實際上是指用戶在知時間內(默認為
0.5
秒)的再次單擊操作。
在鼠標消息中,參數
lParam
包含了鼠標的位置,低字節是
X
坐標,高字節是
Y
坐標。參數
wParam
則包含了一個指示各種虛鍵狀態的值。
通過用戶區消息的
wParam
和
lParam
參數,程序員就可以確定鼠標的位置和狀態。
對于鼠標的消息處理,一般分為兩種,一種要對
Ctrl
等鍵進行監視,另一種則不需要。下面是一個示例
case WM_LbUTTONDWON:?????? //
鼠標按下時
ctrl
和
shift
都被按下
?????? If(( wParam&MK_CONTROL) && ( wParam&MK_SHIFT) )
?????? …
?????? break;
case WM_LBUTTONDOWN:?????? //
不監視組合按鍵
?????? …
?????? break;
此外,要使窗口能監視雙擊消息,必須在注冊窗口類的時候使該類具有
CS_DBLCLKS
屬性才行,否則只能收到兩條單擊消息。
2.????????
光標
可以使用系統光標或者調用
LoadCursor
加載自定義光標資源
???????????
示例程序
在下面的一個例子中,顯示鼠標和鍵盤的消息響應。程序的用戶區被分為四個區域,每個區域里光標設置成不同的樣式。通過監視鍵盤按鍵,可對一個
10
個字符長的緩沖區里輸入字符,并最后顯示在鼠標上方,鼠標移動時同時修改字符輸出的位置。可以按下
BACK
鍵刪掉已經輸入的字符,緩沖區滿時再輸入和空的時候刪字符的操作都被拒絕,并用消息框進行提示。代碼如下:
//
定義的靜態變量
#define
?BufSize?10
static
?
char
?lpszBuffer[BufSize];
static
?
int
?nNumChar?
=
?
0
;
static
?
int
?i?
=
?
0
;
static
?POINT?pt;
????……
LRESULT?CALLBACK?WndProc(HWND?hWnd,?UINT?iMsg,?
?????????????????????????UINT?wParam,?
?????????????????????????LONG?lParam)

{
????HDC?hdc;
????PAINTSTRUCT?ps;
????HCURSOR?hCur;
????
switch
(iMsg)

????
{
????
case
?WM_CHAR:
//
處理非系統鍵的消息
????????
if
(wParam?
==
?VK_BACK)
//
按下退格鍵
????????
{
????????????
if
(nNumChar?
==
?
0
)

????????????
{
????????????????MessageBox(hWnd,?
"
沒有字符可以刪除!
"
,?NULL,?MB_OK);
????????????}
????????????
else
????????????
{
????????????????
--
nNumChar;
????????????????
//
此函數刷新用戶區,會產生PAINT消息
????????????????InvalidateRect(hWnd,?NULL,?TRUE);
????????????}
????????????
break
;
????????}
????????
if
(nNumChar?
>=
?BufSize)
//
字符超過緩沖區大小
????????
{
????????????MessageBox(hWnd,?
"
緩沖區已滿!刪除字符請用退格鍵
"
,?NULL,?MB_OK);
????????????
break
;
????????}
????????lpszBuffer[nNumChar
++
]?
=
?(unsigned?
char
)wParam;
????????InvalidateRect(hWnd,?NULL,?TRUE);
????????
break
;
????????
????
case
?WM_PAINT:
//
將處理過的字符輸出
????????hdc?
=
?BeginPaint(hWnd,?
&
ps);
????????
//
調整坐標使字出現在鼠標上方
?????????TextOut(hdc,?pt.x
-
15
,?pt.y
-
15
,?lpszBuffer,?nNumChar);
????????EndPaint(hWnd,?
&
ps);
????????
break
;

????
case
?WM_MOUSEMOVE:
//
移動鼠標后改變文本輸出坐標并刷新
????????pt.x?
=
?LOWORD(lParam);
????????pt.y?
=
?HIWORD(lParam);
//
鼠標的坐標
????????
//
在不同的區域顯示不同的光標
????????
if
(pt.x?
<
?
400
?
&&
?pt.y?
<
?
400
)
????????????hCur?
=
?LoadCursor(NULL,?IDC_NO);
????????
else
?
if
(pt.x?
>
?
400
?
&&
?pt.y?
<
?
400
)
????????????hCur?
=
?LoadCursor(NULL,?IDC_HELP);
????????
else
?
if
(pt.x?
<
?
400
?
&
?pt.y?
>
?
400
)
????????????hCur?
=
?LoadCursor(NULL,?IDC_SIZEALL);
????????
else
?
if
(pt.x?
>
400
?
&&
?pt.y?
>
?
400
)
????????????hCur?
=
?LoadCursor(NULL,?IDC_CROSS);
????????SetCursor(hCur);
????????InvalidateRect(hWnd,?NULL,?TRUE);
????????
break
;
????
????
case
?WM_DESTROY:
????????PostQuitMessage(
0
);
????????
return
?
0
;
????
default
:
????????
return
?(DefWindowProc(hWnd,?iMsg,?wParam,?lParam));
????}
????
return
?
0
;
}