iczelion tut7 (转)

iczelion tut7 (转)[@more@]

 

第七课 处理鼠标输入消息


本课中我们将学习如何在我们的窗口过程 函数中处理鼠标按键消息。示例 程序演示了如何等待左键按下消息,我们将在按下的位置显示一个字符串。

理论:

和处理键盘输入一样, windows将捕捉鼠标动作并把它们发送到相关窗口。这些活动包括左、右键按下、移动、双击等(译者注:新式鼠标还包括滚轮消息WM_WHEEL)。WINDOWS并不像处理键盘输入那样把所有的鼠标消息都导向有输入焦点的窗口,任何鼠标经过的窗口都将接收到鼠标消息,无论有否输入焦点。另外,窗口还会接收到鼠标在非客户区移动的消息(WM_NCMOVE),但大多数的情况下我们都会将其忽略掉。 对鼠标的每一个按钮都有两个消息:WM_LBUTTONDOWN,WM_RBUTTONDOWN 。对于三键鼠标还会有WM_MBUTTONDOWN和WM_MBUTTONUP消息,当鼠标在某窗口客户区移动时,该窗口将接收到WM_MOUSEMOVE消息。一个窗口若想处理WM_LBUTTON dbCLK或 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 masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
include masm32includegdi32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.lib
includelib masm32libgdi32.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()函数来计算的。


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10752043/viewspace-990280/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10752043/viewspace-990280/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值