#2 Handle scancodes correctly when kbd_mapping_mode = KEY

Open
pgimeno wants to merge 3 commits from pgimeno/pg-handle-scancodes into pgimeno/master

+ 17 - 17
src/events/HotKey.cc

@@ -106,51 +106,51 @@ void HotKey::initDefaultBindings()
 	if (META_HOT_KEYS) {
 	if (META_HOT_KEYS) {
 		// Hot key combos using Mac's Command key.
 		// Hot key combos using Mac's Command key.
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_D, Keys::KM_META)),
+		                            Keys::combine(Keys::K_D, Keys::KM_META), Keys::K_NONE),
 		                       "screenshot -guess-name"));
 		                       "screenshot -guess-name"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_P, Keys::KM_META)),
+		                            Keys::combine(Keys::K_P, Keys::KM_META), Keys::K_NONE),
 		                       "toggle pause"));
 		                       "toggle pause"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_T, Keys::KM_META)),
+		                            Keys::combine(Keys::K_T, Keys::KM_META), Keys::K_NONE),
 		                       "toggle throttle"));
 		                       "toggle throttle"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_L, Keys::KM_META)),
+		                            Keys::combine(Keys::K_L, Keys::KM_META), Keys::K_NONE),
 		                       "toggle console"));
 		                       "toggle console"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_U, Keys::KM_META)),
+		                            Keys::combine(Keys::K_U, Keys::KM_META), Keys::K_NONE),
 		                       "toggle mute"));
 		                       "toggle mute"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_F, Keys::KM_META)),
+		                            Keys::combine(Keys::K_F, Keys::KM_META), Keys::K_NONE),
 		                       "toggle fullscreen"));
 		                       "toggle fullscreen"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_Q, Keys::KM_META)),
+		                            Keys::combine(Keys::K_Q, Keys::KM_META), Keys::K_NONE),
 		                       "exit"));
 		                       "exit"));
 	} else {
 	} else {
 		// Hot key combos for typical PC keyboards.
 		// Hot key combos for typical PC keyboards.
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_PRINT),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_PRINT, Keys::K_NONE),
 		                       "screenshot -guess-name"));
 		                       "screenshot -guess-name"));
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_PAUSE),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_PAUSE, Keys::K_NONE),
 		                       "toggle pause"));
 		                       "toggle pause"));
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F9),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F9, Keys::K_NONE),
 		                       "toggle throttle"));
 		                       "toggle throttle"));
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F10),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F10, Keys::K_NONE),
 		                       "toggle console"));
 		                       "toggle console"));
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F11),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F11, Keys::K_NONE),
 		                       "toggle mute"));
 		                       "toggle mute"));
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F12),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_F12, Keys::K_NONE),
 		                       "toggle fullscreen"));
 		                       "toggle fullscreen"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_F4, Keys::KM_ALT)),
+		                            Keys::combine(Keys::K_F4, Keys::KM_ALT), Keys::K_NONE),
 		                       "exit"));
 		                       "exit"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_PAUSE, Keys::KM_CTRL)),
+		                            Keys::combine(Keys::K_PAUSE, Keys::KM_CTRL), Keys::K_NONE),
 		                       "exit"));
 		                       "exit"));
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
 		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(
-		                            Keys::combine(Keys::K_RETURN, Keys::KM_ALT)),
+		                            Keys::combine(Keys::K_RETURN, Keys::KM_ALT), Keys::K_NONE),
 		                       "toggle fullscreen"));
 		                       "toggle fullscreen"));
 		// and for Android
 		// and for Android
-		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_BACK),
+		bindDefault(HotKeyInfo(make_shared<KeyDownEvent>(Keys::K_BACK, Keys::K_NONE),
 		                       "quitmenu::quit_menu"));
 		                       "quitmenu::quit_menu"));
 	}
 	}
 }
 }

+ 2 - 2
src/events/InputEventFactory.cc

@@ -18,9 +18,9 @@ static EventPtr parseKeyEvent(std::string_view str, uint32_t unicode)
 		throw CommandException("Invalid keycode: ", str);
 		throw CommandException("Invalid keycode: ", str);
 	}
 	}
 	if (keyCode & Keys::KD_RELEASE) {
 	if (keyCode & Keys::KD_RELEASE) {
-		return make_shared<KeyUpEvent>(keyCode);
+		return make_shared<KeyUpEvent>(keyCode, keyCode);
 	} else {
 	} else {
-		return make_shared<KeyDownEvent>(keyCode, unicode);
+		return make_shared<KeyDownEvent>(keyCode, keyCode, unicode);
 	}
 	}
 }
 }
 
 

