242 lines
8.1 KiB
C++
242 lines
8.1 KiB
C++
#include "InputManager.h"
|
|
#include "log/log.h"
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <cmath>
|
|
|
|
InputManager::InputManager() {
|
|
}
|
|
|
|
InputManager::~InputManager() {
|
|
}
|
|
|
|
void InputManager::RegisterAction(const std::string& actionName) {
|
|
if (actions.find(actionName) == actions.end()) {
|
|
actions[actionName] = std::vector<InputBinding>();
|
|
log_debug("Registered input action: %s", actionName.c_str());
|
|
}
|
|
}
|
|
|
|
void InputManager::UnregisterAction(const std::string& actionName) {
|
|
actions.erase(actionName);
|
|
}
|
|
|
|
bool InputManager::HasAction(const std::string& actionName) const {
|
|
return actions.find(actionName) != actions.end();
|
|
}
|
|
|
|
void InputManager::BindKeyboard(const std::string& actionName, int keyCode) {
|
|
RegisterAction(actionName);
|
|
actions[actionName].push_back(InputBinding(InputType::Keyboard, keyCode));
|
|
log_debug("Bound key %d to action: %s", keyCode, actionName.c_str());
|
|
}
|
|
|
|
void InputManager::BindMouseButton(const std::string& actionName, int mouseButton) {
|
|
RegisterAction(actionName);
|
|
actions[actionName].push_back(InputBinding(InputType::MouseButton, mouseButton));
|
|
}
|
|
|
|
void InputManager::BindGamepadButton(const std::string& actionName, int gamepadId, int button) {
|
|
RegisterAction(actionName);
|
|
actions[actionName].push_back(InputBinding(InputType::GamepadButton, button, gamepadId));
|
|
}
|
|
|
|
void InputManager::BindGamepadAxis(const std::string& actionName, int gamepadId, int axis, float threshold, bool negative) {
|
|
RegisterAction(actionName);
|
|
InputBinding binding(InputType::GamepadAxis, axis, gamepadId);
|
|
binding.axisThreshold = threshold;
|
|
binding.negative = negative;
|
|
actions[actionName].push_back(binding);
|
|
}
|
|
|
|
void InputManager::ClearBindings(const std::string& actionName) {
|
|
if (HasAction(actionName)) {
|
|
actions[actionName].clear();
|
|
}
|
|
}
|
|
|
|
bool InputManager::IsActionPressed(const std::string& actionName) const {
|
|
auto it = actions.find(actionName);
|
|
if (it == actions.end()) return false;
|
|
|
|
for (const auto& binding : it->second) {
|
|
if (IsBindingPressed(binding)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputManager::IsActionDown(const std::string& actionName) const {
|
|
auto it = actions.find(actionName);
|
|
if (it == actions.end()) return false;
|
|
|
|
for (const auto& binding : it->second) {
|
|
if (IsBindingDown(binding)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputManager::IsActionReleased(const std::string& actionName) const {
|
|
auto it = actions.find(actionName);
|
|
if (it == actions.end()) return false;
|
|
|
|
for (const auto& binding : it->second) {
|
|
if (IsBindingReleased(binding)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float InputManager::GetActionStrength(const std::string& actionName) const {
|
|
auto it = actions.find(actionName);
|
|
if (it == actions.end()) return 0.0f;
|
|
|
|
float maxStrength = 0.0f;
|
|
for (const auto& binding : it->second) {
|
|
float strength = GetBindingStrength(binding);
|
|
if (std::abs(strength) > std::abs(maxStrength)) {
|
|
maxStrength = strength;
|
|
}
|
|
}
|
|
return maxStrength;
|
|
}
|
|
|
|
bool InputManager::IsBindingPressed(const InputBinding& binding) const {
|
|
switch (binding.type) {
|
|
case InputType::Keyboard:
|
|
return IsKeyPressed(binding.code);
|
|
case InputType::MouseButton:
|
|
return IsMouseButtonPressed(binding.code);
|
|
case InputType::GamepadButton:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
return IsGamepadButtonPressed(binding.gamepadId, binding.code);
|
|
}
|
|
return false;
|
|
case InputType::GamepadAxis: {
|
|
// Axis "pressed" is harder to detect - simplified to just checking threshold
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
float value = GetGamepadAxisMovement(binding.gamepadId, binding.code);
|
|
return binding.negative ? value < -binding.axisThreshold : value > binding.axisThreshold;
|
|
}
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputManager::IsBindingDown(const InputBinding& binding) const {
|
|
switch (binding.type) {
|
|
case InputType::Keyboard:
|
|
return IsKeyDown(binding.code);
|
|
case InputType::MouseButton:
|
|
return IsMouseButtonDown(binding.code);
|
|
case InputType::GamepadButton:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
return IsGamepadButtonDown(binding.gamepadId, binding.code);
|
|
}
|
|
return false;
|
|
case InputType::GamepadAxis:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
float value = GetGamepadAxisMovement(binding.gamepadId, binding.code);
|
|
return binding.negative ? value < -binding.axisThreshold : value > binding.axisThreshold;
|
|
}
|
|
return false;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool InputManager::IsBindingReleased(const InputBinding& binding) const {
|
|
switch (binding.type) {
|
|
case InputType::Keyboard:
|
|
return IsKeyReleased(binding.code);
|
|
case InputType::MouseButton:
|
|
return IsMouseButtonReleased(binding.code);
|
|
case InputType::GamepadButton:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
return IsGamepadButtonReleased(binding.gamepadId, binding.code);
|
|
}
|
|
return false;
|
|
case InputType::GamepadAxis:
|
|
return false; // Axes don't have a clear "released" state
|
|
}
|
|
return false;
|
|
}
|
|
|
|
float InputManager::GetBindingStrength(const InputBinding& binding) const {
|
|
switch (binding.type) {
|
|
case InputType::Keyboard:
|
|
return IsKeyDown(binding.code) ? 1.0f : 0.0f;
|
|
case InputType::MouseButton:
|
|
return IsMouseButtonDown(binding.code) ? 1.0f : 0.0f;
|
|
case InputType::GamepadButton:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
return IsGamepadButtonDown(binding.gamepadId, binding.code) ? 1.0f : 0.0f;
|
|
}
|
|
return 0.0f;
|
|
case InputType::GamepadAxis:
|
|
if (IsGamepadAvailable(binding.gamepadId)) {
|
|
float value = GetGamepadAxisMovement(binding.gamepadId, binding.code);
|
|
return binding.negative ? -value : value;
|
|
}
|
|
return 0.0f;
|
|
}
|
|
return 0.0f;
|
|
}
|
|
|
|
void InputManager::SetupDefaultBindings() {
|
|
// Movement
|
|
BindKeyboard("move_up", KEY_W);
|
|
BindKeyboard("move_up", KEY_UP);
|
|
BindKeyboard("move_down", KEY_S);
|
|
BindKeyboard("move_down", KEY_DOWN);
|
|
BindKeyboard("move_left", KEY_A);
|
|
BindKeyboard("move_left", KEY_LEFT);
|
|
BindKeyboard("move_right", KEY_D);
|
|
BindKeyboard("move_right", KEY_RIGHT);
|
|
|
|
// Actions
|
|
BindKeyboard("jump", KEY_SPACE);
|
|
BindKeyboard("interact", KEY_E);
|
|
BindKeyboard("attack", KEY_LEFT_CONTROL);
|
|
BindMouseButton("attack", MOUSE_BUTTON_LEFT);
|
|
|
|
// Gamepad (if available)
|
|
BindGamepadButton("jump", 0, GAMEPAD_BUTTON_RIGHT_FACE_DOWN);
|
|
BindGamepadButton("interact", 0, GAMEPAD_BUTTON_RIGHT_FACE_RIGHT);
|
|
BindGamepadAxis("move_left", 0, GAMEPAD_AXIS_LEFT_X, 0.3f, true);
|
|
BindGamepadAxis("move_right", 0, GAMEPAD_AXIS_LEFT_X, 0.3f, false);
|
|
|
|
log_info("Input manager: Default bindings configured");
|
|
}
|
|
|
|
std::vector<std::string> InputManager::GetAllActions() const {
|
|
std::vector<std::string> result;
|
|
for (const auto& pair : actions) {
|
|
result.push_back(pair.first);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
const std::vector<InputBinding>& InputManager::GetBindings(const std::string& actionName) const {
|
|
static std::vector<InputBinding> empty;
|
|
auto it = actions.find(actionName);
|
|
if (it != actions.end()) {
|
|
return it->second;
|
|
}
|
|
return empty;
|
|
}
|
|
|
|
void InputManager::LoadFromFile(const std::string& filepath) {
|
|
// TODO: Implement config file loading (JSON or simple text format)
|
|
log_info("Input config loading not yet implemented: %s", filepath.c_str());
|
|
}
|
|
|
|
void InputManager::SaveToFile(const std::string& filepath) const {
|
|
// TODO: Implement config file saving
|
|
log_info("Input config saving not yet implemented: %s", filepath.c_str());
|
|
}
|