[DirectX 11] 7. Mouse Input (마우스 입력)

psj98·2022년 11월 15일
0
post-thumbnail

개요

이전 단계인 "6. Keyboard Input (키보드 입력)" 에서는 Keyboard 이벤트를 처리했습니다.

이번 단계에서는 Mouse 이벤트를 처리하려고 합니다.


MouseEvent

  • 구조체로 마우스의 좌표인 x, y를 선언합니다.
  • 마우스 이벤트 타입을 Enum으로 선언합니다.
  • 마우스 이벤트에 따라 type과 key를 지정합니다.

MouseEvent.h

#pragma once

/* 마우스의 x, y좌표 */
struct MousePoint
{
	int x;
	int y;
};

class MouseEvent
{
public:
	/* 마우스 이벤트 타입 */
	enum EventType
	{
		LPress,    // 왼쪽 버튼 누르기
		LRelease,  // 왼쪽 버튼 떼기
		RPress,    // 오른쪽 버튼 누르기
		RRelease,  // 오른쪽 버튼 떼기
		MPress,    // 휠 버튼 누르기
		MRelease,  // 휠 버튼 떼기
		WheelUp,   // 휠 올리기
		WheelDown, // 휠 내리기
		Move,      // 마우스 움직임
		RAW_MOVE,  // 8번에서 할 예정
		Invalid
	};
private:
	EventType type;
	int x;
	int y;

public:
	MouseEvent();
	MouseEvent(const EventType type, const int x, const int y);
	bool IsValid() const;
	EventType GetType() const;
	MousePoint GetPos() const;
	int GetPosX() const;
	int GetPosY() const;
};

MouseEvent.cpp

#include "MouseEvent.h"

// MouseClass의 mouseBuffer에 값이 없는 경우
MouseEvent::MouseEvent()
	:
	type(EventType::Invalid),
	x(0),
	y(0)
{}

// MouseClass의 mouseBuffer에 값이 있는 경우
MouseEvent::MouseEvent(EventType type, int x, int y)
	:
	type(type),
	x(x),
	y(y)
{}

bool MouseEvent::IsValid() const
{
	return this->type != EventType::Invalid;
}

// MouseEvent의 현재 타입을 가져오는 함수
MouseEvent::EventType MouseEvent::GetType() const
{
	return this->type;
}

// 마우스의 현재 x, y좌표를 가져오는 함수
MousePoint MouseEvent::GetPos() const
{
	return { this->x, this->y };
}

// 마우스의 현재 x좌표를 가져오는 함수
int MouseEvent::GetPosX() const
{
	return this->x;
}

// 마우스의 현재 y좌표를 가져오는 함수
int MouseEvent::GetPosY() const
{
	return this->y;
}

MouseClass

  • 모든 마우스 버튼의 상태와 좌표를 초기화합니다.
  • 마우스 상태에 따라 mouseBuffer에 마우스 이벤트 타입, x, y 좌표를 저장합니다.

MouseClass.h

#pragma once
#include "MouseEvent.h"
#include <queue>

using namespace std;

class MouseClass
{
public:
	/* 각 타입에 따라 mouseBuffer에 마우스 이벤트 타입, x, y 좌표 저장 */
	void OnLeftPressed(int x, int y);
	void OnLeftReleased(int x, int y);
	void OnRightPressed(int x, int y);
	void OnRightReleased(int x, int y);
	void OnMiddlePressed(int x, int y);
	void OnMiddleReleased(int x, int y);
	void OnWheelUp(int x, int y);
	void OnWheelDown(int x, int y);
	void OnMouseMove(int x, int y);

	/* 마우스 버튼이 눌렸는지 체크하는 함수 */
	bool IsLeftDown();
	bool IsMiddleDown();
	bool IsRightDown();

	/* 마우스의 좌표를 가져오는 함수 */
	int GetPosX();
	int GetPosY();
	MousePoint GetPos();

