程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編教程之處理鼠標按鍵消息

匯編教程之處理鼠標按鍵消息

編輯:匯編語言

本課中我們將學習如何在我們的窗口過程函數中處理鼠標按鍵消息。示例程序演示了如何等待左鍵按下消息,我們將在按下的位置顯示一個字符串。

理論:

和處理鍵盤輸入一樣,WINDOWS將捕捉鼠標動作並把它們發送到相關窗口。這些活動包括左、右鍵按下、移動、雙擊等(譯者注:新式鼠標還包括滾輪消息WM_WHEEL)。WINDOWS並不像處理鍵盤輸入那樣把所有的鼠標消息都導向有輸入焦點的窗口,任何鼠標經過的窗口都將接收到鼠標消息,無論有否輸入焦點。另外,窗口還會接收到鼠標在非客戶區移動的消息(WM_NCMOVE),但大多數的情況下我們都會將其忽略掉。 對鼠標的每一個按鈕都有兩個消息:WM_LBUTTONDOWN,WM_RBUTTONDOWN 。對於三鍵鼠標還會有WM_MBUTTONDOWN和WM_MBUTTONUP消息,當鼠標在某窗口客戶區移動時,該窗口將接收到WM_MOUSEMOVE消息。一個窗口若想處理WM_LBUTTONDBCLK或 WM_RBUTTONDBCLK,那麼它的窗口類必須有CS_DBLCLKS風格,否則它就會接受到一堆的按鍵起落(WM_XBUTTONDOWN或WM_XBUTTONUP)的消息。 對於所有的消息,窗口過程函數傳入的參數lParam包含了鼠標的位置,其中底位為x坐標,高位為y坐標,這些坐標值都是相對於窗口客戶區的左上角的值,wParam中則包含了鼠標按鈕的狀態。

例子:

.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib
.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MouseClick db 0 ; 0=no click yet
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hitpoint POINT <>
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL hdc:HDC
LOCAL ps:PAINTSTRUCT
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_LBUTTONDOWN
mov eax,lParam
and eax,0FFFFh
mov hitpoint.x,eax
mov eax,lParam
shr eax,16
mov hitpoint.y,eax
mov MouseClick,TRUE
invoke InvalidateRect,hWnd,NULL,TRUE
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint,hWnd, ADDR ps
mov hdc,eax
.IF MouseClick
invoke lstrlen,ADDR AppName
invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
.ENDIF
invoke EndPaint,hWnd, ADDR ps
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start

分析:

.ELSEIF uMsg==WM_LBUTTONDOWN
mov eax,lParam
and eax,0FFFFh
mov hitpoint.x,eax
mov eax,lParam
shr eax,16
mov hitpoint.y,eax
mov MouseClick,TRUE
invoke InvalidateRect,hWnd,NULL,TRUE

窗口過程處理了WM_LBUTTONDOWN消息,當接收到該消息時,lParam中包含了相對於窗口客戶區左上角的坐標,我們把它保存下來,放到一個結構體變量(POINT)中,該結構體變量的定義如下:

POINT STRUCT
x dd ?
y dd ?
POINT ENDS

然後我們把標志量MouseClick設為TRUE,這表明至少有一次在客戶區的左鍵按下消息。

mov eax,lParam
and eax,0FFFFh
mov hitpoint.x,eax

由於lParam是一個32位長的數,其中高、底16位分別包括了x、y坐標所以我們做一些小處理,以便保存它們。

shr eax,16
mov hitpoint.y,eax

保存完坐標後我們設標志MouseClick為TRUE,這是在處理WM_PAINT時用來判斷是否有鼠標左鍵按下消息。然後我們調用InvalidateRect()函數迫使WINDOWS重新繪制客戶區。

.IF MouseClick
invoke lstrlen,ADDR AppName
invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
.ENDIF

繪制客戶區的代碼首先檢測MouseClick標志位,再決定是否重繪。因為我們在首次顯示窗口時還沒有左鍵按下的消息,所以我們在初始時把該標志設為FALSE,告訴WINDOWS不要重繪客戶區,當有左鍵按下的消息時,它會在鼠標按下的位置繪制字符串。注意在調用TextOut()函數時,其關於字符串長度的參數是調用lstrlen()函數來計算的。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved