diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 5feeaab6d..c1a0dd941 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -151,6 +151,15 @@ enable_hotbar_mouse_wheel (Hotbar: Enable mouse wheel for selection) bool true # Requires: keyboard_mouse invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false +# Save key controls as scancodes (position on the keyboard) instead of keycodes (the +# symbol marked on the key). This allows using the same phsysical keys with multiple +# keyboard layouts, but the new scancode-based settings can not be parsed by older clients. +# Note that this only affects how keybindings are saved in the settings. In particular, +# key controls are always matched based on scancodes regardless of this setting. +# +# Requires: !touch_controls +save_keys_as_scancodes (Save keybindings as scancodes) bool false + [*Touchscreen] # Enables the touchscreen controls, allowing you to play the game with a touchscreen. diff --git a/src/client/keycode.cpp b/src/client/keycode.cpp index 95739a845..4d23cc2d3 100644 --- a/src/client/keycode.cpp +++ b/src/client/keycode.cpp @@ -291,10 +291,14 @@ KeyPress::KeyPress(const std::string_view &name) scancode = RenderingEngine::get_raw_device()->getScancodeFromKey(keycode); } -std::string KeyPress::sym() const +std::string KeyPress::sym(const bool force_scancode) const { + if (scancode == 0) + return ""; + if (force_scancode) + return formatScancode(); const auto &name = lookup_scancode(scancode).Name; - if (!name.empty() || scancode == 0) + if (!name.empty()) return name; return formatScancode(); } diff --git a/src/client/keycode.h b/src/client/keycode.h index 1e93d14ee..b2736c791 100644 --- a/src/client/keycode.h +++ b/src/client/keycode.h @@ -21,7 +21,7 @@ public: KeyPress(const irr::SEvent::SKeyInput &in) : scancode(in.SystemKeyCode) {}; - std::string sym() const; + std::string sym(const bool force_scancode = false) const; std::string name() const; bool operator==(const KeyPress &o) const { diff --git a/src/defaultsettings.cpp b/src/defaultsettings.cpp index bfce22022..b36b50b05 100644 --- a/src/defaultsettings.cpp +++ b/src/defaultsettings.cpp @@ -359,6 +359,7 @@ void set_default_settings() settings->setDefault("repeat_dig_time", "0.0"); settings->setDefault("safe_dig_and_place", "false"); settings->setDefault("random_input", "false"); + settings->setDefault("save_keys_as_scancodes", "false"); settings->setDefault("aux1_descends", "false"); settings->setDefault("doubletap_jump", "false"); settings->setDefault("always_fly_fast", "true"); diff --git a/src/gui/guiKeyChangeMenu.cpp b/src/gui/guiKeyChangeMenu.cpp index 4cbaf29fd..576fa00d6 100644 --- a/src/gui/guiKeyChangeMenu.cpp +++ b/src/gui/guiKeyChangeMenu.cpp @@ -66,6 +66,7 @@ enum GUI_ID_CB_AUX1_DESCENDS, GUI_ID_CB_DOUBLETAP_JUMP, GUI_ID_CB_AUTOJUMP, + GUI_ID_SAVE_AS_SCANCODES, }; GUIKeyChangeMenu::GUIKeyChangeMenu(gui::IGUIEnvironment* env, @@ -93,7 +94,7 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) removeAllChildren(); key_used_text = nullptr; - ScalingInfo info = getScalingInfo(screensize, v2u32(835, 430)); + ScalingInfo info = getScalingInfo(screensize, v2u32(835, 455)); const float s = info.scale; DesiredRect = info.rect; recalculateAbsolutePosition(false); @@ -177,6 +178,19 @@ void GUIKeyChangeMenu::regenerateGui(v2u32 screensize) offset += v2s32(0, 25); } + { + s32 option_x = offset.X; + s32 option_y = offset.Y + 5 * s; + u32 option_w = 280 * s; + { + core::rect rect(0, 0, option_w, 30 * s); + rect += topleft + v2s32(option_x, option_y); + Environment->addCheckBox(g_settings->getBool("save_keys_as_scancodes"), rect, this, + GUI_ID_SAVE_AS_SCANCODES, wstrgettext("Save keybindings as scancodes").c_str()); + } + offset += v2s32(0, 25 * s); + } + { core::rect rect(0, 0, 100 * s, 30 * s); rect += topleft + v2s32(size.X / 2 - 105 * s, size.Y - 40 * s); @@ -206,15 +220,7 @@ void GUIKeyChangeMenu::drawMenu() bool GUIKeyChangeMenu::acceptInput() { - for (key_setting *k : key_settings) { - std::string default_key; - Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key); - - if (k->key.sym() != default_key) - g_settings->set(k->setting_name, k->key.sym()); - else - g_settings->remove(k->setting_name); - } + bool save_as_scancodes = g_settings->getBool("save_keys_as_scancodes"); { gui::IGUIElement *e = getElementFromId(GUI_ID_CB_AUX1_DESCENDS); @@ -231,6 +237,25 @@ bool GUIKeyChangeMenu::acceptInput() if(e && e->getType() == gui::EGUIET_CHECK_BOX) g_settings->setBool("autojump", ((gui::IGUICheckBox*)e)->isChecked()); } + { + gui::IGUIElement *e = getElementFromId(GUI_ID_SAVE_AS_SCANCODES); + if(e && e->getType() == gui::EGUIET_CHECK_BOX) { + save_as_scancodes = ((gui::IGUICheckBox*)e)->isChecked(); + g_settings->setBool("save_keys_as_scancodes", save_as_scancodes); + } + } + + for (key_setting *k : key_settings) { + std::string default_key; + Settings::getLayer(SL_DEFAULTS)->getNoEx(k->setting_name, default_key); + + auto keysym = k->key.sym(save_as_scancodes); + + if (keysym != default_key) + g_settings->set(k->setting_name, keysym); + else + g_settings->remove(k->setting_name); + } clearKeyCache();