鼠标事件
鼠标事件种类分为:
1.左键按下抬起
2.右键按下抬起
3.鼠标移动(坐标)
4.滑轮上下滑动
5.鼠标进入移出客户区
对应的事件代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| 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值记录即可;
1 2 3 4 5 6 7
| 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函数中鼠标消息的拦截处理:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| 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 { 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); }
|
完整代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| 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; };
|
实现中都是简单代码,只列一下滑轮事件的实现;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void Mouse::OnWheelDetla(int x, int y, int delta) noexcept { wheelDeltaCarry += delta; while (wheelDeltaCarry >= WHEEL_DELTA) { wheelDeltaCarry -= WHEEL_DELTA; OnWheelUp(x, y); } while (wheelDeltaCarry <= -WHEEL_DELTA) { wheelDeltaCarry += WHEEL_DELTA; OnWheelDown(x, y); } }
|