Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
307 changes: 302 additions & 5 deletions Engine/src/Razix/Core/OS/RZInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,306 @@
// clang-format on
#include "RZInput.h"

#include "Razix/Platform/GLFW/GLFWInput.h"
#include "Razix/Core/App/RZApplication.h"

void Razix::RZInput::SelectGLFWInputManager()
{
s_Instance = new GLFWInput;
}
// Platform-specific includes
#if defined(RAZIX_USE_GLFW_WINDOWS) || defined(RAZIX_PLATFORM_MACOS) || defined(RAZIX_PLATFORM_UNIX)
#include <GLFW/glfw3.h>
#elif defined(RAZIX_PLATFORM_WINDOWS)
// TODO: Implement Windows-specific input handling
#include <Windows.h>
#endif

namespace Razix {

#if defined(RAZIX_USE_GLFW_WINDOWS) || defined(RAZIX_PLATFORM_MACOS) || defined(RAZIX_PLATFORM_UNIX)
// GLFW implementation for cross-platform input support

static GLFWwindow* GetActiveWindow()
{
return static_cast<GLFWwindow*>(RZApplication::Get().getWindow()->GetNativeWindow());
}

static GLFWgamepadstate GetGamepadState()
{
GLFWgamepadstate state = {};
if (glfwJoystickIsGamepad(GLFW_JOYSTICK_1)) {
glfwGetGamepadState(GLFW_JOYSTICK_1, &state);
}
return state;
}

// Keyboard implementation
bool RZInput::IsKeyPressed(Razix::KeyCode::Key keycode)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto window = GetActiveWindow();
int keyState = glfwGetKey(window, int(keycode));
return keyState == GLFW_PRESS;
}

bool RZInput::IsKeyReleased(Razix::KeyCode::Key keycode)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto window = GetActiveWindow();
int keyState = glfwGetKey(window, int(keycode));
return keyState == GLFW_RELEASE;
}

bool RZInput::IsKeyHeld(Razix::KeyCode::Key keycode)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto window = GetActiveWindow();
int keyState = glfwGetKey(window, int(keycode));
return keyState == GLFW_PRESS || keyState == GLFW_REPEAT;
}

// Mouse implementation
bool RZInput::IsMouseButtonPressed(Razix::KeyCode::MouseKey button)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
bool isPressed = false;
static int oldState = GLFW_RELEASE;
Copy link

Copilot AI Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static variable oldState is not thread-safe and will cause incorrect behavior when multiple threads call IsMouseButtonPressed concurrently. Consider using thread-local storage or a different approach to track button state changes.

Suggested change
static int oldState = GLFW_RELEASE;
thread_local int oldState = GLFW_RELEASE;

Copilot uses AI. Check for mistakes.
auto window = GetActiveWindow();
int newState = glfwGetMouseButton(window, int(button));
if (newState == GLFW_PRESS && oldState == GLFW_RELEASE)
isPressed = true;
oldState = newState;
return isPressed;
}

bool RZInput::IsMouseButtonReleased(Razix::KeyCode::MouseKey button)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
bool isPressed = false;
static int oldState = GLFW_RELEASE;
Copy link

Copilot AI Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The static variable oldState is not thread-safe and will cause incorrect behavior when multiple threads call IsMouseButtonReleased concurrently. This also creates a shared state between IsMouseButtonPressed and IsMouseButtonReleased which is incorrect - each button should have its own state tracking.

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Jul 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both IsMouseButtonPressed and IsMouseButtonReleased functions share the same static oldState variable name, but they should track state independently for each mouse button. This will cause incorrect behavior when checking different mouse buttons or when both functions are used simultaneously.

Copilot uses AI. Check for mistakes.
auto window = GetActiveWindow();
int newState = glfwGetMouseButton(window, int(button));
if (newState == GLFW_RELEASE && oldState == GLFW_PRESS)
isPressed = true;
oldState = newState;
return isPressed;
}