	bool MouseBufferIsEmpty(); // mouseBuffer가 비어있는지 체크하는 함수
	MouseEvent ReadEvent(); // mouseBuffer의 비어있는지 여부에 따라 MouseEvent 타입을 반환

private:
	queue<MouseEvent> mouseBuffer; // MouseEvent 타입을 저장하는 queue
    
    /* 마우스 버튼이 눌렸는지 체크하는 변수 */
	bool leftIsDown = false;
	bool rightIsDown = false;
	bool mbuttonDown = false;
    
    /* 마우스의 x, y좌표 */
	int x = 0;
	int y = 0;
};

MouseClass.cpp

#include "MouseClass.h"

/* 왼쪽 버튼이 눌렸을 때 */
void MouseClass::OnLeftPressed(int x, int y)
{
	this->leftIsDown = true;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::LPress, x, y));
}

/* 왼쪽 버튼이 떼졌을 때 */
void MouseClass::OnLeftReleased(int x, int y)
{
	this->leftIsDown = false;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::LRelease, x, y));
}

/* 오른쪽 버튼이 눌렸을 때 */
void MouseClass::OnRightPressed(int x, int y)
{
	this->rightIsDown = true;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::RPress, x, y));
}

/* 오른쪽 버튼이 떼졌을 때 */
void MouseClass::OnRightReleased(int x, int y)
{
	this->rightIsDown = false;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::RRelease, x, y));
}

/* 휠 버튼이 눌렸을 때 */
void MouseClass::OnMiddlePressed(int x, int y)
{
	this->mbuttonDown = true;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::MPress, x, y));
}

/* 휠 버튼이 떼졌을 때 */
void MouseClass::OnMiddleReleased(int x, int y)
{
	this->mbuttonDown = false;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::MRelease, x, y));
}

/* 휠을 올렸을 때 */
void MouseClass::OnWheelUp(int x, int y)
{
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::WheelUp, x, y));
}

/* 휠을 내렸을 때 */
void MouseClass::OnWheelDown(int x, int y)
{
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::WheelDown, x, y));
}

/* 마우스를 움직였을 때 */
void MouseClass::OnMouseMove(int x, int y)
{
	this->x = x;
	this->y = y;
	this->mouseBuffer.push(MouseEvent(MouseEvent::EventType::Move, x, y));
}

/* 왼쪽 버튼이 눌렸는지 체크하는 함수 */
bool MouseClass::IsLeftDown()
{
	return this->leftIsDown;
}

/* 휠 버튼이 눌렸는지 체크하는 함수 */
bool MouseClass::IsMiddleDown()
{
	return this->mbuttonDown;
}

/* 오른쪽 버튼이 눌렸는지 체크하는 함수 */
bool MouseClass::IsRightDown()
{
	return this->rightIsDown;
}

/* 마우스의 x좌표를 가져오는 함수 */
int MouseClass::GetPosX()
{
	return this->x;
}

/* 마우스의 y좌표를 가져오는 함수 */
int MouseClass::GetPosY()
{
	return this->y;
}

/* 마우스의 좌표를 가져오는 함수 */
MousePoint MouseClass::GetPos()
{
	return{ this->x, this->y };
}

/* mouseBuffer가 비어있는지 체크하는 함수 */
bool MouseClass::MouseBufferIsEmpty()
{
	return this->mouseBuffer.empty();
}

/* mouseBuffer의 비어있는지 여부에 따라 MouseEvent 타입을 반환 */
MouseEvent MouseClass::ReadEvent()
{
	if (this->mouseBuffer.empty())
	{
		return MouseEvent();
	}
	else
	{
		MouseEvent e = this->mouseBuffer.front(); // queue의 front에서 값을 가져옴
		this->mouseBuffer.pop(); // front 값을 삭제
		return e;
	}
}

WindowContainer

WindowContainer.h

