mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 09:15:29 +01: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:
		@@ -16,6 +16,7 @@
 | 
			
		||||
#include "IrrCompileConfig.h"
 | 
			
		||||
#include "position2d.h"
 | 
			
		||||
#include "SColor.h" // video::ECOLOR_FORMAT
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
namespace irr
 | 
			
		||||
{
 | 
			
		||||
@@ -342,6 +343,27 @@ public:
 | 
			
		||||
	{
 | 
			
		||||
		return video::isDriverSupported(driver);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//! Get the corresponding scancode for the keycode.
 | 
			
		||||
	/**
 | 
			
		||||
	\param key The keycode to convert.
 | 
			
		||||
	\return The implementation-dependent scancode for the key (represented by the u32 component) or, if a scancode is not
 | 
			
		||||
	available, the corresponding Irrlicht keycode (represented by the EKEY_CODE component).
 | 
			
		||||
	*/
 | 
			
		||||
	virtual std::variant<u32, EKEY_CODE> getScancodeFromKey(const Keycode &key) const {
 | 
			
		||||
		if (auto pv = std::get_if<EKEY_CODE>(&key))
 | 
			
		||||
			return *pv;
 | 
			
		||||
		return (u32)std::get<wchar_t>(key);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	//! Get the corresponding keycode for the scancode.
 | 
			
		||||
	/**
 | 
			
		||||
	\param scancode The implementation-dependent scancode for the key.
 | 
			
		||||
	\return The corresponding keycode.
 | 
			
		||||
	*/
 | 
			
		||||
	virtual Keycode getKeyFromScancode(const u32 scancode) const {
 | 
			
		||||
		return Keycode(KEY_UNKNOWN, (wchar_t)scancode);
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end namespace irr
 | 
			
		||||
 
 | 
			
		||||
@@ -3,6 +3,7 @@
 | 
			
		||||
// For conditions of distribution and use, see copyright notice in irrlicht.h
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#include <variant>
 | 
			
		||||
 | 
			
		||||
namespace irr
 | 
			
		||||
{
 | 
			
		||||
@@ -182,4 +183,30 @@ enum EKEY_CODE
 | 
			
		||||
	KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are.
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// A Keycode is either a character produced by the key or one of Irrlicht's codes (EKEY_CODE)
 | 
			
		||||
class Keycode : public std::variant<EKEY_CODE, wchar_t> {
 | 
			
		||||
	using super = std::variant<EKEY_CODE, wchar_t>;
 | 
			
		||||
public:
 | 
			
		||||
	Keycode() : Keycode(KEY_KEY_CODES_COUNT, L'\0') {}
 | 
			
		||||
 | 
			
		||||
	Keycode(EKEY_CODE code, wchar_t ch)
 | 
			
		||||
	{
 | 
			
		||||
		emplace(code, ch);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	using super::emplace;
 | 
			
		||||
	void emplace(EKEY_CODE code, wchar_t ch)
 | 
			
		||||
	{
 | 
			
		||||
		if (isValid(code))
 | 
			
		||||
			emplace<EKEY_CODE>(code);
 | 
			
		||||
		else
 | 
			
		||||
			emplace<wchar_t>(ch);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	static bool isValid(EKEY_CODE code)
 | 
			
		||||
	{
 | 
			
		||||
		return code > 0 && code < KEY_KEY_CODES_COUNT;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // end namespace irr
 | 
			
		||||
 
 | 
			
		||||
@@ -27,6 +27,21 @@
 | 
			
		||||
 | 
			
		||||
#include "CSDLManager.h"
 | 
			
		||||
 | 
			
		||||
// Since SDL doesn't have mouse keys as keycodes we need to fall back to EKEY_CODE in some cases.
 | 
			
		||||
static inline bool is_fake_key(irr::EKEY_CODE key) {
 | 
			
		||||
	switch (key) {
 | 
			
		||||
	case irr::KEY_LBUTTON:
 | 
			
		||||
	case irr::KEY_MBUTTON:
 | 
			
		||||
	case irr::KEY_RBUTTON:
 | 
			
		||||
	case irr::KEY_XBUTTON1:
 | 
			
		||||
	case irr::KEY_XBUTTON2:
 | 
			
		||||
		return true;
 | 
			
		||||
 | 
			
		||||
	default:
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int SDLDeviceInstances = 0;
 | 
			
		||||
 | 
			
		||||
namespace irr
 | 
			
		||||
@@ -220,6 +235,35 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtK
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::variant<u32, EKEY_CODE> CIrrDeviceSDL::getScancodeFromKey(const Keycode &key) const
 | 
			
		||||
{
 | 
			
		||||
	u32 keynum = 0;
 | 
			
		||||
	if (const auto *keycode = std::get_if<EKEY_CODE>(&key)) {
 | 
			
		||||
		// Fake keys (e.g. mouse buttons): use EKEY_CODE since there is no corresponding scancode.
 | 
			
		||||
		if (is_fake_key(*keycode))
 | 
			
		||||
			return *keycode;
 | 
			
		||||
		// Try to convert the EKEY_CODE to a SDL scancode.
 | 
			
		||||
		for (const auto &entry: KeyMap) {
 | 
			
		||||
			if (entry.second == *keycode) {
 | 
			
		||||
				keynum = entry.first;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	} else {
 | 
			
		||||
		keynum = std::get<wchar_t>(key);
 | 
			
		||||
	}
 | 
			
		||||
	return (u32)SDL_GetScancodeFromKey(keynum);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Keycode CIrrDeviceSDL::getKeyFromScancode(const u32 scancode) const
 | 
			
		||||
{
 | 
			
		||||
	auto keycode = SDL_GetKeyFromScancode((SDL_Scancode)scancode);
 | 
			
		||||
	const auto &keyentry = KeyMap.find(keycode);
 | 
			
		||||
	auto irrcode = keyentry != KeyMap.end() ? keyentry->second : KEY_UNKNOWN;
 | 
			
		||||
	auto keychar = findCharToPassToIrrlicht(keycode, irrcode, false);
 | 
			
		||||
	return Keycode(irrcode, keychar);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CIrrDeviceSDL::resetReceiveTextInputEvents()
 | 
			
		||||
{
 | 
			
		||||
	gui::IGUIElement *elem = GUIEnvironment->getFocus();
 | 
			
		||||
@@ -822,18 +866,20 @@ bool CIrrDeviceSDL::run()
 | 
			
		||||
 | 
			
		||||
		case SDL_KEYDOWN:
 | 
			
		||||
		case SDL_KEYUP: {
 | 
			
		||||
			SKeyMap mp;
 | 
			
		||||
			mp.SDLKey = SDL_event.key.keysym.sym;
 | 
			
		||||
			s32 idx = KeyMap.binary_search(mp);
 | 
			
		||||
			auto keysym = SDL_event.key.keysym.sym;
 | 
			
		||||
			auto scancode = SDL_event.key.keysym.scancode;
 | 
			
		||||
 | 
			
		||||
			EKEY_CODE key;
 | 
			
		||||
			if (idx == -1)
 | 
			
		||||
				key = (EKEY_CODE)0;
 | 
			
		||||
			else
 | 
			
		||||
				key = (EKEY_CODE)KeyMap[idx].Win32Key;
 | 
			
		||||
			// Treat AC_BACK as the Escape key
 | 
			
		||||
			if (scancode == SDL_SCANCODE_AC_BACK) {
 | 
			
		||||
				scancode = SDL_SCANCODE_ESCAPE;
 | 
			
		||||
				keysym = SDLK_ESCAPE;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			if (key == (EKEY_CODE)0)
 | 
			
		||||
				os::Printer::log("keycode not mapped", core::stringc(mp.SDLKey), ELL_DEBUG);
 | 
			
		||||
			const auto &entry = KeyMap.find(keysym);
 | 
			
		||||
			auto key = entry == KeyMap.end() ? KEY_UNKNOWN : entry->second;
 | 
			
		||||
 | 
			
		||||
			if (!Keycode::isValid(key))
 | 
			
		||||
				os::Printer::log("keycode not mapped", core::stringc(keysym), ELL_DEBUG);
 | 
			
		||||
 | 
			
		||||
			// Make sure to only input special characters if something is in focus, as SDL_TEXTINPUT handles normal unicode already
 | 
			
		||||
			if (SDL_IsTextInputActive() && !keyIsKnownSpecial(key) && (SDL_event.key.keysym.mod & KMOD_CTRL) == 0)
 | 
			
		||||
@@ -844,8 +890,10 @@ bool CIrrDeviceSDL::run()
 | 
			
		||||
			irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
 | 
			
		||||
			irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
 | 
			
		||||
			irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0;
 | 
			
		||||
			irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key,
 | 
			
		||||
			irrevent.KeyInput.Char = findCharToPassToIrrlicht(keysym, key,
 | 
			
		||||
					(SDL_event.key.keysym.mod & KMOD_NUM) != 0);
 | 
			
		||||
			irrevent.KeyInput.SystemKeyCode = scancode;
 | 
			
		||||
 | 
			
		||||
			postEventFromUser(irrevent);
 | 
			
		||||
		} break;
 | 
			
		||||
 | 
			
		||||
@@ -1310,142 +1358,135 @@ void CIrrDeviceSDL::createKeyMap()
 | 
			
		||||
	// the lookuptable, but I'll leave it like that until
 | 
			
		||||
	// I find a better version.
 | 
			
		||||
 | 
			
		||||
	KeyMap.reallocate(105);
 | 
			
		||||
 | 
			
		||||
	// buttons missing
 | 
			
		||||
 | 
			
		||||
	// Android back button = ESC
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_AC_BACK, KEY_ESCAPE));
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RETURN, KEY_RETURN));
 | 
			
		||||
	KeyMap.emplace(SDLK_BACKSPACE, KEY_BACK);
 | 
			
		||||
	KeyMap.emplace(SDLK_TAB, KEY_TAB);
 | 
			
		||||
	KeyMap.emplace(SDLK_CLEAR, KEY_CLEAR);
 | 
			
		||||
	KeyMap.emplace(SDLK_RETURN, KEY_RETURN);
 | 
			
		||||
 | 
			
		||||
	// combined modifiers missing
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PAUSE, KEY_PAUSE));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_CAPSLOCK, KEY_CAPITAL));
 | 
			
		||||
	KeyMap.emplace(SDLK_PAUSE, KEY_PAUSE);
 | 
			
		||||
	KeyMap.emplace(SDLK_CAPSLOCK, KEY_CAPITAL);
 | 
			
		||||
 | 
			
		||||
	// asian letter keys missing
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_ESCAPE, KEY_ESCAPE));
 | 
			
		||||
	KeyMap.emplace(SDLK_ESCAPE, KEY_ESCAPE);
 | 
			
		||||
 | 
			
		||||
	// asian letter keys missing
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_SPACE, KEY_SPACE));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PAGEUP, KEY_PRIOR));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PAGEDOWN, KEY_NEXT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_END, KEY_END));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_HOME, KEY_HOME));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_LEFT, KEY_LEFT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_UP, KEY_UP));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RIGHT, KEY_RIGHT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_DOWN, KEY_DOWN));
 | 
			
		||||
	KeyMap.emplace(SDLK_SPACE, KEY_SPACE);
 | 
			
		||||
	KeyMap.emplace(SDLK_PAGEUP, KEY_PRIOR);
 | 
			
		||||
	KeyMap.emplace(SDLK_PAGEDOWN, KEY_NEXT);
 | 
			
		||||
	KeyMap.emplace(SDLK_END, KEY_END);
 | 
			
		||||
	KeyMap.emplace(SDLK_HOME, KEY_HOME);
 | 
			
		||||
	KeyMap.emplace(SDLK_LEFT, KEY_LEFT);
 | 
			
		||||
	KeyMap.emplace(SDLK_UP, KEY_UP);
 | 
			
		||||
	KeyMap.emplace(SDLK_RIGHT, KEY_RIGHT);
 | 
			
		||||
	KeyMap.emplace(SDLK_DOWN, KEY_DOWN);
 | 
			
		||||
 | 
			
		||||
	// select missing
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, KEY_PRINT));
 | 
			
		||||
	KeyMap.emplace(SDLK_PRINTSCREEN, KEY_PRINT);
 | 
			
		||||
	// execute missing
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PRINTSCREEN, KEY_SNAPSHOT));
 | 
			
		||||
	KeyMap.emplace(SDLK_PRINTSCREEN, KEY_SNAPSHOT);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_INSERT, KEY_INSERT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_DELETE, KEY_DELETE));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_HELP, KEY_HELP));
 | 
			
		||||
	KeyMap.emplace(SDLK_INSERT, KEY_INSERT);
 | 
			
		||||
	KeyMap.emplace(SDLK_DELETE, KEY_DELETE);
 | 
			
		||||
	KeyMap.emplace(SDLK_HELP, KEY_HELP);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_0, KEY_KEY_0));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_1, KEY_KEY_1));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_2, KEY_KEY_2));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_3, KEY_KEY_3));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_4, KEY_KEY_4));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_5, KEY_KEY_5));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_6, KEY_KEY_6));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_7, KEY_KEY_7));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_8, KEY_KEY_8));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_9, KEY_KEY_9));
 | 
			
		||||
	KeyMap.emplace(SDLK_0, KEY_KEY_0);
 | 
			
		||||
	KeyMap.emplace(SDLK_1, KEY_KEY_1);
 | 
			
		||||
	KeyMap.emplace(SDLK_2, KEY_KEY_2);
 | 
			
		||||
	KeyMap.emplace(SDLK_3, KEY_KEY_3);
 | 
			
		||||
	KeyMap.emplace(SDLK_4, KEY_KEY_4);
 | 
			
		||||
	KeyMap.emplace(SDLK_5, KEY_KEY_5);
 | 
			
		||||
	KeyMap.emplace(SDLK_6, KEY_KEY_6);
 | 
			
		||||
	KeyMap.emplace(SDLK_7, KEY_KEY_7);
 | 
			
		||||
	KeyMap.emplace(SDLK_8, KEY_KEY_8);
 | 
			
		||||
	KeyMap.emplace(SDLK_9, KEY_KEY_9);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_a, KEY_KEY_A));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_b, KEY_KEY_B));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_c, KEY_KEY_C));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_d, KEY_KEY_D));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_e, KEY_KEY_E));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_f, KEY_KEY_F));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_g, KEY_KEY_G));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_h, KEY_KEY_H));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_i, KEY_KEY_I));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_j, KEY_KEY_J));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_k, KEY_KEY_K));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_l, KEY_KEY_L));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_m, KEY_KEY_M));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_n, KEY_KEY_N));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_o, KEY_KEY_O));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_p, KEY_KEY_P));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_q, KEY_KEY_Q));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_r, KEY_KEY_R));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_s, KEY_KEY_S));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_t, KEY_KEY_T));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_u, KEY_KEY_U));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_v, KEY_KEY_V));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_w, KEY_KEY_W));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_x, KEY_KEY_X));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_y, KEY_KEY_Y));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_z, KEY_KEY_Z));
 | 
			
		||||
	KeyMap.emplace(SDLK_a, KEY_KEY_A);
 | 
			
		||||
	KeyMap.emplace(SDLK_b, KEY_KEY_B);
 | 
			
		||||
	KeyMap.emplace(SDLK_c, KEY_KEY_C);
 | 
			
		||||
	KeyMap.emplace(SDLK_d, KEY_KEY_D);
 | 
			
		||||
	KeyMap.emplace(SDLK_e, KEY_KEY_E);
 | 
			
		||||
	KeyMap.emplace(SDLK_f, KEY_KEY_F);
 | 
			
		||||
	KeyMap.emplace(SDLK_g, KEY_KEY_G);
 | 
			
		||||
	KeyMap.emplace(SDLK_h, KEY_KEY_H);
 | 
			
		||||
	KeyMap.emplace(SDLK_i, KEY_KEY_I);
 | 
			
		||||
	KeyMap.emplace(SDLK_j, KEY_KEY_J);
 | 
			
		||||
	KeyMap.emplace(SDLK_k, KEY_KEY_K);
 | 
			
		||||
	KeyMap.emplace(SDLK_l, KEY_KEY_L);
 | 
			
		||||
	KeyMap.emplace(SDLK_m, KEY_KEY_M);
 | 
			
		||||
	KeyMap.emplace(SDLK_n, KEY_KEY_N);
 | 
			
		||||
	KeyMap.emplace(SDLK_o, KEY_KEY_O);
 | 
			
		||||
	KeyMap.emplace(SDLK_p, KEY_KEY_P);
 | 
			
		||||
	KeyMap.emplace(SDLK_q, KEY_KEY_Q);
 | 
			
		||||
	KeyMap.emplace(SDLK_r, KEY_KEY_R);
 | 
			
		||||
	KeyMap.emplace(SDLK_s, KEY_KEY_S);
 | 
			
		||||
	KeyMap.emplace(SDLK_t, KEY_KEY_T);
 | 
			
		||||
	KeyMap.emplace(SDLK_u, KEY_KEY_U);
 | 
			
		||||
	KeyMap.emplace(SDLK_v, KEY_KEY_V);
 | 
			
		||||
	KeyMap.emplace(SDLK_w, KEY_KEY_W);
 | 
			
		||||
	KeyMap.emplace(SDLK_x, KEY_KEY_X);
 | 
			
		||||
	KeyMap.emplace(SDLK_y, KEY_KEY_Y);
 | 
			
		||||
	KeyMap.emplace(SDLK_z, KEY_KEY_Z);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_LGUI, KEY_LWIN));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RGUI, KEY_RWIN));
 | 
			
		||||
	KeyMap.emplace(SDLK_LGUI, KEY_LWIN);
 | 
			
		||||
	KeyMap.emplace(SDLK_RGUI, KEY_RWIN);
 | 
			
		||||
	// apps missing
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_POWER, KEY_SLEEP)); //??
 | 
			
		||||
	KeyMap.emplace(SDLK_POWER, KEY_SLEEP); //??
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_0, KEY_NUMPAD0));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_1, KEY_NUMPAD1));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_2, KEY_NUMPAD2));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_3, KEY_NUMPAD3));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_4, KEY_NUMPAD4));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_5, KEY_NUMPAD5));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_6, KEY_NUMPAD6));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_7, KEY_NUMPAD7));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_8, KEY_NUMPAD8));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_9, KEY_NUMPAD9));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_MULTIPLY, KEY_MULTIPLY));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_PLUS, KEY_ADD));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_ENTER, KEY_RETURN));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_MINUS, KEY_SUBTRACT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_PERIOD, KEY_DECIMAL));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_KP_DIVIDE, KEY_DIVIDE));
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_0, KEY_NUMPAD0);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_1, KEY_NUMPAD1);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_2, KEY_NUMPAD2);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_3, KEY_NUMPAD3);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_4, KEY_NUMPAD4);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_5, KEY_NUMPAD5);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_6, KEY_NUMPAD6);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_7, KEY_NUMPAD7);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_8, KEY_NUMPAD8);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_9, KEY_NUMPAD9);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_MULTIPLY, KEY_MULTIPLY);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_PLUS, KEY_ADD);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_ENTER, KEY_RETURN);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_MINUS, KEY_SUBTRACT);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_PERIOD, KEY_DECIMAL);
 | 
			
		||||
	KeyMap.emplace(SDLK_KP_DIVIDE, KEY_DIVIDE);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F1, KEY_F1));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F2, KEY_F2));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F3, KEY_F3));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F4, KEY_F4));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F5, KEY_F5));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F6, KEY_F6));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F7, KEY_F7));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F8, KEY_F8));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F9, KEY_F9));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F10, KEY_F10));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F11, KEY_F11));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F12, KEY_F12));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F13, KEY_F13));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F14, KEY_F14));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_F15, KEY_F15));
 | 
			
		||||
	KeyMap.emplace(SDLK_F1, KEY_F1);
 | 
			
		||||
	KeyMap.emplace(SDLK_F2, KEY_F2);
 | 
			
		||||
	KeyMap.emplace(SDLK_F3, KEY_F3);
 | 
			
		||||
	KeyMap.emplace(SDLK_F4, KEY_F4);
 | 
			
		||||
	KeyMap.emplace(SDLK_F5, KEY_F5);
 | 
			
		||||
	KeyMap.emplace(SDLK_F6, KEY_F6);
 | 
			
		||||
	KeyMap.emplace(SDLK_F7, KEY_F7);
 | 
			
		||||
	KeyMap.emplace(SDLK_F8, KEY_F8);
 | 
			
		||||
	KeyMap.emplace(SDLK_F9, KEY_F9);
 | 
			
		||||
	KeyMap.emplace(SDLK_F10, KEY_F10);
 | 
			
		||||
	KeyMap.emplace(SDLK_F11, KEY_F11);
 | 
			
		||||
	KeyMap.emplace(SDLK_F12, KEY_F12);
 | 
			
		||||
	KeyMap.emplace(SDLK_F13, KEY_F13);
 | 
			
		||||
	KeyMap.emplace(SDLK_F14, KEY_F14);
 | 
			
		||||
	KeyMap.emplace(SDLK_F15, KEY_F15);
 | 
			
		||||
	// no higher F-keys
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_NUMLOCKCLEAR, KEY_NUMLOCK));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_SCROLLLOCK, KEY_SCROLL));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_LSHIFT, KEY_LSHIFT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RSHIFT, KEY_RSHIFT));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_LCTRL, KEY_LCONTROL));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RCTRL, KEY_RCONTROL));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_LALT, KEY_LMENU));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_RALT, KEY_RMENU));
 | 
			
		||||
	KeyMap.emplace(SDLK_NUMLOCKCLEAR, KEY_NUMLOCK);
 | 
			
		||||
	KeyMap.emplace(SDLK_SCROLLLOCK, KEY_SCROLL);
 | 
			
		||||
	KeyMap.emplace(SDLK_LSHIFT, KEY_LSHIFT);
 | 
			
		||||
	KeyMap.emplace(SDLK_RSHIFT, KEY_RSHIFT);
 | 
			
		||||
	KeyMap.emplace(SDLK_LCTRL, KEY_LCONTROL);
 | 
			
		||||
	KeyMap.emplace(SDLK_RCTRL, KEY_RCONTROL);
 | 
			
		||||
	KeyMap.emplace(SDLK_LALT, KEY_LMENU);
 | 
			
		||||
	KeyMap.emplace(SDLK_RALT, KEY_RMENU);
 | 
			
		||||
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PLUS, KEY_PLUS));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_COMMA, KEY_COMMA));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_MINUS, KEY_MINUS));
 | 
			
		||||
	KeyMap.push_back(SKeyMap(SDLK_PERIOD, KEY_PERIOD));
 | 
			
		||||
	KeyMap.emplace(SDLK_PLUS, KEY_PLUS);
 | 
			
		||||
	KeyMap.emplace(SDLK_COMMA, KEY_COMMA);
 | 
			
		||||
	KeyMap.emplace(SDLK_MINUS, KEY_MINUS);
 | 
			
		||||
	KeyMap.emplace(SDLK_PERIOD, KEY_PERIOD);
 | 
			
		||||
 | 
			
		||||
	// some special keys missing
 | 
			
		||||
 | 
			
		||||
	KeyMap.sort();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void CIrrDeviceSDL::CCursorControl::initCursors()
 | 
			
		||||
 
 | 
			
		||||