bool RZInput::IsMouseButtonHeld(Razix::KeyCode::MouseKey button)
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto window = GetActiveWindow();
int buttonState = glfwGetMouseButton(window, int(button));
return buttonState == GLFW_PRESS;
}

std::pair<f32, f32> RZInput::GetMousePosition()
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto window = GetActiveWindow();
d32 xpos, ypos;
glfwGetCursorPos(window, &xpos, &ypos);
return {(f32) xpos, (f32) ypos};
}

f32 RZInput::GetMouseX()
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto [x, y] = GetMousePosition();
return x;
}

f32 RZInput::GetMouseY()
{
RAZIX_PROFILE_FUNCTIONC(RZ_PROFILE_COLOR_CORE);
auto [x, y] = GetMousePosition();
return y;
}

// Gamepad implementation
bool RZInput::IsGamepadConnected()
{
return glfwJoystickPresent(GLFW_JOYSTICK_1) && glfwJoystickIsGamepad(GLFW_JOYSTICK_1);
}

f32 RZInput::GetJoyLeftStickHorizontal()
{
return GetGamepadState().axes[GLFW_GAMEPAD_AXIS_LEFT_X];
}

f32 RZInput::GetJoyLeftStickVertical()
{
return GetGamepadState().axes[GLFW_GAMEPAD_AXIS_LEFT_Y];
}

f32 RZInput::GetJoyRightStickHorizontal()
{
return GetGamepadState().axes[GLFW_GAMEPAD_AXIS_RIGHT_X];
}

f32 RZInput::GetJoyRightStickVertical()
{
return GetGamepadState().axes[GLFW_GAMEPAD_AXIS_RIGHT_Y];
}

f32 RZInput::GetJoyDPadHorizontal()
{
const auto state = GetGamepadState();
int left = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_LEFT] == GLFW_PRESS ? -1 : 0;
int right = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_RIGHT] == GLFW_PRESS ? 1 : 0;
return static_cast<f32>(left + right);
}

f32 RZInput::GetJoyDPadVertical()
{
const auto state = GetGamepadState();
int up = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_UP] == GLFW_PRESS ? -1 : 0;
int down = state.buttons[GLFW_GAMEPAD_BUTTON_DPAD_DOWN] == GLFW_PRESS ? 1 : 0;
return static_cast<f32>(up + down);
}

bool RZInput::IsCrossPressed()
{
return GetGamepadState().buttons[GLFW_GAMEPAD_BUTTON_A] == GLFW_PRESS;
}

bool RZInput::IsCirclePressed()
{
return GetGamepadState().buttons[GLFW_GAMEPAD_BUTTON_B] == GLFW_PRESS;
}

bool RZInput::IsTrianglePressed()
{
return GetGamepadState().buttons[GLFW_GAMEPAD_BUTTON_Y] == GLFW_PRESS;
}

bool RZInput::IsSquarePressed()
{
return GetGamepadState().buttons[GLFW_GAMEPAD_BUTTON_X] == GLFW_PRESS;
}

#elif defined(RAZIX_PLATFORM_WINDOWS)
// Windows-specific implementation (placeholder for future Windows native input)
// For now, we'll use stub implementations

bool RZInput::IsKeyPressed(Razix::KeyCode::Key keycode)
{
// TODO: Implement Windows-specific keyboard input
return false;
}

bool RZInput::IsKeyReleased(Razix::KeyCode::Key keycode)
{
// TODO: Implement Windows-specific keyboard input
return false;
}

bool RZInput::IsKeyHeld(Razix::KeyCode::Key keycode)
{
// TODO: Implement Windows-specific keyboard input
return false;
}

bool RZInput::IsMouseButtonPressed(Razix::KeyCode::MouseKey button)
{
// TODO: Implement Windows-specific mouse input
return false;
}

bool RZInput::IsMouseButtonReleased(Razix::KeyCode::MouseKey button)
{
// TODO: Implement Windows-specific mouse input
return false;
}

bool RZInput::IsMouseButtonHeld(Razix::KeyCode::MouseKey button)
{
// TODO: Implement Windows-specific mouse input
return false;
}

