Fix 24681: Proper filtering of modifiers when handling hotkeys

This adds proper handling for composition of input and also handles
raw key up/down properly when there are modifiers applied to the
keyboard that stops composition.
This commit is contained in:
Andreas Löf 2017-04-08 23:36:58 +12:00
parent 92ca7fdb5e
commit daef8cd22c
4 changed files with 98 additions and 27 deletions

View file

@ -20,18 +20,12 @@
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gettext.hpp"
#include "serialization/unicode.hpp"
#include "sdl/surface.hpp"
#include <boost/algorithm/string/join.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include "utils/functional.hpp"
#include "key.hpp"
#include <SDL.h>
#include <key.hpp>
static lg::log_domain log_config("config");
@ -152,17 +146,27 @@ void hotkey_base::save(config& item) const
hotkey_ptr create_hotkey(const std::string &id, SDL_Event &event)
{
hotkey_ptr base = hotkey_ptr(new hotkey_void);
unsigned mods = sdl_get_mods();
switch (event.type) {
case SDL_KEYDOWN:
case SDL_KEYUP: {
if (mods & KMOD_CTRL || mods & KMOD_ALT || mods & KMOD_GUI || CKey::is_uncomposable(event.key)) {
hotkey_keyboard_ptr keyboard(new hotkey_keyboard());
base = std::dynamic_pointer_cast<hotkey_base>(keyboard);
SDL_Keycode code;
code = event.key.keysym.sym;
keyboard->set_keycode(code);
keyboard->set_text(SDL_GetKeyName(event.key.keysym.sym));
}
}
break;
case SDL_TEXTINPUT: {
hotkey_keyboard_ptr keyboard(new hotkey_keyboard());
base = std::dynamic_pointer_cast<hotkey_base>(keyboard);
SDL_Keycode code;
code = event.key.keysym.sym;
keyboard->set_keycode(code);
break;
keyboard->set_text(std::string(event.text.text));
}
break;
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
hotkey_mouse_ptr mouse(new hotkey_mouse());
@ -279,32 +283,29 @@ void hotkey_mouse::save_helper(config &item) const
const std::string hotkey_keyboard::get_name_helper() const
{
std::string ret = text_;
if (ret.size() == 1) {
boost::algorithm::to_lower(ret);
}
return ret;
return text_;
}
bool hotkey_keyboard::matches_helper(const SDL_Event &event) const
{
unsigned int mods = sdl_get_mods();
if (event.type == SDL_TEXTINPUT && text_.length() == 1) {
if ((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) &&
(mods & KMOD_CTRL || mods & KMOD_ALT || mods & KMOD_GUI ||
CKey::is_uncomposable(event.key))) {
return event.key.keysym.sym == keycode_ && mods == mod_;
}
if (event.type == SDL_TEXTINPUT) {
std::string text = std::string(event.text.text);
boost::algorithm::to_lower(text);
if (text == ":") {
mods = mods & ~KMOD_SHIFT;
}
return text_ == text && mods == mod_;
} else if ((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) &&
(text_.length() > 1 || mods & (KMOD_CTRL|KMOD_ALT|KMOD_GUI)) ) {
return event.key.keysym.sym == keycode_ && mods == mod_;
} else {
return false;
return text_ == text && mods == mod_;
}
return false;
}
bool hotkey_mouse::bindings_equal_helper(hotkey_ptr other) const
@ -474,4 +475,22 @@ std::string get_names(std::string id)
return boost::algorithm::join(names, ", ");
}
bool is_hotkeyable_event(const SDL_Event &event) {
if (event.type == SDL_JOYBUTTONUP ||
event.type == SDL_JOYHATMOTION ||
event.type == SDL_MOUSEBUTTONUP) {
return true;
}
unsigned mods = sdl_get_mods();
if (mods & KMOD_CTRL || mods & KMOD_ALT || mods & KMOD_GUI) {
return event.type == SDL_KEYUP;
} else {
return event.type == SDL_TEXTINPUT ||
(event.type == SDL_KEYUP && CKey::is_uncomposable(event.key));
}
}
}

View file

@ -21,6 +21,7 @@
#include <memory>
#include <vector>
#include <string>
#include <boost/algorithm/string.hpp>
class config;
class CVideo;
@ -256,6 +257,7 @@ public:
void set_text(std::string text)
{
text_ = text;
boost::algorithm::to_lower(text_);
}
/**
@ -437,6 +439,8 @@ void save_hotkeys(config& cfg);
hotkey_ptr show_binding_dialog(CVideo& video, const std::string& id);
bool is_hotkeyable_event(const SDL_Event &event);
}
#endif

View file

@ -14,8 +14,6 @@
#include "key.hpp"
#include <SDL_keyboard.h>
CKey::CKey() :
key_list(SDL_GetKeyboardState(nullptr))
{
@ -25,3 +23,51 @@ bool CKey::operator[](int k) const
{
return key_list[SDL_GetScancodeFromKey(k)] > 0;
}
bool CKey::is_uncomposable(const SDL_KeyboardEvent &event) {
switch (event.keysym.sym) {
case SDLK_RETURN:
case SDLK_ESCAPE:
case SDLK_BACKSPACE:
case SDLK_TAB:
case SDLK_F1:
case SDLK_F2:
case SDLK_F3:
case SDLK_F4:
case SDLK_F5:
case SDLK_F6:
case SDLK_F7:
case SDLK_F8:
case SDLK_F9:
case SDLK_F10:
case SDLK_F11:
case SDLK_F12:
case SDLK_F13:
case SDLK_F14:
case SDLK_F15:
case SDLK_F16:
case SDLK_F17:
case SDLK_F18:
case SDLK_F19:
case SDLK_F20:
case SDLK_F21:
case SDLK_F22:
case SDLK_F23:
case SDLK_F24:
case SDLK_INSERT:
case SDLK_HOME:
case SDLK_PAGEUP:
case SDLK_PAGEDOWN:
case SDLK_DELETE:
case SDLK_END:
case SDLK_UP:
case SDLK_DOWN:
case SDLK_LEFT:
case SDLK_RIGHT:
return true;
default:
return false;
}
}

View file

@ -16,6 +16,7 @@
#define KEY_HPP_INCLUDED
#include <cstdint>
#include <SDL.h>
/**
* Class that keeps track of all the keys on the keyboard.
@ -31,6 +32,7 @@ class CKey
public:
CKey();
bool operator[](int k) const;
static bool is_uncomposable(const SDL_KeyboardEvent &event);
};
#endif