+ 9 - 5
src/events/InputEventGenerator.cc

@@ -271,9 +271,11 @@ void InputEventGenerator::handleKeyDown(const SDL_KeyboardEvent& key, uint32_t u
 		androidButtonB = true;
 		androidButtonB = true;
 	} else*/ {
 	} else*/ {
 		auto mod = normalizeModifier(key.keysym.sym, key.keysym.mod);
 		auto mod = normalizeModifier(key.keysym.sym, key.keysym.mod);
-		auto keyCode = Keys::getCode(
+		auto keyCodes = Keys::getCodes(
 			key.keysym.sym, mod, key.keysym.scancode, false);
 			key.keysym.sym, mod, key.keysym.scancode, false);
-		event = make_shared<KeyDownEvent>(keyCode, unicode);
+		auto keyCode = keyCodes.first;
+		auto scanCode = keyCodes.second;
+		event = make_shared<KeyDownEvent>(keyCode, scanCode, unicode);
 		triggerOsdControlEventsFromKeyEvent(keyCode, false, event);
 		triggerOsdControlEventsFromKeyEvent(keyCode, false, event);
 	}
 	}
 	eventDistributor.distributeEvent(event);
 	eventDistributor.distributeEvent(event);
@@ -285,7 +287,7 @@ void InputEventGenerator::handleText(const char* utf8)
 		auto unicode = utf8::unchecked::next(utf8);
 		auto unicode = utf8::unchecked::next(utf8);
 		if (unicode == 0) return;
 		if (unicode == 0) return;
 		eventDistributor.distributeEvent(
 		eventDistributor.distributeEvent(
-			make_shared<KeyDownEvent>(Keys::K_NONE, unicode));
+			make_shared<KeyDownEvent>(Keys::K_NONE, Keys::K_NONE, unicode));
 	}
 	}
 }
 }
 
 
@@ -313,9 +315,11 @@ void InputEventGenerator::handle(const SDL_Event& evt)
 			androidButtonB = false;
 			androidButtonB = false;
 		} else*/ {
 		} else*/ {
 			auto mod = normalizeModifier(evt.key.keysym.sym, evt.key.keysym.mod);
 			auto mod = normalizeModifier(evt.key.keysym.sym, evt.key.keysym.mod);
-			auto keyCode = Keys::getCode(
+			auto keyCodes = Keys::getCodes(
 				evt.key.keysym.sym, mod, evt.key.keysym.scancode, true);
 				evt.key.keysym.sym, mod, evt.key.keysym.scancode, true);
-			event = make_shared<KeyUpEvent>(keyCode);
+			auto keyCode = keyCodes.first;
+			auto scanCode = keyCodes.second;
+			event = make_shared<KeyUpEvent>(keyCode, scanCode);
 			triggerOsdControlEventsFromKeyEvent(keyCode, true, event);
 			triggerOsdControlEventsFromKeyEvent(keyCode, true, event);
 		}
 		}
 		break;
 		break;

+ 6 - 6
src/events/InputEvents.cc

@@ -24,8 +24,8 @@ TimedEvent::TimedEvent(EventType type_)
 
 
 // class KeyEvent
 // class KeyEvent
 
 
-KeyEvent::KeyEvent(EventType type_, Keys::KeyCode keyCode_, uint32_t unicode_)
-	: TimedEvent(type_), keyCode(keyCode_), unicode(unicode_)
+KeyEvent::KeyEvent(EventType type_, Keys::KeyCode keyCode_, Keys::KeyCode scanCode_, uint32_t unicode_)
+	: TimedEvent(type_), keyCode(keyCode_), scanCode(scanCode_), unicode(unicode_)
 {
 {
 }
 }
 
 
@@ -48,16 +48,16 @@ bool KeyEvent::lessImpl(const Event& other) const
 
 
 // class KeyUpEvent
 // class KeyUpEvent
 
 
-KeyUpEvent::KeyUpEvent(Keys::KeyCode keyCode_)
-	: KeyEvent(OPENMSX_KEY_UP_EVENT, keyCode_, 0)
+KeyUpEvent::KeyUpEvent(Keys::KeyCode keyCode_, Keys::KeyCode scanCode_)
+	: KeyEvent(OPENMSX_KEY_UP_EVENT, keyCode_, scanCode_, 0)
 {
 {
 }
 }
 
 
 
 
 // class KeyDownEvent
 // class KeyDownEvent
 
 
