mirror of
https://github.com/minetest/minetest.git
synced 2025-09-18 03:15:20 +02:00
SDL: Use scancodes for keybindings (#14964)
Co-authored-by: Lars Müller <34514239+appgurueu@users.noreply.github.com> Co-authored-by: sfan5 <sfan5@live.de> Co-authored-by: SmallJoker <SmallJoker@users.noreply.github.com>
This commit is contained in:
@@ -143,7 +143,7 @@ bool MyEventReceiver::OnEvent(const SEvent &event)
|
||||
// Remember whether each key is down or up
|
||||
if (event.EventType == irr::EET_KEY_INPUT_EVENT) {
|
||||
const KeyPress keyCode(event.KeyInput);
|
||||
if (keysListenedFor[keyCode]) {
|
||||
if (keyCode && keysListenedFor[keyCode]) { // ignore key input that is invalid or irrelevant for the game.
|
||||
if (event.KeyInput.PressedDown) {
|
||||
if (!IsKeyDown(keyCode))
|
||||
keyWasPressed.set(keyCode);
|
||||
|
@@ -6,15 +6,18 @@
|
||||
#include "settings.h"
|
||||
#include "log.h"
|
||||
#include "debug.h"
|
||||
#include "renderingengine.h"
|
||||
#include "util/hex.h"
|
||||
#include "util/string.h"
|
||||
#include "util/basic_macros.h"
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
struct table_key {
|
||||
const char *Name;
|
||||
std::string Name; // An EKEY_CODE 'symbol' name as a string
|
||||
irr::EKEY_CODE Key;
|
||||
wchar_t Char; // L'\0' means no character assigned
|
||||
const char *LangName; // NULL means it doesn't have a human description
|
||||
std::string LangName; // empty string means it doesn't have a human description
|
||||
};
|
||||
|
||||
#define DEFINEKEY1(x, lang) /* Irrlicht key without character */ \
|
||||
@@ -30,7 +33,7 @@ struct table_key {
|
||||
|
||||
#define N_(text) text
|
||||
|
||||
static const struct table_key table[] = {
|
||||
static std::vector<table_key> table = {
|
||||
// Keys that can be reliably mapped between Char and Key
|
||||
DEFINEKEY3(0)
|
||||
DEFINEKEY3(1)
|
||||
@@ -126,7 +129,7 @@ static const struct table_key table[] = {
|
||||
DEFINEKEY1(KEY_ADD, N_("Numpad +"))
|
||||
DEFINEKEY1(KEY_SEPARATOR, N_("Numpad ."))
|
||||
DEFINEKEY1(KEY_SUBTRACT, N_("Numpad -"))
|
||||
DEFINEKEY1(KEY_DECIMAL, NULL)
|
||||
DEFINEKEY1(KEY_DECIMAL, N_("Numpad ."))
|
||||
DEFINEKEY1(KEY_DIVIDE, N_("Numpad /"))
|
||||
DEFINEKEY4(1)
|
||||
DEFINEKEY4(2)
|
||||
@@ -221,122 +224,156 @@ static const struct table_key table[] = {
|
||||
DEFINEKEY5("_")
|
||||
};
|
||||
|
||||
static const table_key invalid_key = {"", irr::KEY_UNKNOWN, L'\0', ""};
|
||||
|
||||
#undef N_
|
||||
|
||||
|
||||
static const table_key &lookup_keyname(const char *name)
|
||||
{
|
||||
for (const auto &table_key : table) {
|
||||
if (strcmp(table_key.Name, name) == 0)
|
||||
return table_key;
|
||||
}
|
||||
|
||||
throw UnknownKeycode(name);
|
||||
}
|
||||
|
||||
static const table_key &lookup_keykey(irr::EKEY_CODE key)
|
||||
{
|
||||
for (const auto &table_key : table) {
|
||||
if (table_key.Key == key)
|
||||
return table_key;
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
os << "<Keycode " << (int) key << ">";
|
||||
throw UnknownKeycode(os.str().c_str());
|
||||
}
|
||||
|
||||
static const table_key &lookup_keychar(wchar_t Char)
|
||||
{
|
||||
if (Char == L'\0')
|
||||
return invalid_key;
|
||||
|
||||
for (const auto &table_key : table) {
|
||||
if (table_key.Char == Char)
|
||||
return table_key;
|
||||
}
|
||||
|
||||
std::ostringstream os;
|
||||
os << "<Char " << hex_encode((char*) &Char, sizeof(wchar_t)) << ">";
|
||||
throw UnknownKeycode(os.str().c_str());
|
||||
// Create a new entry in the lookup table if one is not available.
|
||||
auto newsym = wide_to_utf8(std::wstring_view(&Char, 1));
|
||||
table_key new_key {newsym, irr::KEY_KEY_CODES_COUNT, Char, newsym};
|
||||
return table.emplace_back(std::move(new_key));
|
||||
}
|
||||
|
||||
KeyPress::KeyPress(const char *name)
|
||||
static const table_key &lookup_keykey(irr::EKEY_CODE key)
|
||||
{
|
||||
if (strlen(name) == 0) {
|
||||
Key = irr::KEY_KEY_CODES_COUNT;
|
||||
Char = L'\0';
|
||||
m_name = "";
|
||||
if (!Keycode::isValid(key))
|
||||
return invalid_key;
|
||||
|
||||
for (const auto &table_key : table) {
|
||||
if (table_key.Key == key)
|
||||
return table_key;
|
||||
}
|
||||
|
||||
return invalid_key;
|
||||
}
|
||||
|
||||
static const table_key &lookup_keyname(std::string_view name)
|
||||
{
|
||||
if (name.empty())
|
||||
return invalid_key;
|
||||
|
||||
for (const auto &table_key : table) {
|
||||
if (table_key.Name == name)
|
||||
return table_key;
|
||||
}
|
||||
|
||||
auto wname = utf8_to_wide(name);
|
||||
if (wname.empty())
|
||||
return invalid_key;
|
||||
return lookup_keychar(wname[0]);
|
||||
}
|
||||
|
||||
static const table_key &lookup_scancode(const u32 scancode)
|
||||
{
|
||||
auto key = RenderingEngine::get_raw_device()->getKeyFromScancode(scancode);
|
||||
return std::holds_alternative<EKEY_CODE>(key) ?
|
||||
lookup_keykey(std::get<irr::EKEY_CODE>(key)) :
|
||||
lookup_keychar(std::get<wchar_t>(key));
|
||||
}
|
||||
|
||||
static const table_key &lookup_scancode(const std::variant<u32, irr::EKEY_CODE> &scancode)
|
||||
{
|
||||
return std::holds_alternative<irr::EKEY_CODE>(scancode) ?
|
||||
lookup_keykey(std::get<irr::EKEY_CODE>(scancode)) :
|
||||
lookup_scancode(std::get<u32>(scancode));
|
||||
}
|
||||
|
||||
void KeyPress::loadFromKey(irr::EKEY_CODE keycode, wchar_t keychar)
|
||||
{
|
||||
scancode = RenderingEngine::get_raw_device()->getScancodeFromKey(Keycode(keycode, keychar));
|
||||
}
|
||||
|
||||
KeyPress::KeyPress(const std::string &name)
|
||||
{
|
||||
if (loadFromScancode(name))
|
||||
return;
|
||||
}
|
||||
|
||||
if (strlen(name) <= 4) {
|
||||
// Lookup by resulting character
|
||||
int chars_read = mbtowc(&Char, name, 1);
|
||||
FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character");
|
||||
try {
|
||||
auto &k = lookup_keychar(Char);
|
||||
m_name = k.Name;
|
||||
Key = k.Key;
|
||||
return;
|
||||
} catch (UnknownKeycode &e) {};
|
||||
} else {
|
||||
// Lookup by name
|
||||
m_name = name;
|
||||
try {
|
||||
auto &k = lookup_keyname(name);
|
||||
Key = k.Key;
|
||||
Char = k.Char;
|
||||
return;
|
||||
} catch (UnknownKeycode &e) {};
|
||||
}
|
||||
|
||||
// It's not a known key, complain and try to do something
|
||||
Key = irr::KEY_KEY_CODES_COUNT;
|
||||
int chars_read = mbtowc(&Char, name, 1);
|
||||
FATAL_ERROR_IF(chars_read != 1, "Unexpected multibyte character");
|
||||
m_name = "";
|
||||
warningstream << "KeyPress: Unknown key '" << name
|
||||
<< "', falling back to first char." << std::endl;
|
||||
const auto &key = lookup_keyname(name);
|
||||
loadFromKey(key.Key, key.Char);
|
||||
}
|
||||
|
||||
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character)
|
||||
KeyPress::KeyPress(const irr::SEvent::SKeyInput &in)
|
||||
{
|
||||
if (prefer_character)
|
||||
Key = irr::KEY_KEY_CODES_COUNT;
|
||||
else
|
||||
Key = in.Key;
|
||||
Char = in.Char;
|
||||
|
||||
try {
|
||||
if (valid_kcode(Key))
|
||||
m_name = lookup_keykey(Key).Name;
|
||||
if (USE_SDL2) {
|
||||
if (in.SystemKeyCode)
|
||||
scancode.emplace<u32>(in.SystemKeyCode);
|
||||
else
|
||||
m_name = lookup_keychar(Char).Name;
|
||||
} catch (UnknownKeycode &e) {
|
||||
m_name.clear();
|
||||
};
|
||||
scancode.emplace<irr::EKEY_CODE>(in.Key);
|
||||
} else {
|
||||
loadFromKey(in.Key, in.Char);
|
||||
}
|
||||
}
|
||||
|
||||
const char *KeyPress::sym() const
|
||||
std::string KeyPress::formatScancode() const
|
||||
{
|
||||
return m_name.c_str();
|
||||
if (USE_SDL2) {
|
||||
if (auto pv = std::get_if<u32>(&scancode))
|
||||
return *pv == 0 ? "" : "SYSTEM_SCANCODE_" + std::to_string(*pv);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *KeyPress::name() const
|
||||
std::string KeyPress::sym() const
|
||||
{
|
||||
if (m_name.empty())
|
||||
return "";
|
||||
const char *ret;
|
||||
if (valid_kcode(Key))
|
||||
ret = lookup_keykey(Key).LangName;
|
||||
else
|
||||
ret = lookup_keychar(Char).LangName;
|
||||
return ret ? ret : "<Unnamed key>";
|
||||
std::string name = lookup_scancode(scancode).Name;
|
||||
if (USE_SDL2 || name.empty())
|
||||
if (auto newname = formatScancode(); !newname.empty())
|
||||
return newname;
|
||||
return name;
|
||||
}
|
||||
|
||||
const KeyPress EscapeKey("KEY_ESCAPE");
|
||||
std::string KeyPress::name() const
|
||||
{
|
||||
const auto &name = lookup_scancode(scancode).LangName;
|
||||
if (!name.empty())
|
||||
return name;
|
||||
return formatScancode();
|
||||
}
|
||||
|
||||
const KeyPress LMBKey("KEY_LBUTTON");
|
||||
const KeyPress MMBKey("KEY_MBUTTON");
|
||||
const KeyPress RMBKey("KEY_RBUTTON");
|
||||
irr::EKEY_CODE KeyPress::getKeycode() const
|
||||
{
|
||||
return lookup_scancode(scancode).Key;
|
||||
}
|
||||
|
||||
wchar_t KeyPress::getKeychar() const
|
||||
{
|
||||
return lookup_scancode(scancode).Char;
|
||||
}
|
||||
|
||||
bool KeyPress::loadFromScancode(const std::string &name)
|
||||
{
|
||||
if (USE_SDL2) {
|
||||
if (!str_starts_with(name, "SYSTEM_SCANCODE_"))
|
||||
return false;
|
||||
char *p;
|
||||
const auto code = strtoul(name.c_str()+16, &p, 10);
|
||||
if (p != name.c_str() + name.size())
|
||||
return false;
|
||||
scancode.emplace<u32>(code);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, KeyPress> specialKeyCache;
|
||||
const KeyPress &KeyPress::getSpecialKey(const std::string &name)
|
||||
{
|
||||
auto &key = specialKeyCache[name];
|
||||
if (!key)
|
||||
key = KeyPress(name);
|
||||
return key;
|
||||
}
|
||||
|
||||
/*
|
||||
Key config
|
||||
@@ -345,14 +382,18 @@ const KeyPress RMBKey("KEY_RBUTTON");
|
||||
// A simple cache for quicker lookup
|
||||
static std::unordered_map<std::string, KeyPress> g_key_setting_cache;
|
||||
|
||||
const KeyPress &getKeySetting(const char *settingname)
|
||||
const KeyPress &getKeySetting(const std::string &settingname)
|
||||
{
|
||||
auto n = g_key_setting_cache.find(settingname);
|
||||
if (n != g_key_setting_cache.end())
|
||||
return n->second;
|
||||
|
||||
auto keysym = g_settings->get(settingname);
|
||||
auto &ref = g_key_setting_cache[settingname];
|
||||
ref = g_settings->get(settingname).c_str();
|
||||
ref = KeyPress(keysym);
|
||||
if (!keysym.empty() && !ref) {
|
||||
warningstream << "Invalid key '" << keysym << "' for '" << settingname << "'." << std::endl;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
@@ -360,8 +401,3 @@ void clearKeyCache()
|
||||
{
|
||||
g_key_setting_cache.clear();
|
||||
}
|
||||
|
||||
irr::EKEY_CODE keyname_to_keycode(const char *name)
|
||||
{
|
||||
return lookup_keyname(name).Key;
|
||||
}
|
||||
|
@@ -4,62 +4,77 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "exceptions.h"
|
||||
#include "irrlichttypes.h"
|
||||
#include <Keycodes.h>
|
||||
#include <IEventReceiver.h>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
class UnknownKeycode : public BaseException
|
||||
{
|
||||
public:
|
||||
UnknownKeycode(const char *s) :
|
||||
BaseException(s) {};
|
||||
};
|
||||
|
||||
/* A key press, consisting of either an Irrlicht keycode
|
||||
or an actual char */
|
||||
|
||||
/* A key press, consisting of a scancode or a keycode */
|
||||
class KeyPress
|
||||
{
|
||||
public:
|
||||
KeyPress() = default;
|
||||
|
||||
KeyPress(const char *name);
|
||||
KeyPress(const std::string &name);
|
||||
|
||||
KeyPress(const irr::SEvent::SKeyInput &in, bool prefer_character = false);
|
||||
KeyPress(const irr::SEvent::SKeyInput &in);
|
||||
|
||||
bool operator==(const KeyPress &o) const
|
||||
// Get a string representation that is suitable for use in minetest.conf
|
||||
std::string sym() const;
|
||||
|
||||
// Get a human-readable string representation
|
||||
std::string name() const;
|
||||
|
||||
// Get the corresponding keycode or KEY_UNKNOWN if one is not available
|
||||
irr::EKEY_CODE getKeycode() const;
|
||||
|
||||
// Get the corresponding keychar or '\0' if one is not available
|
||||
wchar_t getKeychar() const;
|
||||
|
||||
// Get the scancode or 0 is one is not available
|
||||
u32 getScancode() const
|
||||
{
|
||||
return (Char > 0 && Char == o.Char) || (valid_kcode(Key) && Key == o.Key);
|
||||
if (auto pv = std::get_if<u32>(&scancode))
|
||||
return *pv;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *sym() const;
|
||||
const char *name() const;
|
||||
|
||||
protected:
|
||||
static bool valid_kcode(irr::EKEY_CODE k)
|
||||
{
|
||||
return k > 0 && k < irr::KEY_KEY_CODES_COUNT;
|
||||
bool operator==(const KeyPress &o) const {
|
||||
return scancode == o.scancode;
|
||||
}
|
||||
bool operator!=(const KeyPress &o) const {
|
||||
return !(*this == o);
|
||||
}
|
||||
|
||||
irr::EKEY_CODE Key = irr::KEY_KEY_CODES_COUNT;
|
||||
wchar_t Char = L'\0';
|
||||
std::string m_name = "";
|
||||
// Check whether the keypress is valid
|
||||
operator bool() const
|
||||
{
|
||||
return std::holds_alternative<irr::EKEY_CODE>(scancode) ?
|
||||
Keycode::isValid(std::get<irr::EKEY_CODE>(scancode)) :
|
||||
std::get<u32>(scancode) != 0;
|
||||
}
|
||||
|
||||
static const KeyPress &getSpecialKey(const std::string &name);
|
||||
|
||||
private:
|
||||
bool loadFromScancode(const std::string &name);
|
||||
void loadFromKey(irr::EKEY_CODE keycode, wchar_t keychar);
|
||||
std::string formatScancode() const;
|
||||
|
||||
std::variant<u32, irr::EKEY_CODE> scancode = irr::KEY_UNKNOWN;
|
||||
};
|
||||
|
||||
// Global defines for convenience
|
||||
|
||||
extern const KeyPress EscapeKey;
|
||||
|
||||
extern const KeyPress LMBKey;
|
||||
extern const KeyPress MMBKey; // Middle Mouse Button
|
||||
extern const KeyPress RMBKey;
|
||||
// This implementation defers creation of the objects to make sure that the
|
||||
// IrrlichtDevice is initialized.
|
||||
#define EscapeKey KeyPress::getSpecialKey("KEY_ESCAPE")
|
||||
#define LMBKey KeyPress::getSpecialKey("KEY_LBUTTON")
|
||||
#define MMBKey KeyPress::getSpecialKey("KEY_MBUTTON") // Middle Mouse Button
|
||||
#define RMBKey KeyPress::getSpecialKey("KEY_RBUTTON")
|
||||
|
||||
// Key configuration getter
|
||||
const KeyPress &getKeySetting(const char *settingname);
|
||||
const KeyPress &getKeySetting(const std::string &settingname);
|
||||
|
||||
// Clear fast lookup cache
|
||||
void clearKeyCache();
|
||||
|
||||
irr::EKEY_CODE keyname_to_keycode(const char *name);
|
||||
|
@@ -82,6 +82,7 @@ void set_default_settings()
|
||||
|
||||
// Client
|
||||
settings->setDefault("address", "");
|
||||
settings->setDefault("remote_port", "30000");
|
||||
#if defined(__unix__) && !defined(__APPLE__) && !defined (__ANDROID__)
|
||||
// On Linux+X11 (not Linux+Wayland or Linux+XWayland), I've encountered a bug
|
||||
// where fake mouse events were generated from touch events if in relative
|
||||
@@ -128,65 +129,74 @@ void set_default_settings()
|
||||
settings->setDefault("chat_weblink_color", "#8888FF");
|
||||
|
||||
// Keymap
|
||||
settings->setDefault("remote_port", "30000");
|
||||
settings->setDefault("keymap_forward", "KEY_KEY_W");
|
||||
#if USE_SDL2
|
||||
#define USEKEY2(name, value, _) settings->setDefault(name, value)
|
||||
#else
|
||||
#define USEKEY2(name, _, value) settings->setDefault(name, value)
|
||||
#endif
|
||||
USEKEY2("keymap_forward", "SYSTEM_SCANCODE_26", "KEY_KEY_W");
|
||||
settings->setDefault("keymap_autoforward", "");
|
||||
settings->setDefault("keymap_backward", "KEY_KEY_S");
|
||||
settings->setDefault("keymap_left", "KEY_KEY_A");
|
||||
settings->setDefault("keymap_right", "KEY_KEY_D");
|
||||
settings->setDefault("keymap_jump", "KEY_SPACE");
|
||||
settings->setDefault("keymap_sneak", "KEY_LSHIFT");
|
||||
USEKEY2("keymap_backward", "SYSTEM_SCANCODE_22", "KEY_KEY_S");
|
||||
USEKEY2("keymap_left", "SYSTEM_SCANCODE_4", "KEY_KEY_A");
|
||||
USEKEY2("keymap_right", "SYSTEM_SCANCODE_7", "KEY_KEY_D");
|
||||
USEKEY2("keymap_jump", "SYSTEM_SCANCODE_44", "KEY_SPACE");
|
||||
#if !USE_SDL2 && defined(__MACH__) && defined(__APPLE__)
|
||||
// Altered settings for CIrrDeviceOSX
|
||||
settings->setDefault("keymap_sneak", "KEY_SHIFT");
|
||||
#else
|
||||
USEKEY2("keymap_sneak", "SYSTEM_SCANCODE_225", "KEY_LSHIFT");
|
||||
#endif
|
||||
settings->setDefault("keymap_dig", "KEY_LBUTTON");
|
||||
settings->setDefault("keymap_place", "KEY_RBUTTON");
|
||||
settings->setDefault("keymap_drop", "KEY_KEY_Q");
|
||||
settings->setDefault("keymap_zoom", "KEY_KEY_Z");
|
||||
settings->setDefault("keymap_inventory", "KEY_KEY_I");
|
||||
settings->setDefault("keymap_aux1", "KEY_KEY_E");
|
||||
settings->setDefault("keymap_chat", "KEY_KEY_T");
|
||||
settings->setDefault("keymap_cmd", "/");
|
||||
settings->setDefault("keymap_cmd_local", ".");
|
||||
settings->setDefault("keymap_minimap", "KEY_KEY_V");
|
||||
settings->setDefault("keymap_console", "KEY_F10");
|
||||
USEKEY2("keymap_drop", "SYSTEM_SCANCODE_20", "KEY_KEY_Q");
|
||||
USEKEY2("keymap_zoom", "SYSTEM_SCANCODE_29", "KEY_KEY_Z");
|
||||
USEKEY2("keymap_inventory", "SYSTEM_SCANCODE_12", "KEY_KEY_I");
|
||||
USEKEY2("keymap_aux1", "SYSTEM_SCANCODE_8", "KEY_KEY_E");
|
||||
USEKEY2("keymap_chat", "SYSTEM_SCANCODE_23", "KEY_KEY_T");
|
||||
USEKEY2("keymap_cmd", "SYSTEM_SCANCODE_56", "/");
|
||||
USEKEY2("keymap_cmd_local", "SYSTEM_SCANCODE_55", ".");
|
||||
USEKEY2("keymap_minimap", "SYSTEM_SCANCODE_25", "KEY_KEY_V");
|
||||
USEKEY2("keymap_console", "SYSTEM_SCANCODE_67", "KEY_F10");
|
||||
|
||||
// see <https://github.com/luanti-org/luanti/issues/12792>
|
||||
settings->setDefault("keymap_rangeselect", has_touch ? "KEY_KEY_R" : "");
|
||||
USEKEY2("keymap_rangeselect", has_touch ? "SYSTEM_SCANCODE_21" : "", has_touch ? "KEY_KEY_R" : "");
|
||||
|
||||
settings->setDefault("keymap_freemove", "KEY_KEY_K");
|
||||
USEKEY2("keymap_freemove", "SYSTEM_SCANCODE_14", "KEY_KEY_K");
|
||||
settings->setDefault("keymap_pitchmove", "");
|
||||
settings->setDefault("keymap_fastmove", "KEY_KEY_J");
|
||||
settings->setDefault("keymap_noclip", "KEY_KEY_H");
|
||||
settings->setDefault("keymap_hotbar_next", "KEY_KEY_N");
|
||||
settings->setDefault("keymap_hotbar_previous", "KEY_KEY_B");
|
||||
settings->setDefault("keymap_mute", "KEY_KEY_M");
|
||||
USEKEY2("keymap_fastmove", "SYSTEM_SCANCODE_13", "KEY_KEY_J");
|
||||
USEKEY2("keymap_noclip", "SYSTEM_SCANCODE_11", "KEY_KEY_H");
|
||||
USEKEY2("keymap_hotbar_next", "SYSTEM_SCANCODE_17", "KEY_KEY_N");
|
||||
USEKEY2("keymap_hotbar_previous", "SYSTEM_SCANCODE_5", "KEY_KEY_B");
|
||||
USEKEY2("keymap_mute", "SYSTEM_SCANCODE_16", "KEY_KEY_M");
|
||||
settings->setDefault("keymap_increase_volume", "");
|
||||
settings->setDefault("keymap_decrease_volume", "");
|
||||
settings->setDefault("keymap_cinematic", "");
|
||||
settings->setDefault("keymap_toggle_block_bounds", "");
|
||||
settings->setDefault("keymap_toggle_hud", "KEY_F1");
|
||||
settings->setDefault("keymap_toggle_chat", "KEY_F2");
|
||||
settings->setDefault("keymap_toggle_fog", "KEY_F3");
|
||||
USEKEY2("keymap_toggle_hud", "SYSTEM_SCANCODE_58", "KEY_F1");
|
||||
USEKEY2("keymap_toggle_chat", "SYSTEM_SCANCODE_59", "KEY_F2");
|
||||
USEKEY2("keymap_toggle_fog", "SYSTEM_SCANCODE_60", "KEY_F3");
|
||||
#ifndef NDEBUG
|
||||
settings->setDefault("keymap_toggle_update_camera", "KEY_F4");
|
||||
USEKEY2("keymap_toggle_update_camera", "SYSTEM_SCANCODE_61", "KEY_F4");
|
||||
#else
|
||||
settings->setDefault("keymap_toggle_update_camera", "");
|
||||
#endif
|
||||
settings->setDefault("keymap_toggle_debug", "KEY_F5");
|
||||
settings->setDefault("keymap_toggle_profiler", "KEY_F6");
|
||||
settings->setDefault("keymap_camera_mode", "KEY_KEY_C");
|
||||
settings->setDefault("keymap_screenshot", "KEY_F12");
|
||||
settings->setDefault("keymap_fullscreen", "KEY_F11");
|
||||
settings->setDefault("keymap_increase_viewing_range_min", "+");
|
||||
settings->setDefault("keymap_decrease_viewing_range_min", "-");
|
||||
settings->setDefault("keymap_slot1", "KEY_KEY_1");
|
||||
settings->setDefault("keymap_slot2", "KEY_KEY_2");
|
||||
settings->setDefault("keymap_slot3", "KEY_KEY_3");
|
||||
settings->setDefault("keymap_slot4", "KEY_KEY_4");
|
||||
settings->setDefault("keymap_slot5", "KEY_KEY_5");
|
||||
settings->setDefault("keymap_slot6", "KEY_KEY_6");
|
||||
settings->setDefault("keymap_slot7", "KEY_KEY_7");
|
||||
settings->setDefault("keymap_slot8", "KEY_KEY_8");
|
||||
settings->setDefault("keymap_slot9", "KEY_KEY_9");
|
||||
settings->setDefault("keymap_slot10", "KEY_KEY_0");
|
||||
USEKEY2("keymap_toggle_debug", "SYSTEM_SCANCODE_62", "KEY_F5");
|
||||
USEKEY2("keymap_toggle_profiler", "SYSTEM_SCANCODE_63", "KEY_F6");
|
||||
USEKEY2("keymap_camera_mode", "SYSTEM_SCANCODE_6", "KEY_KEY_C");
|
||||
USEKEY2("keymap_screenshot", "SYSTEM_SCANCODE_69", "KEY_F12");
|
||||
USEKEY2("keymap_fullscreen", "SYSTEM_SCANCODE_68", "KEY_F11");
|
||||
USEKEY2("keymap_increase_viewing_range_min", "SYSTEM_SCANCODE_46", "+");
|
||||
USEKEY2("keymap_decrease_viewing_range_min", "SYSTEM_SCANCODE_45", "-");
|
||||
USEKEY2("keymap_slot1", "SYSTEM_SCANCODE_30", "KEY_KEY_1");
|
||||
USEKEY2("keymap_slot2", "SYSTEM_SCANCODE_31", "KEY_KEY_2");
|
||||
USEKEY2("keymap_slot3", "SYSTEM_SCANCODE_32", "KEY_KEY_3");
|
||||
USEKEY2("keymap_slot4", "SYSTEM_SCANCODE_33", "KEY_KEY_4");
|
||||
USEKEY2("keymap_slot5", "SYSTEM_SCANCODE_34", "KEY_KEY_5");
|
||||
USEKEY2("keymap_slot6", "SYSTEM_SCANCODE_35", "KEY_KEY_6");
|
||||
USEKEY2("keymap_slot7", "SYSTEM_SCANCODE_36", "KEY_KEY_7");
|
||||
USEKEY2("keymap_slot8", "SYSTEM_SCANCODE_37", "KEY_KEY_8");
|
||||
USEKEY2("keymap_slot9", "SYSTEM_SCANCODE_38", "KEY_KEY_9");
|
||||
USEKEY2("keymap_slot10", "SYSTEM_SCANCODE_39", "KEY_KEY_0");
|
||||
settings->setDefault("keymap_slot11", "");
|
||||
settings->setDefault("keymap_slot12", "");
|
||||
settings->setDefault("keymap_slot13", "");
|
||||
@@ -212,16 +222,17 @@ void set_default_settings()
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Default keybinds for quicktune in debug builds
|
||||
settings->setDefault("keymap_quicktune_prev", "KEY_HOME");
|
||||
settings->setDefault("keymap_quicktune_next", "KEY_END");
|
||||
settings->setDefault("keymap_quicktune_dec", "KEY_NEXT");
|
||||
settings->setDefault("keymap_quicktune_inc", "KEY_PRIOR");
|
||||
USEKEY2("keymap_quicktune_prev", "SYSTEM_SCANCODE_74", "KEY_HOME");
|
||||
USEKEY2("keymap_quicktune_next", "SYSTEM_SCANCODE_77", "KEY_END");
|
||||
USEKEY2("keymap_quicktune_dec", "SYSTEM_SCANCODE_81", "KEY_NEXT");
|
||||
USEKEY2("keymap_quicktune_inc", "SYSTEM_SCANCODE_82", "KEY_PRIOR");
|
||||
#else
|
||||
settings->setDefault("keymap_quicktune_prev", "");
|
||||
settings->setDefault("keymap_quicktune_next", "");
|
||||
settings->setDefault("keymap_quicktune_dec", "");
|
||||
settings->setDefault("keymap_quicktune_inc", "");
|
||||
#endif
|
||||
#undef USEKEY2
|
||||
|
||||
// Visuals
|
||||
#ifdef NDEBUG
|
||||
@@ -534,11 +545,6 @@ void set_default_settings()
|
||||
settings->setDefault("display_density_factor", "1");
|
||||
settings->setDefault("dpi_change_notifier", "0");
|
||||
|
||||
// Altered settings for CIrrDeviceOSX
|
||||
#if !USE_SDL2 && defined(__MACH__) && defined(__APPLE__)
|
||||
settings->setDefault("keymap_sneak", "KEY_SHIFT");
|
||||
#endif
|
||||
|
||||
settings->setDefault("touch_layout", "");
|
||||
settings->setDefault("touchscreen_sensitivity", "0.2");
|
||||
settings->setDefault("touchscreen_threshold", "20");
|
||||
|
@@ -252,8 +252,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||
if (event.EventType == EET_KEY_INPUT_EVENT && active_key
|
||||
&& event.KeyInput.PressedDown) {
|
||||
|
||||
bool prefer_character = shift_down;
|
||||
KeyPress kp(event.KeyInput, prefer_character);
|
||||
KeyPress kp(event.KeyInput);
|
||||
|
||||
if (event.KeyInput.Key == irr::KEY_DELETE)
|
||||
kp = KeyPress(""); // To erase key settings
|
||||
@@ -269,7 +268,7 @@ bool GUIKeyChangeMenu::OnEvent(const SEvent& event)
|
||||
|
||||
// Display Key already in use message
|
||||
bool key_in_use = false;
|
||||
if (strcmp(kp.sym(), "") != 0) {
|
||||
if (kp) {
|
||||
for (key_setting *ks : key_settings) {
|
||||
if (ks != active_key && ks->key == kp) {
|
||||
key_in_use = true;
|
||||
|
@@ -147,12 +147,13 @@ bool GUIModalMenu::remapClickOutside(const SEvent &event)
|
||||
if (event.MouseInput.Event == EMIE_LMOUSE_LEFT_UP &&
|
||||
current.isRelated(last)) {
|
||||
SEvent translated{};
|
||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
||||
translated.KeyInput.Key = KEY_ESCAPE;
|
||||
translated.KeyInput.Control = false;
|
||||
translated.KeyInput.Shift = false;
|
||||
translated.KeyInput.PressedDown = true;
|
||||
translated.KeyInput.Char = 0;
|
||||
translated.EventType = EET_KEY_INPUT_EVENT;
|
||||
translated.KeyInput.Key = KEY_ESCAPE;
|
||||
translated.KeyInput.SystemKeyCode = EscapeKey.getScancode();
|
||||
translated.KeyInput.Control = false;
|
||||
translated.KeyInput.Shift = false;
|
||||
translated.KeyInput.PressedDown = true;
|
||||
translated.KeyInput.Char = 0;
|
||||
OnEvent(translated);
|
||||
return true;
|
||||
}
|
||||
|
@@ -13,7 +13,6 @@
|
||||
#include "porting.h"
|
||||
#include "settings.h"
|
||||
#include "client/guiscalingfilter.h"
|
||||
#include "client/keycode.h"
|
||||
#include "client/renderingengine.h"
|
||||
#include "client/texturesource.h"
|
||||
#include "util/numeric.h"
|
||||
@@ -31,15 +30,16 @@
|
||||
|
||||
TouchControls *g_touchcontrols;
|
||||
|
||||
void TouchControls::emitKeyboardEvent(EKEY_CODE keycode, bool pressed)
|
||||
void TouchControls::emitKeyboardEvent(const KeyPress &key, bool pressed)
|
||||
{
|
||||
SEvent e{};
|
||||
e.EventType = EET_KEY_INPUT_EVENT;
|
||||
e.KeyInput.Key = keycode;
|
||||
e.KeyInput.Control = false;
|
||||
e.KeyInput.Shift = false;
|
||||
e.KeyInput.Char = 0;
|
||||
e.KeyInput.PressedDown = pressed;
|
||||
e.EventType = EET_KEY_INPUT_EVENT;
|
||||
e.KeyInput.Key = key.getKeycode();
|
||||
e.KeyInput.Control = false;
|
||||
e.KeyInput.Shift = false;
|
||||
e.KeyInput.Char = key.getKeychar();
|
||||
e.KeyInput.SystemKeyCode = key.getScancode();
|
||||
e.KeyInput.PressedDown = pressed;
|
||||
m_receiver->OnEvent(e);
|
||||
}
|
||||
|
||||
@@ -54,10 +54,10 @@ void TouchControls::loadButtonTexture(IGUIImage *gui_button, const std::string &
|
||||
|
||||
void TouchControls::buttonEmitAction(button_info &btn, bool action)
|
||||
{
|
||||
if (btn.keycode == KEY_UNKNOWN)
|
||||
if (!btn.keypress)
|
||||
return;
|
||||
|
||||
emitKeyboardEvent(btn.keycode, action);
|
||||
emitKeyboardEvent(btn.keypress, action);
|
||||
|
||||
if (action) {
|
||||
if (btn.toggleable == button_info::FIRST_TEXTURE) {
|
||||
@@ -133,12 +133,11 @@ bool TouchControls::buttonsStep(std::vector<button_info> &buttons, float dtime)
|
||||
return has_pointers;
|
||||
}
|
||||
|
||||
static EKEY_CODE id_to_keycode(touch_gui_button_id id)
|
||||
static const KeyPress &id_to_keypress(touch_gui_button_id id)
|
||||
{
|
||||
EKEY_CODE code;
|
||||
// ESC isn't part of the keymap.
|
||||
if (id == exit_id)
|
||||
return KEY_ESCAPE;
|
||||
return EscapeKey;
|
||||
|
||||
std::string key = "";
|
||||
switch (id) {
|
||||
@@ -197,15 +196,11 @@ static EKEY_CODE id_to_keycode(touch_gui_button_id id)
|
||||
break;
|
||||
}
|
||||
assert(!key.empty());
|
||||
std::string resolved = g_settings->get("keymap_" + key);
|
||||
try {
|
||||
code = keyname_to_keycode(resolved.c_str());
|
||||
} catch (UnknownKeycode &e) {
|
||||
code = KEY_UNKNOWN;
|
||||
warningstream << "TouchControls: Unknown key '" << resolved
|
||||
<< "' for '" << key << "', hiding button." << std::endl;
|
||||
}
|
||||
return code;
|
||||
auto &kp = getKeySetting("keymap_" + key);
|
||||
if (!kp)
|
||||
warningstream << "TouchControls: Unbound or invalid key for"
|
||||
<< key << ", hiding button." << std::endl;
|
||||
return kp;
|
||||
}
|
||||
|
||||
|
||||
@@ -355,7 +350,7 @@ bool TouchControls::mayAddButton(touch_gui_button_id id)
|
||||
return false;
|
||||
if (id == aux1_id && m_joystick_triggers_aux1)
|
||||
return false;
|
||||
if (id != overflow_id && id_to_keycode(id) == KEY_UNKNOWN)
|
||||
if (id != overflow_id && !id_to_keypress(id))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
@@ -368,7 +363,7 @@ void TouchControls::addButton(std::vector<button_info> &buttons, touch_gui_butto
|
||||
loadButtonTexture(btn_gui_button, image);
|
||||
|
||||
button_info &btn = buttons.emplace_back();
|
||||
btn.keycode = id_to_keycode(id);
|
||||
btn.keypress = id_to_keypress(id);
|
||||
btn.gui_button = grab_gui_element<IGUIImage>(btn_gui_button);
|
||||
}
|
||||
|
||||
@@ -634,7 +629,7 @@ void TouchControls::translateEvent(const SEvent &event)
|
||||
void TouchControls::applyJoystickStatus()
|
||||
{
|
||||
if (m_joystick_triggers_aux1) {
|
||||
auto key = id_to_keycode(aux1_id);
|
||||
auto key = id_to_keypress(aux1_id);
|
||||
emitKeyboardEvent(key, false);
|
||||
if (m_joystick_status_aux1)
|
||||
emitKeyboardEvent(key, true);
|
||||
@@ -741,11 +736,11 @@ void TouchControls::releaseAll()
|
||||
// Release those manually too since the change initiated by
|
||||
// handleReleaseEvent will only be applied later by applyContextControls.
|
||||
if (m_dig_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(dig_id), false);
|
||||
emitKeyboardEvent(id_to_keypress(dig_id), false);
|
||||
m_dig_pressed = false;
|
||||
}
|
||||
if (m_place_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(place_id), false);
|
||||
emitKeyboardEvent(id_to_keypress(place_id), false);
|
||||
m_place_pressed = false;
|
||||
}
|
||||
}
|
||||
@@ -826,20 +821,20 @@ void TouchControls::applyContextControls(const TouchInteractionMode &mode)
|
||||
target_place_pressed |= now < m_place_pressed_until;
|
||||
|
||||
if (target_dig_pressed && !m_dig_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(dig_id), true);
|
||||
emitKeyboardEvent(id_to_keypress(dig_id), true);
|
||||
m_dig_pressed = true;
|
||||
|
||||
} else if (!target_dig_pressed && m_dig_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(dig_id), false);
|
||||
emitKeyboardEvent(id_to_keypress(dig_id), false);
|
||||
m_dig_pressed = false;
|
||||
}
|
||||
|
||||
if (target_place_pressed && !m_place_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(place_id), true);
|
||||
emitKeyboardEvent(id_to_keypress(place_id), true);
|
||||
m_place_pressed = true;
|
||||
|
||||
} else if (!target_place_pressed && m_place_pressed) {
|
||||
emitKeyboardEvent(id_to_keycode(place_id), false);
|
||||
emitKeyboardEvent(id_to_keypress(place_id), false);
|
||||
m_place_pressed = false;
|
||||
}
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include "itemdef.h"
|
||||
#include "touchscreenlayout.h"
|
||||
#include "util/basic_macros.h"
|
||||
#include "client/keycode.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
@@ -57,7 +58,7 @@ enum class TapState
|
||||
struct button_info
|
||||
{
|
||||
float repeat_counter;
|
||||
EKEY_CODE keycode;
|
||||
KeyPress keypress;
|
||||
std::vector<size_t> pointer_ids;
|
||||
std::shared_ptr<IGUIImage> gui_button = nullptr;
|
||||
|
||||
@@ -202,7 +203,7 @@ private:
|
||||
// for its buttons. We only want static image display, not interactivity,
|
||||
// from Irrlicht.
|
||||
|
||||
void emitKeyboardEvent(EKEY_CODE keycode, bool pressed);
|
||||
void emitKeyboardEvent(const KeyPress &keycode, bool pressed);
|
||||
|
||||
void loadButtonTexture(IGUIImage *gui_button, const std::string &path);
|
||||
void buttonEmitAction(button_info &btn, bool action);
|
||||
|
@@ -15,20 +15,26 @@ public:
|
||||
|
||||
void runTests(IGameDef *gamedef);
|
||||
|
||||
/* TODO: Re-introduce unittests after fully switching to SDL.
|
||||
void testCreateFromString();
|
||||
void testCreateFromSKeyInput();
|
||||
void testCompare();
|
||||
*/
|
||||
};
|
||||
|
||||
static TestKeycode g_test_instance;
|
||||
|
||||
void TestKeycode::runTests(IGameDef *gamedef)
|
||||
{
|
||||
/*
|
||||
TEST(testCreateFromString);
|
||||
TEST(testCreateFromSKeyInput);
|
||||
TEST(testCompare);
|
||||
*/
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#define UASSERTEQ_STR(one, two) UASSERT(strcmp(one, two) == 0)
|
||||
@@ -112,3 +118,5 @@ void TestKeycode::testCompare()
|
||||
in2.Char = L';';
|
||||
UASSERT(KeyPress(in) == KeyPress(in2));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user