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

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

????
case
?WM_MOUSEMOVE:
//
移動(dòng)鼠標(biāo)后改變文本輸出坐標(biāo)并刷新
????????pt.x?
=
?LOWORD(lParam);
????????pt.y?
=
?HIWORD(lParam);
//
鼠標(biāo)的坐標(biāo)
????????
//
在不同的區(qū)域顯示不同的光標(biāo)
????????
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
;
}