16 #define GETTEXT_DOMAIN "wesnoth-lib"
31 #include <boost/algorithm/string.hpp>
36 #define ERR_G LOG_STREAM(err, lg::general())
37 #define LOG_G LOG_STREAM(info, lg::general())
38 #define DBG_G LOG_STREAM(debug, lg::general())
39 #define ERR_CF LOG_STREAM(err, log_config)
48 const int TOUCH_MOUSE_INDEX = 255;
55 if(
mod_ & SDL_KMOD_CTRL) {
59 ret += (!ret.empty() && !boost::algorithm::ends_with(ret,
"+") ?
"+" :
"");
60 if(
mod_ & SDL_KMOD_ALT) {
68 ret += (!ret.empty() && !boost::algorithm::ends_with(ret,
"+") ?
"+" :
"");
69 if(
mod_ & SDL_KMOD_SHIFT) {
73 ret += (!ret.empty() && !boost::algorithm::ends_with(ret,
"+") ?
"+" :
"");
74 if(
mod_ & SDL_KMOD_GUI) {
82 ret += (!ret.empty() && !boost::algorithm::ends_with(ret,
"+") ?
"+" :
"");
88 if(other ==
nullptr) {
96 if(scopematch.none()) {
117 item[
"shift"] = !!(
mod_ & SDL_KMOD_SHIFT);
118 item[
"ctrl"] = !!(
mod_ & SDL_KMOD_CTRL);
119 item[
"cmd"] = !!(
mod_ & SDL_KMOD_GUI);
120 item[
"alt"] = !!(
mod_ & SDL_KMOD_ALT);
127 hotkey_ptr base = std::make_shared<hotkey_void>();
132 case SDL_EVENT_KEY_UP: {
133 if(mods & SDL_KMOD_CTRL || mods & SDL_KMOD_ALT || mods & SDL_KMOD_GUI ||
CKey::is_uncomposable(event.key)
135 auto keyboard = std::make_shared<hotkey_keyboard>();
136 base = std::dynamic_pointer_cast<hotkey_base>(keyboard);
138 code =
event.key.key;
139 keyboard->set_keycode(code);
140 keyboard->set_text(SDL_GetKeyName(event.key.key));
144 case SDL_EVENT_TEXT_INPUT: {
148 auto keyboard = std::make_shared<hotkey_keyboard>();
149 base = std::dynamic_pointer_cast<hotkey_base>(keyboard);
150 std::string text = std::string(event.text.text);
151 keyboard->set_text(text);
152 if(text ==
":" || text ==
"`") {
153 mods = mods & ~SDL_KMOD_SHIFT;
157 case SDL_EVENT_MOUSE_BUTTON_UP: {
158 auto mouse = std::make_shared<hotkey_mouse>();
159 base = std::dynamic_pointer_cast<hotkey_base>(mouse);
160 mouse->set_button(event.button.button);
161 mouse->set_clicks(event.button.clicks);
166 ERR_G <<
"Trying to bind an unknown event type:" <<
event.type;
170 base->set_mods(mods);
171 base->set_command(
id);
172 base->unset_default();
179 hotkey_ptr base = std::make_shared<hotkey_void>();
182 if(!mouse_cfg.
empty()) {
183 auto mouse = std::make_shared<hotkey_mouse>();
184 base = std::dynamic_pointer_cast<hotkey_base>(mouse);
186 if(mouse_cfg.
to_int() == TOUCH_MOUSE_INDEX) {
187 mouse->set_button(TOUCH_MOUSE_INDEX);
189 mouse->set_button(
cfg[
"button"].to_int());
192 if(!
cfg[
"click"].empty()) {
193 mouse->set_clicks(
cfg[
"click"].to_int(1));
197 const std::string& key_cfg =
cfg[
"key"];
198 if(!key_cfg.empty()) {
199 auto keyboard = std::make_shared<hotkey_keyboard>();
200 base = std::dynamic_pointer_cast<hotkey_base>(keyboard);
202 SDL_Keycode keycode = SDL_GetKeyFromName(key_cfg.c_str());
203 if(keycode == SDLK_UNKNOWN) {
204 ERR_G <<
"Unknown key: " << key_cfg;
206 keyboard->set_text(key_cfg);
207 keyboard->set_keycode(keycode);
214 unsigned int mods = 0;
216 if(
cfg[
"shift"].to_bool())
217 mods |= SDL_KMOD_SHIFT;
218 if(
cfg[
"ctrl"].to_bool())
219 mods |= SDL_KMOD_CTRL;
220 if(
cfg[
"cmd"].to_bool())
221 mods |= SDL_KMOD_GUI;
222 if(
cfg[
"alt"].to_bool())
223 mods |= SDL_KMOD_ALT;
225 base->set_mods(mods);
226 base->set_command(
cfg[
"command"].str());
228 cfg[
"disabled"].to_bool() ? base->disable() : base->enable();
236 case SDL_EVENT_MOUSE_BUTTON_UP:
237 case SDL_EVENT_MOUSE_BUTTON_DOWN:
238 case SDL_EVENT_FINGER_DOWN:
239 case SDL_EVENT_FINGER_UP:
251 return button_ == TOUCH_MOUSE_INDEX &&
clicks_ ==
event.button.clicks;
254 return event.button.button ==
button_;
259 std::stringstream hotkey_name;
261 case SDL_BUTTON_LEFT:
262 hotkey_name <<
"left mouse";
264 case SDL_BUTTON_RIGHT:
265 hotkey_name <<
"right mouse";
267 case SDL_BUTTON_MIDDLE:
268 hotkey_name <<
"middle mouse";
271 hotkey_name <<
"mouse back";
274 hotkey_name <<
"mouse forward";
276 case TOUCH_MOUSE_INDEX:
277 hotkey_name <<
"touch";
284 hotkey_name <<
" (clicks: " <<
clicks_ <<
")";
287 return hotkey_name.str();
301 boost::algorithm::to_lower(
text_);
314 if((event.type == SDL_EVENT_KEY_DOWN || event.type == SDL_EVENT_KEY_UP)
320 if(event.type == SDL_EVENT_TEXT_INPUT && !command.
toggle) {
321 std::string text = std::string(event.text.text);
322 boost::algorithm::to_lower(text);
323 if(text ==
":" || text ==
"`") {
324 mods = mods & ~SDL_KMOD_SHIFT;
334 auto other_m = std::dynamic_pointer_cast<hotkey_mouse>(other);
335 if(other_m ==
nullptr) {
339 return button_ == other_m->button_;
352 if(item->get_command() == command) {
361 auto other_k = std::dynamic_pointer_cast<hotkey_keyboard>(other);
362 if(other_k ==
nullptr) {
366 return text_ == other_k->text_;
372 auto iter =
std::find_if(hotkeys_.begin(), hotkeys_.end(),
375 if(iter != hotkeys_.end()) {
378 hotkeys_.push_back(std::move(item));
386 if(item->get_command() == command) {
387 if(item->is_default()) {
404 if(item->matches(event)) {
408 return std::make_shared<hotkey_void>();
416 new_hotkeys.push_back(std::move(item));
420 default_hotkey_cfg_ =
cfg;
421 hotkeys_.
swap(new_hotkeys);
428 item->unset_default();
438 if(!default_hotkey_cfg_.child_range(prefs_list::hotkey).empty()) {
441 ERR_G <<
"no default hotkeys set yet; all hotkeys are now unassigned!";
455 if((!item->is_default() && item->active()) || (item->is_default() && item->is_disabled())) {
464 std::vector<std::string>
names;
466 if(item->get_command() ==
id && !item->null() && !item->is_disabled()) {
467 names.push_back(item->get_name());
473 names.push_back(
"escape");
474 }
else if(
id ==
"quit-to-desktop") {
476 names.push_back(
"cmd+q");
478 names.push_back(
"alt+F4");
487 if(event.type == SDL_EVENT_JOYSTICK_BUTTON_UP || event.type == SDL_EVENT_JOYSTICK_HAT_MOTION || event.type == SDL_EVENT_MOUSE_BUTTON_UP) {
493 if(mods & SDL_KMOD_CTRL || mods & SDL_KMOD_ALT || mods & SDL_KMOD_GUI) {
494 return event.type == SDL_EVENT_KEY_UP;
496 return event.type == SDL_EVENT_TEXT_INPUT ||
event.type == SDL_EVENT_KEY_UP;
std::vector< std::string > names
static bool is_uncomposable(const SDL_KeyboardEvent &event)
Variant for storing WML attributes.
int to_int(int def=0) const
bool empty() const
Tests for an attribute that either was never set or was set to "".
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
child_itors child_range(std::string_view key)
void clear_children(T... keys)
void swap(config &cfg) noexcept
A class grating read only view to a vector of config objects, viewed as one config with all children ...
virtual void save_helper(config &cfg) const =0
const std::string & get_command() const
Returns the string name of the HOTKEY_COMMAND.
std::string get_name() const
Return "name" of hotkey.
virtual bool bindings_equal(const hotkey_ptr &other)
Checks whether the hotkey bindings and scope are equal.
void save(config &cfg) const
Save the hotkey into the configuration object.
virtual bool bindings_equal_helper(hotkey_ptr other) const =0
This is invoked by hotkey_base::bindings_equal as a helper for the concrete classes.
bool matches(const SDL_Event &event) const
Used to evaluate whether:
virtual const std::string get_name_helper() const =0
This is invoked by hotkey_base::get_name and must be implemented by subclasses.
virtual bool matches_helper(const SDL_Event &event) const =0
This is invoked by hotkey_base::matches as a helper for the concrete classes.
void set_text(const std::string &text)
virtual void save_helper(config &cfg) const
virtual const std::string get_name_helper() const
This is invoked by hotkey_base::get_name and must be implemented by subclasses.
virtual bool bindings_equal_helper(hotkey_ptr other) const
This is invoked by hotkey_base::bindings_equal as a helper for the concrete classes.
virtual bool matches_helper(const SDL_Event &event) const
This is invoked by hotkey_base::matches as a helper for the concrete classes.
virtual const std::string get_name_helper() const
This is invoked by hotkey_base::get_name and must be implemented by subclasses.
virtual void save_helper(config &cfg) const
virtual bool matches_helper(const SDL_Event &event) const
This is invoked by hotkey_base::matches as a helper for the concrete classes.
virtual bool bindings_equal_helper(hotkey_ptr other) const
This is invoked by hotkey_base::bindings_equal as a helper for the concrete classes.
Definitions for the interface to Wesnoth Markup Language (WML).
static lg::log_domain log_config("config")
Standard logging facilities (interface).
bool is_touch(const SDL_MouseButtonEvent &event)
Check if this mouse button event is caused by a touch.
Keyboard shortcuts for game actions.
const hotkey_list & get_hotkeys()
Returns the list of hotkeys.
std::string get_names(const std::string &id)
Returns a comma-separated string of hotkey names.
void save_hotkeys(config &cfg)
Save the non-default hotkeys to the config.
std::shared_ptr< class hotkey_base > hotkey_ptr
bool has_hotkey_item(const std::string &command)
const hotkey_ptr get_hotkey(const SDL_Event &event)
Iterate through the list of hotkeys and return a hotkey that matches the SDL_Event and the current ke...
void clear_hotkeys(const std::string &command)
Unset the command bindings for all hotkeys matching the command.
void reset_default_hotkeys()
Reset all hotkeys to the defaults.
hotkey_ptr load_from_config(const config &cfg)
Create and instantiate a hotkey from a config element.
hotkey_ptr create_hotkey(const std::string &id, const SDL_Event &event)
Create a new hotkey item for a command from an SDL_Event.
std::bitset< SCOPE_COUNT > hk_scopes
const hotkey_command & get_hotkey_command(std::string_view command)
Returns the hotkey_command with the given id.
std::vector< hotkey::hotkey_ptr > hotkey_list
void load_custom_hotkeys(const game_config_view &cfg)
Registers all hotkeys present in this config, overwriting any matching default hotkeys.
bool is_scope_active(scope s)
scope
Available hotkey scopes.
void load_default_hotkeys(const game_config_view &cfg)
Registers all hotkeys present in this config.
void add_hotkey(hotkey_ptr item)
Add a hotkey to the list of hotkeys.
bool is_hotkeyable_event(const SDL_Event &event)
unsigned get_mods()
Returns a bitmask of active modifier keys (ctrl, shift, alt, gui).
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
auto * find_if(Container &container, const Predicate &predicate)
Convenience wrapper for using find_if on a container without needing to comare to end()
std::string join(const Range &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string to_string(const Range &range, const Func &op)
This file contains object "key", which is used to store information about keys while annotation parsi...
Stores all information related to functions that can be bound to hotkeys.
bool toggle
Toggle hotkeys have some restrictions on what can be bound to them.
hk_scopes scope
The visibility scope of the command.