-KeyDownEvent::KeyDownEvent(Keys::KeyCode keyCode_, uint32_t unicode_)
-	: KeyEvent(OPENMSX_KEY_DOWN_EVENT, keyCode_, unicode_)
+KeyDownEvent::KeyDownEvent(Keys::KeyCode keyCode_, Keys::KeyCode scanCode_, uint32_t unicode_)
+	: KeyEvent(OPENMSX_KEY_DOWN_EVENT, keyCode_, scanCode_, unicode_)
 {
 {
 }
 }
 
 

+ 7 - 5
src/events/InputEvents.hh

@@ -27,32 +27,34 @@ class KeyEvent : public TimedEvent
 {
 {
 public:
 public:
 	Keys::KeyCode getKeyCode() const { return keyCode; }
 	Keys::KeyCode getKeyCode() const { return keyCode; }
+	Keys::KeyCode getScanCode() const { return scanCode; }
 	uint32_t getUnicode() const { return unicode; }
 	uint32_t getUnicode() const { return unicode; }
 
 
 protected:
 protected:
-	KeyEvent(EventType type, Keys::KeyCode keyCode, uint32_t unicode);
+	KeyEvent(EventType type, Keys::KeyCode keyCode, Keys::KeyCode scanCode, uint32_t unicode);
 	~KeyEvent() = default;
 	~KeyEvent() = default;
 
 
 private:
 private:
 	TclObject toTclList() const override;
 	TclObject toTclList() const override;
 	bool lessImpl(const Event& other) const override;
 	bool lessImpl(const Event& other) const override;
 	const Keys::KeyCode keyCode;
 	const Keys::KeyCode keyCode;
+	const Keys::KeyCode scanCode;
 	const uint32_t unicode;
 	const uint32_t unicode;
 };
 };
 
 
 class KeyUpEvent final : public KeyEvent
 class KeyUpEvent final : public KeyEvent
 {
 {
 public:
 public:
-	explicit KeyUpEvent(Keys::KeyCode keyCode);
+	explicit KeyUpEvent(Keys::KeyCode keyCode, Keys::KeyCode scanCode);
 };
 };
 
 
 class KeyDownEvent final : public KeyEvent
 class KeyDownEvent final : public KeyEvent
 {
 {
 public:
 public:
-	explicit KeyDownEvent(Keys::KeyCode keyCode_)
-		: KeyDownEvent(keyCode_, 0) {}
+	explicit KeyDownEvent(Keys::KeyCode keyCode_, Keys::KeyCode scanCode_)
+		: KeyDownEvent(keyCode_, scanCode_, 0) {}
 
 
-	explicit KeyDownEvent(Keys::KeyCode keyCode, uint32_t unicode);
+	explicit KeyDownEvent(Keys::KeyCode keyCode, Keys::KeyCode scanCode, uint32_t unicode);
 };
 };
 
 
 
 

+ 156 - 2
src/events/Keys.cc

@@ -366,9 +366,10 @@ KeyCode getCode(string_view name)
 	return result;
 	return result;
 }
 }
 
 
