Browse Source

key press events and love.keyboard support arbitrary non-ascii key constants.

Closes #2012.
Sasha Szpakowski 1 year ago
parent
commit
a23d53183e

+ 3 - 230
src/modules/event/sdl/Event.cpp

@@ -240,11 +240,10 @@ Message *Event::convert(const SDL_Event &e)
 
 	const char *txt;
 	const char *txt2;
-	std::map<SDL_Keycode, love::keyboard::Keyboard::Key>::const_iterator keyit;
 
 #ifndef LOVE_MACOS
 	love::touch::sdl::Touch *touchmodule = nullptr;
-	love::touch::Touch::TouchInfo touchinfo;
+	love::touch::Touch::TouchInfo touchinfo = {};
 #endif
 
 	switch (e.type)
@@ -257,10 +256,7 @@ Message *Event::convert(const SDL_Event &e)
 				break;
 		}
 
-		keyit = keys.find(e.key.keysym.sym);
-		if (keyit != keys.end())
-			key = keyit->second;
-
+		love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.sym, key);
 		if (!love::keyboard::Keyboard::getConstant(key, txt))
 			txt = "unknown";
 
@@ -274,10 +270,7 @@ Message *Event::convert(const SDL_Event &e)
 		msg = new Message("keypressed", vargs);
 		break;
 	case SDL_EVENT_KEY_UP:
-		keyit = keys.find(e.key.keysym.sym);
-		if (keyit != keys.end())
-			key = keyit->second;
-
+		love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.sym, key);
 		if (!love::keyboard::Keyboard::getConstant(key, txt))
 			txt = "unknown";
 
@@ -842,226 +835,6 @@ Message *Event::convertWindowEvent(const SDL_Event &e)
 	return msg;
 }
 
