I am making a C++ SDL based game engine, I am finishing the InputManager, let know what you think about it and what fixes can I make?
Take into account:
- It is a singleton, and is called once, but I don't need to explicitly do anything for thread safe because it is already.
- There is a TODO I didn't know if I should implement it or not, because I think I deal with that in two other methods: GamepadButtonPressed and GamepadButtonReleased., help me decide this.
- Yes it is a big mess of Update() but I will be improving upon this when I deal with the EventManager

class InputManager
{
public:
~InputManager();
InputManager(const InputManager&) = delete;
InputManager operator=(const InputManager&) = delete;
static InputManager& GetInstance() noexcept;
void Update();
bool IsKeyPressed(Input::KeyCode key) const;
bool IsKeyReleased(Input::KeyCode key) const;
bool IsMouseButtonPressed(Input::MouseButton button) const;
Point GetMousePosition() const;
bool IsGamepadButtonPressed(Input::GamepadButton button, int gamepadIndex) const;
bool IsGamepadButtonReleased(Input::GamepadButton button, int gamepadIndex) const;

private:
InputManager();
void UpdateKeyboardState();
void SetMouseState(uint8_t mouseButton, bool pressed);
SDL_GameController* GetGamepad(int index);
void GamepadButtonPressed(uint8_t button, int gamepadIndex);
void GamepadButtonReleased(uint8_t button, int gamepadIndex);
void GamepadOpen(int gamepadIndex);
void GamepadClose(int gamepadIndex);

std::unordered_map<Input::KeyCode, bool> currentKeyboardState;
std::unordered_map<Input::KeyCode, bool> previousKeyboardState;
std::unordered_map<Input::MouseButton, bool> mouseButtonsState;
std::vector<SDL_GameController*> gamepads;
std::vector<std::unordered_map<Input::GamepadButton, bool>> currentGamepadState;
std::vector<std::unordered_map<Input::GamepadButton, bool>> previousGamepadState;
};

uint8_t KeyToSDL(Input::KeyCode keyCode);
Input::KeyCode KeyFromSDL(uint8_t sdlKeyCode);
uint8_t MouseButtonToSDL(Input::MouseButton mouseButton);
Input::MouseButton MouseButtonFromSDL(uint8_t sdlMouseButton);
SDL_GameControllerButton GamepadButtonToSDL(Input::GamepadButton gamepadButton);
Input::GamepadButton GamepadButtonFromSDL(SDL_GameControllerButton sdlGamepadButton);

InputManager::InputManager()
{
}

InputManager::~InputManager()
{
for (SDL_GameController* gamepad : gamepads)
{
if (gamepad)
{
SDL_GameControllerClose(gamepad);
}
}
}

InputManager& InputManager::GetInstance() noexcept
{
static InputManager instance;

return instance;
}

void InputManager::Update()
{
previousKeyboardState = currentKeyboardState;

SDL_Event event;
while (SDL_PollEvent(&event))
{
switch (event.type)
{
case SDL_MOUSEBUTTONUP:
{
SetMouseState(event.button.button, false);
break;
}
case SDL_MOUSEBUTTONDOWN:
{
SetMouseState(event.button.button, true);
break;
}
case SDL_CONTROLLERDEVICEADDED:
{
GamepadOpen(event.cdevice.which);
break;
}
case SDL_CONTROLLERDEVICEREMOVED:
{
GamepadClose(event.cdevice.which);
break;
}
case SDL_CONTROLLERBUTTONDOWN:
{
GamepadButtonPressed(event.cbutton.button, event.cbutton.which);
break;
}
case SDL_CONTROLLERBUTTONUP:
{
GamepadButtonReleased(event.cbutton.button, event.cbutton.which);
break;
}
}
}

UpdateKeyboardState();
}

bool InputManager::IsKeyPressed(Input::KeyCode key) const
{
auto currentState = currentKeyboardState.find(key);
auto previousState = previousKeyboardState.find(key);

return (currentState != currentKeyboardState.end() && currentState->second) && (previousState == previousKeyboardState.end() || !previousState->second);
}

bool InputManager::IsKeyReleased(Input::KeyCode key) const
{
auto currentState = currentKeyboardState.find(key);
auto previousState = previousKeyboardState.find(key);

return (previousState != previousKeyboardState.end() && previousState->second) && (currentState == currentKeyboardState.end() || !currentState->second);
}

bool InputManager::IsMouseButtonPressed(Input::MouseButton button) const
{
auto mouseState = mouseButtonsState.find(button);

return (mouseState != mouseButtonsState.end() && mouseState->second);
}

