mirror of
https://github.com/luanti-org/luanti.git
synced 2025-09-30 19:22:14 +00:00
Implement secondary keybindings
This commit is contained in:
parent
4f42b4308c
commit
f767a7a529
7 changed files with 51 additions and 25 deletions
|
@ -26,7 +26,7 @@ void MyEventReceiver::reloadKeybindings()
|
||||||
keybindings[KeyType::DIG] = getKeySetting("keymap_dig");
|
keybindings[KeyType::DIG] = getKeySetting("keymap_dig");
|
||||||
keybindings[KeyType::PLACE] = getKeySetting("keymap_place");
|
keybindings[KeyType::PLACE] = getKeySetting("keymap_place");
|
||||||
|
|
||||||
keybindings[KeyType::ESC] = EscapeKey;
|
keybindings[KeyType::ESC] = std::vector<KeyPress>{EscapeKey};
|
||||||
|
|
||||||
keybindings[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
|
keybindings[KeyType::AUTOFORWARD] = getKeySetting("keymap_autoforward");
|
||||||
|
|
||||||
|
@ -76,7 +76,9 @@ void MyEventReceiver::reloadKeybindings()
|
||||||
// First clear all keys, then re-add the ones we listen for
|
// First clear all keys, then re-add the ones we listen for
|
||||||
keysListenedFor.clear();
|
keysListenedFor.clear();
|
||||||
for (int i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
|
for (int i = 0; i < KeyType::INTERNAL_ENUM_COUNT; i++) {
|
||||||
listenForKey(keybindings[i], static_cast<GameKeyType>(i));
|
for (auto key: keybindings[i]) {
|
||||||
|
listenForKey(key, static_cast<GameKeyType>(i));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,13 +87,11 @@ bool MyEventReceiver::setKeyDown(KeyPress keyCode, bool is_down)
|
||||||
if (keysListenedFor.find(keyCode) == keysListenedFor.end()) // ignore irrelevant key input
|
if (keysListenedFor.find(keyCode) == keysListenedFor.end()) // ignore irrelevant key input
|
||||||
return false;
|
return false;
|
||||||
auto action = keysListenedFor[keyCode];
|
auto action = keysListenedFor[keyCode];
|
||||||
if (is_down) {
|
if (is_down)
|
||||||
physicalKeyDown.insert(keyCode);
|
physicalKeyDown.insert(keyCode);
|
||||||
setKeyDown(action, true);
|
else
|
||||||
} else {
|
|
||||||
physicalKeyDown.erase(keyCode);
|
physicalKeyDown.erase(keyCode);
|
||||||
setKeyDown(action, false);
|
setKeyDown(action, checkKeyDown(action));
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +109,15 @@ void MyEventReceiver::setKeyDown(GameKeyType action, bool is_down)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MyEventReceiver::checkKeyDown(GameKeyType action)
|
||||||
|
{
|
||||||
|
for (auto key: keybindings[action]) {
|
||||||
|
if (physicalKeyDown.find(key) != physicalKeyDown.end())
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool MyEventReceiver::OnEvent(const SEvent &event)
|
bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||||
{
|
{
|
||||||
if (event.EventType == EET_LOG_TEXT_EVENT) {
|
if (event.EventType == EET_LOG_TEXT_EVENT) {
|
||||||
|
@ -138,7 +147,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||||
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
||||||
KeyPress keyCode(event.KeyInput);
|
KeyPress keyCode(event.KeyInput);
|
||||||
|
|
||||||
if (keyCode == getKeySetting("keymap_fullscreen")) {
|
if (keySettingHasMatch("keymap_fullscreen", keyCode)) {
|
||||||
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();
|
||||||
|
|
||||||
|
@ -152,7 +161,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||||
fullscreen_is_down = event.KeyInput.PressedDown;
|
fullscreen_is_down = event.KeyInput.PressedDown;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} else if (keyCode == getKeySetting("keymap_close_world")) {
|
} else if (keySettingHasMatch("keymap_close_world", keyCode)) {
|
||||||
close_world_down = event.KeyInput.PressedDown;
|
close_world_down = event.KeyInput.PressedDown;
|
||||||
|
|
||||||
} else if (keyCode == EscapeKey) {
|
} else if (keyCode == EscapeKey) {
|
||||||
|
|
|
@ -97,13 +97,14 @@ private:
|
||||||
|
|
||||||
bool setKeyDown(KeyPress keyCode, bool is_down);
|
bool setKeyDown(KeyPress keyCode, bool is_down);
|
||||||
void setKeyDown(GameKeyType action, bool is_down);
|
void setKeyDown(GameKeyType action, bool is_down);
|
||||||
|
bool checkKeyDown(GameKeyType action);
|
||||||
|
|
||||||
/* This is faster than using getKeySetting with the tradeoff that functions
|
/* This is faster than using getKeySetting with the tradeoff that functions
|
||||||
* using it must make sure that it's initialised before using it and there is
|
* using it must make sure that it's initialised before using it and there is
|
||||||
* no error handling (for example bounds checking). This is useful here as the
|
* no error handling (for example bounds checking). This is useful here as the
|
||||||
* faster (up to 10x faster) key lookup is an asset.
|
* faster (up to 10x faster) key lookup is an asset.
|
||||||
*/
|
*/
|
||||||
std::array<KeyPress, KeyType::INTERNAL_ENUM_COUNT> keybindings;
|
std::array<std::vector<KeyPress>, KeyType::INTERNAL_ENUM_COUNT> keybindings;
|
||||||
|
|
||||||
s32 mouse_wheel = 0;
|
s32 mouse_wheel = 0;
|
||||||
|
|
||||||
|
|
|
@ -380,23 +380,32 @@ 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, std::vector<KeyPress>> g_key_setting_cache;
|
||||||
|
|
||||||
KeyPress getKeySetting(const std::string &settingname)
|
const std::vector<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())
|
||||||
return n->second;
|
return n->second;
|
||||||
|
|
||||||
auto keysym = g_settings->get(settingname);
|
auto setting_value = g_settings->get(settingname);
|
||||||
auto &ref = g_key_setting_cache[settingname];
|
auto &ref = g_key_setting_cache[settingname];
|
||||||
ref = KeyPress(keysym);
|
for (const auto &keysym: str_split(setting_value, '|')) {
|
||||||
if (!keysym.empty() && !ref) {
|
if (KeyPress kp = keysym) {
|
||||||
warningstream << "Invalid key '" << keysym << "' for '" << settingname << "'." << std::endl;
|
ref.push_back(kp);
|
||||||
|
} else {
|
||||||
|
warningstream << "Invalid key '" << keysym << "' for '" << settingname << "'." << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return ref;
|
return ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool keySettingHasMatch(const std::string &settingname, KeyPress kp)
|
||||||
|
{
|
||||||
|
const auto &keylist = getKeySetting(settingname);
|
||||||
|
return std::find(keylist.begin(), keylist.end(), kp) != keylist.end();
|
||||||
|
}
|
||||||
|
|
||||||
void clearKeyCache()
|
void clearKeyCache()
|
||||||
{
|
{
|
||||||
g_key_setting_cache.clear();
|
g_key_setting_cache.clear();
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <IEventReceiver.h>
|
#include <IEventReceiver.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
/* 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.
|
* This fits into 64 bits, so prefer passing this by value.
|
||||||
|
@ -92,7 +93,13 @@ struct std::hash<KeyPress>
|
||||||
#define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON")
|
#define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON")
|
||||||
|
|
||||||
// Key configuration getter
|
// Key configuration getter
|
||||||
KeyPress getKeySetting(const std::string &settingname);
|
// Note that the reference may be invalidated by a next call to getKeySetting
|
||||||
|
// or a related function, so the value should either be used immediately or
|
||||||
|
// copied elsewhere before calling this again.
|
||||||
|
const std::vector<KeyPress> &getKeySetting(const std::string &settingname);
|
||||||
|
|
||||||
|
// Check whether the key setting includes a key.
|
||||||
|
bool keySettingHasMatch(const std::string &settingname, KeyPress kp);
|
||||||
|
|
||||||
// Clear fast lookup cache
|
// Clear fast lookup cache
|
||||||
void clearKeyCache();
|
void clearKeyCache();
|
||||||
|
|
|
@ -436,7 +436,7 @@ bool GUIChatConsole::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Key input
|
// Key input
|
||||||
if (KeyPress(event.KeyInput) == getKeySetting("keymap_console")) {
|
if (keySettingHasMatch("keymap_console", event.KeyInput)) {
|
||||||
closeConsole();
|
closeConsole();
|
||||||
|
|
||||||
// inhibit open so the_game doesn't reopen immediately
|
// inhibit open so the_game doesn't reopen immediately
|
||||||
|
|
|
@ -3995,7 +3995,7 @@ bool GUIFormSpecMenu::preprocessEvent(const SEvent& event)
|
||||||
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
if (event.EventType == EET_KEY_INPUT_EVENT) {
|
||||||
KeyPress kp(event.KeyInput);
|
KeyPress kp(event.KeyInput);
|
||||||
if (kp == EscapeKey
|
if (kp == EscapeKey
|
||||||
|| kp == getKeySetting("keymap_inventory")
|
|| keySettingHasMatch("keymap_inventory", kp)
|
||||||
|| event.KeyInput.Key==KEY_RETURN) {
|
|| event.KeyInput.Key==KEY_RETURN) {
|
||||||
gui::IGUIElement *focused = Environment->getFocus();
|
gui::IGUIElement *focused = Environment->getFocus();
|
||||||
if (focused && isMyChild(focused) &&
|
if (focused && isMyChild(focused) &&
|
||||||
|
@ -4094,17 +4094,17 @@ bool GUIFormSpecMenu::OnEvent(const SEvent& event)
|
||||||
}
|
}
|
||||||
if (event.KeyInput.PressedDown && (
|
if (event.KeyInput.PressedDown && (
|
||||||
(kp == EscapeKey) ||
|
(kp == EscapeKey) ||
|
||||||
((m_client != NULL) && (kp == getKeySetting("keymap_inventory"))))) {
|
((m_client != NULL) && (keySettingHasMatch("keymap_inventory", kp))))) {
|
||||||
tryClose();
|
tryClose();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_client != NULL && event.KeyInput.PressedDown &&
|
if (m_client != NULL && event.KeyInput.PressedDown &&
|
||||||
(kp == getKeySetting("keymap_screenshot"))) {
|
(keySettingHasMatch("keymap_screenshot", kp))) {
|
||||||
m_client->makeScreenshot();
|
m_client->makeScreenshot();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.KeyInput.PressedDown && kp == getKeySetting("keymap_toggle_debug")) {
|
if (event.KeyInput.PressedDown && keySettingHasMatch("keymap_toggle_debug", kp)) {
|
||||||
if (!m_client || m_client->checkPrivilege("debug"))
|
if (!m_client || m_client->checkPrivilege("debug"))
|
||||||
m_show_debug = !m_show_debug;
|
m_show_debug = !m_show_debug;
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,11 +212,11 @@ static KeyPress id_to_keypress(touch_gui_button_id id)
|
||||||
auto setting_name = id_to_setting(id);
|
auto setting_name = id_to_setting(id);
|
||||||
|
|
||||||
assert(!setting_name.empty());
|
assert(!setting_name.empty());
|
||||||
auto kp = getKeySetting(setting_name);
|
const auto &keylist = getKeySetting(setting_name);
|
||||||
if (!kp)
|
if (keylist.empty())
|
||||||
warningstream << "TouchControls: Unbound or invalid key for "
|
warningstream << "TouchControls: Unbound or invalid key for "
|
||||||
<< setting_name << ", hiding button." << std::endl;
|
<< setting_name << ", hiding button." << std::endl;
|
||||||
return kp;
|
return keylist[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue