全部博文(290)
分类:
2007-12-12 23:24:06
Tutorial 7: Mouse Input
We will learn how to receive and respond to mouse input in our window procedure. The example program will wait for left mouse clicks and display a text string at the exact clicked spot in the client area.
我们将要学习如何在我们的窗口程序中接收和响应鼠标输入。示例程序将等待鼠标单击事件并在客户区中鼠标点击的地方显示一个字符串。
Download the example here.
Theory:
原理:
As with keyboard input, Windows detects and sends notifications about mouse activities that are relevant to each window. Those activities include left and right clicks, mouse cursor movement over window, double clicks. Unlike keyboard input which is directed to the window that has input focus, mouse messages are sent to any window that the mouse cursor is over, active or not. In addition, there are mouse messages about the non-client area too. But most of the time, we can blissfully ignore them. We can focus on those relating to the client area.
和键盘输入一样,windows检测并发送鼠标活动消息给与之相关联的窗口.这些活动包括单击鼠标左右键,鼠标光标在窗口上移动或双击鼠标. 鼠标输入并不像键盘输入那样把注意力集中在窗口的输入焦点上.任何鼠标光标经过的窗口都将接收到鼠标消息.而不管它是不是在窗口上有活动.另外,这些鼠标消息对于非客户区也是一样,( WM_NCMOVE) 但是大多时候我们充满喜悦的忽略了它们 .( 这些客户区消息) ,这样我们能把焦点放在涉及客户区的输入上.
There are two messages for each mouse button:
每一个鼠标按钮都有两个消息:
WM_LBUTTONDOWN,WM_RBUTTONDOWN and WM_LBUTTONUP, WM_RBUTTONUP messages.
For a mouse with three buttons, there are also WM_MBUTTONDOWN and WM_MBUTTONUP. When the mouse cursor moves over the client area, Windows sends WM_MOUSEMOVE messages to the window under the cursor.
单击鼠标左键,单击鼠标右键和释放鼠标左键,释放鼠标右键消息.对于有三个按钮的鼠标,还有WM_MBUTTONDOWN和WM_MBUTTONUP消息.当鼠标光标在客户区上移动的时候,windows发送WM_MOUSEMOVE消息给在光标下的那个窗口.
A window can receive double click messages, WM_LBUTTONDBCLK or WM_RBUTTONDBCLK, if and only if its window class has CS_DBLCLKS style flag, else the window will receive only a series of mouse button up and down messages.
一个窗口可以接收鼠标双击消息, WM_LBUTTONDBCLK (左键双击事件消息) 或是WM_RBUTTONDBCLK(右键双击事件消息),如果一个窗口想接收这两个消息,那么它的窗口类必须设置CS_DBLCLKS式样。,否则这个窗口将接收到一连串的鼠标按下和释放的消息。
For all these messages, the value of lParam contains the position of the mouse. The low word is the x-coordinate, and the high word is the y-coordinate relative to upper left corner of the client area of the window. wParam indicates the state of the mouse buttons and Shift and Ctrl keys.
在所有的这些窗口中,Lparam包含鼠标的位置.低位字是X坐标,高位字是y坐标,这两个坐标值是相对于关联窗口的客户区左上角而言的.wParam用于指明鼠标按钮shift键和ctrl键的状态.
Example:
.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
Analysis:
.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
The window procedure waits for left mouse button click. When it receives WM_LBUTTONDOWN, lParam contains the coordinate of the mouse cursor in the client area. It saves the coordinate in a variable of type POINT which is defined as:
窗口程序等待鼠标左键单击事件.当它接收到WM_LBUTTONDOWM消息的时候,lparam参数中包含了在客户区中的鼠标光标的坐标值.这个值被保存在一个POINT类型的坐标变量结构中,这个结构定义如下:
POINT STRUCT
x dd ?
y dd ?
POINT ENDS
and sets the flag, MouseClick, to TRUE, meaning that there's at least a left mouse button click in the client area.
然后设置标志量MouseClick为TRUE,意思是在这个客户区中至少有一个鼠标左键单击事件发生.
mov eax,lParam
and eax,0FFFFh
mov hitpoint.x,eax
Since x-coordinate is the low word of lParam and the members of POINT structure are 32-bit in size, we have to zero out the high word of eax prior to storing it in hitpoint.x.
因为x坐标值规定存放在lparam的低字节(16位)中而我们的存放在point结构变量中的坐标值是32位的 ,所以我们必须用0填充eax的高字节(16位)并把它存贮在hitpoint.x变量中.
shr eax,16
mov hitpoint.y,eax
Because y-coordinate is the high word of lParam, we must put it in the low word of eax prior to storing it in hitpoint.y. We do this by shifting eax 16 bits to the right.
因为y坐标是在lparam的高字节中,我们通过在eax中右移16位来把eax中高位字存储在hitpoint.y中.
After storing the mouse position, we set the flag, MouseClick, to TRUE in order to let the painting code in WM_PAINT section know that there's at least a click in the client area so it can draw the string at the mouse position. Next we call InvalidateRect function to force the window to repaint its entire client area.
在储存了鼠标的位置后,我们设置mouseclick标志为TRUE是为了让在WM_PAINT消息中的绘画代码知道在客户区中至少有一个单击事件发生以便让它能将字符串绘制在鼠标点击的位置.下一步,我们将调用InvalidateRect函数来强制windows重绘它的整个客户区.
.IF MouseClick
invoke lstrlen,ADDR AppName
invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
.ENDIF
The painting code in WM_PAINT section must check if MouseClick is true, since when the window was created, it received a WM_PAINT message which at that time, no mouse click had occurred so it should not draw the string in the client area. We initialize MouseClick to FALSE and change its value to TRUE when an actual mouse click occurs.
If at least one mouse click has occurred, it draws the string in the client area at the mouse position. Note that it calls lstrlen to get the length of the string to display and sends the length as the last parameter of TextOut function.
在WM_PAINT节区的绘画代码中必须检查mouseclick是否为真.因为当窗口被创建时,它在那时接收一个WM_PAINT消息,如果没有鼠标单击事件出现,那么它就不会在客户区中绘制这个字符串.我们初始化mouseclick标志为FALSE并且当实际的鼠标单击事件发生时将它的值改为TRUE.
如果有一个鼠标单击事件发生,它将在客户区中鼠标光标的位置处绘制这个字符串.注意,它调用lstrlen函数来获得需要显示的字串长度并传递这个长度值给Textout函数的最后一个参数.
This article come from Iczelion's asm page
风向改变 翻译于 12.13日 晚