Win32鼠标事件

Win32鼠标事件

一.鼠标事件

鼠标事件种类分为:

1.左键按下抬起

2.右键按下抬起

3.鼠标移动(坐标)

4.滑轮上下滑动

5.鼠标进入移出客户区

对应的事件代码如下:

class Event
{
public:
	enum class Type
	{
		LPress,
		LRelease,
		RPress,
		RRelease,
		WheelUp,
		WheelDown,
		Move,	
        Enter,
		Leave,
		Invalid
	};
private:
	Type type;
	bool leftIsPressed;
	bool rightIsPressed;
	int x;
	int y;
public:
	Event() noexcept
		:
		type(Type::Invalid),
		leftIsPressed(false),
		rightIsPressed(false),
		x(0),
		y(0)
	{}	
    Event( Type type,const Mouse& parent ) noexcept
		:
		type( type ),
		leftIsPressed( parent.leftIsPressed ),
		rightIsPressed( parent.rightIsPressed ),
		x( parent.x ),
		y( parent.y )
        {}
	Type GetType() const noexcept
	{
		return type;
	}
	std::pair<int,int> GetPos() const noexcept
	{
		return{ x,y };	
    }
	int GetPosX() const noexcept
	{
		return x;
	}
	int GetPosY() const noexcept
	{
		return y;
	}
	bool LeftIsPressed() const noexcept
	{
		return leftIsPressed;
	}
	bool RightIsPressed() const noexcept
    {
		return rightIsPressed;
	}
};

二.状态管理

由于鼠标键位没有键盘那么多,只需要一个Queue存储所有事件;

其他状态使用bool值记录即可;

	int x;
	int y;
	bool leftIsPressed = false;
	bool rightIsPressed = false;
	bool isInWindow = false;
	int wheelDeltaCarry = 0;
	std::queue<Event> buffer;

滑轮移动:

Windows的滑轮移动事件,wParam代表滑动间隔,标准是120,可以按倍数增加;

因此滑轮检测记录数值,每到120的倍数触发一次事件;

超出屏幕:

超出屏幕有两种情况,鼠标有键位按下和没有键位按下;

按下超出,鼠标被屏幕捕获(capture,Win32Api),无法超出屏幕,松开时解除;

未按下时正常;

以下是WindowProc函数中鼠标消息的拦截处理:

/*****************鼠标消息******************/
	case WM_MOUSEMOVE:
	{
		const POINTS pt = MAKEPOINTS(lParam);
		//是否在客户区内
		if (pt.x >= 0 && pt.x < width && pt.y >= 0 && pt.y < height)
		{
			mouse.OnMouseMove(pt.x, pt.y);
			if (!mouse.IsInWindow())
			{
				SetCapture(hWnd);
				mouse.OnMouseEnter();
			}
		}
		else
		{
			//左右键是否按下,也可以使用LeftIsPressd(),不允许鼠标按下时离开客户区
			if (wParam & (MK_LBUTTON | MK_RBUTTON))
			{
				mouse.OnMouseMove(pt.x, pt.y);
			}
			else
			{
				ReleaseCapture();
				mouse.OnMouseLeave();
			}
		}
		break;
	}
	case WM_LBUTTONDOWN:
	{
		const POINTS pt = MAKEPOINTS(lParam);
		mouse.OnLeftPressed(pt.x, pt.y);
		break;
	}
	case WM_RBUTTONDOWN:
	{	
		const POINTS pt = MAKEPOINTS(lParam);
		mouse.OnRightPressed(pt.x, pt.y);
		break;
	}
	case WM_LBUTTONUP:
	{
		const POINTS pt = MAKEPOINTS(lParam);
		mouse.OnLeftReleased(pt.x, pt.y);
		break;
	}
	case WM_RBUTTONUP:
	{
		const POINTS pt = MAKEPOINTS(lParam);
		mouse.OnRightReleased(pt.x, pt.y);
		break;
	}
	case WM_MOUSEWHEEL:		
	{
		const POINTS pt = MAKEPOINTS(lParam);
		const int delta = GET_WHEEL_DELTA_WPARAM(wParam);
		mouse.OnWheelDetla(pt.x, pt.y, delta);
	}
/*****************鼠标消息******************/

完整代码:

class Mouse
{
	friend class Window;
public:
	class Event{}//上面展示过,省略;
public:
	Mouse() = default;
	Mouse( const Mouse& ) = delete;
	Mouse& operator=( const Mouse& ) = delete;
	std::pair<int,int> GetPos() const noexcept;
	int GetPosX() const noexcept;
	int GetPosY() const noexcept;
	bool IsInWindow() const noexcept;
	bool LeftIsPressed() const noexcept;
	bool RightIsPressed() const noexcept;
	std::optional<Mouse::Event> Read() noexcept;
	bool IsEmpty() const noexcept
	{
		return buffer.empty();
	}
	void Flush() noexcept;
private:
	void OnMouseMove( int x,int y ) noexcept;
	void OnMouseLeave() noexcept;
	void OnMouseEnter() noexcept;
	void OnLeftPressed( int x,int y ) noexcept;
	void OnLeftReleased( int x,int y ) noexcept;
	void OnRightPressed( int x,int y ) noexcept;
	void OnRightReleased( int x,int y ) noexcept;
	void OnWheelUp( int x,int y ) noexcept;
	void OnWheelDown( int x,int y ) noexcept;
	void TrimBuffer() noexcept;
	void OnWheelDetla(int x, int y,int delta) noexcept;
private:
	static constexpr unsigned int bufferSize = 16u;
	int x;
	int y;
	bool leftIsPressed = false;
	bool rightIsPressed = false;
	bool isInWindow = false;
	int wheelDeltaCarry = 0;
	std::queue<Event> buffer;
};

实现中都是简单代码,只列一下滑轮事件的实现;

void Mouse::OnWheelDetla(int x, int y, int delta) noexcept
{
	wheelDeltaCarry += delta;
	//鼠标滑轮的dpi是120每格子,超过这个值就触发一次事件
	while (wheelDeltaCarry >= WHEEL_DELTA)
	{
		wheelDeltaCarry -= WHEEL_DELTA;
		OnWheelUp(x, y);
	}
	while (wheelDeltaCarry <= -WHEEL_DELTA)
	{
		wheelDeltaCarry += WHEEL_DELTA;
		OnWheelDown(x, y);
	}
}
posted @ 2021-10-05 16:52  小紫苏  阅读(914)  评论(0编辑  收藏  举报