-std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
-{
-	using love::keyboard::Keyboard;
-
-	std::map<SDL_Keycode, Keyboard::Key> k;
-
-	k[SDLK_UNKNOWN] = Keyboard::KEY_UNKNOWN;
-
-	k[SDLK_RETURN] = Keyboard::KEY_RETURN;
-	k[SDLK_ESCAPE] = Keyboard::KEY_ESCAPE;
-	k[SDLK_BACKSPACE] = Keyboard::KEY_BACKSPACE;
-	k[SDLK_TAB] = Keyboard::KEY_TAB;
-	k[SDLK_SPACE] = Keyboard::KEY_SPACE;
-	k[SDLK_EXCLAIM] = Keyboard::KEY_EXCLAIM;
-	k[SDLK_QUOTEDBL] = Keyboard::KEY_QUOTEDBL;
-	k[SDLK_HASH] = Keyboard::KEY_HASH;
-	k[SDLK_PERCENT] = Keyboard::KEY_PERCENT;
-	k[SDLK_DOLLAR] = Keyboard::KEY_DOLLAR;
-	k[SDLK_AMPERSAND] = Keyboard::KEY_AMPERSAND;
-	k[SDLK_QUOTE] = Keyboard::KEY_QUOTE;
-	k[SDLK_LEFTPAREN] = Keyboard::KEY_LEFTPAREN;
-	k[SDLK_RIGHTPAREN] = Keyboard::KEY_RIGHTPAREN;
-	k[SDLK_ASTERISK] = Keyboard::KEY_ASTERISK;
-	k[SDLK_PLUS] = Keyboard::KEY_PLUS;
-	k[SDLK_COMMA] = Keyboard::KEY_COMMA;
-	k[SDLK_MINUS] = Keyboard::KEY_MINUS;
-	k[SDLK_PERIOD] = Keyboard::KEY_PERIOD;
-	k[SDLK_SLASH] = Keyboard::KEY_SLASH;
-	k[SDLK_0] = Keyboard::KEY_0;
-	k[SDLK_1] = Keyboard::KEY_1;
-	k[SDLK_2] = Keyboard::KEY_2;
-	k[SDLK_3] = Keyboard::KEY_3;
-	k[SDLK_4] = Keyboard::KEY_4;
-	k[SDLK_5] = Keyboard::KEY_5;
-	k[SDLK_6] = Keyboard::KEY_6;
-	k[SDLK_7] = Keyboard::KEY_7;
-	k[SDLK_8] = Keyboard::KEY_8;
-	k[SDLK_9] = Keyboard::KEY_9;
-	k[SDLK_COLON] = Keyboard::KEY_COLON;
-	k[SDLK_SEMICOLON] = Keyboard::KEY_SEMICOLON;
-	k[SDLK_LESS] = Keyboard::KEY_LESS;
-	k[SDLK_EQUALS] = Keyboard::KEY_EQUALS;
-	k[SDLK_GREATER] = Keyboard::KEY_GREATER;
-	k[SDLK_QUESTION] = Keyboard::KEY_QUESTION;
-	k[SDLK_AT] = Keyboard::KEY_AT;
-
-	k[SDLK_LEFTBRACKET] = Keyboard::KEY_LEFTBRACKET;
-	k[SDLK_BACKSLASH] = Keyboard::KEY_BACKSLASH;
-	k[SDLK_RIGHTBRACKET] = Keyboard::KEY_RIGHTBRACKET;
-	k[SDLK_CARET] = Keyboard::KEY_CARET;
-	k[SDLK_UNDERSCORE] = Keyboard::KEY_UNDERSCORE;
-	k[SDLK_BACKQUOTE] = Keyboard::KEY_BACKQUOTE;
-	k[SDLK_a] = Keyboard::KEY_A;
-	k[SDLK_b] = Keyboard::KEY_B;
-	k[SDLK_c] = Keyboard::KEY_C;
-	k[SDLK_d] = Keyboard::KEY_D;
-	k[SDLK_e] = Keyboard::KEY_E;
-	k[SDLK_f] = Keyboard::KEY_F;
-	k[SDLK_g] = Keyboard::KEY_G;
-	k[SDLK_h] = Keyboard::KEY_H;
-	k[SDLK_i] = Keyboard::KEY_I;
-	k[SDLK_j] = Keyboard::KEY_J;
-	k[SDLK_k] = Keyboard::KEY_K;
-	k[SDLK_l] = Keyboard::KEY_L;
-	k[SDLK_m] = Keyboard::KEY_M;
-	k[SDLK_n] = Keyboard::KEY_N;
-	k[SDLK_o] = Keyboard::KEY_O;
-	k[SDLK_p] = Keyboard::KEY_P;
-	k[SDLK_q] = Keyboard::KEY_Q;
-	k[SDLK_r] = Keyboard::KEY_R;
-	k[SDLK_s] = Keyboard::KEY_S;
-	k[SDLK_t] = Keyboard::KEY_T;
-	k[SDLK_u] = Keyboard::KEY_U;
-	k[SDLK_v] = Keyboard::KEY_V;
-	k[SDLK_w] = Keyboard::KEY_W;
-	k[SDLK_x] = Keyboard::KEY_X;
-	k[SDLK_y] = Keyboard::KEY_Y;
-	k[SDLK_z] = Keyboard::KEY_Z;
-
-	k[SDLK_CAPSLOCK] = Keyboard::KEY_CAPSLOCK;
-
-	k[SDLK_F1] = Keyboard::KEY_F1;
-	k[SDLK_F2] = Keyboard::KEY_F2;
-	k[SDLK_F3] = Keyboard::KEY_F3;
-	k[SDLK_F4] = Keyboard::KEY_F4;
-	k[SDLK_F5] = Keyboard::KEY_F5;
-	k[SDLK_F6] = Keyboard::KEY_F6;
-	k[SDLK_F7] = Keyboard::KEY_F7;
-	k[SDLK_F8] = Keyboard::KEY_F8;
-	k[SDLK_F9] = Keyboard::KEY_F9;
-	k[SDLK_F10] = Keyboard::KEY_F10;
-	k[SDLK_F11] = Keyboard::KEY_F11;
-	k[SDLK_F12] = Keyboard::KEY_F12;
-
-	k[SDLK_PRINTSCREEN] = Keyboard::KEY_PRINTSCREEN;
-	k[SDLK_SCROLLLOCK] = Keyboard::KEY_SCROLLLOCK;
-	k[SDLK_PAUSE] = Keyboard::KEY_PAUSE;
-	k[SDLK_INSERT] = Keyboard::KEY_INSERT;
-	k[SDLK_HOME] = Keyboard::KEY_HOME;
-	k[SDLK_PAGEUP] = Keyboard::KEY_PAGEUP;
-	k[SDLK_DELETE] = Keyboard::KEY_DELETE;
-	k[SDLK_END] = Keyboard::KEY_END;
-	k[SDLK_PAGEDOWN] = Keyboard::KEY_PAGEDOWN;
-	k[SDLK_RIGHT] = Keyboard::KEY_RIGHT;
-	k[SDLK_LEFT] = Keyboard::KEY_LEFT;
-	k[SDLK_DOWN] = Keyboard::KEY_DOWN;
-	k[SDLK_UP] = Keyboard::KEY_UP;
-
-	k[SDLK_NUMLOCKCLEAR] = Keyboard::KEY_NUMLOCKCLEAR;
-	k[SDLK_KP_DIVIDE] = Keyboard::KEY_KP_DIVIDE;
-	k[SDLK_KP_MULTIPLY] = Keyboard::KEY_KP_MULTIPLY;
-	k[SDLK_KP_MINUS] = Keyboard::KEY_KP_MINUS;
-	k[SDLK_KP_PLUS] = Keyboard::KEY_KP_PLUS;
-	k[SDLK_KP_ENTER] = Keyboard::KEY_KP_ENTER;
-	k[SDLK_KP_0] = Keyboard::KEY_KP_0;
-	k[SDLK_KP_1] = Keyboard::KEY_KP_1;
-	k[SDLK_KP_2] = Keyboard::KEY_KP_2;
-	k[SDLK_KP_3] = Keyboard::KEY_KP_3;
-	k[SDLK_KP_4] = Keyboard::KEY_KP_4;
-	k[SDLK_KP_5] = Keyboard::KEY_KP_5;
-	k[SDLK_KP_6] = Keyboard::KEY_KP_6;
-	k[SDLK_KP_7] = Keyboard::KEY_KP_7;
-	k[SDLK_KP_8] = Keyboard::KEY_KP_8;
-	k[SDLK_KP_9] = Keyboard::KEY_KP_9;
-	k[SDLK_KP_PERIOD] = Keyboard::KEY_KP_PERIOD;
-	k[SDLK_KP_COMMA] = Keyboard::KEY_KP_COMMA;
-	k[SDLK_KP_EQUALS] = Keyboard::KEY_KP_EQUALS;
-
-	k[SDLK_APPLICATION] = Keyboard::KEY_APPLICATION;
-	k[SDLK_POWER] = Keyboard::KEY_POWER;
-	k[SDLK_F13] = Keyboard::KEY_F13;
-	k[SDLK_F14] = Keyboard::KEY_F14;
-	k[SDLK_F15] = Keyboard::KEY_F15;
-	k[SDLK_F16] = Keyboard::KEY_F16;
-	k[SDLK_F17] = Keyboard::KEY_F17;
-	k[SDLK_F18] = Keyboard::KEY_F18;
-	k[SDLK_F19] = Keyboard::KEY_F19;
-	k[SDLK_F20] = Keyboard::KEY_F20;
-	k[SDLK_F21] = Keyboard::KEY_F21;
-	k[SDLK_F22] = Keyboard::KEY_F22;
-	k[SDLK_F23] = Keyboard::KEY_F23;
-	k[SDLK_F24] = Keyboard::KEY_F24;
-	k[SDLK_EXECUTE] = Keyboard::KEY_EXECUTE;
-	k[SDLK_HELP] = Keyboard::KEY_HELP;
-	k[SDLK_MENU] = Keyboard::KEY_MENU;
-	k[SDLK_SELECT] = Keyboard::KEY_SELECT;
-	k[SDLK_STOP] = Keyboard::KEY_STOP;
-	k[SDLK_AGAIN] = Keyboard::KEY_AGAIN;
-	k[SDLK_UNDO] = Keyboard::KEY_UNDO;
-	k[SDLK_CUT] = Keyboard::KEY_CUT;
-	k[SDLK_COPY] = Keyboard::KEY_COPY;
-	k[SDLK_PASTE] = Keyboard::KEY_PASTE;
-	k[SDLK_FIND] = Keyboard::KEY_FIND;
-	k[SDLK_MUTE] = Keyboard::KEY_MUTE;
-	k[SDLK_VOLUMEUP] = Keyboard::KEY_VOLUMEUP;
-	k[SDLK_VOLUMEDOWN] = Keyboard::KEY_VOLUMEDOWN;
-
-	k[SDLK_ALTERASE] = Keyboard::KEY_ALTERASE;
-	k[SDLK_SYSREQ] = Keyboard::KEY_SYSREQ;
-	k[SDLK_CANCEL] = Keyboard::KEY_CANCEL;
-	k[SDLK_CLEAR] = Keyboard::KEY_CLEAR;
-	k[SDLK_PRIOR] = Keyboard::KEY_PRIOR;
-	k[SDLK_RETURN2] = Keyboard::KEY_RETURN2;
-	k[SDLK_SEPARATOR] = Keyboard::KEY_SEPARATOR;
-	k[SDLK_OUT] = Keyboard::KEY_OUT;
-	k[SDLK_OPER] = Keyboard::KEY_OPER;
-	k[SDLK_CLEARAGAIN] = Keyboard::KEY_CLEARAGAIN;
-
-	k[SDLK_THOUSANDSSEPARATOR] = Keyboard::KEY_THOUSANDSSEPARATOR;
-	k[SDLK_DECIMALSEPARATOR] = Keyboard::KEY_DECIMALSEPARATOR;
-	k[SDLK_CURRENCYUNIT] = Keyboard::KEY_CURRENCYUNIT;
-	k[SDLK_CURRENCYSUBUNIT] = Keyboard::KEY_CURRENCYSUBUNIT;
-
-	k[SDLK_LCTRL] = Keyboard::KEY_LCTRL;
-	k[SDLK_LSHIFT] = Keyboard::KEY_LSHIFT;
-	k[SDLK_LALT] = Keyboard::KEY_LALT;
-	k[SDLK_LGUI] = Keyboard::KEY_LGUI;
-	k[SDLK_RCTRL] = Keyboard::KEY_RCTRL;
-	k[SDLK_RSHIFT] = Keyboard::KEY_RSHIFT;
-	k[SDLK_RALT] = Keyboard::KEY_RALT;
-	k[SDLK_RGUI] = Keyboard::KEY_RGUI;
-
-	k[SDLK_MODE] = Keyboard::KEY_MODE;
-
-	k[SDLK_AUDIONEXT] = Keyboard::KEY_AUDIONEXT;
-	k[SDLK_AUDIOPREV] = Keyboard::KEY_AUDIOPREV;
-	k[SDLK_AUDIOSTOP] = Keyboard::KEY_AUDIOSTOP;
-	k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY;
-	k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE;
-	k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT;
-	k[SDLK_WWW] = Keyboard::KEY_WWW;
-	k[SDLK_MAIL] = Keyboard::KEY_MAIL;
-	k[SDLK_CALCULATOR] = Keyboard::KEY_CALCULATOR;
-	k[SDLK_COMPUTER] = Keyboard::KEY_COMPUTER;
-	k[SDLK_AC_SEARCH] = Keyboard::KEY_APP_SEARCH;
-	k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME;
-	k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK;
-	k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD;
-	k[SDLK_AC_STOP] = Keyboard::KEY_APP_STOP;
-	k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH;
-	k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS;
-
-	k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN;
-	k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP;
-	k[SDLK_DISPLAYSWITCH] = Keyboard::KEY_DISPLAYSWITCH;
-	k[SDLK_KBDILLUMTOGGLE] = Keyboard::KEY_KBDILLUMTOGGLE;
-	k[SDLK_KBDILLUMDOWN] = Keyboard::KEY_KBDILLUMDOWN;
-	k[SDLK_KBDILLUMUP] = Keyboard::KEY_KBDILLUMUP;
-	k[SDLK_EJECT] = Keyboard::KEY_EJECT;
-	k[SDLK_SLEEP] = Keyboard::KEY_SLEEP;
-
-#ifdef LOVE_ANDROID
-	k[SDLK_AC_BACK] = Keyboard::KEY_ESCAPE;
-#endif
-
-	return k;
-}
-
-std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::keys = Event::createKeyMap();
-
 } // sdl
 } // event
 } // love

+ 0 - 6
src/modules/event/sdl/Event.h

@@ -28,9 +28,6 @@
 // SDL
 #include <SDL_events.h>
 
-// STL
-#include <map>
-
 namespace love
 {
 namespace event
@@ -72,9 +69,6 @@ private:
 	Message *convertJoystickEvent(const SDL_Event &e) const;
 	Message *convertWindowEvent(const SDL_Event &e);
 
-	static std::map<SDL_Keycode, love::keyboard::Keyboard::Key> createKeyMap();
-	static std::map<SDL_Keycode, love::keyboard::Keyboard::Key> keys;
-
 }; // Event
 
 } // sdl

+ 63 - 4
src/modules/keyboard/Keyboard.cpp

@@ -19,6 +19,7 @@
  **/
 
 #include "common/config.h"
+#include "libraries/utf8/utf8.h"
 
 #include "Keyboard.h"
 