std::pair<f32, f32> RZInput::GetMousePosition()
{
// TODO: Implement Windows-specific mouse position
return {0.0f, 0.0f};
}

f32 RZInput::GetMouseX()
{
auto [x, y] = GetMousePosition();
return x;
}

f32 RZInput::GetMouseY()
{
auto [x, y] = GetMousePosition();
return y;
}

bool RZInput::IsGamepadConnected()
{
// TODO: Implement Windows-specific gamepad detection
return false;
}

f32 RZInput::GetJoyLeftStickHorizontal()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

f32 RZInput::GetJoyLeftStickVertical()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

f32 RZInput::GetJoyRightStickHorizontal()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

f32 RZInput::GetJoyRightStickVertical()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

f32 RZInput::GetJoyDPadHorizontal()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

f32 RZInput::GetJoyDPadVertical()
{
// TODO: Implement Windows-specific gamepad input
return 0.0f;
}

bool RZInput::IsCrossPressed()
{
// TODO: Implement Windows-specific gamepad input
return false;
}

bool RZInput::IsCirclePressed()
{
// TODO: Implement Windows-specific gamepad input
return false;
}

bool RZInput::IsTrianglePressed()
{
// TODO: Implement Windows-specific gamepad input
return false;
}

bool RZInput::IsSquarePressed()
{
// TODO: Implement Windows-specific gamepad input
return false;
}

#else
#error "Unsupported platform for input system"
#endif

} // namespace Razix
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot can you move GLFW and windows implementaino into their own files, so that I can select per-platform input, like if ass PS5 or other OS and need to override a input, Just remove s_Instance change which you did well, leep the GLFWInput in the class and make it so that adding new devices and input classes per platform is easier

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've refactored the input system as requested! The GLFW and Windows implementations are now in separate platform-specific files:

Structure created:

  • Engine/src/Razix/Platform/GLFW/GLFWInput.h/cpp - Cross-platform GLFW implementation
  • Engine/src/Razix/Platform/Windows/WindowsInput.h/cpp - Native Windows implementation with Win32 API + XInput

Restored original architecture:

  • Kept the virtual interface with s_Instance (removed the static function approach)
  • Added extensible platform selection methods: SelectGLFWInputManager(), SelectWindowsInputManager()
  • Structure ready for easy addition of new devices: PS5, Xbox, Linux, etc.

Benefits:

  • Each platform implementation is self-contained
  • Runtime switching between input implementations
  • Easy to add new input devices per platform
  • Clean separation for maintainability

Commit: 619c41a