-KeyCode getCode(SDL_Keycode key, Uint16 mod, SDL_Scancode scancode, bool release)
+std::pair<KeyCode, KeyCode> getCodes(SDL_Keycode key, Uint16 mod, SDL_Scancode scancode, bool release)
 {
 {
 	KeyCode result;
 	KeyCode result;
+	KeyCode scan;
 	switch (key) {
 	switch (key) {
 	case SDLK_BACKSPACE:      result = K_BACKSPACE;         break;
 	case SDLK_BACKSPACE:      result = K_BACKSPACE;         break;
 	case SDLK_TAB:            result = K_TAB;               break;
 	case SDLK_TAB:            result = K_TAB;               break;
@@ -533,6 +534,149 @@ KeyCode getCode(SDL_Keycode key, Uint16 mod, SDL_Scancode scancode, bool release
 	default:                  result = K_UNKNOWN;           break;
 	default:                  result = K_UNKNOWN;           break;
 	}
 	}
 
 
+	switch (scancode) {
+	case SDL_SCANCODE_BACKSPACE:      scan = K_BACKSPACE;         break;
+	case SDL_SCANCODE_TAB:            scan = K_TAB;               break;
+	case SDL_SCANCODE_CLEAR:          scan = K_CLEAR;             break;
+	case SDL_SCANCODE_RETURN:         scan = K_RETURN;            break;
+	case SDL_SCANCODE_PAUSE:          scan = K_PAUSE;             break;
+	case SDL_SCANCODE_ESCAPE:         scan = K_ESCAPE;            break;
+	case SDL_SCANCODE_SPACE:          scan = K_SPACE;             break;
+	case SDL_SCANCODE_APOSTROPHE:     scan = K_QUOTE;             break;
+	case SDL_SCANCODE_COMMA:          scan = K_COMMA;             break;
+	case SDL_SCANCODE_MINUS:          scan = K_MINUS;             break;
+	case SDL_SCANCODE_PERIOD:         scan = K_PERIOD;            break;
+	case SDL_SCANCODE_SLASH:          scan = K_SLASH;             break;
+	case SDL_SCANCODE_0:              scan = K_0;                 break;
+	case SDL_SCANCODE_1:              scan = K_1;                 break;
+	case SDL_SCANCODE_2:              scan = K_2;                 break;
+	case SDL_SCANCODE_3:              scan = K_3;                 break;
+	case SDL_SCANCODE_4:              scan = K_4;                 break;
+	case SDL_SCANCODE_5:              scan = K_5;                 break;
+	case SDL_SCANCODE_6:              scan = K_6;                 break;
+	case SDL_SCANCODE_7:              scan = K_7;                 break;
+	case SDL_SCANCODE_8:              scan = K_8;                 break;
+	case SDL_SCANCODE_9:              scan = K_9;                 break;
+	case SDL_SCANCODE_SEMICOLON:      scan = K_SEMICOLON;         break;
+	case SDL_SCANCODE_EQUALS:         scan = K_EQUALS;            break;
+
+	case SDL_SCANCODE_LEFTBRACKET:    scan = K_LEFTBRACKET;       break;
+	case SDL_SCANCODE_BACKSLASH:      scan = K_BACKSLASH;         break;
+	case SDL_SCANCODE_RIGHTBRACKET:   scan = K_RIGHTBRACKET;      break;
+	case SDL_SCANCODE_GRAVE:          scan = K_BACKQUOTE;         break;
+	case SDL_SCANCODE_A:              scan = K_A;                 break;
+	case SDL_SCANCODE_B:              scan = K_B;                 break;
+	case SDL_SCANCODE_C:              scan = K_C;                 break;
+	case SDL_SCANCODE_D:              scan = K_D;                 break;
+	case SDL_SCANCODE_E:              scan = K_E;                 break;
+	case SDL_SCANCODE_F:              scan = K_F;                 break;
+	case SDL_SCANCODE_G:              scan = K_G;                 break;
+	case SDL_SCANCODE_H:              scan = K_H;                 break;
+	case SDL_SCANCODE_I:              scan = K_I;                 break;
+	case SDL_SCANCODE_J:              scan = K_J;                 break;
+	case SDL_SCANCODE_K:              scan = K_K;                 break;
+	case SDL_SCANCODE_L:              scan = K_L;                 break;
+	case SDL_SCANCODE_M:              scan = K_M;                 break;
+	case SDL_SCANCODE_N:              scan = K_N;                 break;
+	case SDL_SCANCODE_O:              scan = K_O;                 break;
+	case SDL_SCANCODE_P:              scan = K_P;                 break;
+	case SDL_SCANCODE_Q:              scan = K_Q;                 break;
+	case SDL_SCANCODE_R:              scan = K_R;                 break;
+	case SDL_SCANCODE_S:              scan = K_S;                 break;
+	case SDL_SCANCODE_T:              scan = K_T;                 break;
+	case SDL_SCANCODE_U:              scan = K_U;                 break;
+	case SDL_SCANCODE_V:              scan = K_V;                 break;
+	case SDL_SCANCODE_W:              scan = K_W;                 break;
+	case SDL_SCANCODE_X:              scan = K_X;                 break;
+	case SDL_SCANCODE_Y:              scan = K_Y;                 break;
+	case SDL_SCANCODE_Z:              scan = K_Z;                 break;
+	case SDL_SCANCODE_DELETE:         scan = K_DELETE;            break;
+
+	// Numeric keypad
+	case SDL_SCANCODE_KP_0:           scan = K_KP0;               break;
+	case SDL_SCANCODE_KP_1:           scan = K_KP1;               break;
+	case SDL_SCANCODE_KP_2:           scan = K_KP2;               break;
+	case SDL_SCANCODE_KP_3:           scan = K_KP3;               break;
+	case SDL_SCANCODE_KP_4:           scan = K_KP4;               break;
+	case SDL_SCANCODE_KP_5:           scan = K_KP5;               break;
+	case SDL_SCANCODE_KP_6:           scan = K_KP6;               break;
+	case SDL_SCANCODE_KP_7:           scan = K_KP7;               break;
+	case SDL_SCANCODE_KP_8:           scan = K_KP8;               break;
+	case SDL_SCANCODE_KP_9:           scan = K_KP9;               break;
+	case SDL_SCANCODE_KP_PERIOD:      scan = K_KP_PERIOD;         break;
+	case SDL_SCANCODE_KP_DIVIDE:      scan = K_KP_DIVIDE;         break;
+	case SDL_SCANCODE_KP_MULTIPLY:    scan = K_KP_MULTIPLY;       break;
+	case SDL_SCANCODE_KP_MINUS:       scan = K_KP_MINUS;          break;
+	case SDL_SCANCODE_KP_PLUS:        scan = K_KP_PLUS;           break;
+	case SDL_SCANCODE_KP_ENTER:       scan = K_KP_ENTER;          break;
+	case SDL_SCANCODE_KP_EQUALS:      scan = K_KP_EQUALS;         break;
+
+	// Arrows + Home/End pad
+	case SDL_SCANCODE_UP:             scan = K_UP;                break;
+	case SDL_SCANCODE_DOWN:           scan = K_DOWN;              break;
+	case SDL_SCANCODE_RIGHT:          scan = K_RIGHT;             break;
+	case SDL_SCANCODE_LEFT:           scan = K_LEFT;              break;
+	case SDL_SCANCODE_INSERT:         scan = K_INSERT;            break;
+	case SDL_SCANCODE_HOME:           scan = K_HOME;              break;
+	case SDL_SCANCODE_END:            scan = K_END;               break;
+	case SDL_SCANCODE_PAGEUP:         scan = K_PAGEUP;            break;
+	case SDL_SCANCODE_PAGEDOWN:       scan = K_PAGEDOWN;          break;
+
+	// Function keys
+	case SDL_SCANCODE_F1:             scan = K_F1;                break;
+	case SDL_SCANCODE_F2:             scan = K_F2;                break;
+	case SDL_SCANCODE_F3:             scan = K_F3;                break;
+	case SDL_SCANCODE_F4:             scan = K_F4;                break;
+	case SDL_SCANCODE_F5:             scan = K_F5;                break;
+	case SDL_SCANCODE_F6:             scan = K_F6;                break;
+	case SDL_SCANCODE_F7:             scan = K_F7;                break;
+	case SDL_SCANCODE_F8:             scan = K_F8;                break;
+	case SDL_SCANCODE_F9:             scan = K_F9;                break;
+	case SDL_SCANCODE_F10:            scan = K_F10;               break;
+	case SDL_SCANCODE_F11:            scan = K_F11;               break;
+	case SDL_SCANCODE_F12:            scan = K_F12;               break;
+	case SDL_SCANCODE_F13:            scan = K_F13;               break;
+	case SDL_SCANCODE_F14:            scan = K_F14;               break;
+	case SDL_SCANCODE_F15:            scan = K_F15;               break;
+	case SDL_SCANCODE_F16:            scan = K_F16;               break;
+	case SDL_SCANCODE_F17:            scan = K_F17;               break;
+	case SDL_SCANCODE_F18:            scan = K_F18;               break;
+	case SDL_SCANCODE_F19:            scan = K_F19;               break;
+	case SDL_SCANCODE_F20:            scan = K_F20;               break;
+	case SDL_SCANCODE_F21:            scan = K_F21;               break;
+	case SDL_SCANCODE_F22:            scan = K_F22;               break;
+	case SDL_SCANCODE_F23:            scan = K_F23;               break;
+	case SDL_SCANCODE_F24:            scan = K_F24;               break;
+
+	// Key state modifier keys
+	case SDL_SCANCODE_NUMLOCKCLEAR:   scan = K_NUMLOCK;           break;
+	case SDL_SCANCODE_CAPSLOCK:       scan = K_CAPSLOCK;          break;
+	case SDL_SCANCODE_SCROLLLOCK:     scan = K_SCROLLLOCK;        break;
+	case SDL_SCANCODE_RSHIFT:         scan = K_RSHIFT;            break;
+	case SDL_SCANCODE_LSHIFT:         scan = K_LSHIFT;            break;
+	case SDL_SCANCODE_RCTRL:          scan = K_RCTRL;             break;
+	case SDL_SCANCODE_LCTRL:          scan = K_LCTRL;             break;
+	case SDL_SCANCODE_RALT:           scan = K_RALT;              break;
+	case SDL_SCANCODE_LALT:           scan = K_LALT;              break;
+	case SDL_SCANCODE_LGUI:           scan = K_LSUPER;            break; // Left "Windows" key
+	case SDL_SCANCODE_RGUI:           scan = K_RSUPER;            break; // Right "Windows" key
+	case SDL_SCANCODE_MODE:           scan = K_MODE;              break; // "Alt Gr" key
+
+	// Miscellaneous function keys
+	case SDL_SCANCODE_HELP:           scan = K_HELP;              break;
+	case SDL_SCANCODE_PRINTSCREEN:    scan = K_PRINT;             break;
+	case SDL_SCANCODE_SYSREQ:         scan = K_SYSREQ;            break;
+	case SDL_SCANCODE_APPLICATION:    scan = K_MENU;              break;
+	case SDL_SCANCODE_MENU:           scan = K_MENU;              break;
+	case SDL_SCANCODE_POWER:          scan = K_POWER;             break; // Power Macintosh power key
+	case SDL_SCANCODE_UNDO:           scan = K_UNDO;              break;
+
+	// Application Control keys
+	case SDL_SCANCODE_AC_BACK:        scan = K_BACK;              break;
+
+	default:                          scan = K_UNKNOWN;           break;
+	}
+
 	// Handle keys that don't have a key code but do have a scan code.
 	// Handle keys that don't have a key code but do have a scan code.
 	if (result == K_UNKNOWN) {
 	if (result == K_UNKNOWN) {
 		// Assume it is a Japanese keyboard and check
 		// Assume it is a Japanese keyboard and check
@@ -560,30 +704,40 @@ KeyCode getCode(SDL_Keycode key, Uint16 mod, SDL_Scancode scancode, bool release
 			result = K_RALT;
 			result = K_RALT;
 		default:
 		default:
 			break; // nothing, silence compiler warning
 			break; // nothing, silence compiler warning
+			// TODO: Maybe better to default to the scancode?
+			// Just so unknown keys do something.
+			//result = scan;
+			//break;
 		}
 		}
 	}
 	}
 
 
 	// Apply modifiers.
 	// Apply modifiers.
 	if (mod & KMOD_CTRL) {
 	if (mod & KMOD_CTRL) {
 		result = static_cast<KeyCode>(result | KM_CTRL);
 		result = static_cast<KeyCode>(result | KM_CTRL);
+		scan   = static_cast<KeyCode>(scan | KM_CTRL);
 	}
 	}
 	if (mod & KMOD_SHIFT) {
 	if (mod & KMOD_SHIFT) {
 		result = static_cast<KeyCode>(result | KM_SHIFT);
 		result = static_cast<KeyCode>(result | KM_SHIFT);
+		scan   = static_cast<KeyCode>(scan | KM_SHIFT);
 	}
 	}
 	if (mod & KMOD_ALT) {
 	if (mod & KMOD_ALT) {
 		result = static_cast<KeyCode>(result | KM_ALT);
 		result = static_cast<KeyCode>(result | KM_ALT);
+		scan   = static_cast<KeyCode>(scan | KM_ALT);
 	}
 	}
 	if (mod & KMOD_GUI) {
 	if (mod & KMOD_GUI) {
 		result = static_cast<KeyCode>(result | KM_META);
 		result = static_cast<KeyCode>(result | KM_META);
+		scan   = static_cast<KeyCode>(scan | KM_META);
 	}
 	}
 	if (mod & KMOD_MODE) {
 	if (mod & KMOD_MODE) {
 		result = static_cast<KeyCode>(result | KM_MODE);
 		result = static_cast<KeyCode>(result | KM_MODE);
+		scan   = static_cast<KeyCode>(scan | KM_MODE);
 	}
 	}
 
 
 	if (release) {
 	if (release) {
 		result = static_cast<KeyCode>(result | KD_RELEASE);
 		result = static_cast<KeyCode>(result | KD_RELEASE);
+		scan   = static_cast<KeyCode>(scan | KD_RELEASE);
 	}
 	}
-	return result;
+	return {result, scan};
 }
 }
 
 
 string getName(KeyCode keyCode)
 string getName(KeyCode keyCode)