@@ -34,12 +35,70 @@ Keyboard::Keyboard(const char *name)
 
 bool Keyboard::getConstant(const char *in, Key &out)
 {
-	return keys.find(in, out);
+	auto it = stringToKey.find(in);
+	if (it != stringToKey.end())
+	{
+		out = (Key)it->second;
+		return true;
+	}
+
+	std::string text(in);
+	uint32 codepoint = 0;
+
+	try
+	{
+		codepoint = utf8::peek_next(text.begin(), text.end());
+	}
+	catch (utf8::exception &)
+	{
+		return false;
+	}
+
+	if (codepoint > 0)
+	{
+		stringToKey[text] = codepoint;
+		out = (Key)codepoint;
+	}
+
+	return false;
 }
 
 bool Keyboard::getConstant(Key in, const char *&out)
 {
-	return keys.find(in, out);
+	if (keyToString.empty())
+	{
+		for (const auto &kvp : stringToKey)
+			keyToString[kvp.second] = kvp.first;
+	}
+
+	auto it = keyToString.find(in);
+	if (it != keyToString.end())
+	{
+		out = it->second.c_str();
+		return true;
+	}
+
+	char u[5] = { 0, 0, 0, 0, 0 };
+	ptrdiff_t length = 0;
+
+	try
+	{
+		char *end = utf8::unchecked::append(in, u);
+		length = end - u;
+	}
+	catch (utf8::exception &)
+	{
+		return false;
+	}
+
+	if (length > 0)
+	{
+		keyToString[in] = std::string(u, length);
+		out = keyToString[in].c_str();
+		return true;
+	}
+
+	return false;
 }
 
 bool Keyboard::getConstant(const char *in, Scancode &out)
@@ -62,7 +121,7 @@ bool Keyboard::getConstant(ModifierKey in, const char *&out)
 	return modifiers.find(in, out);
 }
 
-StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
+std::map<std::string, uint32> Keyboard::stringToKey =
 {
 	{"unknown", Keyboard::KEY_UNKNOWN},
 
@@ -270,7 +329,7 @@ StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
 	{"sleep", Keyboard::KEY_SLEEP},
 };
 
-StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM> Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries));
+std::map<uint32, std::string> Keyboard::keyToString;
 
 StringMap<Keyboard::Scancode, Keyboard::SCANCODE_MAX_ENUM>::Entry Keyboard::scancodeEntries[] =
 {

+ 225 - 218
src/modules/keyboard/Keyboard.h

@@ -27,6 +27,7 @@
 
 // C++
 #include <vector>
+#include <map>
 
 namespace love
 {
@@ -37,219 +38,6 @@ class Keyboard : public Module
 {
 public:
 
-	/**
-	 * Keyboard keys. They are dependent on the current layout of the keyboard.
-	 **/
-	enum Key
-	{
-		KEY_UNKNOWN,
-
-		KEY_RETURN,
-		KEY_ESCAPE,
-		KEY_BACKSPACE,
-		KEY_TAB,
-		KEY_SPACE,
-		KEY_EXCLAIM,
-		KEY_QUOTEDBL,
-		KEY_HASH,
-		KEY_PERCENT,
-		KEY_DOLLAR,
-		KEY_AMPERSAND,
-		KEY_QUOTE,
-		KEY_LEFTPAREN,
-		KEY_RIGHTPAREN,
-		KEY_ASTERISK,
-		KEY_PLUS,
-		KEY_COMMA,
-		KEY_MINUS,
-		KEY_PERIOD,
-		KEY_SLASH,
-		KEY_0,
-		KEY_1,
-		KEY_2,
-		KEY_3,
-		KEY_4,
-		KEY_5,
-		KEY_6,
-		KEY_7,
-		KEY_8,
-		KEY_9,
-		KEY_COLON,
-		KEY_SEMICOLON,
-		KEY_LESS,
-		KEY_EQUALS,
-		KEY_GREATER,
-		KEY_QUESTION,
-		KEY_AT,
-
-		KEY_LEFTBRACKET,
-		KEY_BACKSLASH,
-		KEY_RIGHTBRACKET,
-		KEY_CARET,
-		KEY_UNDERSCORE,
-		KEY_BACKQUOTE,
-		KEY_A,
-		KEY_B,
-		KEY_C,
-		KEY_D,
-		KEY_E,
-		KEY_F,
-		KEY_G,
-		KEY_H,
-		KEY_I,
-		KEY_J,
-		KEY_K,
-		KEY_L,
-		KEY_M,
-		KEY_N,
-		KEY_O,
-		KEY_P,
-		KEY_Q,
-		KEY_R,
-		KEY_S,
-		KEY_T,
-		KEY_U,
-		KEY_V,
-		KEY_W,
-		KEY_X,
-		KEY_Y,
-		KEY_Z,
-
-		KEY_CAPSLOCK,
-
-		KEY_F1,
-		KEY_F2,
-		KEY_F3,
-		KEY_F4,
-		KEY_F5,
-		KEY_F6,
-		KEY_F7,
-		KEY_F8,
-		KEY_F9,
-		KEY_F10,
-		KEY_F11,
-		KEY_F12,
-
-		KEY_PRINTSCREEN,
-		KEY_SCROLLLOCK,
-		KEY_PAUSE,
-		KEY_INSERT,
-		KEY_HOME,
-		KEY_PAGEUP,
-		KEY_DELETE,
-		KEY_END,
-		KEY_PAGEDOWN,
-		KEY_RIGHT,
-		KEY_LEFT,
-		KEY_DOWN,
-		KEY_UP,
-
-		KEY_NUMLOCKCLEAR,
-		KEY_KP_DIVIDE,
-		KEY_KP_MULTIPLY,
-		KEY_KP_MINUS,
-		KEY_KP_PLUS,
-		KEY_KP_ENTER,
-		KEY_KP_1,
-		KEY_KP_2,
-		KEY_KP_3,
-		KEY_KP_4,
-		KEY_KP_5,
-		KEY_KP_6,
-		KEY_KP_7,
-		KEY_KP_8,
-		KEY_KP_9,
-		KEY_KP_0,
-		KEY_KP_PERIOD,
-		KEY_KP_COMMA,
-		KEY_KP_EQUALS,
-
-		KEY_APPLICATION,
-		KEY_POWER,
-		KEY_F13,
-		KEY_F14,
-		KEY_F15,
-		KEY_F16,
-		KEY_F17,
-		KEY_F18,
-		KEY_F19,
-		KEY_F20,
-		KEY_F21,
-		KEY_F22,
-		KEY_F23,
-		KEY_F24,
-		KEY_EXECUTE,
-		KEY_HELP,
-		KEY_MENU,
-		KEY_SELECT,
-		KEY_STOP,
-		KEY_AGAIN,
-		KEY_UNDO,
-		KEY_CUT,
-		KEY_COPY,
-		KEY_PASTE,
-		KEY_FIND,
-		KEY_MUTE,
-		KEY_VOLUMEUP,
-		KEY_VOLUMEDOWN,
-
-		KEY_ALTERASE,
-		KEY_SYSREQ,
-		KEY_CANCEL,
-		KEY_CLEAR,
-		KEY_PRIOR,
-		KEY_RETURN2,
-		KEY_SEPARATOR,
-		KEY_OUT,
-		KEY_OPER,
-		KEY_CLEARAGAIN,
-
-		KEY_THOUSANDSSEPARATOR,
-		KEY_DECIMALSEPARATOR,
-		KEY_CURRENCYUNIT,
-		KEY_CURRENCYSUBUNIT,
-
-		KEY_LCTRL,
-		KEY_LSHIFT,
-		KEY_LALT,
-		KEY_LGUI,
-		KEY_RCTRL,
-		KEY_RSHIFT,
-		KEY_RALT,
-		KEY_RGUI,
-
-		KEY_MODE,
-
-		KEY_AUDIONEXT,
-		KEY_AUDIOPREV,
-		KEY_AUDIOSTOP,
-		KEY_AUDIOPLAY,
-		KEY_AUDIOMUTE,
-		KEY_MEDIASELECT,
-		KEY_WWW,
-		KEY_MAIL,
-		KEY_CALCULATOR,
-		KEY_COMPUTER,
-		KEY_APP_SEARCH,
-		KEY_APP_HOME,
-		KEY_APP_BACK,
-		KEY_APP_FORWARD,
-		KEY_APP_STOP,
-		KEY_APP_REFRESH,
-		KEY_APP_BOOKMARKS,
-
-		KEY_BRIGHTNESSDOWN,
-		KEY_BRIGHTNESSUP,
-		KEY_DISPLAYSWITCH,
-		KEY_KBDILLUMTOGGLE,
-		KEY_KBDILLUMDOWN,
-		KEY_KBDILLUMUP,
-		KEY_EJECT,
-		KEY_SLEEP,
-
-		KEY_MAX_ENUM
-	};
-
 	/**
 	 * Scancodes represent physical keys independent of the current layout.
 	 * Their names may not match the names of the keys printed on the keyboard.
@@ -520,17 +308,236 @@ public:
 	};
 
 	/**
-	 * Modifier keys. These are special keys that temporarily modifies the normal function of a button when active.
+	 * Modifier keys. These are special keys that temporarily modify the normal function of a button when active.
 	 **/
-	enum ModifierKey {
+	enum ModifierKey
+	{
 		MODKEY_NUMLOCK,
 		MODKEY_CAPSLOCK,
 		MODKEY_SCROLLLOCK,
 		MODKEY_MODE,
-
 		MODKEY_MAX_ENUM
 	};
 
+	static constexpr uint32 KEY_SCANCODE_MASK = 1u << 30;
+
+	#define LOVE_KEY(scancode) (scancode | KEY_SCANCODE_MASK)
+
+	/**
+	 * Keyboard keys. They are dependent on the current layout of the keyboard.
+	 * This is not a full list of all keys - any unicode character can be a key,
+	 * which is why the ASCII keys in this list use their ASCII value directly.
+	 **/
+	enum Key
+	{
+		KEY_UNKNOWN = 0,
+
+		KEY_RETURN = '\r',
+		KEY_ESCAPE = '\x1B',
+		KEY_BACKSPACE = '\b',
+		KEY_TAB = '\t',
+		KEY_SPACE = ' ',
+		KEY_EXCLAIM = '!',
+		KEY_QUOTEDBL = '"',
+		KEY_HASH = '#',
+		KEY_PERCENT = '%',
+		KEY_DOLLAR = '$',
+		KEY_AMPERSAND = '&',
+		KEY_QUOTE = '\'',
+		KEY_LEFTPAREN = '(',
+		KEY_RIGHTPAREN = ')',
+		KEY_ASTERISK = '*',
+		KEY_PLUS = '+',
+		KEY_COMMA = ',',
+		KEY_MINUS = '-',
+		KEY_PERIOD = '.',
+		KEY_SLASH = '/',
+		KEY_0 = '0',
+		KEY_1 = '1',
+		KEY_2 = '2',
+		KEY_3 = '3',
+		KEY_4 = '4',
+		KEY_5 = '5',
+		KEY_6 = '6',
+		KEY_7 = '7',
+		KEY_8 = '8',
+		KEY_9 = '9',
+		KEY_COLON = ':',
+		KEY_SEMICOLON = ';',
+		KEY_LESS = '<',
+		KEY_EQUALS = '=',
+		KEY_GREATER = '>',
+		KEY_QUESTION = '?',
+		KEY_AT = '@',
+
+		KEY_LEFTBRACKET = '[',
+		KEY_BACKSLASH = '\\',
+		KEY_RIGHTBRACKET = ']',
+		KEY_CARET = '^',
+		KEY_UNDERSCORE = '_',
+		KEY_BACKQUOTE = '`',
+		KEY_A = 'a',
+		KEY_B = 'b',
+		KEY_C = 'c',
+		KEY_D = 'd',
+		KEY_E = 'e',
+		KEY_F = 'f',
+		KEY_G = 'g',
+		KEY_H = 'h',
+		KEY_I = 'i',
+		KEY_J = 'j',
+		KEY_K = 'k',
+		KEY_L = 'l',
+		KEY_M = 'm',
+		KEY_N = 'n',
+		KEY_O = 'o',
+		KEY_P = 'p',
+		KEY_Q = 'q',
+		KEY_R = 'r',
+		KEY_S = 's',
+		KEY_T = 't',
+		KEY_U = 'u',
+		KEY_V = 'v',
+		KEY_W = 'w',
+		KEY_X = 'x',
+		KEY_Y = 'y',
+		KEY_Z = 'z',
+
+		KEY_CAPSLOCK = LOVE_KEY(SCANCODE_CAPSLOCK),
+
+		KEY_F1 = LOVE_KEY(SCANCODE_F1),
+		KEY_F2 = LOVE_KEY(SCANCODE_F2),
+		KEY_F3 = LOVE_KEY(SCANCODE_F3),
+		KEY_F4 = LOVE_KEY(SCANCODE_F4),
+		KEY_F5 = LOVE_KEY(SCANCODE_F5),
+		KEY_F6 = LOVE_KEY(SCANCODE_F6),
+		KEY_F7 = LOVE_KEY(SCANCODE_F7),
+		KEY_F8 = LOVE_KEY(SCANCODE_F8),
+		KEY_F9 = LOVE_KEY(SCANCODE_F9),
+		KEY_F10 = LOVE_KEY(SCANCODE_F10),
+		KEY_F11 = LOVE_KEY(SCANCODE_F11),
+		KEY_F12 = LOVE_KEY(SCANCODE_F12),
+
+		KEY_PRINTSCREEN = LOVE_KEY(SCANCODE_PRINTSCREEN),
+		KEY_SCROLLLOCK = LOVE_KEY(SCANCODE_SCROLLLOCK),
+		KEY_PAUSE = LOVE_KEY(SCANCODE_PAUSE),
+		KEY_INSERT = LOVE_KEY(SCANCODE_INSERT),
+		KEY_HOME = LOVE_KEY(SCANCODE_HOME),
+		KEY_PAGEUP = LOVE_KEY(SCANCODE_PAGEUP),
+		KEY_DELETE = LOVE_KEY(SCANCODE_DELETE),
+		KEY_END = LOVE_KEY(SCANCODE_END),
+		KEY_PAGEDOWN = LOVE_KEY(SCANCODE_PAGEDOWN),
+		KEY_RIGHT = LOVE_KEY(SCANCODE_RIGHT),
+		KEY_LEFT = LOVE_KEY(SCANCODE_LEFT),
+		KEY_DOWN = LOVE_KEY(SCANCODE_DOWN),
+		KEY_UP = LOVE_KEY(SCANCODE_UP),
+
+		KEY_NUMLOCKCLEAR = LOVE_KEY(SCANCODE_NUMLOCKCLEAR),
+		KEY_KP_DIVIDE = LOVE_KEY(SCANCODE_KP_DIVIDE),
+		KEY_KP_MULTIPLY = LOVE_KEY(SCANCODE_KP_MULTIPLY),
+		KEY_KP_MINUS = LOVE_KEY(SCANCODE_KP_MINUS),
+		KEY_KP_PLUS = LOVE_KEY(SCANCODE_KP_PLUS),
+		KEY_KP_ENTER = LOVE_KEY(SCANCODE_KP_ENTER),
+		KEY_KP_1 = LOVE_KEY(SCANCODE_KP_1),
+		KEY_KP_2 = LOVE_KEY(SCANCODE_KP_2),
+		KEY_KP_3 = LOVE_KEY(SCANCODE_KP_3),
+		KEY_KP_4 = LOVE_KEY(SCANCODE_KP_4),
+		KEY_KP_5 = LOVE_KEY(SCANCODE_KP_5),
+		KEY_KP_6 = LOVE_KEY(SCANCODE_KP_6),
+		KEY_KP_7 = LOVE_KEY(SCANCODE_KP_7),
+		KEY_KP_8 = LOVE_KEY(SCANCODE_KP_8),
+		KEY_KP_9 = LOVE_KEY(SCANCODE_KP_9),
+		KEY_KP_0 = LOVE_KEY(SCANCODE_KP_0),
+		KEY_KP_PERIOD = LOVE_KEY(SCANCODE_KP_PERIOD),
+		KEY_KP_COMMA = LOVE_KEY(SCANCODE_KP_COMMA),
+		KEY_KP_EQUALS = LOVE_KEY(SCANCODE_KP_EQUALS),
+
+		KEY_APPLICATION = LOVE_KEY(SCANCODE_APPLICATION),
+		KEY_POWER = LOVE_KEY(SCANCODE_POWER),
+		KEY_F13 = LOVE_KEY(SCANCODE_F13),
+		KEY_F14 = LOVE_KEY(SCANCODE_F14),
+		KEY_F15 = LOVE_KEY(SCANCODE_F15),
+		KEY_F16 = LOVE_KEY(SCANCODE_F16),
+		KEY_F17 = LOVE_KEY(SCANCODE_F17),
+		KEY_F18 = LOVE_KEY(SCANCODE_F18),
+		KEY_F19 = LOVE_KEY(SCANCODE_F19),
+		KEY_F20 = LOVE_KEY(SCANCODE_F20),
+		KEY_F21 = LOVE_KEY(SCANCODE_F21),
+		KEY_F22 = LOVE_KEY(SCANCODE_F22),
+		KEY_F23 = LOVE_KEY(SCANCODE_F23),
+		KEY_F24 = LOVE_KEY(SCANCODE_F24),
+		KEY_EXECUTE = LOVE_KEY(SCANCODE_EXECUTE),
+		KEY_HELP = LOVE_KEY(SCANCODE_HELP),
+		KEY_MENU = LOVE_KEY(SCANCODE_MENU),
+		KEY_SELECT = LOVE_KEY(SCANCODE_SELECT),
+		KEY_STOP = LOVE_KEY(SCANCODE_STOP),
+		KEY_AGAIN = LOVE_KEY(SCANCODE_AGAIN),
+		KEY_UNDO = LOVE_KEY(SCANCODE_UNDO),
+		KEY_CUT = LOVE_KEY(SCANCODE_CUT),
+		KEY_COPY = LOVE_KEY(SCANCODE_COPY),
+		KEY_PASTE = LOVE_KEY(SCANCODE_PASTE),
+		KEY_FIND = LOVE_KEY(SCANCODE_FIND),
+		KEY_MUTE = LOVE_KEY(SCANCODE_MUTE),
+		KEY_VOLUMEUP = LOVE_KEY(SCANCODE_VOLUMEUP),
+		KEY_VOLUMEDOWN = LOVE_KEY(SCANCODE_VOLUMEDOWN),
+
+		KEY_ALTERASE = LOVE_KEY(SCANCODE_ALTERASE),
+		KEY_SYSREQ = LOVE_KEY(SCANCODE_SYSREQ),
+		KEY_CANCEL = LOVE_KEY(SCANCODE_CANCEL),
+		KEY_CLEAR = LOVE_KEY(SCANCODE_CLEAR),
+		KEY_PRIOR = LOVE_KEY(SCANCODE_PRIOR),
+		KEY_RETURN2 = LOVE_KEY(SCANCODE_RETURN2),
+		KEY_SEPARATOR = LOVE_KEY(SCANCODE_SEPARATOR),
+		KEY_OUT = LOVE_KEY(SCANCODE_OUT),
+		KEY_OPER = LOVE_KEY(SCANCODE_OPER),
+		KEY_CLEARAGAIN = LOVE_KEY(SCANCODE_CLEARAGAIN),
+
+		KEY_THOUSANDSSEPARATOR = LOVE_KEY(SCANCODE_THOUSANDSSEPARATOR),
+		KEY_DECIMALSEPARATOR = LOVE_KEY(SCANCODE_DECIMALSEPARATOR),
+		KEY_CURRENCYUNIT = LOVE_KEY(SCANCODE_CURRENCYUNIT),
+		KEY_CURRENCYSUBUNIT = LOVE_KEY(SCANCODE_CURRENCYSUBUNIT),
+
+		KEY_LCTRL = LOVE_KEY(SCANCODE_LCTRL),
+		KEY_LSHIFT = LOVE_KEY(SCANCODE_LSHIFT),
+		KEY_LALT = LOVE_KEY(SCANCODE_LALT),
+		KEY_LGUI = LOVE_KEY(SCANCODE_LGUI),
+		KEY_RCTRL = LOVE_KEY(SCANCODE_RCTRL),
+		KEY_RSHIFT = LOVE_KEY(SCANCODE_RSHIFT),
+		KEY_RALT = LOVE_KEY(SCANCODE_RALT),
+		KEY_RGUI = LOVE_KEY(SCANCODE_RGUI),
+
+		KEY_MODE = LOVE_KEY(SCANCODE_MODE),
+
+		KEY_AUDIONEXT = LOVE_KEY(SCANCODE_AUDIONEXT),
+		KEY_AUDIOPREV = LOVE_KEY(SCANCODE_AUDIOPREV),
+		KEY_AUDIOSTOP = LOVE_KEY(SCANCODE_AUDIOSTOP),
+		KEY_AUDIOPLAY = LOVE_KEY(SCANCODE_AUDIOPLAY),
+		KEY_AUDIOMUTE = LOVE_KEY(SCANCODE_AUDIOMUTE),
+		KEY_MEDIASELECT = LOVE_KEY(SCANCODE_MEDIASELECT),
+		KEY_WWW = LOVE_KEY(SCANCODE_WWW),
+		KEY_MAIL = LOVE_KEY(SCANCODE_MAIL),
+		KEY_CALCULATOR = LOVE_KEY(SCANCODE_CALCULATOR),
+		KEY_COMPUTER = LOVE_KEY(SCANCODE_COMPUTER),
+		KEY_APP_SEARCH = LOVE_KEY(SCANCODE_AC_SEARCH),
+		KEY_APP_HOME = LOVE_KEY(SCANCODE_AC_HOME),
+		KEY_APP_BACK = LOVE_KEY(SCANCODE_AC_BACK),
+		KEY_APP_FORWARD = LOVE_KEY(SCANCODE_AC_FORWARD),
+		KEY_APP_STOP = LOVE_KEY(SCANCODE_AC_STOP),
+		KEY_APP_REFRESH = LOVE_KEY(SCANCODE_AC_REFRESH),
+		KEY_APP_BOOKMARKS = LOVE_KEY(SCANCODE_AC_BOOKMARKS),
+
+		KEY_BRIGHTNESSDOWN = LOVE_KEY(SCANCODE_BRIGHTNESSDOWN),
+		KEY_BRIGHTNESSUP = LOVE_KEY(SCANCODE_BRIGHTNESSUP),
+		KEY_DISPLAYSWITCH = LOVE_KEY(SCANCODE_DISPLAYSWITCH),
+		KEY_KBDILLUMTOGGLE = LOVE_KEY(SCANCODE_KBDILLUMTOGGLE),
+		KEY_KBDILLUMDOWN = LOVE_KEY(SCANCODE_KBDILLUMDOWN),
+		KEY_KBDILLUMUP = LOVE_KEY(SCANCODE_KBDILLUMUP),
+		KEY_EJECT = LOVE_KEY(SCANCODE_EJECT),
+		KEY_SLEEP = LOVE_KEY(SCANCODE_SLEEP),
+	};
+
+	#undef LOVE_KEY
+
 	virtual ~Keyboard() {}
 
 	/**
@@ -617,8 +624,8 @@ protected:
 
 private:
 
-	static StringMap<Key, KEY_MAX_ENUM>::Entry keyEntries[];
-	static StringMap<Key, KEY_MAX_ENUM> keys;
+	static std::map<uint32, std::string> keyToString;
+	static std::map<std::string, uint32> stringToKey;
 
 	static StringMap<Scancode, SCANCODE_MAX_ENUM>::Entry scancodeEntries[];
 	static StringMap<Scancode, SCANCODE_MAX_ENUM> scancodes;

+ 211 - 226
src/modules/keyboard/sdl/Keyboard.cpp

@@ -22,6 +22,7 @@
 
 #include "Keyboard.h"
 #include "window/Window.h"
+#include "common/config.h"
 
 // SDL before 2.0.18 lack KMOD_SCROLL. Use KMOD_RESERVED instead.
 #if !SDL_VERSION_ATLEAST(2, 0, 18)
@@ -57,10 +58,13 @@ bool Keyboard::isDown(const std::vector<Key> &keylist) const
 
 	for (Key key : keylist)
 	{
-		SDL_Scancode scancode = SDL_GetScancodeFromKey(keymap[key]);
-
-		if (state[scancode])
-			return true;
+		SDL_Keycode sdlkey = SDLK_UNKNOWN;
+		if (getConstant(key, sdlkey))
+		{
+			SDL_Scancode scancode = SDL_GetScancodeFromKey(sdlkey);
+			if (state[scancode])
+				return true;
+		}
 	}
 
 	return false;
@@ -120,23 +124,18 @@ Keyboard::Key Keyboard::getKeyFromScancode(Scancode scancode) const
 
 	SDL_Keycode sdlkey = SDL_GetKeyFromScancode(sdlscancode);
 
-	for (int i = 0; i < KEY_MAX_ENUM; i++)
-	{
-		if (keymap[i] == sdlkey)
-			return (Key) i;
-	}
-
-	return KEY_UNKNOWN;
+	Key key = KEY_UNKNOWN;
+	getConstant(sdlkey, key);
+	return key;
 }
 
 Keyboard::Scancode Keyboard::getScancodeFromKey(Key key) const
 {
 	Scancode scancode = SCANCODE_UNKNOWN;
 
-	if (key != KEY_MAX_ENUM)
+	SDL_Keycode sdlkey = SDLK_UNKNOWN;
+	if (getConstant(key, sdlkey))
 	{
-		SDL_Keycode sdlkey = keymap[key];
-
 		SDL_Scancode sdlscancode = SDL_GetScancodeFromKey(sdlkey);
 		scancodes.find(sdlscancode, scancode);
 	}
@@ -183,6 +182,65 @@ bool Keyboard::hasScreenKeyboard() const
 	return SDL_HasScreenKeyboardSupport() != SDL_FALSE;
 }
 
+bool Keyboard::getConstant(Key in, SDL_Keycode &out)
+{
+	if (in & KEY_SCANCODE_MASK)
+	{
+		auto it = keyToSDLKey.find(in);
+		if (it != keyToSDLKey.end())
+		{
+			out = it->second;
+			return true;
+		}
+	}
+	else
+	{
+		// All other keys use the same value as their ASCII character
+		// representation in SDL and in love.
+		out = (SDL_Keycode)in;
+		return true;
+	}
+
+	return false;
+}
+
+bool Keyboard::getConstant(SDL_Keycode in, Key &out)
+{
+#ifdef LOVE_ANDROID
+	// TODO: Can this be done more cleanly?
+	if (in == SDLK_AC_BACK)
+	{
+		out = KEY_ESCAPE;
+		return true;
+	}
+#endif
+
+	if (in & SDLK_SCANCODE_MASK)
+	{
+		if (sdlKeyToKey.empty())
+		{
+			for (const auto& kvp : keyToSDLKey)
+				sdlKeyToKey[kvp.second] = kvp.first;
+		}
+
+		auto it = sdlKeyToKey.find(in);
+		if (it != sdlKeyToKey.end())
+		{
+			out = it->second;
+			return true;
+		}
+	}
+	else
+	{
+		// All other keys use the same value as their ASCII character
+		// representation in SDL and in love.
+		out = (Key)in;
+		return true;
+	}
+
+	return false;
+}
+
 bool Keyboard::getConstant(Scancode in, SDL_Scancode &out)
 {
 	return scancodes.find(in, out);
@@ -193,220 +251,147 @@ bool Keyboard::getConstant(SDL_Scancode in, Scancode &out)
 	return scancodes.find(in, out);
 }
 
-const SDL_Keycode *Keyboard::createKeyMap()
+std::map<Keyboard::Key, SDL_Keycode> Keyboard::keyToSDLKey =
 {
-	// Array must be static so its lifetime continues once the function returns.
-	static SDL_Keycode k[Keyboard::KEY_MAX_ENUM] = {SDLK_UNKNOWN};
-
-	k[Keyboard::KEY_UNKNOWN] = SDLK_UNKNOWN;
-
-	k[Keyboard::KEY_RETURN] = SDLK_RETURN;
-	k[Keyboard::KEY_ESCAPE] = SDLK_ESCAPE;
-	k[Keyboard::KEY_BACKSPACE] = SDLK_BACKSPACE;
-	k[Keyboard::KEY_TAB] = SDLK_TAB;
-	k[Keyboard::KEY_SPACE] = SDLK_SPACE;
-	k[Keyboard::KEY_EXCLAIM] = SDLK_EXCLAIM;
-	k[Keyboard::KEY_QUOTEDBL] = SDLK_QUOTEDBL;
-	k[Keyboard::KEY_HASH] = SDLK_HASH;
-	k[Keyboard::KEY_PERCENT] = SDLK_PERCENT;
-	k[Keyboard::KEY_DOLLAR] = SDLK_DOLLAR;
-	k[Keyboard::KEY_AMPERSAND] = SDLK_AMPERSAND;
-	k[Keyboard::KEY_QUOTE] = SDLK_QUOTE;
-	k[Keyboard::KEY_LEFTPAREN] = SDLK_LEFTPAREN;
-	k[Keyboard::KEY_RIGHTPAREN] = SDLK_RIGHTPAREN;
-	k[Keyboard::KEY_ASTERISK] = SDLK_ASTERISK;
-	k[Keyboard::KEY_PLUS] = SDLK_PLUS;
-	k[Keyboard::KEY_COMMA] = SDLK_COMMA;
-	k[Keyboard::KEY_MINUS] = SDLK_MINUS;
-	k[Keyboard::KEY_PERIOD] = SDLK_PERIOD;
-	k[Keyboard::KEY_SLASH] = SDLK_SLASH;
-	k[Keyboard::KEY_0] = SDLK_0;
-	k[Keyboard::KEY_1] = SDLK_1;
-	k[Keyboard::KEY_2] = SDLK_2;
-	k[Keyboard::KEY_3] = SDLK_3;
-	k[Keyboard::KEY_4] = SDLK_4;
-	k[Keyboard::KEY_5] = SDLK_5;
-	k[Keyboard::KEY_6] = SDLK_6;
-	k[Keyboard::KEY_7] = SDLK_7;
-	k[Keyboard::KEY_8] = SDLK_8;
-	k[Keyboard::KEY_9] = SDLK_9;
-	k[Keyboard::KEY_COLON] = SDLK_COLON;
-	k[Keyboard::KEY_SEMICOLON] = SDLK_SEMICOLON;
-	k[Keyboard::KEY_LESS] = SDLK_LESS;
-	k[Keyboard::KEY_EQUALS] = SDLK_EQUALS;
-	k[Keyboard::KEY_GREATER] = SDLK_GREATER;
-	k[Keyboard::KEY_QUESTION] = SDLK_QUESTION;
-	k[Keyboard::KEY_AT] = SDLK_AT;
-
-	k[Keyboard::KEY_LEFTBRACKET] = SDLK_LEFTBRACKET;
-	k[Keyboard::KEY_BACKSLASH] = SDLK_BACKSLASH;
-	k[Keyboard::KEY_RIGHTBRACKET] = SDLK_RIGHTBRACKET;
-	k[Keyboard::KEY_CARET] = SDLK_CARET;
-	k[Keyboard::KEY_UNDERSCORE] = SDLK_UNDERSCORE;
-	k[Keyboard::KEY_BACKQUOTE] = SDLK_BACKQUOTE;
-	k[Keyboard::KEY_A] = SDLK_a;
-	k[Keyboard::KEY_B] = SDLK_b;
-	k[Keyboard::KEY_C] = SDLK_c;
-	k[Keyboard::KEY_D] = SDLK_d;
-	k[Keyboard::KEY_E] = SDLK_e;
-	k[Keyboard::KEY_F] = SDLK_f;
-	k[Keyboard::KEY_G] = SDLK_g;
-	k[Keyboard::KEY_H] = SDLK_h;
-	k[Keyboard::KEY_I] = SDLK_i;
-	k[Keyboard::KEY_J] = SDLK_j;
-	k[Keyboard::KEY_K] = SDLK_k;
-	k[Keyboard::KEY_L] = SDLK_l;
-	k[Keyboard::KEY_M] = SDLK_m;
-	k[Keyboard::KEY_N] = SDLK_n;
-	k[Keyboard::KEY_O] = SDLK_o;
-	k[Keyboard::KEY_P] = SDLK_p;
-	k[Keyboard::KEY_Q] = SDLK_q;
-	k[Keyboard::KEY_R] = SDLK_r;
-	k[Keyboard::KEY_S] = SDLK_s;
-	k[Keyboard::KEY_T] = SDLK_t;
-	k[Keyboard::KEY_U] = SDLK_u;
-	k[Keyboard::KEY_V] = SDLK_v;
-	k[Keyboard::KEY_W] = SDLK_w;
-	k[Keyboard::KEY_X] = SDLK_x;
-	k[Keyboard::KEY_Y] = SDLK_y;
-	k[Keyboard::KEY_Z] = SDLK_z;
-
-	k[Keyboard::KEY_CAPSLOCK] = SDLK_CAPSLOCK;
-
-	k[Keyboard::KEY_F1] = SDLK_F1;
-	k[Keyboard::KEY_F2] = SDLK_F2;
-	k[Keyboard::KEY_F3] = SDLK_F3;
-	k[Keyboard::KEY_F4] = SDLK_F4;
-	k[Keyboard::KEY_F5] = SDLK_F5;
-	k[Keyboard::KEY_F6] = SDLK_F6;
-	k[Keyboard::KEY_F7] = SDLK_F7;
-	k[Keyboard::KEY_F8] = SDLK_F8;
-	k[Keyboard::KEY_F9] = SDLK_F9;
-	k[Keyboard::KEY_F10] = SDLK_F10;
-	k[Keyboard::KEY_F11] = SDLK_F11;
-	k[Keyboard::KEY_F12] = SDLK_F12;
-
-	k[Keyboard::KEY_PRINTSCREEN] = SDLK_PRINTSCREEN;
-	k[Keyboard::KEY_SCROLLLOCK] = SDLK_SCROLLLOCK;
-	k[Keyboard::KEY_PAUSE] = SDLK_PAUSE;
-	k[Keyboard::KEY_INSERT] = SDLK_INSERT;
-	k[Keyboard::KEY_HOME] = SDLK_HOME;
-	k[Keyboard::KEY_PAGEUP] = SDLK_PAGEUP;
-	k[Keyboard::KEY_DELETE] = SDLK_DELETE;
-	k[Keyboard::KEY_END] = SDLK_END;
-	k[Keyboard::KEY_PAGEDOWN] = SDLK_PAGEDOWN;
-	k[Keyboard::KEY_RIGHT] = SDLK_RIGHT;
-	k[Keyboard::KEY_LEFT] = SDLK_LEFT;
-	k[Keyboard::KEY_DOWN] = SDLK_DOWN;
-	k[Keyboard::KEY_UP] = SDLK_UP;
-
-	k[Keyboard::KEY_NUMLOCKCLEAR] = SDLK_NUMLOCKCLEAR;
-	k[Keyboard::KEY_KP_DIVIDE] = SDLK_KP_DIVIDE;
-	k[Keyboard::KEY_KP_MULTIPLY] = SDLK_KP_MULTIPLY;
-	k[Keyboard::KEY_KP_MINUS] = SDLK_KP_MINUS;
-	k[Keyboard::KEY_KP_PLUS] = SDLK_KP_PLUS;
-	k[Keyboard::KEY_KP_ENTER] = SDLK_KP_ENTER;
-	k[Keyboard::KEY_KP_0] = SDLK_KP_0;
-	k[Keyboard::KEY_KP_1] = SDLK_KP_1;
-	k[Keyboard::KEY_KP_2] = SDLK_KP_2;
-	k[Keyboard::KEY_KP_3] = SDLK_KP_3;
-	k[Keyboard::KEY_KP_4] = SDLK_KP_4;
-	k[Keyboard::KEY_KP_5] = SDLK_KP_5;
-	k[Keyboard::KEY_KP_6] = SDLK_KP_6;
-	k[Keyboard::KEY_KP_7] = SDLK_KP_7;
-	k[Keyboard::KEY_KP_8] = SDLK_KP_8;
-	k[Keyboard::KEY_KP_9] = SDLK_KP_9;
-	k[Keyboard::KEY_KP_PERIOD] = SDLK_KP_PERIOD;
-	k[Keyboard::KEY_KP_COMMA] = SDLK_KP_COMMA;
-	k[Keyboard::KEY_KP_EQUALS] = SDLK_KP_EQUALS;
-
-	k[Keyboard::KEY_APPLICATION] = SDLK_APPLICATION;
-	k[Keyboard::KEY_POWER] = SDLK_POWER;
-	k[Keyboard::KEY_F13] = SDLK_F13;
-	k[Keyboard::KEY_F14] = SDLK_F14;
-	k[Keyboard::KEY_F15] = SDLK_F15;
-	k[Keyboard::KEY_F16] = SDLK_F16;
-	k[Keyboard::KEY_F17] = SDLK_F17;
-	k[Keyboard::KEY_F18] = SDLK_F18;
-	k[Keyboard::KEY_F19] = SDLK_F19;
-	k[Keyboard::KEY_F20] = SDLK_F20;
-	k[Keyboard::KEY_F21] = SDLK_F21;
-	k[Keyboard::KEY_F22] = SDLK_F22;
-	k[Keyboard::KEY_F23] = SDLK_F23;
-	k[Keyboard::KEY_F24] = SDLK_F24;
-	k[Keyboard::KEY_EXECUTE] = SDLK_EXECUTE;
-	k[Keyboard::KEY_HELP] = SDLK_HELP;
-	k[Keyboard::KEY_MENU] = SDLK_MENU;
-	k[Keyboard::KEY_SELECT] = SDLK_SELECT;
-	k[Keyboard::KEY_STOP] = SDLK_STOP;
-	k[Keyboard::KEY_AGAIN] = SDLK_AGAIN;
-	k[Keyboard::KEY_UNDO] = SDLK_UNDO;
-	k[Keyboard::KEY_CUT] = SDLK_CUT;
-	k[Keyboard::KEY_COPY] = SDLK_COPY;
-	k[Keyboard::KEY_PASTE] = SDLK_PASTE;
-	k[Keyboard::KEY_FIND] = SDLK_FIND;
-	k[Keyboard::KEY_MUTE] = SDLK_MUTE;
-	k[Keyboard::KEY_VOLUMEUP] = SDLK_VOLUMEUP;
-	k[Keyboard::KEY_VOLUMEDOWN] = SDLK_VOLUMEDOWN;
-
-	k[Keyboard::KEY_ALTERASE] = SDLK_ALTERASE;
-	k[Keyboard::KEY_SYSREQ] = SDLK_SYSREQ;
-	k[Keyboard::KEY_CANCEL] = SDLK_CANCEL;
-	k[Keyboard::KEY_CLEAR] = SDLK_CLEAR;
-	k[Keyboard::KEY_PRIOR] = SDLK_PRIOR;
-	k[Keyboard::KEY_RETURN2] = SDLK_RETURN2;
-	k[Keyboard::KEY_SEPARATOR] = SDLK_SEPARATOR;
-	k[Keyboard::KEY_OUT] = SDLK_OUT;
-	k[Keyboard::KEY_OPER] = SDLK_OPER;
-	k[Keyboard::KEY_CLEARAGAIN] = SDLK_CLEARAGAIN;
-
-	k[Keyboard::KEY_THOUSANDSSEPARATOR] = SDLK_THOUSANDSSEPARATOR;
-	k[Keyboard::KEY_DECIMALSEPARATOR] = SDLK_DECIMALSEPARATOR;
-	k[Keyboard::KEY_CURRENCYUNIT] = SDLK_CURRENCYUNIT;
-	k[Keyboard::KEY_CURRENCYSUBUNIT] = SDLK_CURRENCYSUBUNIT;
-
-	k[Keyboard::KEY_LCTRL] = SDLK_LCTRL;
-	k[Keyboard::KEY_LSHIFT] = SDLK_LSHIFT;
-	k[Keyboard::KEY_LALT] = SDLK_LALT;
-	k[Keyboard::KEY_LGUI] = SDLK_LGUI;
-	k[Keyboard::KEY_RCTRL] = SDLK_RCTRL;
-	k[Keyboard::KEY_RSHIFT] = SDLK_RSHIFT;
-	k[Keyboard::KEY_RALT] = SDLK_RALT;
-	k[Keyboard::KEY_RGUI] = SDLK_RGUI;
-
-	k[Keyboard::KEY_MODE] = SDLK_MODE;
-
-	k[Keyboard::KEY_AUDIONEXT] = SDLK_AUDIONEXT;
-	k[Keyboard::KEY_AUDIOPREV] = SDLK_AUDIOPREV;
-	k[Keyboard::KEY_AUDIOSTOP] = SDLK_AUDIOSTOP;
-	k[Keyboard::KEY_AUDIOPLAY] = SDLK_AUDIOPLAY;
-	k[Keyboard::KEY_AUDIOMUTE] = SDLK_AUDIOMUTE;
-	k[Keyboard::KEY_MEDIASELECT] = SDLK_MEDIASELECT;
-	k[Keyboard::KEY_WWW] = SDLK_WWW;
-	k[Keyboard::KEY_MAIL] = SDLK_MAIL;
-	k[Keyboard::KEY_CALCULATOR] = SDLK_CALCULATOR;
-	k[Keyboard::KEY_COMPUTER] = SDLK_COMPUTER;
-	k[Keyboard::KEY_APP_SEARCH] = SDLK_AC_SEARCH;
-	k[Keyboard::KEY_APP_HOME] = SDLK_AC_HOME;
-	k[Keyboard::KEY_APP_BACK] = SDLK_AC_BACK;
-	k[Keyboard::KEY_APP_FORWARD] = SDLK_AC_FORWARD;
-	k[Keyboard::KEY_APP_STOP] = SDLK_AC_STOP;
-	k[Keyboard::KEY_APP_REFRESH] = SDLK_AC_REFRESH;
-	k[Keyboard::KEY_APP_BOOKMARKS] = SDLK_AC_BOOKMARKS;
-
-	k[Keyboard::KEY_BRIGHTNESSDOWN] = SDLK_BRIGHTNESSDOWN;
-	k[Keyboard::KEY_BRIGHTNESSUP] = SDLK_BRIGHTNESSUP;
-	k[Keyboard::KEY_DISPLAYSWITCH] = SDLK_DISPLAYSWITCH;
-	k[Keyboard::KEY_KBDILLUMTOGGLE] = SDLK_KBDILLUMTOGGLE;
-	k[Keyboard::KEY_KBDILLUMDOWN] = SDLK_KBDILLUMDOWN;
-	k[Keyboard::KEY_KBDILLUMUP] = SDLK_KBDILLUMUP;
-	k[Keyboard::KEY_EJECT] = SDLK_EJECT;
-	k[Keyboard::KEY_SLEEP] = SDLK_SLEEP;
-
-	return k;
-}
+	// ASCII characters don't need to go here since they can be directly
+	// converted.
+
+	{ KEY_UNKNOWN, SDLK_UNKNOWN },
+
+	{ KEY_CAPSLOCK, SDLK_CAPSLOCK },
+
+	{ KEY_F1, SDLK_F1 },
+	{ KEY_F2, SDLK_F2 },
+	{ KEY_F3, SDLK_F3 },
+	{ KEY_F4, SDLK_F4 },
+	{ KEY_F5, SDLK_F5 },
+	{ KEY_F6, SDLK_F6 },
+	{ KEY_F7, SDLK_F7 },
+	{ KEY_F8, SDLK_F8 },
+	{ KEY_F9, SDLK_F9 },
+	{ KEY_F10, SDLK_F10 },
+	{ KEY_F11, SDLK_F11 },
+	{ KEY_F12, SDLK_F12 },
+
+	{ KEY_PRINTSCREEN, SDLK_PRINTSCREEN },
+	{ KEY_SCROLLLOCK, SDLK_SCROLLLOCK },
+	{ KEY_PAUSE, SDLK_PAUSE },
+	{ KEY_INSERT, SDLK_INSERT },
+	{ KEY_HOME, SDLK_HOME },
+	{ KEY_PAGEUP, SDLK_PAGEUP },
+	{ KEY_DELETE, SDLK_DELETE },
+	{ KEY_END, SDLK_END },
+	{ KEY_PAGEDOWN, SDLK_PAGEDOWN },
+	{ KEY_RIGHT, SDLK_RIGHT },
+	{ KEY_LEFT, SDLK_LEFT },
+	{ KEY_DOWN, SDLK_DOWN },
+	{ KEY_UP, SDLK_UP },
+
+	{ KEY_NUMLOCKCLEAR, SDLK_NUMLOCKCLEAR },
+	{ KEY_KP_DIVIDE, SDLK_KP_DIVIDE },
+	{ KEY_KP_MULTIPLY, SDLK_KP_MULTIPLY },
+	{ KEY_KP_MINUS, SDLK_KP_MINUS },
+	{ KEY_KP_PLUS, SDLK_KP_PLUS },
+	{ KEY_KP_ENTER, SDLK_KP_ENTER },
+	{ KEY_KP_0, SDLK_KP_0 },
+	{ KEY_KP_1, SDLK_KP_1 },
+	{ KEY_KP_2, SDLK_KP_2 },
+	{ KEY_KP_3, SDLK_KP_3 },
+	{ KEY_KP_4, SDLK_KP_4 },
+	{ KEY_KP_5, SDLK_KP_5 },
+	{ KEY_KP_6, SDLK_KP_6 },
+	{ KEY_KP_7, SDLK_KP_7 },
+	{ KEY_KP_8, SDLK_KP_8 },
+	{ KEY_KP_9, SDLK_KP_9 },
+	{ KEY_KP_PERIOD, SDLK_KP_PERIOD },
+	{ KEY_KP_COMMA, SDLK_KP_COMMA },
+	{ KEY_KP_EQUALS, SDLK_KP_EQUALS },
+
+	{ KEY_APPLICATION, SDLK_APPLICATION },
+	{ KEY_POWER, SDLK_POWER },
+	{ KEY_F13, SDLK_F13 },
+	{ KEY_F14, SDLK_F14 },
+	{ KEY_F15, SDLK_F15 },
+	{ KEY_F16, SDLK_F16 },
+	{ KEY_F17, SDLK_F17 },
+	{ KEY_F18, SDLK_F18 },
+	{ KEY_F19, SDLK_F19 },
+	{ KEY_F20, SDLK_F20 },
+	{ KEY_F21, SDLK_F21 },
+	{ KEY_F22, SDLK_F22 },
+	{ KEY_F23, SDLK_F23 },
+	{ KEY_F24, SDLK_F24 },
+	{ KEY_EXECUTE, SDLK_EXECUTE },
+	{ KEY_HELP, SDLK_HELP },
+	{ KEY_MENU, SDLK_MENU },
+	{ KEY_SELECT, SDLK_SELECT },
+	{ KEY_STOP, SDLK_STOP },
+	{ KEY_AGAIN, SDLK_AGAIN },
+	{ KEY_UNDO, SDLK_UNDO },
+	{ KEY_CUT, SDLK_CUT },
+	{ KEY_COPY, SDLK_COPY },
+	{ KEY_PASTE, SDLK_PASTE },
+	{ KEY_FIND, SDLK_FIND },
+	{ KEY_MUTE, SDLK_MUTE },
+	{ KEY_VOLUMEUP, SDLK_VOLUMEUP },
+	{ KEY_VOLUMEDOWN, SDLK_VOLUMEDOWN },
+
+	{ KEY_ALTERASE, SDLK_ALTERASE },
+	{ KEY_SYSREQ, SDLK_SYSREQ },
+	{ KEY_CANCEL, SDLK_CANCEL },
+	{ KEY_CLEAR, SDLK_CLEAR },
+	{ KEY_PRIOR, SDLK_PRIOR },
+	{ KEY_RETURN2, SDLK_RETURN2 },
+	{ KEY_SEPARATOR, SDLK_SEPARATOR },
+	{ KEY_OUT, SDLK_OUT },
+	{ KEY_OPER, SDLK_OPER },
+	{ KEY_CLEARAGAIN, SDLK_CLEARAGAIN },
+
+	{ KEY_THOUSANDSSEPARATOR, SDLK_THOUSANDSSEPARATOR },
+	{ KEY_DECIMALSEPARATOR, SDLK_DECIMALSEPARATOR },
+	{ KEY_CURRENCYUNIT, SDLK_CURRENCYUNIT },
+	{ KEY_CURRENCYSUBUNIT, SDLK_CURRENCYSUBUNIT },
+
+	{ KEY_LCTRL, SDLK_LCTRL },
+	{ KEY_LSHIFT, SDLK_LSHIFT },
+	{ KEY_LALT, SDLK_LALT },
+	{ KEY_LGUI, SDLK_LGUI },
+	{ KEY_RCTRL, SDLK_RCTRL },
+	{ KEY_RSHIFT, SDLK_RSHIFT },
+	{ KEY_RALT, SDLK_RALT },
+	{ KEY_RGUI, SDLK_RGUI },
+
+	{ KEY_MODE, SDLK_MODE },
+
+	{ KEY_AUDIONEXT, SDLK_AUDIONEXT },
+	{ KEY_AUDIOPREV, SDLK_AUDIOPREV },
+	{ KEY_AUDIOSTOP, SDLK_AUDIOSTOP },
+	{ KEY_AUDIOPLAY, SDLK_AUDIOPLAY },
+	{ KEY_AUDIOMUTE, SDLK_AUDIOMUTE },
+	{ KEY_MEDIASELECT, SDLK_MEDIASELECT },
+	{ KEY_WWW, SDLK_WWW },
+	{ KEY_MAIL, SDLK_MAIL },
+	{ KEY_CALCULATOR, SDLK_CALCULATOR },
+	{ KEY_COMPUTER, SDLK_COMPUTER },
+	{ KEY_APP_SEARCH, SDLK_AC_SEARCH },
+	{ KEY_APP_HOME, SDLK_AC_HOME },
+	{ KEY_APP_BACK, SDLK_AC_BACK },
+	{ KEY_APP_FORWARD, SDLK_AC_FORWARD },
+	{ KEY_APP_STOP, SDLK_AC_STOP },
+	{ KEY_APP_REFRESH, SDLK_AC_REFRESH },
+	{ KEY_APP_BOOKMARKS, SDLK_AC_BOOKMARKS },
+
+	{ KEY_BRIGHTNESSDOWN, SDLK_BRIGHTNESSDOWN },
+	{ KEY_BRIGHTNESSUP, SDLK_BRIGHTNESSUP },
+	{ KEY_DISPLAYSWITCH, SDLK_DISPLAYSWITCH },
+	{ KEY_KBDILLUMTOGGLE, SDLK_KBDILLUMTOGGLE },
+	{ KEY_KBDILLUMDOWN, SDLK_KBDILLUMDOWN },
+	{ KEY_KBDILLUMUP, SDLK_KBDILLUMUP },
+	{ KEY_EJECT, SDLK_EJECT },
+	{ KEY_SLEEP, SDLK_SLEEP },
+};
 
-const SDL_Keycode *Keyboard::keymap = Keyboard::createKeyMap();
+std::map<SDL_Keycode, Keyboard::Key> Keyboard::sdlKeyToKey;
 
 EnumMap<Keyboard::Scancode, SDL_Scancode, SDL_NUM_SCANCODES>::Entry Keyboard::scancodeEntries[] =
 {

+ 7 - 2
src/modules/keyboard/sdl/Keyboard.h

@@ -28,6 +28,8 @@
 // SDL
 #include <SDL_keyboard.h>
 
+#include <map>
+
 namespace love
 {
 namespace keyboard
@@ -55,6 +57,9 @@ public:
 	bool hasTextInput() const;
 	bool hasScreenKeyboard() const;
 
+	static bool getConstant(Key in, SDL_Keycode &out);
+	static bool getConstant(SDL_Keycode in, Key &out);
+
 	static bool getConstant(Scancode in, SDL_Scancode &out);
 	static bool getConstant(SDL_Scancode in, Scancode &out);
 
@@ -64,8 +69,8 @@ private:
 	// The real implementation is in love::event::sdl::Event::Convert.
 	bool key_repeat;
 
-	static const SDL_Keycode *createKeyMap();
-	static const SDL_Keycode *keymap;
+	static std::map<Key, SDL_Keycode> keyToSDLKey;
+	static std::map<SDL_Keycode, Key> sdlKeyToKey;
 
 	static EnumMap<Scancode, SDL_Scancode, SDL_NUM_SCANCODES>::Entry scancodeEntries[];
 	static EnumMap<Scancode, SDL_Scancode, SDL_NUM_SCANCODES> scancodes;