78 changes: 22 additions & 56 deletions Engine/src/Razix/Core/OS/RZInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,64 +11,30 @@ namespace Razix {
class RAZIX_API RZInput
{
public:
// TODO: Use a better API convention for selecting input API implementation
// TODO: ReWrite this using a simple static function design pattern rather than using Impls, this is cumbersome to extend
/* Selects the GLFW Input class for polling and reporting input events */
static void SelectGLFWInputManager();

// Keyboard
inline static bool IsKeyPressed(Razix::KeyCode::Key keycode) { return s_Instance->IsKeyPressedImpl(int(keycode)); }
inline static bool IsKeyReleased(Razix::KeyCode::Key keycode) { return s_Instance->IsKeyReleasedImpl(int(keycode)); }
inline static bool IsKeyHeld(Razix::KeyCode::Key keycode) { return s_Instance->IsIsKeyHeldImpl(int(keycode)); }
static bool IsKeyPressed(Razix::KeyCode::Key keycode);
static bool IsKeyReleased(Razix::KeyCode::Key keycode);
static bool IsKeyHeld(Razix::KeyCode::Key keycode);

// Mouse
inline static bool IsMouseButtonPressed(Razix::KeyCode::MouseKey button) { return s_Instance->IsMouseButtonPressedImpl(int(button)); }
inline static bool IsMouseButtonReleased(Razix::KeyCode::MouseKey button) { return s_Instance->IsMouseButtonReleasedImpl(int(button)); }
inline static bool IsMouseButtonHeld(Razix::KeyCode::MouseKey button) { return s_Instance->IsMouseButtonHeldImpl(int(button)); }
inline static std::pair<f32, f32> GetMousePosition() { return s_Instance->GetMousePositionImpl(); }
inline static f32 GetMouseX() { return s_Instance->GetMouseXImpl(); }
inline static f32 GetMouseY() { return s_Instance->GetMouseYImpl(); }

// This is written with the PS5 DualSense controller in mind
// TODO: Support all DualSense buttons
inline static bool IsGamepadConnected() { return s_Instance->IsGamepadConnectedImpl(); }

inline static f32 GetJoyLeftStickHorizontal() { return s_Instance->GetJoyLeftStickHorizontalImpl(); }
inline static f32 GetJoyLeftStickVertical() { return s_Instance->GetJoyLeftStickVerticalImpl(); }
inline static f32 GetJoyRightStickHorizontal() { return s_Instance->GetJoyRightStickHorizontalImpl(); }
inline static f32 GetJoyRightStickVertical() { return s_Instance->GetJoyRightStickVerticalImpl(); }
inline static f32 GetJoyDPadHorizontal() { return s_Instance->GetJoyDPadHorizontalImpl(); }
inline static f32 GetJoyDPadVertical() { return s_Instance->GetJoyDPadVerticalImpl(); }

inline static bool IsCrossPressed() { return s_Instance->IsCrossPressedImpl(); }
inline static bool IsCirclePressed() { return s_Instance->IsCirclePressedImpl(); }
inline static bool IsTrianglePressed() { return s_Instance->IsTrianglePressedImpl(); }
inline static bool IsSquarePressed() { return s_Instance->IsSquarePressedImpl(); }

protected:
virtual bool IsKeyPressedImpl(int keycode) = 0;
virtual bool IsKeyReleasedImpl(int keycode) = 0;
virtual bool IsIsKeyHeldImpl(int keycode) = 0;
virtual bool IsMouseButtonPressedImpl(int button) = 0;
virtual bool IsMouseButtonReleasedImpl(int button) = 0;
virtual bool IsMouseButtonHeldImpl(int button) = 0;
virtual std::pair<f32, f32> GetMousePositionImpl() = 0;
virtual f32 GetMouseXImpl() = 0;
virtual f32 GetMouseYImpl() = 0;

virtual bool IsGamepadConnectedImpl() = 0;
virtual f32 GetJoyLeftStickHorizontalImpl() = 0;
virtual f32 GetJoyLeftStickVerticalImpl() = 0;
virtual f32 GetJoyRightStickHorizontalImpl() = 0;
virtual f32 GetJoyRightStickVerticalImpl() = 0;
virtual f32 GetJoyDPadHorizontalImpl() = 0;
virtual f32 GetJoyDPadVerticalImpl() = 0;
virtual bool IsCrossPressedImpl() = 0;
virtual bool IsCirclePressedImpl() = 0;
virtual bool IsTrianglePressedImpl() = 0;
virtual bool IsSquarePressedImpl() = 0;

protected:
static RZInput* s_Instance;
static bool IsMouseButtonPressed(Razix::KeyCode::MouseKey button);
static bool IsMouseButtonReleased(Razix::KeyCode::MouseKey button);
static bool IsMouseButtonHeld(Razix::KeyCode::MouseKey button);
static std::pair<f32, f32> GetMousePosition();
static f32 GetMouseX();
static f32 GetMouseY();

// Gamepad support for multi-device HID (PS5 DualSense, Xbox controllers, etc.)
static bool IsGamepadConnected();
static f32 GetJoyLeftStickHorizontal();
static f32 GetJoyLeftStickVertical();
static f32 GetJoyRightStickHorizontal();
static f32 GetJoyRightStickVertical();
static f32 GetJoyDPadHorizontal();
static f32 GetJoyDPadVertical();
static bool IsCrossPressed();
static bool IsCirclePressed();
static bool IsTrianglePressed();
static bool IsSquarePressed();
};
} // namespace Razix
Loading