+ 2 - 1
src/events/Keys.hh

@@ -3,6 +3,7 @@
 
 
 #include <SDL_stdinc.h>
 #include <SDL_stdinc.h>
 #include <SDL_keycode.h>
 #include <SDL_keycode.h>
+#include <SDL_scancode.h>
 #include <string>
 #include <string>
 #include <string_view>
 #include <string_view>
 
 
@@ -217,7 +218,7 @@ enum KeyCode {
  */
  */
 KeyCode getCode(std::string_view name);
 KeyCode getCode(std::string_view name);
 
 
-KeyCode getCode(SDL_Keycode key, Uint16 mod = KMOD_NONE, SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN, bool release = false);
+std::pair<KeyCode, KeyCode> getCodes(SDL_Keycode key, Uint16 mod = KMOD_NONE, SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN, bool release = false);
 
 
 /**
 /**
  * Translate key code to key name.
  * Translate key code to key name.

+ 19 - 5
src/input/Keyboard.cc

@@ -350,6 +350,12 @@ bool Keyboard::processQueuedEvent(const Event& event, EmuTime::param time)
 	bool down = event.getType() == OPENMSX_KEY_DOWN_EVENT;
 	bool down = event.getType() == OPENMSX_KEY_DOWN_EVENT;
 	auto key = static_cast<Keys::KeyCode>(
 	auto key = static_cast<Keys::KeyCode>(
 		int(keyEvent.getKeyCode()) & int(Keys::K_MASK));
 		int(keyEvent.getKeyCode()) & int(Keys::K_MASK));
+	auto scan = static_cast<Keys::KeyCode>(
+		int(keyEvent.getScanCode()) & int(Keys::K_MASK));
+	if (keyboardSettings.getMappingMode() == KeyboardSettings::POSITIONAL_MAPPING) {
+		// Use scancode instead of keycode
+		key = scan;
+	}
 	if (down) {
 	if (down) {
 		// TODO: refactor debug(...) method to expect a std::string and then adapt
 		// TODO: refactor debug(...) method to expect a std::string and then adapt
 		// all invocations of it to provide a properly formatted string, using the C++
 		// all invocations of it to provide a properly formatted string, using the C++
@@ -520,6 +526,12 @@ bool Keyboard::processKeyEvent(EmuTime::param time, bool down, const KeyEvent& k
 	Keys::KeyCode keyCode = keyEvent.getKeyCode();
 	Keys::KeyCode keyCode = keyEvent.getKeyCode();
 	auto key = static_cast<Keys::KeyCode>(
 	auto key = static_cast<Keys::KeyCode>(
 		int(keyCode) & int(Keys::K_MASK));
 		int(keyCode) & int(Keys::K_MASK));
+	auto scan = static_cast<Keys::KeyCode>(
+		int(keyEvent.getScanCode()) & int(Keys::K_MASK));
+	if (keyboardSettings.getMappingMode() == KeyboardSettings::POSITIONAL_MAPPING) {
+		// Use scancode instead of keycode
+		key = scan;
+	}
 	unsigned unicode;
 	unsigned unicode;
 
 
 	bool isOnKeypad =
 	bool isOnKeypad =
@@ -537,9 +549,10 @@ bool Keyboard::processKeyEvent(EmuTime::param time, bool down, const KeyEvent& k
 	if (down) {
 	if (down) {
 		UnicodeKeymap::KeyInfo keyInfo;
 		UnicodeKeymap::KeyInfo keyInfo;
 		if (isOnKeypad ||
 		if (isOnKeypad ||
-		    keyboardSettings.getMappingMode() == KeyboardSettings::KEY_MAPPING) {
+		    keyboardSettings.getMappingMode() == KeyboardSettings::KEY_MAPPING ||
+		    keyboardSettings.getMappingMode() == KeyboardSettings::POSITIONAL_MAPPING) {
 			// User entered a key on numeric keypad or the driver is in KEY
 			// User entered a key on numeric keypad or the driver is in KEY
-			// mapping mode.
+			// or POSITIONAL mapping mode.
 			// First option (keypad) maps to same unicode as some other key
 			// First option (keypad) maps to same unicode as some other key
 			// combinations (e.g. digit on main keyboard or TAB/DEL).
 			// combinations (e.g. digit on main keyboard or TAB/DEL).
 			// Use unicode to handle the more common combination and use direct
 			// Use unicode to handle the more common combination and use direct
@@ -988,8 +1001,9 @@ void Keyboard::MsxKeyEventQueue::executeUntil(EmuTime::param time)
 		// The processor pressed the CODE/KANA key
 		// The processor pressed the CODE/KANA key
 		// Schedule a CODE/KANA release event, to be processed
 		// Schedule a CODE/KANA release event, to be processed
 		// before any of the other events in the queue
 		// before any of the other events in the queue
+		auto codeKanaHostKey = keyboard.keyboardSettings.getCodeKanaHostKey();
 		eventQueue.push_front(make_shared<KeyUpEvent>(
 		eventQueue.push_front(make_shared<KeyUpEvent>(
-			keyboard.keyboardSettings.getCodeKanaHostKey()));
+			codeKanaHostKey, codeKanaHostKey));
 	} else {
 	} else {
 		// The event has been completely processed. Delete it from the queue
 		// The event has been completely processed. Delete it from the queue
 		if (!eventQueue.empty()) {
 		if (!eventQueue.empty()) {
@@ -1200,7 +1214,7 @@ void Keyboard::CapsLockAligner::executeUntil(EmuTime::param time)
 			break;
 			break;
 		case MUST_DISTRIBUTE_KEY_RELEASE: {
 		case MUST_DISTRIBUTE_KEY_RELEASE: {
 			auto& keyboard = OUTER(Keyboard, capsLockAligner);
 			auto& keyboard = OUTER(Keyboard, capsLockAligner);
-			auto event = make_shared<KeyUpEvent>(Keys::K_CAPSLOCK);
+			auto event = make_shared<KeyUpEvent>(Keys::K_CAPSLOCK, Keys::K_CAPSLOCK);
 			keyboard.msxEventDistributor.distributeEvent(event, time);
 			keyboard.msxEventDistributor.distributeEvent(event, time);
 			state = IDLE;
 			state = IDLE;
 			break;
 			break;
@@ -1228,7 +1242,7 @@ void Keyboard::CapsLockAligner::alignCapsLock(EmuTime::param time)
 		keyboard.debug("Resyncing host and MSX CAPS lock\n");
 		keyboard.debug("Resyncing host and MSX CAPS lock\n");
 		// note: send out another event iso directly calling
 		// note: send out another event iso directly calling
 		// processCapslockEvent() because we want this to be recorded
 		// processCapslockEvent() because we want this to be recorded
-		auto event = make_shared<KeyDownEvent>(Keys::K_CAPSLOCK);
+		auto event = make_shared<KeyDownEvent>(Keys::K_CAPSLOCK, Keys::K_CAPSLOCK);
 		keyboard.msxEventDistributor.distributeEvent(event, time);
 		keyboard.msxEventDistributor.distributeEvent(event, time);
 		keyboard.debug("Sending fake CAPS release\n");
 		keyboard.debug("Sending fake CAPS release\n");
 		state = MUST_DISTRIBUTE_KEY_RELEASE;
 		state = MUST_DISTRIBUTE_KEY_RELEASE;

+ 3 - 2
src/input/KeyboardSettings.cc

@@ -38,8 +38,9 @@ KeyboardSettings::KeyboardSettings(CommandController& commandController)
 		"kbd_mapping_mode",
 		"kbd_mapping_mode",
 		"Keyboard mapping mode",
 		"Keyboard mapping mode",
 		CHARACTER_MAPPING, EnumSetting<MappingMode>::Map{
 		CHARACTER_MAPPING, EnumSetting<MappingMode>::Map{
-			{"KEY",       KEY_MAPPING},
-			{"CHARACTER", CHARACTER_MAPPING}})
+			{"KEY",        KEY_MAPPING},
+			{"CHARACTER",  CHARACTER_MAPPING},
+			{"POSITIONAL", POSITIONAL_MAPPING}})
 	, alwaysEnableKeypad(commandController,
 	, alwaysEnableKeypad(commandController,
 		"kbd_numkeypad_always_enabled",
 		"kbd_numkeypad_always_enabled",
 		"Numeric keypad is always enabled, even on an MSX that does not have one",
 		"Numeric keypad is always enabled, even on an MSX that does not have one",

+ 0 - 0
src/input/KeyboardSettings.hh


Some files were not shown because too many files changed in this diff