In this lesson, we'll learn how to handle mouse button messages in our window procedure functions. The sample program demonstrates how to wait for the left button to press the message, and we will display a string in the pressed position.
Theory:
As with keyboard input, Windows captures mouse actions and sends them to related windows. These activities include left and right key press, move, double-click, etc. (Translator Note: The new mouse also includes wheel message Wm_wheel). Windows does not direct all mouse messages to a window that has input focus as it does with keyboard input, and any window that passes through the mouse will receive a mouse message, regardless of whether or not the focus is entered. In addition, the window receives a message (Wm_ncmove) that the mouse moves in a non-client area, but in most cases we ignore it. There are two messages for each button on the mouse: Wm_lbuttondown,wm_rbuttondown. There will also be wm_mbuttondown and wm_mbuttonup messages for the three-button mouse, which will receive the WM_MOUSEMOVE message when the mouse is moved in a client area of a window. If a window wants to handle WM_LBUTTONDBCLK or WM_RBUTTONDBCLK, its window class must have a cs_dblclks style, otherwise it will receive a bunch of keystrokes (Wm_xbuttondown or Wm_xbuttonup) messages. For all messages, the window procedure function passes in the parameter lparam contains the mouse position, in which the bottom bit is the X coordinate, the high position is the Y coordinate, these coordinates values are relative to the window client area's upper-left corner value, wparam contains the mouse button's state.
Example:
.386
. Model Flat,stdcall
Option Casemap:none
WinMain Proto:D Word,:D Word,:D Word,:D Word
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", 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 process handles the WM_LBUTTONDOWN message, and when the message is received, the lparam contains the coordinates relative to the upper-left corner of the window client area, which we save and place in a struct variable (point), which is defined as follows:
POINT STRUCT
x dd ?
y dd ?
POINT ENDS
Then we set the flag quantity MouseClick to True, which means that at least one time in the client area the left key presses the message.
mov eax,lParam
and eax,0FFFFh
mov hitpoint.x,eax
Since LPARAM is a 32-bit long number, where the high and bottom 16 bits include the x and y coordinates, we do some small processing to save them.
shr eax,16
mov hitpoint.y,eax
After we save the coordinates, we set the flag MouseClick to True, which is used to determine if the left mouse button presses the message when handling the WM_PAINT. Then we call the InvalidateRect () function to force Windows to redraw the client area.
.IF MouseClick
invoke lstrlen,ADDR AppName
invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
.ENDIF
The code that paints the client area first detects the MouseClick flag bit and then decides whether to redraw it. Because we don't have the left-click message when we first display the window, we set the flag to false at the beginning, telling windows not to redraw the client area, and when the left-click message is clicked, it draws the string at the position of the mouse. Note that when the TextOut () function is invoked, its arguments about the length of the string are evaluated by calling the Lstrlen () function.