1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-06-27 16:36:03 +00:00

Improve KeyPress handling (#15923)

* Pass KeyPress by value
* TouchControls: add setting change callback for keybindings
This commit is contained in:
y5nw 2025-03-21 12:07:51 +01:00 committed by GitHub
parent ead44a27ca
commit 4ba438a7ec
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 51 additions and 37 deletions

View file

@ -77,7 +77,7 @@ void KeyCache::populate()
if (handler) { if (handler) {
// First clear all keys, then re-add the ones we listen for // First clear all keys, then re-add the ones we listen for
handler->dontListenForKeys(); handler->dontListenForKeys();
for (const KeyPress &k : key) { for (auto k : key) {
handler->listenForKey(k); handler->listenForKey(k);
} }
handler->listenForKey(EscapeKey); handler->listenForKey(EscapeKey);
@ -111,7 +111,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
// This is separate from other keyboard handling so that it also works in menus. // This is separate from other keyboard handling so that it also works in menus.
if (event.EventType == EET_KEY_INPUT_EVENT) { if (event.EventType == EET_KEY_INPUT_EVENT) {
const KeyPress keyCode(event.KeyInput); KeyPress keyCode(event.KeyInput);
if (keyCode == getKeySetting("keymap_fullscreen")) { if (keyCode == getKeySetting("keymap_fullscreen")) {
if (event.KeyInput.PressedDown && !fullscreen_is_down) { if (event.KeyInput.PressedDown && !fullscreen_is_down) {
IrrlichtDevice *device = RenderingEngine::get_raw_device(); IrrlichtDevice *device = RenderingEngine::get_raw_device();
@ -142,7 +142,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
// Remember whether each key is down or up // Remember whether each key is down or up
if (event.EventType == irr::EET_KEY_INPUT_EVENT) { if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
const KeyPress keyCode(event.KeyInput); KeyPress keyCode(event.KeyInput);
if (keyCode && keysListenedFor[keyCode]) { // ignore key input that is invalid or irrelevant for the game. if (keyCode && keysListenedFor[keyCode]) { // ignore key input that is invalid or irrelevant for the game.
if (event.KeyInput.PressedDown) { if (event.KeyInput.PressedDown) {
if (!IsKeyDown(keyCode)) if (!IsKeyDown(keyCode))

View file

@ -53,7 +53,7 @@ class KeyList : private std::list<KeyPress>
typedef super::iterator iterator; typedef super::iterator iterator;
typedef super::const_iterator const_iterator; typedef super::const_iterator const_iterator;
virtual const_iterator find(const KeyPress &key) const virtual const_iterator find(KeyPress key) const
{ {
const_iterator f(begin()); const_iterator f(begin());
const_iterator e(end()); const_iterator e(end());
@ -68,7 +68,7 @@ class KeyList : private std::list<KeyPress>
return e; return e;
} }
virtual iterator find(const KeyPress &key) virtual iterator find(KeyPress key)
{ {
iterator f(begin()); iterator f(begin());
iterator e(end()); iterator e(end());
@ -86,13 +86,13 @@ class KeyList : private std::list<KeyPress>
public: public:
void clear() { super::clear(); } void clear() { super::clear(); }
void set(const KeyPress &key) void set(KeyPress key)
{ {
if (find(key) == end()) if (find(key) == end())
push_back(key); push_back(key);
} }
void unset(const KeyPress &key) void unset(KeyPress key)
{ {
iterator p(find(key)); iterator p(find(key));
@ -100,7 +100,7 @@ public:
erase(p); erase(p);
} }
void toggle(const KeyPress &key) void toggle(KeyPress key)
{ {
iterator p(this->find(key)); iterator p(this->find(key));
@ -112,12 +112,12 @@ public:
void append(const KeyList &other) void append(const KeyList &other)
{ {
for (const KeyPress &key : other) { for (auto key : other) {
set(key); set(key);
} }
} }
bool operator[](const KeyPress &key) const { return find(key) != end(); } bool operator[](KeyPress key) const { return find(key) != end(); }
}; };
class MyEventReceiver : public IEventReceiver class MyEventReceiver : public IEventReceiver
@ -126,10 +126,10 @@ public:
// This is the one method that we have to implement // This is the one method that we have to implement
virtual bool OnEvent(const SEvent &event); virtual bool OnEvent(const SEvent &event);
bool IsKeyDown(const KeyPress &keyCode) const { return keyIsDown[keyCode]; } bool IsKeyDown(KeyPress keyCode) const { return keyIsDown[keyCode]; }
// Checks whether a key was down and resets the state // Checks whether a key was down and resets the state
bool WasKeyDown(const KeyPress &keyCode) bool WasKeyDown(KeyPress keyCode)
{ {
bool b = keyWasDown[keyCode]; bool b = keyWasDown[keyCode];
if (b) if (b)
@ -139,13 +139,13 @@ public:
// Checks whether a key was just pressed. State will be cleared // Checks whether a key was just pressed. State will be cleared
// in the subsequent iteration of Game::processPlayerInteraction // in the subsequent iteration of Game::processPlayerInteraction
bool WasKeyPressed(const KeyPress &keycode) const { return keyWasPressed[keycode]; } bool WasKeyPressed(KeyPress keycode) const { return keyWasPressed[keycode]; }
// Checks whether a key was just released. State will be cleared // Checks whether a key was just released. State will be cleared
// in the subsequent iteration of Game::processPlayerInteraction // in the subsequent iteration of Game::processPlayerInteraction
bool WasKeyReleased(const KeyPress &keycode) const { return keyWasReleased[keycode]; } bool WasKeyReleased(KeyPress keycode) const { return keyWasReleased[keycode]; }
void listenForKey(const KeyPress &keyCode) void listenForKey(KeyPress keyCode)
{ {
keysListenedFor.set(keyCode); keysListenedFor.set(keyCode);
} }
@ -247,7 +247,7 @@ public:
virtual void clearWasKeyPressed() {} virtual void clearWasKeyPressed() {}
virtual void clearWasKeyReleased() {} virtual void clearWasKeyReleased() {}
virtual void listenForKey(const KeyPress &keyCode) {} virtual void listenForKey(KeyPress keyCode) {}
virtual void dontListenForKeys() {} virtual void dontListenForKeys() {}
virtual v2s32 getMousePos() = 0; virtual v2s32 getMousePos() = 0;
@ -316,7 +316,7 @@ public:
m_receiver->clearWasKeyReleased(); m_receiver->clearWasKeyReleased();
} }
virtual void listenForKey(const KeyPress &keyCode) virtual void listenForKey(KeyPress keyCode)
{ {
m_receiver->listenForKey(keyCode); m_receiver->listenForKey(keyCode);
} }

View file

@ -367,7 +367,7 @@ bool KeyPress::loadFromScancode(const std::string &name)
} }
std::unordered_map<std::string, KeyPress> specialKeyCache; std::unordered_map<std::string, KeyPress> specialKeyCache;
const KeyPress &KeyPress::getSpecialKey(const std::string &name) KeyPress KeyPress::getSpecialKey(const std::string &name)
{ {
auto &key = specialKeyCache[name]; auto &key = specialKeyCache[name];
if (!key) if (!key)
@ -382,7 +382,7 @@ const KeyPress &KeyPress::getSpecialKey(const std::string &name)
// A simple cache for quicker lookup // A simple cache for quicker lookup
static std::unordered_map<std::string, KeyPress> g_key_setting_cache; static std::unordered_map<std::string, KeyPress> g_key_setting_cache;
const KeyPress &getKeySetting(const std::string &settingname) KeyPress getKeySetting(const std::string &settingname)
{ {
auto n = g_key_setting_cache.find(settingname); auto n = g_key_setting_cache.find(settingname);
if (n != g_key_setting_cache.end()) if (n != g_key_setting_cache.end())

View file

@ -10,7 +10,9 @@
#include <string> #include <string>
#include <variant> #include <variant>
/* A key press, consisting of a scancode or a keycode */ /* A key press, consisting of a scancode or a keycode.
* This fits into 64 bits, so prefer passing this by value.
*/
class KeyPress class KeyPress
{ {
public: public:
@ -40,10 +42,10 @@ public:
return 0; return 0;
} }
bool operator==(const KeyPress &o) const { bool operator==(KeyPress o) const {
return scancode == o.scancode; return scancode == o.scancode;
} }
bool operator!=(const KeyPress &o) const { bool operator!=(KeyPress o) const {
return !(*this == o); return !(*this == o);
} }
@ -55,7 +57,7 @@ public:
std::get<u32>(scancode) != 0; std::get<u32>(scancode) != 0;
} }
static const KeyPress &getSpecialKey(const std::string &name); static KeyPress getSpecialKey(const std::string &name);
private: private:
bool loadFromScancode(const std::string &name); bool loadFromScancode(const std::string &name);
@ -74,7 +76,7 @@ private:
#define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON") #define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON")
// Key configuration getter // Key configuration getter
const KeyPress &getKeySetting(const std::string &settingname); KeyPress getKeySetting(const std::string &settingname);
// Clear fast lookup cache // Clear fast lookup cache
void clearKeyCache(); void clearKeyCache();

View file

@ -205,6 +205,8 @@ void GUIKeyChangeMenu::drawMenu()
bool GUIKeyChangeMenu::acceptInput() bool GUIKeyChangeMenu::acceptInput()
{ {
clearKeyCache();
for (key_setting *k : key_settings) { for (key_setting *k : key_settings) {
std::string default_key; std::string default_key;
Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key); Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key);
@ -231,8 +233,6 @@ bool GUIKeyChangeMenu::acceptInput()
g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked()); g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked());
} }
clearKeyCache();
g_gamecallback->signalKeyConfigChange(); g_gamecallback->signalKeyConfigChange();
return true; return true;

View file

@ -31,7 +31,7 @@
TouchControls *g_touchcontrols; TouchControls *g_touchcontrols;
void TouchControls::emitKeyboardEvent(const KeyPress &key, bool pressed) void TouchControls::emitKeyboardEvent(KeyPress key, bool pressed)
{ {
SEvent e{}; SEvent e{};
e.EventType = EET_KEY_INPUT_EVENT; e.EventType = EET_KEY_INPUT_EVENT;
@ -142,12 +142,8 @@ bool TouchControls::buttonsStep(std::vector<button_info> &buttons, float dtime)
return has_pointers; return has_pointers;
} }
static const KeyPress &id_to_keypress(touch_gui_button_id id) static std::string id_to_setting(touch_gui_button_id id)
{ {
// ESC isn't part of the keymap.
if (id == exit_id)
return EscapeKey;
std::string key = ""; std::string key = "";
switch (id) { switch (id) {
case dig_id: case dig_id:
@ -204,11 +200,22 @@ static const KeyPress &id_to_keypress(touch_gui_button_id id)
default: default:
break; break;
} }
assert(!key.empty()); return key.empty() ? key : "keymap_" + key;
auto &kp = getKeySetting("keymap_" + key); }
static KeyPress id_to_keypress(touch_gui_button_id id)
{
// ESC isn't part of the keymap.
if (id == exit_id)
return EscapeKey;
auto setting_name = id_to_setting(id);
assert(!setting_name.empty());
auto kp = getKeySetting(setting_name);
if (!kp) if (!kp)
warningstream << "TouchControls: Unbound or invalid key for" warningstream << "TouchControls: Unbound or invalid key for "
<< key << ", hiding button." << std::endl; << setting_name << ", hiding button." << std::endl;
return kp; return kp;
} }
@ -232,6 +239,11 @@ TouchControls::TouchControls(IrrlichtDevice *device, ISimpleTextureSource *tsrc)
readSettings(); readSettings();
for (auto name : setting_names) for (auto name : setting_names)
g_settings->registerChangedCallback(name, settingChangedCallback, this); g_settings->registerChangedCallback(name, settingChangedCallback, this);
// Also update layout when keybindings change (e.g. for convertibles)
for (u8 id = 0; id < touch_gui_button_id_END; id++)
if (auto name = id_to_setting((touch_gui_button_id)id); !name.empty())
g_settings->registerChangedCallback(name, settingChangedCallback, this);
} }
void TouchControls::settingChangedCallback(const std::string &name, void *data) void TouchControls::settingChangedCallback(const std::string &name, void *data)

View file

@ -204,7 +204,7 @@ private:
// for its buttons. We only want static image display, not interactivity, // for its buttons. We only want static image display, not interactivity,
// from Irrlicht. // from Irrlicht.
void emitKeyboardEvent(const KeyPress &keycode, bool pressed); void emitKeyboardEvent(KeyPress keycode, bool pressed);
void loadButtonTexture(IGUIImage *gui_button, const std::string &path); void loadButtonTexture(IGUIImage *gui_button, const std::string &path);
void buttonEmitAction(button_info &btn, bool action); void buttonEmitAction(button_info &btn, bool action);