Antkeeper  0.0.1
keyboard-config-menu-state.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 Christopher J. Howard
3  *
4  * This file is part of Antkeeper source code.
5  *
6  * Antkeeper source code is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Antkeeper source code is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Antkeeper source code. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
22 #include "game/controls.hpp"
23 #include <engine/scene/text.hpp>
24 #include <engine/debug/log.hpp>
26 #include "game/menu.hpp"
27 #include "game/controls.hpp"
28 #include "game/strings.hpp"
30 #include <format>
31 #include <utility>
32 
33 using namespace hash::literals;
34 
36  game_state(ctx),
37  action_remapped(false)
38 {
39  debug::log_trace("Entering keyboard config menu state...");
40 
41  // Add control menu items
42  add_control_item(ctx.movement_action_map, ctx.move_forward_action, "control_move_forward");
43  add_control_item(ctx.movement_action_map, ctx.move_back_action, "control_move_back");
44  add_control_item(ctx.movement_action_map, ctx.move_left_action, "control_move_left");
45  add_control_item(ctx.movement_action_map, ctx.move_right_action, "control_move_right");
46  add_control_item(ctx.movement_action_map, ctx.move_up_action, "control_move_up");
47  add_control_item(ctx.movement_action_map, ctx.move_down_action, "control_move_down");
48  add_control_item(ctx.movement_action_map, ctx.pause_action, "control_pause");
49 
50  // Construct menu item texts
51  back_text = std::make_unique<scene::text>();
52 
53  // Build list of menu item texts
54  ctx.menu_item_texts.push_back({back_text.get(), nullptr});
55 
56  // Set content of menu item texts
57  back_text->set_content(get_string(ctx, "back"));
58 
59  // Init menu item index
60  ::menu::init_menu_item_index(ctx, "keyboard_config");
61 
67 
68  // Construct menu item callbacks
69  auto select_back_callback = [&ctx]()
70  {
71  // Disable menu controls
72  ctx.function_queue.push(std::bind(::disable_menu_controls, std::ref(ctx)));
73 
75  (
76  ctx,
77  [&ctx]()
78  {
79  // Queue change to controls menu state
80  ctx.function_queue.push
81  (
82  [&ctx]()
83  {
84  ctx.state_machine.pop();
85  ctx.state_machine.emplace(std::make_unique<controls_menu_state>(ctx));
86  }
87  );
88  }
89  );
90  };
91 
92  // Build list of menu select callbacks
93  ctx.menu_select_callbacks.push_back(select_back_callback);
94 
95  // Build list of menu left callbacks
96  ctx.menu_left_callbacks.push_back(nullptr);
97 
98  // Build list of menu right callbacks
99  ctx.menu_right_callbacks.push_back(nullptr);
100 
101  // Set menu back callback
102  ctx.menu_back_callback = select_back_callback;
103 
104  // Enable menu controls next frame
105  ctx.function_queue.push(std::bind(::enable_menu_controls, std::ref(ctx)));
106 
107  // Fade in menu
108  ::menu::fade_in(ctx, nullptr);
109 
110  debug::log_trace("Entered keyboard config menu state");
111 }
112 
114 {
115  debug::log_trace("Exiting keyboard config menu state...");
116 
117  // Destruct menu
123 
124  if (action_remapped)
125  {
126  // Update control profile
128 
129  // Save control profile
130  ctx.resource_manager->set_write_path(ctx.controls_path);
132  }
133 
134  debug::log_trace("Exited keyboard config menu state...");
135 }
136 
137 std::string keyboard_config_menu_state::get_mapping_string(const input::action_map& action_map, const input::action& control)
138 {
139  std::string mapping_string;
140 
141  if (auto key_mappings = action_map.get_key_mappings(control); !key_mappings.empty())
142  {
143  const auto& key_mapping = key_mappings.front();
144 
145  // Get name of scancode string from scancode
146  std::string scancode_string_name = std::format("scancode_{:02x}", std::to_underlying(key_mapping.scancode));
147 
148  // Set mapping string to scancode string
149  mapping_string = get_string(ctx, hash::fnv1a32<char>(scancode_string_name));
150  }
151  else if (auto mouse_button_mappings = action_map.get_mouse_button_mappings(control); !mouse_button_mappings.empty())
152  {
153  const auto& mouse_button_mapping = mouse_button_mappings.front();
154  switch (mouse_button_mapping.button)
155  {
157  mapping_string = get_string(ctx, "mouse_button_left");
158  break;
159 
161  mapping_string = get_string(ctx, "mouse_button_middle");
162  break;
163 
165  mapping_string = get_string(ctx, "mouse_button_right");
166  break;
167 
168  default:
169  {
170  std::string format_string = get_string(ctx, "mouse_button_n_format");
171  mapping_string = std::vformat(format_string, std::make_format_args(std::to_underlying(mouse_button_mapping.button)));
172  break;
173  }
174  }
175  }
176  else if (auto mouse_scroll_mappings = action_map.get_mouse_scroll_mappings(control); !mouse_scroll_mappings.empty())
177  {
178  const auto& mouse_scroll_mapping = mouse_scroll_mappings.front();
179 
180  if (mouse_scroll_mapping.axis == input::mouse_scroll_axis::x)
181  {
182  if (!mouse_scroll_mapping.direction)
183  {
184  mapping_string = get_string(ctx, "mouse_scroll_left");
185  }
186  else
187  {
188  mapping_string = get_string(ctx, "mouse_scroll_right");
189  }
190  }
191  else
192  {
193  if (!mouse_scroll_mapping.direction)
194  {
195  mapping_string = get_string(ctx, "mouse_scroll_up");
196  }
197  else
198  {
199  mapping_string = get_string(ctx, "mouse_scroll_down");
200  }
201  }
202  }
203  else
204  {
205  mapping_string = get_string(ctx, "control_unmapped");
206  }
207 
208  return mapping_string;
209 }
210 
211 void keyboard_config_menu_state::add_control_item(input::action_map& action_map, input::action& control, hash::fnv1a32_t control_name_hash)
212 {
213  // Construct texts
214  auto name_text = std::make_unique<scene::text>();
215  auto value_text = std::make_unique<scene::text>();
216 
217  // Add texts to list of menu item texts
218  ctx.menu_item_texts.push_back({name_text.get(), value_text.get()});
219 
220  // Set control name and mapping texts
221  name_text->set_content(get_string(ctx, control_name_hash));
222  value_text->set_content(get_mapping_string(action_map, control));
223 
224  // Callback invoked when an input has been mapped to the control
225  auto input_mapped_callback = [this, &ctx = this->ctx, action_map = &action_map, control = &control, value_text = value_text.get()](const auto& event)
226  {
227  this->action_remapped = true;
228 
229  // Remove key mappings, mouse button mappings, and mouse scroll mappings mapped to the control
230  action_map->remove_mappings(*control, input::mapping_type::key);
231  action_map->remove_mappings(*control, input::mapping_type::mouse_button);
232  action_map->remove_mappings(*control, input::mapping_type::mouse_scroll);
233 
234  //if (event.mapping.scancode != input::scancode::escape && event.mapping.scancode != input::scancode::backspace)
235  {
236  // Map generated input mapping to the control
237  action_map->add_mapping(*control, event.mapping);
238  }
239 
240  // Update control mapping text
241  value_text->set_content(this->get_mapping_string(*action_map, *control));
243 
244  // Queue disabling of input mapper re-enabling of menu controls
245  ctx.function_queue.push
246  (
247  [&ctx]()
248  {
251  }
252  );
253  };
254 
255  // Callback invoked when the control menu item has been selected
256  auto select_callback = [this, &ctx = this->ctx, action_map = &action_map, control = &control, value_text = value_text.get(), input_mapped_callback]()
257  {
258  // Set control mapping text to "..."
259  value_text->set_content(get_string(ctx, "control_mapping"));
261 
262  // Setup input mapped callbacks
263  key_mapped_subscription = ctx.input_mapper.get_key_mapped_channel().subscribe
264  (
265  input_mapped_callback
266  );
267  mouse_button_mapped_subscription = ctx.input_mapper.get_mouse_button_mapped_channel().subscribe
268  (
269  input_mapped_callback
270  );
271  mouse_scroll_mapped_subscription = ctx.input_mapper.get_mouse_scroll_mapped_channel().subscribe
272  (
273  input_mapped_callback
274  );
275 
276  // Queue disabling of menu controls and enabling of input mapper
277  ctx.function_queue.push
278  (
279  [&]()
280  {
282  ctx.input_mapper.connect(ctx.input_manager->get_event_dispatcher());
283  }
284  );
285  };
286 
287  control_item_texts.emplace_back(std::move(name_text));
288  control_item_texts.emplace_back(std::move(value_text));
289 
290  // Register menu item callbacks
291  ctx.menu_select_callbacks.push_back(select_callback);
292  ctx.menu_left_callbacks.push_back(nullptr);
293  ctx.menu_right_callbacks.push_back(nullptr);
294 }
Abstract base class for game states.
Definition: game-state.hpp:29
::game & ctx
Definition: game-state.hpp:44
Definition: game.hpp:121
std::vector< std::function< void()> > menu_left_callbacks
Definition: game.hpp:348
input::action move_up_action
Definition: game.hpp:220
input::action move_down_action
Definition: game.hpp:221
std::vector< std::function< void()> > menu_right_callbacks
Definition: game.hpp:349
hsm::state_machine< game_state > state_machine
Definition: game.hpp:299
input::action move_right_action
Definition: game.hpp:219
input::action pause_action
Definition: game.hpp:224
std::vector< std::function< void()> > menu_select_callbacks
Definition: game.hpp:347
std::filesystem::path controls_path
Definition: game.hpp:159
std::string control_profile_filename
Definition: game.hpp:195
input::action move_left_action
Definition: game.hpp:218
input::action move_forward_action
Definition: game.hpp:216
std::vector< std::tuple< scene::text *, scene::text * > > menu_item_texts
Definition: game.hpp:351
std::unique_ptr< resource_manager > resource_manager
Definition: game.hpp:152
std::queue< std::function< void()> > function_queue
Definition: game.hpp:303
input::action move_back_action
Definition: game.hpp:217
std::function< void()> menu_back_callback
Definition: game.hpp:350
input::action_map movement_action_map
Definition: game.hpp:213
input::mapper input_mapper
Definition: game.hpp:214
std::unique_ptr< app::input_manager > input_manager
Definition: game.hpp:172
std::shared_ptr<::control_profile > control_profile
Definition: game.hpp:196
Maps input to a set of contextually-related actions.
Definition: action-map.hpp:43
std::vector< key_mapping > get_key_mappings(const action &action) const
Returns all of the key mappings associated with an action.
Definition: action-map.cpp:442
std::vector< mouse_button_mapping > get_mouse_button_mappings(const action &action) const
Returns all of the mouse button mappings associated with an action.
Definition: action-map.cpp:457
std::vector< mouse_scroll_mapping > get_mouse_scroll_mappings(const action &action) const
Returns all of the mouse scroll associated with an action.
Definition: action-map.cpp:487
Evaluates an activation state given input values and publishes events on activation state changes.
Definition: action.hpp:33
::event::channel< mouse_scroll_mapped_event > & get_mouse_scroll_mapped_channel() noexcept
Returns the channel through which mouse scroll mapped events are published.
Definition: mapper.hpp:84
::event::channel< key_mapped_event > & get_key_mapped_channel() noexcept
Returns the channel through which key mapped events are published.
Definition: mapper.hpp:66
void disconnect()
Disconnects all input event signals from the mapper.
Definition: mapper.cpp:35
::event::channel< mouse_button_mapped_event > & get_mouse_button_mapped_channel() noexcept
Returns the channel through which mouse button mapped events are published.
Definition: mapper.hpp:72
void connect(::event::dispatcher &dispatcher)
Connects the input event signals of an event dispatcher to the mapper.
Definition: mapper.cpp:25
void update_control_profile(::game &ctx, ::control_profile &profile)
Updates a control profile after actions have been remapped.
Definition: controls.cpp:273
void enable_menu_controls(::game &ctx)
void disable_menu_controls(::game &ctx)
log_message< log_message_severity::trace, Args... > log_trace
Formats and logs a trace message.
Definition: log.hpp:88
Publish-subscribe messaging.
Definition: channel.hpp:32
format
Image and vertex formats.
Definition: format.hpp:29
User-defined literals for compile-time string hashing.
Definition: fnv1a.hpp:232
@ middle
Middle mouse button.
@ right
Right mouse button.
@ left
Left mouse button.
@ key
Key mapping.
@ mouse_button
Mouse button mapping.
@ mouse_scroll
Mouse scroll mapping.
void init_menu_item_index(::game &ctx, hash::fnv1a32_t menu_name)
Definition: menu.cpp:31
void update_text_color(::game &ctx)
Definition: menu.cpp:59
void clear_callbacks(::game &ctx)
Definition: menu.cpp:197
void delete_animations(::game &ctx)
Definition: menu.cpp:191
void align_text(::game &ctx, bool center, bool has_back, float anchor_y)
Definition: menu.cpp:73
void setup_animations(::game &ctx)
Definition: menu.cpp:206
void add_text_to_ui(::game &ctx)
Definition: menu.cpp:166
void fade_out(::game &ctx, const std::function< void()> &end_callback)
Definition: menu.cpp:263
void update_text_font(::game &ctx)
Definition: menu.cpp:44
void fade_in(::game &ctx, const std::function< void()> &end_callback)
Definition: menu.cpp:233
void remove_text_from_ui(::game &ctx)
Definition: menu.cpp:176
void delete_text(::game &ctx)
Definition: menu.cpp:186
std::string get_string(const ::game &ctx, hash::fnv1a32_t key)
Returns a localized string.
Definition: strings.cpp:23
32-bit FNV-1a hash value.
Definition: fnv1a.hpp:117