// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. #pragma once #include "InputDevice.h" /// /// Represents a single hardware mouse device. Used by the Input to report raw mouse input events. /// /// /// The mouse device position is in screen-space (not game client window space). /// API_CLASS(NoSpawn) class FLAXENGINE_API Mouse : public InputDevice { DECLARE_SCRIPTING_TYPE_NO_SPAWN(Mouse); public: /// /// The mouse state. /// struct State { /// /// The mouse position. /// Vector2 MousePosition; /// /// The mouse wheel delta. /// float MouseWheelDelta; /// /// The mouse buttons state. /// bool MouseButtons[(int32)MouseButton::MAX]; /// /// Clears the state. /// void Clear() { Platform::MemoryClear(this, sizeof(State)); } }; protected: State _state; State _prevState; explicit Mouse() : InputDevice(SpawnParams(Guid::New(), TypeInitializer), TEXT("Mouse")) { _state.Clear(); _prevState.Clear(); } public: /// /// Gets the position of the mouse in the screen-space coordinates. /// /// The mouse position API_PROPERTY() FORCE_INLINE Vector2 GetPosition() const { return _state.MousePosition; } /// /// Gets the delta position of the mouse in the screen-space coordinates. /// /// The mouse position delta API_PROPERTY() FORCE_INLINE Vector2 GetPositionDelta() const { return _state.MousePosition - _prevState.MousePosition; } /// /// Gets the mouse wheel change during the last frame. /// /// Mouse wheel value delta API_PROPERTY() FORCE_INLINE float GetScrollDelta() const { return _state.MouseWheelDelta; } /// /// Gets the mouse button state (true if being pressed during the current frame). /// /// Mouse button to check /// True if user holds down the button, otherwise false. API_FUNCTION() FORCE_INLINE bool GetButton(MouseButton button) const { return _state.MouseButtons[static_cast(button)]; } /// /// Gets the mouse button down state (true if was pressed during the current frame). /// /// Mouse button to check /// True if user starts pressing down the button, otherwise false. API_FUNCTION() FORCE_INLINE bool GetButtonDown(MouseButton button) const { return _state.MouseButtons[static_cast(button)] && !_prevState.MouseButtons[static_cast(button)]; } /// /// Gets the mouse button up state (true if was released during the current frame). /// /// Mouse button to check /// True if user releases the button, otherwise false. API_FUNCTION() FORCE_INLINE bool GetButtonUp(MouseButton button) const { return !_state.MouseButtons[static_cast(button)] && _prevState.MouseButtons[static_cast(button)]; } public: /// /// Sets the mouse position. /// /// The new position. virtual void SetMousePosition(const Vector2& newPosition) = 0; /// /// Called when mouse cursor gets moved by the application. Invalidates the previous cached mouse position to prevent mouse jitter when locking the cursor programatically. /// /// The new mouse position. void OnMouseMoved(const Vector2& newPosition) { _prevState.MousePosition = newPosition; _state.MousePosition = newPosition; } /// /// Called when mouse button goes down. /// /// The mouse position. /// The button. /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseDown(const Vector2& position, const MouseButton button, Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseDown; e.Target = target; e.MouseData.Button = button; e.MouseData.Position = position; } /// /// Called when mouse button goes up. /// /// The mouse position. /// The button. /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseUp(const Vector2& position, const MouseButton button, Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseUp; e.Target = target; e.MouseData.Button = button; e.MouseData.Position = position; } /// /// Called when mouse double clicks. /// /// The mouse position. /// The button. /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseDoubleClick(const Vector2& position, const MouseButton button, Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseDoubleClick; e.Target = target; e.MouseData.Button = button; e.MouseData.Position = position; } /// /// Called when mouse moves. /// /// The mouse position. /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseMove(const Vector2& position, Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseMove; e.Target = target; e.MouseData.Position = position; } /// /// Called when mouse leaves the input source area. /// /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseLeave(Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseLeave; e.Target = target; } /// /// Called when mouse wheel moves. /// /// The mouse position. /// The normalized delta (range [-1;1]). /// The target window to receive this event, otherwise input system will pick the window automatically. void OnMouseWheel(const Vector2& position, const float delta, Window* target = nullptr) { Event& e = _queue.AddOne(); e.Type = EventType::MouseWheel; e.Target = target; e.MouseWheelData.WheelDelta = delta; e.MouseWheelData.Position = position; } public: // [InputDevice] void ResetState() override { InputDevice::ResetState(); _prevState.Clear(); _state.Clear(); } bool Update(EventQueue& queue) final override { // Move the current state to the previous Platform::MemoryCopy(&_prevState, &_state, sizeof(State)); // Gather new events if (UpdateState()) return true; // Handle events _state.MouseWheelDelta = 0; for (int32 i = 0; i < _queue.Count(); i++) { const Event& e = _queue[i]; switch (e.Type) { case EventType::MouseDown: { _state.MouseButtons[static_cast(e.MouseData.Button)] = true; break; } case EventType::MouseUp: { _state.MouseButtons[static_cast(e.MouseData.Button)] = false; break; } case EventType::MouseDoubleClick: { break; } case EventType::MouseWheel: { _state.MouseWheelDelta += e.MouseWheelData.WheelDelta; break; } case EventType::MouseMove: { _state.MousePosition = e.MouseData.Position; break; } case EventType::MouseLeave: { break; } } } // Send events further queue.Add(_queue); _queue.Clear(); return false; } };