Browse Source

Added love.keyboard.getKeyFromScancode and love.keyboard.getScancodeFromKey. Resolves issue #982.

Scancodes represent a physical key independent of the keyboard's current layout. For example, pressing the key located where 'q' is on a U.S. keyboard will produce the key 'q' and the scancode 'q' when using a U.S. keyboard layout, but when using a French keyboard layout it will produce the key 'a' and the scancode 'q'.

Scancodes are useful for creating default controls that have the same physical locations on on all keyboards.
Alex Szpakowski 10 years ago
parent
commit
a314b18515

+ 277 - 2
src/modules/keyboard/Keyboard.cpp

@@ -27,18 +27,30 @@ namespace love
 namespace keyboard
 namespace keyboard
 {
 {
 
 
-bool Keyboard::getConstant(const char *in, Keyboard::Key &out)
+bool Keyboard::getConstant(const char *in, Key &out)
 {
 {
 	return keys.find(in, out);
 	return keys.find(in, out);
 }
 }
 
 
-bool Keyboard::getConstant(Keyboard::Key in, const char  *&out)
+bool Keyboard::getConstant(Key in, const char *&out)
 {
 {
 	return keys.find(in, out);
 	return keys.find(in, out);
 }
 }
 
 
+bool Keyboard::getConstant(const char *in, Scancode &out)
+{
+	return scancodes.find(in, out);
+}
+
+bool Keyboard::getConstant(Scancode in, const char *&out)
+{
+	return scancodes.find(in, out);
+}
+
 StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
 StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
 {
 {
+	{"unknown", Keyboard::KEY_UNKNOWN},
+
 	{"return", Keyboard::KEY_RETURN},
 	{"return", Keyboard::KEY_RETURN},
 	{"escape", Keyboard::KEY_ESCAPE},
 	{"escape", Keyboard::KEY_ESCAPE},
 	{"backspace", Keyboard::KEY_BACKSPACE},
 	{"backspace", Keyboard::KEY_BACKSPACE},
@@ -244,6 +256,269 @@ StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM>::Entry Keyboard::keyEntries[] =
 
 
 StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM> Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries));
 StringMap<Keyboard::Key, Keyboard::KEY_MAX_ENUM> Keyboard::keys(Keyboard::keyEntries, sizeof(Keyboard::keyEntries));
 
 
+StringMap<Keyboard::Scancode, Keyboard::SCANCODE_MAX_ENUM>::Entry Keyboard::scancodeEntries[] =
+{
+	{"unknown", SCANCODE_UNKNOWN},
+
+	{"a", SCANCODE_A},
+	{"b", SCANCODE_B},
+	{"c", SCANCODE_C},
+	{"d", SCANCODE_D},
+	{"e", SCANCODE_E},
+	{"f", SCANCODE_F},
+	{"g", SCANCODE_G},
+	{"h", SCANCODE_H},
+	{"i", SCANCODE_I},
+	{"j", SCANCODE_J},
+	{"k", SCANCODE_K},
+	{"l", SCANCODE_L},
+	{"m", SCANCODE_M},
+	{"n", SCANCODE_N},
+	{"o", SCANCODE_O},
+	{"p", SCANCODE_P},
+	{"q", SCANCODE_Q},
+	{"r", SCANCODE_R},
+	{"s", SCANCODE_S},
+	{"t", SCANCODE_T},
+	{"u", SCANCODE_U},
+	{"v", SCANCODE_V},
+	{"w", SCANCODE_W},
+	{"x", SCANCODE_X},
+	{"y", SCANCODE_Y},
+	{"z", SCANCODE_Z},
+
+	{"1", SCANCODE_1},
+	{"2", SCANCODE_2},
+	{"3", SCANCODE_3},
+	{"4", SCANCODE_4},
+	{"5", SCANCODE_5},
+	{"6", SCANCODE_6},
+	{"7", SCANCODE_7},
+	{"8", SCANCODE_8},
+	{"9", SCANCODE_9},
+	{"0", SCANCODE_0},
+
+	{"return", SCANCODE_RETURN},
+	{"escape", SCANCODE_ESCAPE},
+	{"backspace", SCANCODE_BACKSPACE},
+	{"tab", SCANCODE_TAB},
+	{" ", SCANCODE_SPACE},
+
+	{"-", SCANCODE_MINUS},
+	{"=", SCANCODE_EQUALS},
+	{"[", SCANCODE_LEFTBRACKET},
+	{"]", SCANCODE_RIGHTBRACKET},
+	{"\\", SCANCODE_BACKSLASH},
+	{"nonus#", SCANCODE_NONUSHASH},
+	{";", SCANCODE_SEMICOLON},
+	{"'", SCANCODE_APOSTROPHE},
+	{"`", SCANCODE_GRAVE},
+	{",", SCANCODE_COMMA},
+	{".", SCANCODE_PERIOD},
+	{"/", SCANCODE_SLASH},
+
+	{"capslock", SCANCODE_CAPSLOCK},
+
+	{"f1", SCANCODE_F1},
+	{"f2", SCANCODE_F2},
+	{"f3", SCANCODE_F3},
+	{"f4", SCANCODE_F4},
+	{"f5", SCANCODE_F5},
+	{"f6", SCANCODE_F6},
+	{"f7", SCANCODE_F7},
+	{"f8", SCANCODE_F8},
+	{"f9", SCANCODE_F9},
+	{"f10", SCANCODE_F10},
+	{"f11", SCANCODE_F11},
+	{"f12", SCANCODE_F12},
+
+	{"printscreen", SCANCODE_PRINTSCREEN},
+	{"scrolllock", SCANCODE_SCROLLLOCK},
+	{"pause", SCANCODE_PAUSE},
+	{"insert", SCANCODE_INSERT},
+	{"home", SCANCODE_HOME},
+	{"pageup", SCANCODE_PAGEUP},
+	{"delete", SCANCODE_DELETE},
+	{"end", SCANCODE_END},
+	{"pagedown", SCANCODE_PAGEDOWN},
+	{"right", SCANCODE_RIGHT},
+	{"left", SCANCODE_LEFT},
+	{"down", SCANCODE_DOWN},
+	{"up", SCANCODE_UP},
+
+	{"numlock", SCANCODE_NUMLOCKCLEAR},
+	{"kp/", SCANCODE_KP_DIVIDE},
+	{"kp*", SCANCODE_KP_MULTIPLY},
+	{"kp-", SCANCODE_KP_MINUS},
+	{"kp+", SCANCODE_KP_PLUS},
+	{"kpenter", SCANCODE_KP_ENTER},
+	{"kp1", SCANCODE_KP_1},
+	{"kp2", SCANCODE_KP_2},
+	{"kp3", SCANCODE_KP_3},
+	{"kp4", SCANCODE_KP_4},
+	{"kp5", SCANCODE_KP_5},
+	{"kp6", SCANCODE_KP_6},
+	{"kp7", SCANCODE_KP_7},
+	{"kp8", SCANCODE_KP_8},
+	{"kp9", SCANCODE_KP_9},
+	{"kp0", SCANCODE_KP_0},
+	{"kp.", SCANCODE_KP_PERIOD},
+
+	{"nonusbackslash", SCANCODE_NONUSBACKSLASH},
+	{"application", SCANCODE_APPLICATION},
+	{"power", SCANCODE_POWER},
+	{"=", SCANCODE_KP_EQUALS},
+	{"f13", SCANCODE_F13},
+	{"f14", SCANCODE_F14},
+	{"f15", SCANCODE_F15},
+	{"f16", SCANCODE_F16},
+	{"f17", SCANCODE_F17},
+	{"f18", SCANCODE_F18},
+	{"f19", SCANCODE_F19},
+	{"f20", SCANCODE_F20},
+	{"f21", SCANCODE_F21},
+	{"f22", SCANCODE_F22},
+	{"f23", SCANCODE_F23},
+	{"f24", SCANCODE_F24},
+	{"execute", SCANCODE_EXECUTE},
+	{"help", SCANCODE_HELP},
+	{"menu", SCANCODE_MENU},
+	{"select", SCANCODE_SELECT},
+	{"stop", SCANCODE_STOP},
+	{"again", SCANCODE_AGAIN},
+	{"undo", SCANCODE_UNDO},
+	{"cut", SCANCODE_CUT},
+	{"copy", SCANCODE_COPY},
+	{"paste", SCANCODE_PASTE},
+	{"find", SCANCODE_FIND},
+	{"mute", SCANCODE_MUTE},
+	{"volumeup", SCANCODE_VOLUMEUP},
+	{"volumedown", SCANCODE_VOLUMEDOWN},
+	{"kp,", SCANCODE_KP_COMMA},
+	{"kp=400", SCANCODE_KP_EQUALSAS400},
+
+	{"international1", SCANCODE_INTERNATIONAL1},
+	{"international2", SCANCODE_INTERNATIONAL2},
+	{"international3", SCANCODE_INTERNATIONAL3},
+	{"international4", SCANCODE_INTERNATIONAL4},
+	{"international5", SCANCODE_INTERNATIONAL5},
+	{"international6", SCANCODE_INTERNATIONAL6},
+	{"international7", SCANCODE_INTERNATIONAL7},
+	{"international8", SCANCODE_INTERNATIONAL8},
+	{"international9", SCANCODE_INTERNATIONAL9},
+	{"lang1", SCANCODE_LANG1},
+	{"lang2", SCANCODE_LANG2},
+	{"lang3", SCANCODE_LANG3},
+	{"lang4", SCANCODE_LANG4},
+	{"lang5", SCANCODE_LANG5},
+	{"lang6", SCANCODE_LANG6},
+	{"lang7", SCANCODE_LANG7},
+	{"lang8", SCANCODE_LANG8},
+	{"lang9", SCANCODE_LANG9},
+
+	{"alterase", SCANCODE_ALTERASE},
+	{"sysreq", SCANCODE_SYSREQ},
+	{"cancel", SCANCODE_CANCEL},
+	{"clear", SCANCODE_CLEAR},
+	{"prior", SCANCODE_PRIOR},
+	{"return2", SCANCODE_RETURN2},
+	{"separator", SCANCODE_SEPARATOR},
+	{"out", SCANCODE_OUT},
+	{"oper", SCANCODE_OPER},
+	{"clearagain", SCANCODE_CLEARAGAIN},
+	{"crsel", SCANCODE_CRSEL},
+	{"exsel", SCANCODE_EXSEL},
+
+	{"kp00", SCANCODE_KP_00},
+	{"kp000", SCANCODE_KP_000},
+	{"thsousandsseparator", SCANCODE_THOUSANDSSEPARATOR},
+	{"decimalseparator", SCANCODE_DECIMALSEPARATOR},
+	{"currencyunit", SCANCODE_CURRENCYUNIT},
+	{"currencysubunit", SCANCODE_CURRENCYSUBUNIT},
+	{"kp(", SCANCODE_KP_LEFTPAREN},
+	{"kp)", SCANCODE_KP_RIGHTPAREN},
+	{"kp{", SCANCODE_KP_LEFTBRACE},
+	{"kp}", SCANCODE_KP_RIGHTBRACE},
+	{"kptab", SCANCODE_KP_TAB},
+	{"kpbackspace", SCANCODE_KP_BACKSPACE},
+	{"kpa", SCANCODE_KP_A},
+	{"kpb", SCANCODE_KP_B},
+	{"kpc", SCANCODE_KP_C},
+	{"kpd", SCANCODE_KP_D},
+	{"kpe", SCANCODE_KP_E},
+	{"kpf", SCANCODE_KP_F},
+	{"kpxor", SCANCODE_KP_XOR},
+	{"kpower", SCANCODE_KP_POWER},
+	{"kp%", SCANCODE_KP_PERCENT},
+	{"kp<", SCANCODE_KP_LESS},
+	{"kp>", SCANCODE_KP_GREATER},
+	{"kp&", SCANCODE_KP_AMPERSAND},
+	{"kp&&", SCANCODE_KP_DBLAMPERSAND},
+	{"kp|", SCANCODE_KP_VERTICALBAR},
+	{"kp||", SCANCODE_KP_DBLVERTICALBAR},
+	{"kp:", SCANCODE_KP_COLON},
+	{"kp#", SCANCODE_KP_HASH},
+	{"kp ", SCANCODE_KP_SPACE},
+	{"kp@", SCANCODE_KP_AT},
+	{"kp!", SCANCODE_KP_EXCLAM},
+	{"kpmemstore", SCANCODE_KP_MEMSTORE},
+	{"kpmemrecall", SCANCODE_KP_MEMRECALL},
+	{"kpmemclear", SCANCODE_KP_MEMCLEAR},
+	{"kpmem+", SCANCODE_KP_MEMADD},
+	{"kpmem-", SCANCODE_KP_MEMSUBTRACT},
+	{"kpmem*", SCANCODE_KP_MEMMULTIPLY},
+	{"kpmem/", SCANCODE_KP_MEMDIVIDE},
+	{"kp+-", SCANCODE_KP_PLUSMINUS},
+	{"kpclear", SCANCODE_KP_CLEAR},
+	{"kpclearentry", SCANCODE_KP_CLEARENTRY},
+	{"kpbinary", SCANCODE_KP_BINARY},
+	{"kpoctal", SCANCODE_KP_OCTAL},
+	{"kpdecimal", SCANCODE_KP_DECIMAL},
+	{"kphex", SCANCODE_KP_HEXADECIMAL},
+
+	{"lctrl", SCANCODE_LCTRL},
+	{"lshift", SCANCODE_LSHIFT},
+	{"lalt", SCANCODE_LALT},
+	{"lgui", SCANCODE_LGUI},
+	{"rctrl", SCANCODE_RCTRL},
+	{"rshift", SCANCODE_RSHIFT},
+	{"ralt", SCANCODE_RALT},
+	{"rgui", SCANCODE_RGUI},
+
+	{"mode", SCANCODE_MODE},
+
+	{"audionext", SCANCODE_AUDIONEXT},
+	{"audioprev", SCANCODE_AUDIOPREV},
+	{"audiostop", SCANCODE_AUDIOSTOP},
+	{"audioplay", SCANCODE_AUDIOPLAY},
+	{"audiomute", SCANCODE_AUDIOMUTE},
+	{"mediaselect", SCANCODE_MEDIASELECT},
+	{"www", SCANCODE_WWW},
+	{"mail", SCANCODE_MAIL},
+	{"calculator", SCANCODE_CALCULATOR},
+	{"computer", SCANCODE_COMPUTER},
+	{"acsearch", SCANCODE_AC_SEARCH},
+	{"achome", SCANCODE_AC_HOME},
+	{"acback", SCANCODE_AC_BACK},
+	{"acforward", SCANCODE_AC_FORWARD},
+	{"acstop", SCANCODE_AC_STOP},
+	{"acrefresh", SCANCODE_AC_REFRESH},
+	{"acbookmarks", SCANCODE_AC_BOOKMARKS},
+
+	{"brightnessdown", SCANCODE_BRIGHTNESSDOWN},
+	{"brightnessup", SCANCODE_BRIGHTNESSUP},
+	{"displayswitch", SCANCODE_DISPLAYSWITCH},
+	{"kbdillumtoggle", SCANCODE_KBDILLUMTOGGLE},
+	{"kbdillumdown", SCANCODE_KBDILLUMDOWN},
+	{"kbdillumup", SCANCODE_KBDILLUMUP},
+	{"eject", SCANCODE_EJECT},
+	{"sleep", SCANCODE_SLEEP},
+	
+	{"app1", SCANCODE_APP1},
+	{"app2", SCANCODE_APP2},
+};
+
+StringMap<Keyboard::Scancode, Keyboard::SCANCODE_MAX_ENUM> Keyboard::scancodes(Keyboard::scancodeEntries, sizeof(Keyboard::scancodeEntries));
 
 
 } // keyboard
 } // keyboard
 } // love
 } // love

