// 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;
}
};