#pragma once
#include "RenderWindow.h"
#include "Keyboard/KeyboardClass.h"
#include "Mouse/MouseClass.h" // 추가

class WindowContainer
{
public:
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
	RenderWindow render_window;
	KeyboardClass keyboard;
	MouseClass mouse; // 추가
private:

};
  • MouseClass 타입의 mouse 변수 선언

WindowContainer.cpp

#include "WindowContainer.h"

LRESULT WindowContainer::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	/* -- 키보드 메시지 -- */
	/* 이전과 동일 */

	/* -- 마우스 메시지 -- */
    /* 마우스 커서가 이동할 때 */
	case WM_MOUSEMOVE:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnMouseMove(x, y);
		return 0;
	}

	/* 마우스 왼쪽 버튼이 눌렸을 때 */
	case WM_LBUTTONDOWN:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnLeftPressed(x, y);
		return 0;
	}
	
    /* 마우스 오른쪽 버튼이 눌렸을 때 */
	case WM_RBUTTONDOWN:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnRightPressed(x, y);
		return 0;
	}

	/* 마우스 휠 버튼이 눌렸을 때 */
	case WM_MBUTTONDOWN:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnMiddlePressed(x, y);
		return 0;
	}

	/* 마우스 왼쪽 버튼이 떼졌을 때 */
	case WM_LBUTTONUP:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnLeftReleased(x, y);
		return 0;
	}

	/* 마우스 오른쪽 버튼이 떼졌을 때 */
	case WM_RBUTTONUP:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnRightReleased(x, y);
		return 0;
	}

	/* 마우스 휠 버튼이 떼졌을 때 */
	case WM_MBUTTONUP:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
		mouse.OnMiddleReleased(x, y);
		return 0;
	}

	/* 마우스 휠을 회전할 때 */
	case WM_MOUSEWHEEL:
	{
		int x = LOWORD(lParam);
		int y = HIWORD(lParam);
        
        // 값이 0보다 크면, 휠을 올림
		if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
		{
			mouse.OnWheelUp(x, y);
		}
        
        // 값이 0보다 작으면, 휠을 내림
		else if (GET_WHEEL_DELTA_WPARAM(wParam) < 0)
		{
			mouse.OnWheelDown(x, y);
		}
        
		return 0;
	}

	default:
		/* 처리되지 않은 모든 메시지의 디폴트 처리를 수행 */
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
}

각 마우스의 이벤트에 따라 MouseClass의 함수를 실행하고 x, y좌표를 전달합니다.


Engine

Engine.cpp

#include "Engine.h"

/* 동일 */

void Engine::Update()
{
	/* 동일 */

	while (!mouse.MouseBufferIsEmpty())
	{
		MouseEvent me = mouse.ReadEvent();

		/* 마우스 x, y좌표 테스트 */
		string outmsg = "X : ";
		outmsg += to_string(me.GetPosX());
		outmsg += ", Y : ";
		outmsg += to_string(me.GetPosY());
		outmsg += "\n";
		OutputDebugStringA(outmsg.c_str());

		/* 마우스 휠 클릭 테스트 */
		if (me.GetType() == MouseEvent::EventType::MPress)
		{
			OutputDebugStringA("Mouse MPress\n");
		}

		else if (me.GetType() == MouseEvent::EventType::MRelease)
		{
			OutputDebugStringA("Mouse MReleased\n");
		}
	}
}
  • 마우스 이벤트가 잘 작동하는지 확인하기 위한 테스트

필요한 부가적인 정보

  • wParam
    • 논리형이며 키 값이 눌러졌는지 상태 확인
    • 핸들 또는 정수를 받아들일 때 주로 사용
  • lParam
    • 좌표의 의미를 가지며, 4byte로 이루어져 있음
    • 2byte씩 잘라서 x, y값으로 사용
    • 포인터 값을 전달할 때 사용
  • LOWORD : X의 값
  • HIWORD : Y의 값
profile
SSAFY 9기

0개의 댓글