Programming 版 (精华区)

发信人: zhangyan (今朝有水今朝灌), 信区: Programming
标  题: Iczelion Win32汇编教程(7)
发信站: 哈工大紫丁香 (2001年02月14日16:12:17 星期三), 站内信件

第七课 处理鼠标输入消息
----------------------------------------------------------------------------
----
本课中我们将学习如何在我们的窗口过程函数中处理鼠标按键消息。示例程序演示了如
何等待左键按下消息,我们将在按下的位置显示一个字符串。
理论:
和处理键盘输入一样,WINDOWS将捕捉鼠标动作并把它们发送到相关窗口。这些活动包括
左、右键按下、移动、双击等(译者注:新式鼠标还包括滚轮消息WM_WHEEL)。WINDOWS并
不像处理键盘输入那样把所有的鼠标消息都导向有输入焦点的窗口,任何鼠标经过的窗
口都将接收到鼠标消息,无论有否输入焦点。另外,窗口还会接收到鼠标在非客户区移
动的消息(WM_NCMOVE),但大多数的情况下我们都会将其忽略掉。 对鼠标的每一个按
钮都有两个消息:WM_LBUTTONDOWN,WM_RBUTTONDOWN 。对于三键鼠标还会有WM_MBUTTON
DOWN和WM_MBUTTONUP消息,当鼠标在某窗口客户区移动时,该窗口将接收到WM_MOUSEMO
VE消息。一个窗口若想处理WM_LBUTTONDBCLK或 WM_RBUTTONDBCLK,那么它的窗口类必须
有CS_DBLCLKS风格,否则它就会接受到一堆的按键起落(WM_XBUTTONDOWN或WM_XBUTTON
UP)的消息。 对于所有的消息,窗口过程函数传入的参数lParam包含了鼠标的位置,其
中底位为x坐标,高位为y坐标,这些坐标值都是相对于窗口客户区的左上角的值,wPar
am中则包含了鼠标按钮的状态。
例子:
.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()函数来计算的。

--
Take it slow,     Set it couse,     Make it happen.

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.97.235.21]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:4.377毫秒