Point InputManager::GetMousePosition() const
{
int x = 0;
int y = 0;
SDL_GetMouseState(&x, &y);

return Point(x, y);
}

bool InputManager::IsGamepadButtonPressed(Input::GamepadButton button, int gamepadIndex) const
{
bool pressed = false;
if (gamepadIndex >= 0 && gamepadIndex < static_cast<int>(currentGamepadState.size()))
{
auto currentState = currentGamepadState[gamepadIndex].find(button);
auto previousState = previousGamepadState[gamepadIndex].find(button);
pressed = (previousState != previousGamepadState[gamepadIndex].end() && previousState->second) && (currentState == currentGamepadState[gamepadIndex].end() || !currentState->second);
}

return pressed;
}

bool InputManager::IsGamepadButtonReleased(Input::GamepadButton button, int gamepadIndex) const
{
bool released = false;
if (gamepadIndex >= 0 && gamepadIndex < static_cast<int>(currentGamepadState.size()))
{
auto currentState = currentGamepadState[gamepadIndex].find(button);
auto previousState = previousGamepadState[gamepadIndex].find(button);
released = (previousState != previousGamepadState[gamepadIndex].end() && previousState->second) && (currentState == currentGamepadState[gamepadIndex].end() || !currentState->second);
}

return released;
}

void InputManager::SetMouseState(uint8_t mouseButton, bool pressed)
{
mouseButtonsState[MouseButtonFromSDL(mouseButton)] = pressed;
}

void InputManager::UpdateKeyboardState()
{
int numKeys;
const Uint8* keyStates = SDL_GetKeyboardState(&numKeys);

for (int i = 0; i < numKeys; ++i)
{
Input::KeyCode code = KeyFromSDL(i);

currentKeyboardState[code] = keyStates[i] != 0;
}
}

SDL_GameController* InputManager::GetGamepad(int index)
{
if (index < static_cast<int>(gamepads.size()))
{
return gamepads[index];
}
return nullptr;
}

void InputManager::GamepadButtonPressed(uint8_t button, int gamepadIndex)
{
if (gamepadIndex >= 0)
{
if (gamepadIndex >= static_cast<int>(currentGamepadState.size()))
{
currentGamepadState.resize(gamepadIndex + 1);
previousGamepadState.resize(gamepadIndex + 1);
}

Input::GamepadButton gamepadButton = GamepadButtonFromSDL(static_cast<SDL_GameControllerButton>(button));
previousGamepadState[gamepadIndex][gamepadButton] = currentGamepadState[gamepadIndex][gamepadButton];
currentGamepadState[gamepadIndex][gamepadButton] = true;
}
}

void InputManager::GamepadButtonReleased(uint8_t button, int gamepadIndex)
{
if (gamepadIndex >= 0)
{
if (gamepadIndex >= static_cast<int>(currentGamepadState.size()))
{
currentGamepadState.resize(gamepadIndex + 1);
previousGamepadState.resize(gamepadIndex + 1);
}

Input::GamepadButton gamepadButton = GamepadButtonFromSDL(static_cast<SDL_GameControllerButton>(button));
previousGamepadState[gamepadIndex][gamepadButton] = currentGamepadState[gamepadIndex][gamepadButton];
currentGamepadState[gamepadIndex][gamepadButton] = false;
}
}

void InputManager::GamepadOpen(int gamepadIndex)
{
SDL_GameController* controller = SDL_GameControllerOpen(gamepadIndex);
if (controller)
{
if (gamepadIndex >= static_cast<int>(gamepads.size()))
{
gamepads.resize(gamepadIndex + 1, nullptr);
}
gamepads[gamepadIndex] = controller;
// TODO: Here you should also initialize the state maps for the new controller
// INITIALIZE CURRENT AND PREVIOUS AS FALSE FOR THE NEW CONTROLLER
}
else
{
std::string errorMsg = "ERROR: Gamepad " + std::to_string(gamepadIndex) + " could not be open: " + std::string(SDL_GetError());
SDL_LogError(SDL_LOG_CATEGORY_ERROR, errorMsg.c_str());
}
}

void InputManager::GamepadClose(int gamepadIndex)
{
if (gamepadIndex < static_cast<int>(gamepads.size()) && gamepads[gamepadIndex])
{
SDL_GameControllerClose(gamepads[gamepadIndex]);
gamepads[gamepadIndex] = nullptr;
}
}