+ 291 - 1
src/modules/keyboard/Keyboard.h

@@ -34,6 +34,9 @@ class Keyboard : public Module
 {
 {
 public:
 public:
 
 
+	/**
+	 * Keyboard keys. They are dependent on the current layout of the keyboard.
+	 **/
 	enum Key
 	enum Key
 	{
 	{
 		KEY_UNKNOWN,
 		KEY_UNKNOWN,
@@ -244,6 +247,275 @@ public:
 		KEY_MAX_ENUM
 		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.
+	 * Some of them are very esoteric...
+	 **/
+	enum Scancode
+	{
+		SCANCODE_UNKNOWN,
+
+		SCANCODE_A,
+		SCANCODE_B,
+		SCANCODE_C,
+		SCANCODE_D,
+		SCANCODE_E,
+		SCANCODE_F,
+		SCANCODE_G,
+		SCANCODE_H,
+		SCANCODE_I,
+		SCANCODE_J,
+		SCANCODE_K,
+		SCANCODE_L,
+		SCANCODE_M,
+		SCANCODE_N,
+		SCANCODE_O,
+		SCANCODE_P,
+		SCANCODE_Q,
+		SCANCODE_R,
+		SCANCODE_S,
+		SCANCODE_T,
+		SCANCODE_U,
+		SCANCODE_V,
+		SCANCODE_W,
+		SCANCODE_X,
+		SCANCODE_Y,
+		SCANCODE_Z,
+
+		SCANCODE_1,
+		SCANCODE_2,
+		SCANCODE_3,
+		SCANCODE_4,
+		SCANCODE_5,
+		SCANCODE_6,
+		SCANCODE_7,
+		SCANCODE_8,
+		SCANCODE_9,
+		SCANCODE_0,
+
+		SCANCODE_RETURN,
+		SCANCODE_ESCAPE,
+		SCANCODE_BACKSPACE,
+		SCANCODE_TAB,
+		SCANCODE_SPACE,
+
+		SCANCODE_MINUS,
+		SCANCODE_EQUALS,
+		SCANCODE_LEFTBRACKET,
+		SCANCODE_RIGHTBRACKET,
+		SCANCODE_BACKSLASH,
+		SCANCODE_NONUSHASH,
+		SCANCODE_SEMICOLON,
+		SCANCODE_APOSTROPHE,
+		SCANCODE_GRAVE,
+		SCANCODE_COMMA,
+		SCANCODE_PERIOD,
+		SCANCODE_SLASH,
+
+		SCANCODE_CAPSLOCK,
+
+		SCANCODE_F1,
+		SCANCODE_F2,
+		SCANCODE_F3,
+		SCANCODE_F4,
+		SCANCODE_F5,
+		SCANCODE_F6,
+		SCANCODE_F7,
+		SCANCODE_F8,
+		SCANCODE_F9,
+		SCANCODE_F10,
+		SCANCODE_F11,
+		SCANCODE_F12,
+
+		SCANCODE_PRINTSCREEN,
+		SCANCODE_SCROLLLOCK,
+		SCANCODE_PAUSE,
+		SCANCODE_INSERT,
+		SCANCODE_HOME,
+		SCANCODE_PAGEUP,
+		SCANCODE_DELETE,
+		SCANCODE_END,
+		SCANCODE_PAGEDOWN,
+		SCANCODE_RIGHT,
+		SCANCODE_LEFT,
+		SCANCODE_DOWN,
+		SCANCODE_UP,
+
+		SCANCODE_NUMLOCKCLEAR,
+		SCANCODE_KP_DIVIDE,
+		SCANCODE_KP_MULTIPLY,
+		SCANCODE_KP_MINUS,
+		SCANCODE_KP_PLUS,
+		SCANCODE_KP_ENTER,
+		SCANCODE_KP_1,
+		SCANCODE_KP_2,
+		SCANCODE_KP_3,
+		SCANCODE_KP_4,
+		SCANCODE_KP_5,
+		SCANCODE_KP_6,
+		SCANCODE_KP_7,
+		SCANCODE_KP_8,
+		SCANCODE_KP_9,
+		SCANCODE_KP_0,
+		SCANCODE_KP_PERIOD,
+
+		SCANCODE_NONUSBACKSLASH,
+		SCANCODE_APPLICATION,
+		SCANCODE_POWER,
+		SCANCODE_KP_EQUALS,
+		SCANCODE_F13,
+		SCANCODE_F14,
+		SCANCODE_F15,
+		SCANCODE_F16,
+		SCANCODE_F17,
+		SCANCODE_F18,
+		SCANCODE_F19,
+		SCANCODE_F20,
+		SCANCODE_F21,
+		SCANCODE_F22,
+		SCANCODE_F23,
+		SCANCODE_F24,
+		SCANCODE_EXECUTE,
+		SCANCODE_HELP,
+		SCANCODE_MENU,
+		SCANCODE_SELECT,
+		SCANCODE_STOP,
+		SCANCODE_AGAIN,
+		SCANCODE_UNDO,
+		SCANCODE_CUT,
+		SCANCODE_COPY,
+		SCANCODE_PASTE,
+		SCANCODE_FIND,
+		SCANCODE_MUTE,
+		SCANCODE_VOLUMEUP,
+		SCANCODE_VOLUMEDOWN,
+		SCANCODE_KP_COMMA,
+		SCANCODE_KP_EQUALSAS400,
+
+		SCANCODE_INTERNATIONAL1,
+		SCANCODE_INTERNATIONAL2,
+		SCANCODE_INTERNATIONAL3,
+		SCANCODE_INTERNATIONAL4,
+		SCANCODE_INTERNATIONAL5,
+		SCANCODE_INTERNATIONAL6,
+		SCANCODE_INTERNATIONAL7,
+		SCANCODE_INTERNATIONAL8,
+		SCANCODE_INTERNATIONAL9,
+		SCANCODE_LANG1,
+		SCANCODE_LANG2,
+		SCANCODE_LANG3,
+		SCANCODE_LANG4,
+		SCANCODE_LANG5,
+		SCANCODE_LANG6,
+		SCANCODE_LANG7,
+		SCANCODE_LANG8,
+		SCANCODE_LANG9,
+
+		SCANCODE_ALTERASE,
+		SCANCODE_SYSREQ,
+		SCANCODE_CANCEL,
+		SCANCODE_CLEAR,
+		SCANCODE_PRIOR,
+		SCANCODE_RETURN2,
+		SCANCODE_SEPARATOR,
+		SCANCODE_OUT,
+		SCANCODE_OPER,
+		SCANCODE_CLEARAGAIN,
+		SCANCODE_CRSEL,
+		SCANCODE_EXSEL,
+
+		SCANCODE_KP_00,
+		SCANCODE_KP_000,
+		SCANCODE_THOUSANDSSEPARATOR,
+		SCANCODE_DECIMALSEPARATOR,
+		SCANCODE_CURRENCYUNIT,
+		SCANCODE_CURRENCYSUBUNIT,
+		SCANCODE_KP_LEFTPAREN,
+		SCANCODE_KP_RIGHTPAREN,
+		SCANCODE_KP_LEFTBRACE,
+		SCANCODE_KP_RIGHTBRACE,
+		SCANCODE_KP_TAB,
+		SCANCODE_KP_BACKSPACE,
+		SCANCODE_KP_A,
+		SCANCODE_KP_B,
+		SCANCODE_KP_C,
+		SCANCODE_KP_D,
+		SCANCODE_KP_E,
+		SCANCODE_KP_F,
+		SCANCODE_KP_XOR,
+		SCANCODE_KP_POWER,
+		SCANCODE_KP_PERCENT,
+		SCANCODE_KP_LESS,
+		SCANCODE_KP_GREATER,
+		SCANCODE_KP_AMPERSAND,
+		SCANCODE_KP_DBLAMPERSAND,
+		SCANCODE_KP_VERTICALBAR,
+		SCANCODE_KP_DBLVERTICALBAR,
+		SCANCODE_KP_COLON,
+		SCANCODE_KP_HASH,
+		SCANCODE_KP_SPACE,
+		SCANCODE_KP_AT,
+		SCANCODE_KP_EXCLAM,
+		SCANCODE_KP_MEMSTORE,
+		SCANCODE_KP_MEMRECALL,
+		SCANCODE_KP_MEMCLEAR,
+		SCANCODE_KP_MEMADD,
+		SCANCODE_KP_MEMSUBTRACT,
+		SCANCODE_KP_MEMMULTIPLY,
+		SCANCODE_KP_MEMDIVIDE,
+		SCANCODE_KP_PLUSMINUS,
+		SCANCODE_KP_CLEAR,
+		SCANCODE_KP_CLEARENTRY,
+		SCANCODE_KP_BINARY,
+		SCANCODE_KP_OCTAL,
+		SCANCODE_KP_DECIMAL,
+		SCANCODE_KP_HEXADECIMAL,
+
+		SCANCODE_LCTRL,
+		SCANCODE_LSHIFT,
+		SCANCODE_LALT,
+		SCANCODE_LGUI,
+		SCANCODE_RCTRL,
+		SCANCODE_RSHIFT,
+		SCANCODE_RALT,
+		SCANCODE_RGUI,
+
+		SCANCODE_MODE,
+
+		SCANCODE_AUDIONEXT,
+		SCANCODE_AUDIOPREV,
+		SCANCODE_AUDIOSTOP,
+		SCANCODE_AUDIOPLAY,
+		SCANCODE_AUDIOMUTE,
+		SCANCODE_MEDIASELECT,
+		SCANCODE_WWW,
+		SCANCODE_MAIL,
+		SCANCODE_CALCULATOR,
+		SCANCODE_COMPUTER,
+		SCANCODE_AC_SEARCH,
+		SCANCODE_AC_HOME,
+		SCANCODE_AC_BACK,
+		SCANCODE_AC_FORWARD,
+		SCANCODE_AC_STOP,
+		SCANCODE_AC_REFRESH,
+		SCANCODE_AC_BOOKMARKS,
+		
+		SCANCODE_BRIGHTNESSDOWN,
+		SCANCODE_BRIGHTNESSUP,
+		SCANCODE_DISPLAYSWITCH,
+		SCANCODE_KBDILLUMTOGGLE,
+		SCANCODE_KBDILLUMDOWN,
+		SCANCODE_KBDILLUMUP,
+		SCANCODE_EJECT,
+		SCANCODE_SLEEP,
+		
+		SCANCODE_APP1,
+		SCANCODE_APP2,
+
+		SCANCODE_MAX_ENUM
+	};
+
 	virtual ~Keyboard() {}
 	virtual ~Keyboard() {}
 
 
 	// Implements Module.
 	// Implements Module.
@@ -268,6 +540,18 @@ public:
 	 **/
 	 **/
 	virtual bool isDown(Key *keylist) const = 0;
 	virtual bool isDown(Key *keylist) const = 0;
 
 
+	/**
+	 * Gets the key corresponding to the specified scancode according to the
+	 * current keyboard layout.
+	 **/
+	virtual Key getKeyFromScancode(Scancode scancode) const = 0;
+
+	/**
+	 * Gets the scancode corresponding to the specified key according to the
+	 * current keyboard layout.
+	 **/
+	virtual Scancode getScancodeFromKey(Key key) const = 0;
+
 	/**
 	/**
 	 * Sets whether text input events should be sent
 	 * Sets whether text input events should be sent
 	 * @param enable Whether to send text input events.
 	 * @param enable Whether to send text input events.
@@ -280,13 +564,19 @@ public:
 	virtual bool hasTextInput() const = 0;
 	virtual bool hasTextInput() const = 0;
 
 
 	static bool getConstant(const char *in, Key &out);
 	static bool getConstant(const char *in, Key &out);
-	static bool getConstant(Key in, const char  *&out);
+	static bool getConstant(Key in, const char *&out);
+
+	static bool getConstant(const char *in, Scancode &out);
+	static bool getConstant(Scancode in, const char *&out);
 
 
 private:
 private:
 
 
 	static StringMap<Key, KEY_MAX_ENUM>::Entry keyEntries[];
 	static StringMap<Key, KEY_MAX_ENUM>::Entry keyEntries[];
 	static StringMap<Key, KEY_MAX_ENUM> keys;
 	static StringMap<Key, KEY_MAX_ENUM> keys;
 
 
+	static StringMap<Scancode, SCANCODE_MAX_ENUM>::Entry scancodeEntries[];
+	static StringMap<Scancode, SCANCODE_MAX_ENUM> scancodes;
+
 }; // Keyboard
 }; // Keyboard
 
 
 } // keyboard
 } // keyboard

+ 295 - 0
src/modules/keyboard/sdl/Keyboard.cpp

@@ -61,6 +61,37 @@ bool Keyboard::isDown(Key *keylist) const
 	return false;
 	return false;
 }
 }
 
 
+Keyboard::Key Keyboard::getKeyFromScancode(Scancode scancode) const
+{
+	SDL_Scancode sdlscancode = SDL_SCANCODE_UNKNOWN;
+	scancodes.find(scancode, sdlscancode);
+
+	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;
+}
+
+Keyboard::Scancode Keyboard::getScancodeFromKey(Key key) const
+{
+	Scancode scancode = SCANCODE_UNKNOWN;
+
+	if (key != KEY_MAX_ENUM)
+	{
+		SDL_Keycode sdlkey = keymap[key];
+
+		SDL_Scancode sdlscancode = SDL_GetScancodeFromKey(sdlkey);
+		scancodes.find(sdlscancode, scancode);
+	}
+
+	return scancode;
+}
+
 void Keyboard::setTextInput(bool enable)
 void Keyboard::setTextInput(bool enable)
 {
 {
 	if (enable)
 	if (enable)
@@ -288,6 +319,270 @@ const SDL_Keycode *Keyboard::createKeyMap()
 
 
 const SDL_Keycode *Keyboard::keymap = Keyboard::createKeyMap();
 const SDL_Keycode *Keyboard::keymap = Keyboard::createKeyMap();
 
 
+EnumMap<Keyboard::Scancode, SDL_Scancode, SDL_NUM_SCANCODES>::Entry Keyboard::scancodeEntries[] =
+{
+	{SCANCODE_UNKNOWN, SDL_SCANCODE_UNKNOWN},
+
+	{SCANCODE_A, SDL_SCANCODE_A},
+	{SCANCODE_B, SDL_SCANCODE_B},
+	{SCANCODE_C, SDL_SCANCODE_C},
+	{SCANCODE_D, SDL_SCANCODE_D},
+	{SCANCODE_E, SDL_SCANCODE_E},
+	{SCANCODE_F, SDL_SCANCODE_F},
+	{SCANCODE_G, SDL_SCANCODE_G},
+	{SCANCODE_H, SDL_SCANCODE_H},
+	{SCANCODE_I, SDL_SCANCODE_I},
+	{SCANCODE_J, SDL_SCANCODE_J},
+	{SCANCODE_K, SDL_SCANCODE_K},
+	{SCANCODE_L, SDL_SCANCODE_L},
+	{SCANCODE_M, SDL_SCANCODE_M},
+	{SCANCODE_N, SDL_SCANCODE_N},
+	{SCANCODE_O, SDL_SCANCODE_O},
+	{SCANCODE_P, SDL_SCANCODE_P},
+	{SCANCODE_Q, SDL_SCANCODE_Q},
+	{SCANCODE_R, SDL_SCANCODE_R},
+	{SCANCODE_S, SDL_SCANCODE_S},
+	{SCANCODE_T, SDL_SCANCODE_T},
+	{SCANCODE_U, SDL_SCANCODE_U},
+	{SCANCODE_V, SDL_SCANCODE_V},
+	{SCANCODE_W, SDL_SCANCODE_W},
+	{SCANCODE_X, SDL_SCANCODE_X},
+	{SCANCODE_Y, SDL_SCANCODE_Y},
+	{SCANCODE_Z, SDL_SCANCODE_Z},
+
+	{SCANCODE_1, SDL_SCANCODE_1},
+	{SCANCODE_2, SDL_SCANCODE_2},
+	{SCANCODE_3, SDL_SCANCODE_3},
+	{SCANCODE_4, SDL_SCANCODE_4},
+	{SCANCODE_5, SDL_SCANCODE_5},
+	{SCANCODE_6, SDL_SCANCODE_6},
+	{SCANCODE_7, SDL_SCANCODE_7},
+	{SCANCODE_8, SDL_SCANCODE_8},
+	{SCANCODE_9, SDL_SCANCODE_9},
+	{SCANCODE_0, SDL_SCANCODE_0},
+
+	{SCANCODE_RETURN, SDL_SCANCODE_RETURN},
+	{SCANCODE_ESCAPE, SDL_SCANCODE_ESCAPE},
+	{SCANCODE_BACKSPACE, SDL_SCANCODE_BACKSPACE},
+	{SCANCODE_TAB, SDL_SCANCODE_TAB},
+	{SCANCODE_SPACE, SDL_SCANCODE_SPACE},
+
+	{SCANCODE_MINUS, SDL_SCANCODE_MINUS},
+	{SCANCODE_EQUALS, SDL_SCANCODE_EQUALS},
+	{SCANCODE_LEFTBRACKET, SDL_SCANCODE_LEFTBRACKET},
+	{SCANCODE_RIGHTBRACKET, SDL_SCANCODE_RIGHTBRACKET},
+	{SCANCODE_BACKSLASH, SDL_SCANCODE_BACKSLASH},
+	{SCANCODE_NONUSHASH, SDL_SCANCODE_NONUSHASH},
+	{SCANCODE_SEMICOLON, SDL_SCANCODE_SEMICOLON},
+	{SCANCODE_APOSTROPHE, SDL_SCANCODE_APOSTROPHE},
+	{SCANCODE_GRAVE, SDL_SCANCODE_GRAVE},
+	{SCANCODE_COMMA, SDL_SCANCODE_COMMA},
+	{SCANCODE_PERIOD, SDL_SCANCODE_PERIOD},
+	{SCANCODE_SLASH, SDL_SCANCODE_SLASH},
+
+	{SCANCODE_CAPSLOCK, SDL_SCANCODE_CAPSLOCK},
+
+	{SCANCODE_F1, SDL_SCANCODE_F1},
+	{SCANCODE_F2, SDL_SCANCODE_F2},
+	{SCANCODE_F3, SDL_SCANCODE_F3},
+	{SCANCODE_F4, SDL_SCANCODE_F4},
+	{SCANCODE_F5, SDL_SCANCODE_F5},
+	{SCANCODE_F6, SDL_SCANCODE_F6},
+	{SCANCODE_F7, SDL_SCANCODE_F7},
+	{SCANCODE_F8, SDL_SCANCODE_F8},
+	{SCANCODE_F9, SDL_SCANCODE_F9},
+	{SCANCODE_F10, SDL_SCANCODE_F10},
+	{SCANCODE_F11, SDL_SCANCODE_F11},
+	{SCANCODE_F12, SDL_SCANCODE_F12},
+
+	{SCANCODE_PRINTSCREEN, SDL_SCANCODE_PRINTSCREEN},
+	{SCANCODE_SCROLLLOCK, SDL_SCANCODE_SCROLLLOCK},
+	{SCANCODE_PAUSE, SDL_SCANCODE_PAUSE},
+	{SCANCODE_INSERT, SDL_SCANCODE_INSERT},
+	{SCANCODE_HOME, SDL_SCANCODE_HOME},
+	{SCANCODE_PAGEUP, SDL_SCANCODE_PAGEUP},
+	{SCANCODE_DELETE, SDL_SCANCODE_DELETE},
+	{SCANCODE_END, SDL_SCANCODE_END},
+	{SCANCODE_PAGEDOWN, SDL_SCANCODE_PAGEDOWN},
+	{SCANCODE_RIGHT, SDL_SCANCODE_RIGHT},
+	{SCANCODE_LEFT, SDL_SCANCODE_LEFT},
+	{SCANCODE_DOWN, SDL_SCANCODE_DOWN},
+	{SCANCODE_UP, SDL_SCANCODE_UP},
+
+	{SCANCODE_NUMLOCKCLEAR, SDL_SCANCODE_NUMLOCKCLEAR},
+	{SCANCODE_KP_DIVIDE, SDL_SCANCODE_KP_DIVIDE},
+	{SCANCODE_KP_MULTIPLY, SDL_SCANCODE_KP_MULTIPLY},
+	{SCANCODE_KP_MINUS, SDL_SCANCODE_KP_MINUS},
+	{SCANCODE_KP_PLUS, SDL_SCANCODE_KP_PLUS},
+	{SCANCODE_KP_ENTER, SDL_SCANCODE_KP_ENTER},
+	{SCANCODE_KP_1, SDL_SCANCODE_KP_1},
+	{SCANCODE_KP_2, SDL_SCANCODE_KP_2},
+	{SCANCODE_KP_3, SDL_SCANCODE_KP_3},
+	{SCANCODE_KP_4, SDL_SCANCODE_KP_4},
+	{SCANCODE_KP_5, SDL_SCANCODE_KP_5},
+	{SCANCODE_KP_6, SDL_SCANCODE_KP_6},
+	{SCANCODE_KP_7, SDL_SCANCODE_KP_7},
+	{SCANCODE_KP_8, SDL_SCANCODE_KP_8},
+	{SCANCODE_KP_9, SDL_SCANCODE_KP_9},
+	{SCANCODE_KP_0, SDL_SCANCODE_KP_0},
+	{SCANCODE_KP_PERIOD, SDL_SCANCODE_KP_PERIOD},
+
+	{SCANCODE_NONUSBACKSLASH, SDL_SCANCODE_NONUSBACKSLASH},
+	{SCANCODE_APPLICATION, SDL_SCANCODE_APPLICATION},
+	{SCANCODE_POWER, SDL_SCANCODE_POWER},
+	{SCANCODE_KP_EQUALS, SDL_SCANCODE_KP_EQUALS},
+	{SCANCODE_F13, SDL_SCANCODE_F13},
+	{SCANCODE_F14, SDL_SCANCODE_F14},
+	{SCANCODE_F15, SDL_SCANCODE_F15},
+	{SCANCODE_F16, SDL_SCANCODE_F16},
+	{SCANCODE_F17, SDL_SCANCODE_F17},
+	{SCANCODE_F18, SDL_SCANCODE_F18},
+	{SCANCODE_F19, SDL_SCANCODE_F19},
+	{SCANCODE_F20, SDL_SCANCODE_F20},
+	{SCANCODE_F21, SDL_SCANCODE_F21},
+	{SCANCODE_F22, SDL_SCANCODE_F22},
+	{SCANCODE_F23, SDL_SCANCODE_F23},
+	{SCANCODE_F24, SDL_SCANCODE_F24},
+	{SCANCODE_EXECUTE, SDL_SCANCODE_EXECUTE},
+	{SCANCODE_HELP, SDL_SCANCODE_HELP},
+	{SCANCODE_MENU, SDL_SCANCODE_MENU},
+	{SCANCODE_SELECT, SDL_SCANCODE_SELECT},
+	{SCANCODE_STOP, SDL_SCANCODE_STOP},
+	{SCANCODE_AGAIN, SDL_SCANCODE_AGAIN},
+	{SCANCODE_UNDO, SDL_SCANCODE_UNDO},
+	{SCANCODE_CUT, SDL_SCANCODE_CUT},
+	{SCANCODE_COPY, SDL_SCANCODE_COPY},
+	{SCANCODE_PASTE, SDL_SCANCODE_PASTE},
+	{SCANCODE_FIND, SDL_SCANCODE_FIND},
+	{SCANCODE_MUTE, SDL_SCANCODE_MUTE},
+	{SCANCODE_VOLUMEUP, SDL_SCANCODE_VOLUMEUP},
+	{SCANCODE_VOLUMEDOWN, SDL_SCANCODE_VOLUMEDOWN},
+	{SCANCODE_KP_COMMA, SDL_SCANCODE_KP_COMMA},
+	{SCANCODE_KP_EQUALSAS400, SDL_SCANCODE_KP_EQUALSAS400},
+
+	{SCANCODE_INTERNATIONAL1, SDL_SCANCODE_INTERNATIONAL1},
+	{SCANCODE_INTERNATIONAL2, SDL_SCANCODE_INTERNATIONAL2},
+	{SCANCODE_INTERNATIONAL3, SDL_SCANCODE_INTERNATIONAL3},
+	{SCANCODE_INTERNATIONAL4, SDL_SCANCODE_INTERNATIONAL4},
+	{SCANCODE_INTERNATIONAL5, SDL_SCANCODE_INTERNATIONAL5},
+	{SCANCODE_INTERNATIONAL6, SDL_SCANCODE_INTERNATIONAL6},
+	{SCANCODE_INTERNATIONAL7, SDL_SCANCODE_INTERNATIONAL7},
+	{SCANCODE_INTERNATIONAL8, SDL_SCANCODE_INTERNATIONAL8},
+	{SCANCODE_INTERNATIONAL9, SDL_SCANCODE_INTERNATIONAL9},
+	{SCANCODE_LANG1, SDL_SCANCODE_LANG1},
+	{SCANCODE_LANG2, SDL_SCANCODE_LANG2},
+	{SCANCODE_LANG3, SDL_SCANCODE_LANG3},
+	{SCANCODE_LANG4, SDL_SCANCODE_LANG4},
+	{SCANCODE_LANG5, SDL_SCANCODE_LANG5},
+	{SCANCODE_LANG6, SDL_SCANCODE_LANG6},
+	{SCANCODE_LANG7, SDL_SCANCODE_LANG7},
+	{SCANCODE_LANG8, SDL_SCANCODE_LANG8},
+	{SCANCODE_LANG9, SDL_SCANCODE_LANG9},
+
+	{SCANCODE_ALTERASE, SDL_SCANCODE_ALTERASE},
+	{SCANCODE_SYSREQ, SDL_SCANCODE_SYSREQ},
+	{SCANCODE_CANCEL, SDL_SCANCODE_CANCEL},
+	{SCANCODE_CLEAR, SDL_SCANCODE_CLEAR},
+	{SCANCODE_PRIOR, SDL_SCANCODE_PRIOR},
+	{SCANCODE_RETURN2, SDL_SCANCODE_RETURN2},
+	{SCANCODE_SEPARATOR, SDL_SCANCODE_SEPARATOR},
+	{SCANCODE_OUT, SDL_SCANCODE_OUT},
+	{SCANCODE_OPER, SDL_SCANCODE_OPER},
+	{SCANCODE_CLEARAGAIN, SDL_SCANCODE_CLEARAGAIN},
+	{SCANCODE_CRSEL, SDL_SCANCODE_CRSEL},
+	{SCANCODE_EXSEL, SDL_SCANCODE_EXSEL},
+
+	{SCANCODE_KP_00, SDL_SCANCODE_KP_00},
+	{SCANCODE_KP_000, SDL_SCANCODE_KP_000},
+	{SCANCODE_THOUSANDSSEPARATOR, SDL_SCANCODE_THOUSANDSSEPARATOR},
+	{SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_DECIMALSEPARATOR},
+	{SCANCODE_CURRENCYUNIT, SDL_SCANCODE_CURRENCYUNIT},
+	{SCANCODE_CURRENCYSUBUNIT, SDL_SCANCODE_CURRENCYSUBUNIT},
+	{SCANCODE_KP_LEFTPAREN, SDL_SCANCODE_KP_LEFTPAREN},
+	{SCANCODE_KP_RIGHTPAREN, SDL_SCANCODE_KP_RIGHTPAREN},
+	{SCANCODE_KP_LEFTBRACE, SDL_SCANCODE_KP_LEFTBRACE},
+	{SCANCODE_KP_RIGHTBRACE, SDL_SCANCODE_KP_RIGHTBRACE},
+	{SCANCODE_KP_TAB, SDL_SCANCODE_KP_TAB},
+	{SCANCODE_KP_BACKSPACE, SDL_SCANCODE_KP_BACKSPACE},
+	{SCANCODE_KP_A, SDL_SCANCODE_KP_A},
+	{SCANCODE_KP_B, SDL_SCANCODE_KP_B},
+	{SCANCODE_KP_C, SDL_SCANCODE_KP_C},
+	{SCANCODE_KP_D, SDL_SCANCODE_KP_D},
+	{SCANCODE_KP_E, SDL_SCANCODE_KP_E},
+	{SCANCODE_KP_F, SDL_SCANCODE_KP_F},
+	{SCANCODE_KP_XOR, SDL_SCANCODE_KP_XOR},
+	{SCANCODE_KP_POWER, SDL_SCANCODE_KP_POWER},
+	{SCANCODE_KP_PERCENT, SDL_SCANCODE_KP_PERCENT},
+	{SCANCODE_KP_LESS, SDL_SCANCODE_KP_LESS},
+	{SCANCODE_KP_GREATER, SDL_SCANCODE_KP_GREATER},
+	{SCANCODE_KP_AMPERSAND, SDL_SCANCODE_KP_AMPERSAND},
+	{SCANCODE_KP_DBLAMPERSAND, SDL_SCANCODE_KP_DBLAMPERSAND},
+	{SCANCODE_KP_VERTICALBAR, SDL_SCANCODE_KP_VERTICALBAR},
+	{SCANCODE_KP_DBLVERTICALBAR, SDL_SCANCODE_KP_DBLVERTICALBAR},
+	{SCANCODE_KP_COLON, SDL_SCANCODE_KP_COLON},
+	{SCANCODE_KP_HASH, SDL_SCANCODE_KP_HASH},
+	{SCANCODE_KP_SPACE, SDL_SCANCODE_KP_SPACE},
+	{SCANCODE_KP_AT, SDL_SCANCODE_KP_AT},
+	{SCANCODE_KP_EXCLAM, SDL_SCANCODE_KP_EXCLAM},
+	{SCANCODE_KP_MEMSTORE, SDL_SCANCODE_KP_MEMSTORE},
+	{SCANCODE_KP_MEMRECALL, SDL_SCANCODE_KP_MEMRECALL},
+	{SCANCODE_KP_MEMCLEAR, SDL_SCANCODE_KP_MEMCLEAR},
+	{SCANCODE_KP_MEMADD, SDL_SCANCODE_KP_MEMADD},
+	{SCANCODE_KP_MEMSUBTRACT, SDL_SCANCODE_KP_MEMSUBTRACT},
+	{SCANCODE_KP_MEMMULTIPLY, SDL_SCANCODE_KP_MEMMULTIPLY},
+	{SCANCODE_KP_MEMDIVIDE, SDL_SCANCODE_KP_MEMDIVIDE},
+	{SCANCODE_KP_PLUSMINUS, SDL_SCANCODE_KP_PLUSMINUS},
+	{SCANCODE_KP_CLEAR, SDL_SCANCODE_KP_CLEAR},
+	{SCANCODE_KP_CLEARENTRY, SDL_SCANCODE_KP_CLEARENTRY},
+	{SCANCODE_KP_BINARY, SDL_SCANCODE_KP_BINARY},
+	{SCANCODE_KP_OCTAL, SDL_SCANCODE_KP_OCTAL},
+	{SCANCODE_KP_DECIMAL, SDL_SCANCODE_KP_DECIMAL},
+	{SCANCODE_KP_HEXADECIMAL, SDL_SCANCODE_KP_HEXADECIMAL},
+
+	{SCANCODE_LCTRL, SDL_SCANCODE_LCTRL},
+	{SCANCODE_LSHIFT, SDL_SCANCODE_LSHIFT},
+	{SCANCODE_LALT, SDL_SCANCODE_LALT},
+	{SCANCODE_LGUI, SDL_SCANCODE_LGUI},
+	{SCANCODE_RCTRL, SDL_SCANCODE_RCTRL},
+	{SCANCODE_RSHIFT, SDL_SCANCODE_RSHIFT},
+	{SCANCODE_RALT, SDL_SCANCODE_RALT},
+	{SCANCODE_RGUI, SDL_SCANCODE_RGUI},
+
+	{SCANCODE_MODE, SDL_SCANCODE_MODE},
+
+	{SCANCODE_AUDIONEXT, SDL_SCANCODE_AUDIONEXT},
+	{SCANCODE_AUDIOPREV, SDL_SCANCODE_AUDIOPREV},
+	{SCANCODE_AUDIOSTOP, SDL_SCANCODE_AUDIOSTOP},
+	{SCANCODE_AUDIOPLAY, SDL_SCANCODE_AUDIOPLAY},
+	{SCANCODE_AUDIOMUTE, SDL_SCANCODE_AUDIOMUTE},
+	{SCANCODE_MEDIASELECT, SDL_SCANCODE_MEDIASELECT},
+	{SCANCODE_WWW, SDL_SCANCODE_WWW},
+	{SCANCODE_MAIL, SDL_SCANCODE_MAIL},
+	{SCANCODE_CALCULATOR, SDL_SCANCODE_CALCULATOR},
+	{SCANCODE_COMPUTER, SDL_SCANCODE_COMPUTER},
+	{SCANCODE_AC_SEARCH, SDL_SCANCODE_AC_SEARCH},
+	{SCANCODE_AC_HOME, SDL_SCANCODE_AC_HOME},
+	{SCANCODE_AC_BACK, SDL_SCANCODE_AC_BACK},
+	{SCANCODE_AC_FORWARD, SDL_SCANCODE_AC_FORWARD},
+	{SCANCODE_AC_STOP, SDL_SCANCODE_AC_STOP},
+	{SCANCODE_AC_REFRESH, SDL_SCANCODE_AC_REFRESH},
+	{SCANCODE_AC_BOOKMARKS, SDL_SCANCODE_AC_BOOKMARKS},
+
+	{SCANCODE_BRIGHTNESSDOWN, SDL_SCANCODE_BRIGHTNESSDOWN},
+	{SCANCODE_BRIGHTNESSUP, SDL_SCANCODE_BRIGHTNESSUP},
+	{SCANCODE_DISPLAYSWITCH, SDL_SCANCODE_DISPLAYSWITCH},
+	{SCANCODE_KBDILLUMTOGGLE, SDL_SCANCODE_KBDILLUMTOGGLE},
+	{SCANCODE_KBDILLUMDOWN, SDL_SCANCODE_KBDILLUMDOWN},
+	{SCANCODE_KBDILLUMUP, SDL_SCANCODE_KBDILLUMUP},
+	{SCANCODE_EJECT, SDL_SCANCODE_EJECT},
+	{SCANCODE_SLEEP, SDL_SCANCODE_SLEEP},
+	
+	{SCANCODE_APP1, SDL_SCANCODE_APP1},
+	{SCANCODE_APP2, SDL_SCANCODE_APP2},
+};
+
+EnumMap<Keyboard::Scancode, SDL_Scancode, SDL_NUM_SCANCODES> Keyboard::scancodes(Keyboard::scancodeEntries, sizeof(Keyboard::scancodeEntries));
+
 } // sdl
 } // sdl
 } // keyboard
 } // keyboard
 } // love
 } // love

+ 6 - 0
src/modules/keyboard/sdl/Keyboard.h

@@ -48,6 +48,9 @@ public:
 	bool hasKeyRepeat() const;
 	bool hasKeyRepeat() const;
 	bool isDown(Key *keylist) const;
 	bool isDown(Key *keylist) const;
 
 
+	Key getKeyFromScancode(Scancode scancode) const;
+	Scancode getScancodeFromKey(Key key) const;
+
 	void setTextInput(bool enable);
 	void setTextInput(bool enable);
 	bool hasTextInput() const;
 	bool hasTextInput() const;
 
 
@@ -60,6 +63,9 @@ private:
 	static const SDL_Keycode *createKeyMap();
 	static const SDL_Keycode *createKeyMap();
 	static const SDL_Keycode *keymap;
 	static const SDL_Keycode *keymap;
 
 
+	static EnumMap<Scancode, SDL_Scancode, SDL_NUM_SCANCODES>::Entry scancodeEntries[];
+	static EnumMap<Scancode, SDL_Scancode, SDL_NUM_SCANCODES> scancodes;
+
 }; // Keyboard
 }; // Keyboard
 
 
 } // sdl
 } // sdl

+ 36 - 0
src/modules/keyboard/wrap_Keyboard.cpp

@@ -62,6 +62,40 @@ int w_isDown(lua_State *L)
 	return 1;
 	return 1;
 }
 }
 
 
+int w_getScancodeFromKey(lua_State *L)
+{
+	const char *keystr = luaL_checkstring(L, 1);
+	Keyboard::Key key;
+	if (!Keyboard::getConstant(keystr, key))
+		return luaL_error(L, "Invalid key constant: %s", keystr);
+
+	Keyboard::Scancode scancode = instance()->getScancodeFromKey(key);
+
+	const char *scancodestr;
+	if (!Keyboard::getConstant(scancode, scancodestr))
+		return luaL_error(L, "Unknown scancode.");
+
+	lua_pushstring(L, scancodestr);
+	return 1;
+}
+
+int w_getKeyFromScancode(lua_State *L)
+{
+	const char *scancodestr = luaL_checkstring(L, 1);
+	Keyboard::Scancode scancode;
+	if (!Keyboard::getConstant(scancodestr, scancode))
+		return luaL_error(L, "Invalid scancode: %s", scancode);
+
+	Keyboard::Key key = instance()->getKeyFromScancode(scancode);
+
+	const char *keystr;
+	if (!Keyboard::getConstant(key, keystr))
+		return luaL_error(L, "Unknown key constant");
+
+	lua_pushstring(L, keystr);
+	return 1;
+}
+
 int w_setTextInput(lua_State *L)
 int w_setTextInput(lua_State *L)
 {
 {
 	instance()->setTextInput(luax_toboolean(L, 1));
 	instance()->setTextInput(luax_toboolean(L, 1));
@@ -82,6 +116,8 @@ static const luaL_Reg functions[] =
 	{ "setTextInput", w_setTextInput },
 	{ "setTextInput", w_setTextInput },
 	{ "hasTextInput", w_hasTextInput },
 	{ "hasTextInput", w_hasTextInput },
 	{ "isDown", w_isDown },
 	{ "isDown", w_isDown },
+	{ "getScancodeFromKey", w_getScancodeFromKey },
+	{ "getKeyFromScancode", w_getKeyFromScancode },
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 

+ 2 - 0
src/modules/keyboard/wrap_Keyboard.h

@@ -33,6 +33,8 @@ namespace keyboard
 int w_setKeyRepeat(lua_State *L);
 int w_setKeyRepeat(lua_State *L);
 int w_hasKeyRepeat(lua_State *L);
 int w_hasKeyRepeat(lua_State *L);
 int w_isDown(lua_State *L);
 int w_isDown(lua_State *L);
+int w_getKeyFromScancode(lua_State *L);
+int w_getScancodeFromkey(lua_State *L);
 int w_setTextInput(lua_State *L);
 int w_setTextInput(lua_State *L);
 int w_hasTextInput(lua_State *L);
 int w_hasTextInput(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_keyboard(lua_State *L);
 extern "C" LOVE_EXPORT int luaopen_love_keyboard(lua_State *L);