diff --git a/builtin/common/menu.lua b/builtin/common/menu.lua
index 165286470..4eb3dfe44 100644
--- a/builtin/common/menu.lua
+++ b/builtin/common/menu.lua
@@ -9,3 +9,7 @@ mt_color_green = "#72FF63"
mt_color_dark_green = "#25C191"
mt_color_orange = "#FF8800"
mt_color_red = "#FF3300"
+
+function core.are_keycodes_equal(k1, k2)
+ return core.normalize_keycode(k1) == core.normalize_keycode(k2)
+end
diff --git a/builtin/common/misc_helpers.lua b/builtin/common/misc_helpers.lua
index a1f352afa..29aa3e5c2 100644
--- a/builtin/common/misc_helpers.lua
+++ b/builtin/common/misc_helpers.lua
@@ -634,6 +634,10 @@ if core.gettext then -- for client and mainmenu
function fgettext(text, ...)
return core.formspec_escape(fgettext_ne(text, ...))
end
+
+ function hgettext(text, ...)
+ return core.hypertext_escape(fgettext_ne(text, ...))
+ end
end
local ESCAPE_CHAR = string.char(0x1b)
diff --git a/builtin/common/settings/dlg_settings.lua b/builtin/common/settings/dlg_settings.lua
index e19ed7351..77fc8be3f 100644
--- a/builtin/common/settings/dlg_settings.lua
+++ b/builtin/common/settings/dlg_settings.lua
@@ -778,11 +778,11 @@ end
if INIT == "mainmenu" then
- function create_settings_dlg()
+ function create_settings_dlg(page_id)
load()
local dlg = dialog_create("dlg_settings", get_formspec, buttonhandler, eventhandler)
- dlg.data.page_id = update_filtered_pages("")
+ dlg.data.page_id = page_id or update_filtered_pages("")
return dlg
end
diff --git a/builtin/mainmenu/dlg_rebind_keys.lua b/builtin/mainmenu/dlg_rebind_keys.lua
new file mode 100644
index 000000000..d1b442004
--- /dev/null
+++ b/builtin/mainmenu/dlg_rebind_keys.lua
@@ -0,0 +1,108 @@
+-- Luanti
+-- SPDX-License-Identifier: LGPL-2.1-or-later
+-- Modified based on dlg_reinstall_mtg.lua
+-- Note that this is only needed for migrating from <5.11 to 5.12.
+
+local doc_url = "https://docs.luanti.org/for-players/controls/"
+local SETTING_NAME = "no_keycode_migration_warning"
+
+local function get_formspec(dialogdata)
+ local markup = table.concat({
+ "" .. hgettext("Keybindings changed") .. "",
+ hgettext("The input handling system was reworked in Luanti 5.12.0."),
+ hgettext("As a result, your keybindings may have been changed."),
+ hgettext("Check out the key settings or refer to the documentation:"),
+ (""):format(doc_url),
+ }, "\n")
+
+ return table.concat({
+ "formspec_version[6]",
+ "size[12,7]",
+ "hypertext[0.5,0.5;11,4.7;text;", core.formspec_escape(markup), "]",
+ "container[0.5,5.7]",
+ "button[0,0;4,0.8;dismiss;", fgettext("Close"), "]",
+ "button[4.5,0;6.5,0.8;reconfigure;", fgettext("Open settings"), "]",
+ "container_end[]",
+ })
+end
+
+local function close_dialog(this)
+ cache_settings:set_bool(SETTING_NAME, true)
+ this:delete()
+end
+
+local function buttonhandler(this, fields)
+ if fields.reconfigure then
+ close_dialog(this)
+
+ local maintab = ui.find_by_name("maintab")
+
+ local dlg = create_settings_dlg("controls_keyboard_and_mouse")
+ dlg:set_parent(maintab)
+ maintab:hide()
+ dlg:show()
+
+ return true
+ end
+
+ if fields.dismiss then
+ close_dialog(this)
+ return true
+ end
+
+ if fields.text == "action:doc_url" then
+ core.open_url(doc_url)
+ end
+end
+
+local function eventhandler(event)
+ if event == "DialogShow" then
+ mm_game_theme.set_engine()
+ return true
+ elseif event == "MenuQuit" then
+ -- Don't allow closing the dialog with ESC, but still allow exiting
+ -- Luanti
+ core.close()
+ return true
+ end
+ return false
+end
+
+local function create_rebind_keys_dlg()
+ local dlg = dialog_create("dlg_rebind_keys", get_formspec,
+ buttonhandler, eventhandler)
+ return dlg
+end
+
+function migrate_keybindings()
+ -- Show migration dialog if the user upgraded from an earlier version
+ -- and this has not yet been shown before, *or* if keys settings had to be changed
+ if core.is_first_run then
+ cache_settings:set_bool(SETTING_NAME, true)
+ end
+ local has_migration = not cache_settings:get_bool(SETTING_NAME)
+
+ -- normalize all existing key settings, this converts them from KEY_KEY_C to SYSTEM_SCANCODE_6
+ local settings = core.settings:to_table()
+ for name, value in pairs(settings) do
+ if name:match("^keymap_") then
+ local normalized = core.normalize_keycode(value)
+ if value ~= normalized then
+ has_migration = true
+ core.settings:set(name, normalized)
+ end
+ end
+ end
+
+ if not has_migration then
+ return
+ end
+
+ local maintab = ui.find_by_name("maintab")
+
+ local dlg = create_rebind_keys_dlg()
+ dlg:set_parent(maintab)
+ maintab:hide()
+ dlg:show()
+ ui.update()
+end
diff --git a/builtin/mainmenu/dlg_reinstall_mtg.lua b/builtin/mainmenu/dlg_reinstall_mtg.lua
index 4defa6646..c167b2656 100644
--- a/builtin/mainmenu/dlg_reinstall_mtg.lua
+++ b/builtin/mainmenu/dlg_reinstall_mtg.lua
@@ -54,10 +54,10 @@ end
local function get_formspec(dialogdata)
local markup = table.concat({
- "", fgettext("Minetest Game is no longer installed by default"), "\n",
- fgettext("For a long time, Luanti shipped with a default game called \"Minetest Game\". " ..
+ "", hgettext("Minetest Game is no longer installed by default"), "\n",
+ hgettext("For a long time, Luanti shipped with a default game called \"Minetest Game\". " ..
"Since version 5.8.0, Luanti ships without a default game."), "\n",
- fgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
+ hgettext("If you want to continue playing in your Minetest Game worlds, you need to reinstall Minetest Game."),
})
return table.concat({
diff --git a/builtin/mainmenu/init.lua b/builtin/mainmenu/init.lua
index 1394d13f1..14185a484 100644
--- a/builtin/mainmenu/init.lua
+++ b/builtin/mainmenu/init.lua
@@ -35,6 +35,7 @@ dofile(menupath .. DIR_DELIM .. "dlg_register.lua")
dofile(menupath .. DIR_DELIM .. "dlg_rename_modpack.lua")
dofile(menupath .. DIR_DELIM .. "dlg_version_info.lua")
dofile(menupath .. DIR_DELIM .. "dlg_reinstall_mtg.lua")
+dofile(menupath .. DIR_DELIM .. "dlg_rebind_keys.lua")
dofile(menupath .. DIR_DELIM .. "dlg_clients_list.lua")
dofile(menupath .. DIR_DELIM .. "dlg_server_list_mods.lua")
@@ -112,6 +113,7 @@ local function init_globals()
ui.update()
check_reinstall_mtg()
+ migrate_keybindings()
check_new_version()
end
diff --git a/src/main.cpp b/src/main.cpp
index b2affdb70..95a2f7be4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -777,10 +777,13 @@ static bool read_config_file(const Settings &cmd_args)
}
// If no path found, use the first one (menu creates the file)
- if (g_settings_path.empty())
+ if (g_settings_path.empty()) {
g_settings_path = filenames[0];
+ g_first_run = true;
+ }
}
- infostream << "Global configuration file: " << g_settings_path << std::endl;
+ infostream << "Global configuration file: " << g_settings_path
+ << (g_first_run ? " (first run)" : "") << std::endl;
return true;
}
diff --git a/src/script/lua_api/l_mainmenu.cpp b/src/script/lua_api/l_mainmenu.cpp
index 3d096e018..4b878ee1c 100644
--- a/src/script/lua_api/l_mainmenu.cpp
+++ b/src/script/lua_api/l_mainmenu.cpp
@@ -1089,6 +1089,9 @@ void ModApiMainMenu::Initialize(lua_State *L, int top)
API_FCT(open_dir);
API_FCT(share_file);
API_FCT(do_async_callback);
+
+ lua_pushboolean(L, g_first_run);
+ lua_setfield(L, top, "is_first_run");
}
/******************************************************************************/
diff --git a/src/script/lua_api/l_menu_common.cpp b/src/script/lua_api/l_menu_common.cpp
index 8b3ffda4e..428b902c9 100644
--- a/src/script/lua_api/l_menu_common.cpp
+++ b/src/script/lua_api/l_menu_common.cpp
@@ -35,11 +35,10 @@ int ModApiMenuCommon::l_irrlicht_device_supports_touch(lua_State *L)
}
-int ModApiMenuCommon::l_are_keycodes_equal(lua_State *L)
+int ModApiMenuCommon::l_normalize_keycode(lua_State *L)
{
- auto k1 = luaL_checkstring(L, 1);
- auto k2 = luaL_checkstring(L, 2);
- lua_pushboolean(L, KeyPress(k1) == KeyPress(k2));
+ auto keystr = luaL_checkstring(L, 1);
+ lua_pushstring(L, KeyPress(keystr).sym().c_str());
return 1;
}
@@ -49,7 +48,7 @@ void ModApiMenuCommon::Initialize(lua_State *L, int top)
API_FCT(gettext);
API_FCT(get_active_driver);
API_FCT(irrlicht_device_supports_touch);
- API_FCT(are_keycodes_equal);
+ API_FCT(normalize_keycode);
}
diff --git a/src/script/lua_api/l_menu_common.h b/src/script/lua_api/l_menu_common.h
index 8cbd58f11..2c1756fa5 100644
--- a/src/script/lua_api/l_menu_common.h
+++ b/src/script/lua_api/l_menu_common.h
@@ -13,7 +13,7 @@ private:
static int l_gettext(lua_State *L);
static int l_get_active_driver(lua_State *L);
static int l_irrlicht_device_supports_touch(lua_State *L);
- static int l_are_keycodes_equal(lua_State *L);
+ static int l_normalize_keycode(lua_State *L);
public:
static void Initialize(lua_State *L, int top);
diff --git a/src/settings.cpp b/src/settings.cpp
index 6a7607cc3..2dccf45de 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -22,6 +22,7 @@
Settings *g_settings = nullptr;
static SettingsHierarchy g_hierarchy;
std::string g_settings_path;
+bool g_first_run = false;
std::unordered_map Settings::s_flags;
diff --git a/src/settings.h b/src/settings.h
index 9bc0e80d9..95083058a 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -18,6 +18,8 @@ struct NoiseParams;
// Global objects
extern Settings *g_settings; // Same as Settings::getLayer(SL_GLOBAL);
extern std::string g_settings_path;
+/// Is set to true if the engine runs for the first time
+extern bool g_first_run;
// Type for a settings changed callback function
typedef void (*SettingsChangedCallback)(const std::string &name, void *data);
diff --git a/util/updatepo.sh b/util/updatepo.sh
index 2b9f4a276..edb03c5d2 100755
--- a/util/updatepo.sh
+++ b/util/updatepo.sh
@@ -58,6 +58,7 @@ xgettext --package-name=luanti \
--keyword=fwgettext \
--keyword=fgettext \
--keyword=fgettext_ne \
+ --keyword=hgettext \
--keyword=strgettext \
--keyword=wstrgettext \
--keyword=core.gettext \