Tutorial 7: Mouse Input
이번 장에서는, 윈도우 프로시저에서 마우스 메세지를 어떻게 처리하는 지를 설명한다. 예제에서는, 마우스의 왼쪽 클릭 버튼이 눌려지면, 작업영역에 문자열을 출력하는 예제이다.
소스 | 실행 결과 |
|
6장에서 살펴본 키보드 입력때와 같이, 윈도우는 마우스 이벤트가 발생할 경우 해당 윈도우에게 메세지를 전해주는 방식이다. 이런 동작에는, 왼쪽 버튼 클릭이나 오른쪽 버튼 클릭, 마우스 커서의 이동, 더블 클릭등이 있다. 다만, 포커스가 있는 윈도우에 전송하는 키보드 입력과는 다르게, 마우스 커서가 겹쳐진윈도우라면, 그 윈도우가 활성화 되지 않았더라도 마우스 메세지가 전송된다.추가로, 작업영역이 아닌 곳에서도 발생하는 마우스 메세지가 있다. 그러나, 비작업영역의 메세지를 처리하는 경우는 거의 없기 때문에, 무시해도 상관없다(DefWinProc가 처리한다). 그러므로, 작업영역에 보내진 마우스 메세지에 대해서만 초점을 맞춘다.
마우스 버튼 하나에 대해, 마우스 메세지는 2개 있다. 즉, 버튼은 최소한 2개가 있으므로, WM_LBUTTONDOWN, WM_RBUTTONDOWN 과 WM_LBUTTONUP, WM_RBUTTONUP 이라는 메세지가 존재한다. 버튼이 3개인 마우스는 WM_MBUTTONDOWN 과 WM_MBUTTONUP 이라는 마우스 메세지가 있다. 작업영역에 마우스 커서가 이동될 경우 Windows 는 그 윈도우에 WM_MOUSEMOVE 메세지를 전송하게 된다.
또한, 더블 클릭 메세지도 WM_LBUTTONDBCLK 과 WM_RBUTTONDBCLK 메세지에 의해 인식 될 수 있지만, 이경우, 윈도우 클래스의 스타일에 CS_DBLCLKS 플래그가 설정되어 있어야만 가능하다. 그렇지 않으면 단지, 두번 연속적으로 발생되는 Down->UP 메세지가 발생하는 것이다.
이런 모든 마우스 메세지에서는, lParam의 값에 마우스의 좌표값이 전달된다. 작업영역의 좌상단을 원점으로 하며 하위워드(워드 =2Byte)가 X좌표, 상위 워드가 Y좌표를 가지게 된다. wParam 에는 마우스버튼과 쉬프트 키, 컨트롤 키 상태를 나타내는 것이 저장되어 있다.(자주 사용하지는 않는다)
|
|
|
.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형은 다음과 같이 정의되어 있다.
POINT STRUCT x dd ? y dd ? POINT ENDS다음으로, MouseClick 플래그를 TRUE로 하고 있다. 이것은, 최소한 한번은 작업영역에서 왼쪽버튼을 눌렀음을 나타내고 있다.
mov eax, lParam and eax, 0FFFFh mov hitpoint.x, eaxX좌표는 lParam 의 하위 워드(16비트)이므로, POINT형이 32비트이므로, lParam의 상위워드를 클리어 해서, X좌표를 얻어서, hitpoint.x 에 대입하고 있다.
shr eax, 16 mov hitpoint.y, eaxY좌표는 lParam의 상위 워드이므로, 16비트 만큼 오른쪽으로 쉬프트 해서 상위워드를 하위워드의 위치로 쉬프트 해서 , hitpoint.y 에 대입한다.
마우스의 X, Y좌표를 얻은 후, MouseClick 플래그를 TRUE로 해서, WM_PAINT 섹션에서 작업영역에서 최소한 마우스를 한번은 클릭했다는 것을 알려주어, 만약, WM_PAINT 섹션에 들어가게 되면, 이 플래그값을 기초로 해서 마우스의 좌표에 문자열을 출력하게 된다.
다음에, InvalidateRect 함수를 호출 해서, 윈도우에 강제로 작업영역 전체의 화면 복구처리를 하도록 한다.
.IF MouseClick invoke lstrlen, ADDR AppName invoke TextOut, hdc, hitpoint.x, hitpoint.y, ADDR AppName, eax .ENDIFWM_PAINT 섹션의 출력처리는, MouseClick 플래그가 TRUE인지를 체크해야 한다. 이렇게 하지 않으면 클릭하지 않는 상태에서도 문자열을 출력해 버리기 때문이다. 그래서, 초기화할때는 MouseClick 플래그를 FALSE로 설정해서, 실제로 마우스 클릭했을 경우에만, TRUE로 설정하게 한다.
마우스를 클릭하게 되면 클릭한 마우스의 커서 위치에 문자열이 출력된다. 출력처리 전에, lstrlen 함수를 호출 해서, 출력문자열의 길이를 구해서 TextOut 함수의 마지막 인수에 넘겨줘야한다.