@@ -24,6 +24,7 @@
 | 
			
		||||
#include <SDL_syswm.h>
 | 
			
		||||
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
 | 
			
		||||
namespace irr
 | 
			
		||||
{
 | 
			
		||||
@@ -286,6 +287,9 @@ private:
 | 
			
		||||
	// Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0).
 | 
			
		||||
	static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock);
 | 
			
		||||
 | 
			
		||||
	std::variant<u32, EKEY_CODE> getScancodeFromKey(const Keycode &key) const override;
 | 
			
		||||
	Keycode getKeyFromScancode(const u32 scancode) const override;
 | 
			
		||||
 | 
			
		||||
	// Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
 | 
			
		||||
	void resetReceiveTextInputEvents();
 | 
			
		||||
 | 
			
		||||
@@ -319,24 +323,9 @@ private:
 | 
			
		||||
 | 
			
		||||
	core::rect<s32> lastElemPos;
 | 
			
		||||
 | 
			
		||||
	struct SKeyMap
 | 
			
		||||
	{
 | 
			
		||||
		SKeyMap() {}
 | 
			
		||||
		SKeyMap(s32 x11, s32 win32) :
 | 
			
		||||
				SDLKey(x11), Win32Key(win32)
 | 
			
		||||
		{
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		s32 SDLKey;
 | 
			
		||||
		s32 Win32Key;
 | 
			
		||||
 | 
			
		||||
		bool operator<(const SKeyMap &o) const
 | 
			
		||||
		{
 | 
			
		||||
			return SDLKey < o.SDLKey;
 | 
			
		||||
		}
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	core::array<SKeyMap> KeyMap;
 | 
			
		||||
	// TODO: This is only used for scancode/keycode conversion with EKEY_CODE (among other things, for Luanti
 | 
			
		||||
	// to display keys to users). Drop this along with EKEY_CODE.
 | 
			
		||||
	std::unordered_map<SDL_Keycode, EKEY_CODE> KeyMap;
 | 
			
		||||
 | 
			
		||||
	s32 CurrentTouchCount;
 | 
			
		||||
	bool IsInBackground;
 | 
			
		||||
 
 | 
			
		||||
@@ -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