lxgui
gui_key_binder.cpp
1 #include "lxgui/gui_key_binder.hpp"
2 
3 #include "lxgui/gui_event_emitter.hpp"
4 #include "lxgui/gui_out.hpp"
5 #include "lxgui/input_dispatcher.hpp"
6 #include "lxgui/utils_std.hpp"
7 #include "lxgui/utils_string.hpp"
8 
9 #include <lxgui/extern_sol2_state.hpp>
10 
11 namespace lxgui::gui {
12 
13 utils::connection
14 key_binder::register_key_binding(std::string_view name, sol::protected_function lua_function) {
15  auto function = [lua_function = std::move(lua_function)]() {
16  // Call function
17  auto result = lua_function();
18 
19  // Handle errors
20  if (!result.valid()) {
21  throw gui::exception(result.get<sol::error>().what());
22  }
23  };
24 
25  return register_key_binding(name, std::move(function));
26 }
27 
29  auto iter =
30  utils::find_if(key_bindings_, [&](const auto& binding) { return binding.name == name; });
31 
32  if (iter == key_bindings_.end()) {
33  gui::out << gui::error << "key_binder: a binding already exists with name '" << name << "'."
34  << std::endl;
35  return {};
36  }
37 
38  key_binding binding;
39  binding.name = std::string(name);
40  auto connection = binding.signal.connect(std::move(function));
41  key_bindings_.push_back(std::move(binding));
42 
43  return connection;
44 }
45 
47  std::string_view name,
48  input::key key_id,
49  bool shift_is_pressed,
50  bool ctrl_is_pressed,
51  bool alt_is_pressed) {
52  auto iter =
53  utils::find_if(key_bindings_, [&](const auto& binding) { return binding.name == name; });
54 
55  if (iter == key_bindings_.end()) {
56  gui::out << gui::error << "key_binder: no binding with name '" << name << "'." << std::endl;
57  return;
58  }
59 
60  iter->key_id = key_id;
61  iter->shift_is_pressed =
62  shift_is_pressed || key_id == input::key::k_lshift || key_id == input::key::k_rshift;
63  iter->ctrl_is_pressed =
64  ctrl_is_pressed || key_id == input::key::k_lcontrol || key_id == input::key::k_rcontrol;
65  iter->alt_is_pressed =
66  alt_is_pressed || key_id == input::key::k_lmenu || key_id == input::key::k_rmenu;
67 }
68 
69 void key_binder::set_key_binding(std::string_view name, std::string_view key_name) {
70  bool shift_is_pressed = false;
71  bool ctrl_is_pressed = false;
72  bool alt_is_pressed = false;
73 
74  const auto tokens = utils::cut(key_name, "-");
75  for (auto token : tokens) {
76  if (token == "Shift")
77  shift_is_pressed = true;
78  else if (token == "Ctrl")
79  ctrl_is_pressed = true;
80  else if (token == "Alt")
81  alt_is_pressed = true;
82  }
83 
85  name, input::get_key_from_codename(tokens.back()), shift_is_pressed, ctrl_is_pressed,
86  alt_is_pressed);
87 }
88 
89 void key_binder::remove_key_binding(std::string_view name) {
90  auto iter =
91  utils::find_if(key_bindings_, [&](const auto& binding) { return binding.name == name; });
92 
93  if (iter == key_bindings_.end()) {
94  gui::out << gui::error << "key_binder: no binding with name '" << name << "'." << std::endl;
95  return;
96  }
97 
98  key_bindings_.erase(iter);
99 }
100 
101 key_binder::key_binding* key_binder::find_binding_(
102  input::key key_id, bool shift_is_pressed, bool ctrl_is_pressed, bool alt_is_pressed) {
103  auto iter = utils::find_if(key_bindings_, [&](const auto& binding) {
104  return binding.key_id == key_id && binding.shift_is_pressed == shift_is_pressed &&
105  binding.ctrl_is_pressed == ctrl_is_pressed &&
106  binding.alt_is_pressed == alt_is_pressed;
107  });
108 
109  if (iter == key_bindings_.end())
110  return nullptr;
111 
112  return &*iter;
113 }
114 
116  input::key key_id, bool shift_is_pressed, bool ctrl_is_pressed, bool alt_is_pressed) {
117  auto* binding = find_binding_(key_id, shift_is_pressed, ctrl_is_pressed, alt_is_pressed);
118  if (!binding)
119  return false;
120 
121  try {
122  binding->signal();
123  } catch (const std::exception& e) {
124  throw std::runtime_error("Bound action: " + binding->name + ": " + std::string(e.what()));
125  }
126 
127  return true;
128 }
129 
130 } // namespace lxgui::gui
Exception to be thrown by GUI code.
void set_key_binding(std::string_view name, std::string_view key_name)
Binds an action to a key.
signal_type::function_type function_type
Type of a keybinding callback.
utils::connection register_key_binding(std::string_view name, sol::protected_function lua_function)
Registers an action as a possible key binding.
void remove_key_binding(std::string_view name)
Unbinds an action.
bool on_key_down(input::key key_id, bool shift_is_pressed, bool ctrl_is_pressed, bool alt_is_pressed)
Called when a key is pressed.
Object representing the connection between a slot and a signal.
std::ostream out
const std::string error
Definition: gui_out.cpp:7
@ k_lcontrol
Enter on main keyboard.
@ k_rshift
/ on main keyboard
@ k_rcontrol
Enter on numeric keypad.
key get_key_from_codename(std::string_view key_name)
Returns the key code from the standard English name of a key.
Definition: input_keys.cpp:240
auto find_if(C &v, T &&f)
Definition: utils_std.hpp:19