R-Type
Distributed multiplayer game engine in C++
Loading...
Searching...
No Matches
KeyBindings.cpp
Go to the documentation of this file.
1/*
2** EPITECH PROJECT, 2026
3** r-type
4** File description:
5** KeyBindings - Centralized key binding management implementation
6*/
7
9#include <fstream>
10#include <sstream>
11#include "../common/Logger/Logger.hpp"
12
13namespace Input {
14
16 static KeyBindings instance;
17 return instance;
18 }
19
23
25 _bindings.clear();
26
27 // Movement - WASD primary, Gamepad D-Pad secondary
28 _bindings[GameAction::MOVE_UP] = {KEY_W, GamepadButtonToBinding(GAMEPAD_BUTTON_LEFT_FACE_UP)};
29 _bindings[GameAction::MOVE_DOWN] = {KEY_S, GamepadButtonToBinding(GAMEPAD_BUTTON_LEFT_FACE_DOWN)};
30 _bindings[GameAction::MOVE_LEFT] = {KEY_A, GamepadButtonToBinding(GAMEPAD_BUTTON_LEFT_FACE_LEFT)};
31 _bindings[GameAction::MOVE_RIGHT] = {KEY_D, GamepadButtonToBinding(GAMEPAD_BUTTON_LEFT_FACE_RIGHT)};
32
33 // Combat - Space primary, Gamepad A button secondary
34 _bindings[GameAction::SHOOT] = {KEY_SPACE, GamepadButtonToBinding(GAMEPAD_BUTTON_RIGHT_FACE_DOWN)};
35
36 // UI/System - Escape primary, Gamepad Start secondary
37 _bindings[GameAction::PAUSE_MENU] = {KEY_ESCAPE, GamepadButtonToBinding(GAMEPAD_BUTTON_MIDDLE_RIGHT)};
38 _bindings[GameAction::CHAT_OPEN] = {KEY_T, KEY_ENTER};
39
40 // Menu Navigation
41 _bindings[GameAction::MENU_NEXT] = {KEY_TAB, KEY_DOWN};
42 _bindings[GameAction::MENU_PREVIOUS] = {KEY_UP, KEY_NULL}; // Shift+Tab handled specially
44 GamepadButtonToBinding(GAMEPAD_BUTTON_RIGHT_FACE_DOWN)};
45 _bindings[GameAction::MENU_BACK] = {KEY_ESCAPE,
46 GamepadButtonToBinding(GAMEPAD_BUTTON_RIGHT_FACE_RIGHT)};
47
49 }
50
52 auto it = _bindings.find(action);
53 if (it != _bindings.end()) {
54 return it->second.primary;
55 }
56 return KEY_NULL;
57 }
58
60 auto it = _bindings.find(action);
61 if (it != _bindings.end()) {
62 return it->second.secondary;
63 }
64 return KEY_NULL;
65 }
66
67 void KeyBindings::SetPrimaryKey(GameAction action, int key) {
68 _bindings[action].primary = key;
70 }
71
73 _bindings[action].secondary = key;
75 }
76
78 _bindings[action].secondary = KEY_NULL;
80 }
81
82 bool KeyBindings::IsKeyBoundToAction(GameAction action, int key) const {
83 auto it = _bindings.find(action);
84 if (it != _bindings.end()) {
85 return it->second.primary == key || it->second.secondary == key;
86 }
87 return false;
88 }
89
90 std::string KeyBindings::GetKeyName(int key) {
91 // Common keys
92 static const std::unordered_map<int, std::string> keyNames = {
93 {KEY_NULL, "None"},
94 {KEY_SPACE, "Space"},
95 {KEY_ESCAPE, "Escape"},
96 {KEY_ENTER, "Enter"},
97 {KEY_KP_ENTER, "Numpad Enter"},
98 {KEY_TAB, "Tab"},
99 {KEY_BACKSPACE, "Backspace"},
100 {KEY_DELETE, "Delete"},
101 {KEY_INSERT, "Insert"},
102 {KEY_HOME, "Home"},
103 {KEY_END, "End"},
104 {KEY_PAGE_UP, "Page Up"},
105 {KEY_PAGE_DOWN, "Page Down"},
106 {KEY_UP, "Up Arrow"},
107 {KEY_DOWN, "Down Arrow"},
108 {KEY_LEFT, "Left Arrow"},
109 {KEY_RIGHT, "Right Arrow"},
110 {KEY_LEFT_SHIFT, "Left Shift"},
111 {KEY_RIGHT_SHIFT, "Right Shift"},
112 {KEY_LEFT_CONTROL, "Left Ctrl"},
113 {KEY_RIGHT_CONTROL, "Right Ctrl"},
114 {KEY_LEFT_ALT, "Left Alt"},
115 {KEY_RIGHT_ALT, "Right Alt"},
116 // Letters
117 {KEY_A, "A"},
118 {KEY_B, "B"},
119 {KEY_C, "C"},
120 {KEY_D, "D"},
121 {KEY_E, "E"},
122 {KEY_F, "F"},
123 {KEY_G, "G"},
124 {KEY_H, "H"},
125 {KEY_I, "I"},
126 {KEY_J, "J"},
127 {KEY_K, "K"},
128 {KEY_L, "L"},
129 {KEY_M, "M"},
130 {KEY_N, "N"},
131 {KEY_O, "O"},
132 {KEY_P, "P"},
133 {KEY_Q, "Q"},
134 {KEY_R, "R"},
135 {KEY_S, "S"},
136 {KEY_T, "T"},
137 {KEY_U, "U"},
138 {KEY_V, "V"},
139 {KEY_W, "W"},
140 {KEY_X, "X"},
141 {KEY_Y, "Y"},
142 {KEY_Z, "Z"},
143 // Numbers
144 {KEY_ZERO, "0"},
145 {KEY_ONE, "1"},
146 {KEY_TWO, "2"},
147 {KEY_THREE, "3"},
148 {KEY_FOUR, "4"},
149 {KEY_FIVE, "5"},
150 {KEY_SIX, "6"},
151 {KEY_SEVEN, "7"},
152 {KEY_EIGHT, "8"},
153 {KEY_NINE, "9"},
154 // Function keys
155 {KEY_F1, "F1"},
156 {KEY_F2, "F2"},
157 {KEY_F3, "F3"},
158 {KEY_F4, "F4"},
159 {KEY_F5, "F5"},
160 {KEY_F6, "F6"},
161 {KEY_F7, "F7"},
162 {KEY_F8, "F8"},
163 {KEY_F9, "F9"},
164 {KEY_F10, "F10"},
165 {KEY_F11, "F11"},
166 {KEY_F12, "F12"},
167 // Numpad
168 {KEY_KP_0, "Numpad 0"},
169 {KEY_KP_1, "Numpad 1"},
170 {KEY_KP_2, "Numpad 2"},
171 {KEY_KP_3, "Numpad 3"},
172 {KEY_KP_4, "Numpad 4"},
173 {KEY_KP_5, "Numpad 5"},
174 {KEY_KP_6, "Numpad 6"},
175 {KEY_KP_7, "Numpad 7"},
176 {KEY_KP_8, "Numpad 8"},
177 {KEY_KP_9, "Numpad 9"},
178 // Mouse buttons (if needed)
179 {KEY_MINUS, "-"},
180 {KEY_EQUAL, "="},
181 {KEY_LEFT_BRACKET, "["},
182 {KEY_RIGHT_BRACKET, "]"},
183 {KEY_SEMICOLON, ";"},
184 {KEY_APOSTROPHE, "'"},
185 {KEY_COMMA, ","},
186 {KEY_PERIOD, "."},
187 {KEY_SLASH, "/"},
188 {KEY_BACKSLASH, "\\"},
189 {KEY_GRAVE, "`"},
190 };
191
192 auto it = keyNames.find(key);
193 if (it != keyNames.end()) {
194 return it->second;
195 }
196 return "Unknown";
197 }
198
199 std::string KeyBindings::GetGamepadButtonName(int button) {
200 static const std::unordered_map<int, std::string> buttonNames = {
201 {GAMEPAD_BUTTON_UNKNOWN, "Unknown"},
202 {GAMEPAD_BUTTON_LEFT_FACE_UP, "D-Pad Up"},
203 {GAMEPAD_BUTTON_LEFT_FACE_RIGHT, "D-Pad Right"},
204 {GAMEPAD_BUTTON_LEFT_FACE_DOWN, "D-Pad Down"},
205 {GAMEPAD_BUTTON_LEFT_FACE_LEFT, "D-Pad Left"},
206 {GAMEPAD_BUTTON_RIGHT_FACE_UP, "Y"},
207 {GAMEPAD_BUTTON_RIGHT_FACE_RIGHT, "B"},
208 {GAMEPAD_BUTTON_RIGHT_FACE_DOWN, "A"},
209 {GAMEPAD_BUTTON_RIGHT_FACE_LEFT, "X"},
210 {GAMEPAD_BUTTON_LEFT_TRIGGER_1, "LB"},
211 {GAMEPAD_BUTTON_LEFT_TRIGGER_2, "LT"},
212 {GAMEPAD_BUTTON_RIGHT_TRIGGER_1, "RB"},
213 {GAMEPAD_BUTTON_RIGHT_TRIGGER_2, "RT"},
214 {GAMEPAD_BUTTON_MIDDLE_LEFT, "Select"},
215 {GAMEPAD_BUTTON_MIDDLE, "Guide"},
216 {GAMEPAD_BUTTON_MIDDLE_RIGHT, "Start"},
217 {GAMEPAD_BUTTON_LEFT_THUMB, "L3"},
218 {GAMEPAD_BUTTON_RIGHT_THUMB, "R3"},
219 };
220
221 auto it = buttonNames.find(button);
222 if (it != buttonNames.end()) {
223 return it->second;
224 }
225 return "Gamepad ?";
226 }
227
228 std::string KeyBindings::GetBindingName(int binding) {
229 if (binding == KEY_NULL) {
230 return "None";
231 }
232 if (IsGamepadBinding(binding)) {
234 }
235 return GetKeyName(binding);
236 }
237
239 static const std::unordered_map<GameAction, std::string> actionNames = {
240 {GameAction::MOVE_UP, "Move Up"},
241 {GameAction::MOVE_DOWN, "Move Down"},
242 {GameAction::MOVE_LEFT, "Move Left"},
243 {GameAction::MOVE_RIGHT, "Move Right"},
244 {GameAction::SHOOT, "Shoot"},
245 {GameAction::PAUSE_MENU, "Pause Menu"},
246 {GameAction::CHAT_OPEN, "Open Chat"},
247 {GameAction::MENU_NEXT, "Menu Next"},
248 {GameAction::MENU_PREVIOUS, "Menu Previous"},
249 {GameAction::MENU_CONFIRM, "Menu Confirm"},
250 {GameAction::MENU_BACK, "Menu Back"},
251 };
252
253 auto it = actionNames.find(action);
254 if (it != actionNames.end()) {
255 return it->second;
256 }
257 return "Unknown Action";
258 }
259
260 void KeyBindings::SetOnBindingsChanged(std::function<void()> callback) {
261 _onBindingsChanged = std::move(callback);
262 }
263
269
270 bool KeyBindings::SaveToFile(const std::string &filepath) const {
271 std::ofstream file(filepath);
272 if (!file.is_open()) {
273 LOG_ERROR("[KeyBindings] Failed to open file for saving: ", filepath);
274 return false;
275 }
276
277 for (const auto &[action, binding] : _bindings) {
278 file << static_cast<int>(action) << " " << binding.primary << " " << binding.secondary << "\n";
279 }
280
281 LOG_INFO("[KeyBindings] Saved bindings to: ", filepath);
282 return true;
283 }
284
285 bool KeyBindings::LoadFromFile(const std::string &filepath) {
286 std::ifstream file(filepath);
287 if (!file.is_open()) {
288 LOG_WARNING("[KeyBindings] No bindings file found, using defaults: ", filepath);
289 return false;
290 }
291
292 std::string line;
293 while (std::getline(file, line)) {
294 std::istringstream iss(line);
295 int actionInt = 0;
296 int primary = 0;
297 int secondary = 0;
298 if (iss >> actionInt >> primary >> secondary) {
299 auto action = static_cast<GameAction>(actionInt);
300 _bindings[action] = {primary, secondary};
301 }
302 }
303
304 LOG_INFO("[KeyBindings] Loaded bindings from: ", filepath);
306 return true;
307 }
308
309} // namespace Input
#define LOG_INFO(...)
Definition Logger.hpp:181
#define LOG_ERROR(...)
Definition Logger.hpp:183
#define LOG_WARNING(...)
Definition Logger.hpp:182
Centralized key binding manager (Singleton)
void SetPrimaryKey(GameAction action, int key)
Set the primary key for an action.
static KeyBindings & getInstance()
Get the singleton instance.
void SetSecondaryKey(GameAction action, int key)
Set the secondary key for an action.
static std::string GetActionName(GameAction action)
Get human-readable name of an action.
static std::string GetGamepadButtonName(int button)
Get human-readable name of a gamepad button.
void ClearSecondaryKey(GameAction action)
Clear the secondary key for an action.
bool IsKeyBoundToAction(GameAction action, int key) const
Check if a key is bound to an action (primary or secondary)
int GetPrimaryKey(GameAction action) const
Get the primary key for an action.
bool SaveToFile(const std::string &filepath) const
Save bindings to a file.
static std::string GetBindingName(int binding)
Get human-readable name of a binding (keyboard key or gamepad button)
int GetSecondaryKey(GameAction action) const
Get the secondary key for an action.
bool LoadFromFile(const std::string &filepath)
Load bindings from a file.
std::function< void()> _onBindingsChanged
void SetOnBindingsChanged(std::function< void()> callback)
Set callback for when bindings change.
static std::string GetKeyName(int key)
Get human-readable name of a key.
void ResetToDefaults()
Reset all bindings to defaults.
std::unordered_map< GameAction, KeyBinding > _bindings
GameAction
Enumeration of all bindable game actions.
int BindingToGamepadButton(int binding)
Extract gamepad button from a binding value.
bool IsGamepadBinding(int binding)
Check if a binding value represents a gamepad button.
int GamepadButtonToBinding(int button)
Convert a gamepad button to a binding value.