[Scummvm-git-logs] scummvm master -> 01dcad98f737538238ccb603b865c769600d0adc

sev- noreply at scummvm.org
Mon Aug 18 10:17:01 UTC 2025


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
01dcad98f7 EFH: Add Complete keymapper support


Commit: 01dcad98f737538238ccb603b865c769600d0adc
    https://github.com/scummvm/scummvm/commit/01dcad98f737538238ccb603b865c769600d0adc
Author: aunnoman1 (aunnoman123 at outlook.com)
Date: 2025-08-18T12:16:58+02:00

Commit Message:
EFH: Add Complete keymapper support

Changed paths:
    engines/efh/efh.cpp
    engines/efh/efh.h
    engines/efh/fight.cpp
    engines/efh/menu.cpp
    engines/efh/metaengine.cpp
    engines/efh/sound.cpp
    engines/efh/utils.cpp


diff --git a/engines/efh/efh.cpp b/engines/efh/efh.cpp
index e0064d2a593..bb88da20f60 100644
--- a/engines/efh/efh.cpp
+++ b/engines/efh/efh.cpp
@@ -155,9 +155,9 @@ Common::Error EfhEngine::run() {
 }
 
 void EfhEngine::handleEvents() {
-	Common::KeyCode retVal = getLastCharAfterAnimCount(4, false);
+	Common::CustomEventType retVal = getLastCharAfterAnimCount(4,false);
 
-	switch (_customAction) {
+	switch (retVal) {
 	case kActionSave:
 		handleActionSave();
 		break;
@@ -197,38 +197,31 @@ void EfhEngine::handleEvents() {
 	case kActionCharacter3Status:
 		showCharacterStatus(2);
 		break;
+	// debug cases to test sound
+	case kActionSound13:
+		generateSound(13);
+		break;
+	case kActionSound14:
+		generateSound(14);
+		break;
+	case kActionSound15:
+		generateSound(15);
+		break;
+	case kActionSound5:
+		generateSound(5);
+		break;
+	case kActionSound10:
+		generateSound(10);
+		break;
+	case kActionSound9:
+		generateSound(9);
+		break;
+	case kActionSound16:
+		generateSound(16);
+		break;
 	default:
 		break;
 	}
-
-	// debug cases to test sound
-	if (ConfMan.getBool("dump_scripts")) {
-		switch (retVal) {
-		case Common::KEYCODE_4:
-			generateSound(13);
-			break;
-		case Common::KEYCODE_5:
-			generateSound(14);
-			break;
-		case Common::KEYCODE_6:
-			generateSound(15);
-			break;
-		case Common::KEYCODE_7:
-			generateSound(5);
-			break;
-		case Common::KEYCODE_8:
-			generateSound(10);
-			break;
-		case Common::KEYCODE_9:
-			generateSound(9);
-			break;
-		case Common::KEYCODE_0:
-			generateSound(16);
-			break;
-		default:
-			break;
-		}
-	}
 }
 
 void EfhEngine::handleActionSave() {
@@ -240,8 +233,10 @@ void EfhEngine::handleActionSave() {
 		if (counter == 0)
 			displayFctFullScreen();
 	}
-	Common::KeyCode input = waitForKey();
-	if (input == Common::KEYCODE_y) {
+	setKeymap(kKeymapMenu);
+	Common::CustomEventType input = waitForKey();
+	setKeymap(kKeymapDefault);
+	if (input == kActionYes) {
 		displayMenuAnswerString("-> Yes <-", 24, 296, 169);
 		sayText("Yes", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 		getInput(2);
@@ -264,8 +259,10 @@ void EfhEngine::handleActionLoad() {
 		if (counter == 0)
 			displayFctFullScreen();
 	}
-	Common::KeyCode input = waitForKey();
-	if (input == Common::KEYCODE_y) {
+	setKeymap(kKeymapMenu);
+	Common::CustomEventType input = waitForKey();
+	setKeymap(kKeymapDefault);
+	if (input == kActionYes) {
 		displayMenuAnswerString("-> Yes <-", 24, 296, 169);
 		sayText("Yes", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 		getInput(2);
@@ -294,8 +291,8 @@ void EfhEngine::playIntro() {
 	// Load animations on previous picture with GF
 	loadImageSet(63, _circleImageBuf, _circleImageSubFileArray, _decompBuf);
 	readImpFile(100, false);
-	Common::KeyCode lastInput = getLastCharAfterAnimCount(8);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	Common::CustomEventType lastInput = getLastCharAfterAnimCount(8);
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	// With GF on the bed
@@ -306,7 +303,7 @@ void EfhEngine::playIntro() {
 	drawText(_imp2PtrArray[0], 6, 150, 268, 186, false);
 
 	lastInput = getLastCharAfterAnimCount(80);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	// Poof
@@ -318,7 +315,7 @@ void EfhEngine::playIntro() {
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
 	drawText(_imp2PtrArray[1], 6, 150, 268, 186, false);
 	lastInput = getLastCharAfterAnimCount(80);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	// On the phone
@@ -330,7 +327,7 @@ void EfhEngine::playIntro() {
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
 	drawText(_imp2PtrArray[2], 6, 150, 268, 186, false);
 	lastInput = getLastCharAfterAnimCount(80);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
@@ -339,7 +336,7 @@ void EfhEngine::playIntro() {
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
 	drawText(_imp2PtrArray[3], 6, 150, 268, 186, false);
 	lastInput = getLastCharAfterAnimCount(80);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
@@ -348,7 +345,7 @@ void EfhEngine::playIntro() {
 	displayRawDataAtPos(_circleImageSubFileArray[0], 0, 144);
 	drawText(_imp2PtrArray[4], 6, 150, 268, 186, false);
 	lastInput = getLastCharAfterAnimCount(80);
-	if (lastInput == Common::KEYCODE_ESCAPE)
+	if (lastInput == kActionSkipVideo)
 		return;
 
 	displayRawDataAtPos(_circleImageSubFileArray[3], 110, 16);
@@ -423,7 +420,9 @@ void EfhEngine::initEngine() {
 	loadImageSet(62, _circleImageBuf, _circleImageSubFileArray, _decompBuf);
 	fileName = "titlsong";
 	readFileToBuffer(fileName, _titleSong);
-	Common::KeyCode lastInput = Common::KEYCODE_INVALID;
+	Common::CustomEventType lastInput = kActionNone;
+
+	setKeymap(kKeymapSkipSong);
 
 	if (_loadSaveSlot == -1) {
 		sayText("Richard and Alan's Escape from Hell\nCopyright 1990 Electronic Arts\n"
@@ -432,9 +431,13 @@ void EfhEngine::initEngine() {
 		stopTextToSpeech();
 	}
 
-	if (lastInput != Common::KEYCODE_ESCAPE && _loadSaveSlot == -1)
+	setKeymap(kKeymapSkipVideo);
+
+	if (lastInput != kActionSkipSongAndIntro && _loadSaveSlot == -1)
 		playIntro();
 
+	setKeymap(kKeymapDefault);
+
 	loadImageSet(6, _circleImageBuf, _circleImageSubFileArray, _decompBuf);
 	readImpFile(99, false);
 	_introDoneFl = true;
@@ -748,7 +751,7 @@ void EfhEngine::displayLowStatusScreen(bool flag) {
 
 		if (counter == 0 && flag)
 			displayFctFullScreen();
-		
+
 		_sayLowStatusScreen = false;
 	}
 }
@@ -860,42 +863,43 @@ void EfhEngine::handleWinSequence() {
 		getInput(1);
 	}
 
-	Common::KeyCode input = Common::KEYCODE_INVALID;
+	Common::CustomEventType input = kActionNone;
+	setKeymap(kKeymapSkipVideo);
 
-	while (input != Common::KEYCODE_ESCAPE && !shouldQuit()) {
+	while (input != kActionSkipVideo && !shouldQuit()) {
 		displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0);
 		displayFctFullScreen();
 		displayRawDataAtPos(winSeqSubFilesArray1[0], 0, 0);
 		input = getInput(32);
-		if (input != Common::KEYCODE_ESCAPE) {
+		if (input != kActionSkipVideo) {
 			displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72);
 			displayFctFullScreen();
 			displayRawDataAtPos(winSeqSubFilesArray2[10], 136, 72);
 			input = getInput(1);
 		}
 
-		if (input != Common::KEYCODE_ESCAPE) {
+		if (input != kActionSkipVideo) {
 			displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72);
 			displayFctFullScreen();
 			displayRawDataAtPos(winSeqSubFilesArray2[11], 136, 72);
 			input = getInput(1);
 		}
 
-		if (input != Common::KEYCODE_ESCAPE) {
+		if (input != kActionSkipVideo) {
 			displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72);
 			displayFctFullScreen();
 			displayRawDataAtPos(winSeqSubFilesArray2[12], 136, 72);
 			input = getInput(1);
 		}
 
-		if (input != Common::KEYCODE_ESCAPE) {
+		if (input != kActionSkipVideo) {
 			displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72);
 			displayFctFullScreen();
 			displayRawDataAtPos(winSeqSubFilesArray2[13], 136, 72);
 			input = getInput(1);
 		}
 
-		if (input != Common::KEYCODE_ESCAPE) {
+		if (input != kActionSkipVideo) {
 			displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72);
 			displayFctFullScreen();
 			displayRawDataAtPos(winSeqSubFilesArray2[14], 136, 72);
@@ -903,6 +907,8 @@ void EfhEngine::handleWinSequence() {
 		}
 	}
 
+	setKeymap(kKeymapDefault);
+
 	free(decompBuffer);
 	free(winSeqBuf3);
 	free(winSeqBuf4);
@@ -936,18 +942,31 @@ bool EfhEngine::giveItemTo(int16 charId, int16 objectId, int16 fromCharId) {
 int16 EfhEngine::chooseCharacterToReplace() {
 	debugC(3, kDebugEngine, "chooseCharacterToReplace");
 
-	Common::KeyCode maxVal = (Common::KeyCode)(Common::KEYCODE_0 + _teamSize);
-	Common::KeyCode input;
-	for (;;) {
+	Common::CustomEventType input = kActionNone;
+	int16 charId = -1;
+
+	setKeymap(kKeymapCharacterSelection);
+
+	while (charId == -1) {
 		input = waitForKey();
-		if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0 || (input > Common::KEYCODE_1 && input <= maxVal))
+		if (input == kActionCancelCharacterSelection)
 			break;
+		for (int i = 0; i < ARRAYSIZE(_efhTeamSelectionCodes); ++i) {
+			if (input == _efhTeamSelectionCodes[i]._action) {
+				if (_efhTeamSelectionCodes[i]._id > 0 && _efhTeamSelectionCodes[i]._id < _teamSize) {
+					charId =  _efhTeamSelectionCodes[i]._id;
+					break;
+				}
+			}
+		}
 	}
 
-	if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0)
+	setKeymap(kKeymapDefault);
+
+	if (input == kActionCancelCharacterSelection)
 		return 0x1B;
 
-	return (int16)input - (int16)Common::KEYCODE_1;
+	return charId;
 }
 
 int16 EfhEngine::handleCharacterJoining() {
@@ -1925,11 +1944,17 @@ bool EfhEngine::handleTalk(int16 monsterId, int16 arg2, int16 itemId) {
 				}
 				sayText("Will you do this?", kNoRestriction);
 				setTextColorRed();
-				Common::KeyCode input = waitForKey();
-				if (input == Common::KEYCODE_y) {
+
+				setKeymap(kKeymapMenu);
+
+				Common::CustomEventType input = waitForKey();
+				if (input == kActionYes) {
 					removeCharacterFromTeam(charId);
 					displayImp1Text(_npcBuf[npcId].field14_textId);
 				}
+
+				setKeymap(kKeymapDefault);
+
 				displayAnimFrames(0xFE, true);
 				return true;
 			}
@@ -2361,18 +2386,31 @@ void EfhEngine::setCharacterObjectToBroken(int16 charId, int16 objectId) {
 int16 EfhEngine::selectOtherCharFromTeam() {
 	debugC(3, kDebugEngine, "selectOtherCharFromTeam");
 
-	Common::KeyCode maxVal = (Common::KeyCode) (Common::KEYCODE_0 + _teamSize);
-	Common::KeyCode input = Common::KEYCODE_INVALID;
-	for (;;) {
+	Common::CustomEventType input = kActionNone;
+	int16 charId = -1;
+
+	setKeymap(kKeymapCharacterSelection);
+
+	while (charId == -1) {
 		input = waitForKey();
-		if (input == Common::KEYCODE_ESCAPE || (input >= Common::KEYCODE_0 && input <= maxVal))
+		if (input == kActionCancelCharacterSelection)
 			break;
+		for (int i = 0; i < ARRAYSIZE(_efhTeamSelectionCodes); ++i) {
+			if (input == _efhTeamSelectionCodes[i]._action) {
+				if (_efhTeamSelectionCodes[i]._id < _teamSize) {
+					charId = _efhTeamSelectionCodes[i]._id;
+					break;
+				}
+			}
+		}
 	}
 
-	if (input == Common::KEYCODE_ESCAPE || input == Common::KEYCODE_0)
+	setKeymap(kKeymapDefault);
+
+	if (input == kActionCancelCharacterSelection)
 		return 0x1B;
 
-	return (int16)input - (int16)Common::KEYCODE_1;
+	return charId;
 }
 
 bool EfhEngine::checkMonsterCollision() {
@@ -2466,20 +2504,23 @@ bool EfhEngine::checkMonsterCollision() {
 				_sayMenu = false;
 			}
 
-			Common::KeyCode input = waitForKey();
+			setKeymap(kKeymapInteraction);
+
+			Common::CustomEventType input = waitForKey();
+
+			setKeymap(kKeymapDefault);
 
 			switch (input) {
-			case Common::KEYCODE_a: // Attack
+			case kActionStartFight: // Attack
 				sayText("Attack", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				handleFight(monsterId);
 				endLoop = true;
 				break;
-			case Common::KEYCODE_ESCAPE:
-			case Common::KEYCODE_l: // Leave
+			case kActionLeave: // Leave
 				sayText("Leave", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				endLoop = true;
 				break;
-			case Common::KEYCODE_s: // Status
+			case kActionStatus: // Status
 				sayText("Status", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_sayMenu = true;
 				handleStatusMenu(1, _teamChar[0]._id);
@@ -2487,7 +2528,7 @@ bool EfhEngine::checkMonsterCollision() {
 				_tempTextPtr = nullptr;
 				drawGameScreenAndTempText(true);
 				break;
-			case Common::KEYCODE_t: // Talk
+			case kActionTalk: // Talk
 				sayText("Talk", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_initiatedTalkByMenu = true;
 				startTalkMenu(monsterId);
@@ -2497,6 +2538,9 @@ bool EfhEngine::checkMonsterCollision() {
 				break;
 			}
 		} while (!endLoop && !shouldQuit());
+
+		setKeymap(kKeymapDefault);
+
 		return false;
 	}
 
diff --git a/engines/efh/efh.h b/engines/efh/efh.h
index f2ca873538d..0ed865185fa 100644
--- a/engines/efh/efh.h
+++ b/engines/efh/efh.h
@@ -266,7 +266,10 @@ enum TTSMenuRestriction {
 
 enum EFHAction {
 	kActionNone,
-	kActionExit,
+	kActionQuit,
+	kActionSkipVideo,
+	kActionSkipSong,
+	kActionSkipSongAndIntro,
 	kActionSave,
 	kActionLoad,
 	kActionMoveUp,
@@ -279,7 +282,135 @@ enum EFHAction {
 	kActionMoveDownRight,
 	kActionCharacter1Status,
 	kActionCharacter2Status,
-	kActionCharacter3Status
+	kActionCharacter3Status,
+	kActionYes,
+	kActionNo,
+	kActionCharacter1,
+	kActionCharacter2,
+	kActionCharacter3,
+	kActionCancelCharacterSelection,
+	kActionStartFight,
+	kActionLeave,
+	kActionStatus,
+	kActionTalk,
+	kActionAttack,
+	kActionDefend,
+	kActionHide,
+	kActionRun,
+	kActionTeamStatus,
+	kActionTerrain,
+	kActionEnemy1,
+	kActionEnemy2,
+	kActionEnemy3,
+	kActionEnemy4,
+	kActionEnemy5,
+	kActionCancelEnemySelection,
+	kActionreset,
+	kActionExitStatusMenu,
+	kActionActive,
+	kActionDrop,
+	kActionEquip,
+	kActionGive,
+	kActionInfo,
+	kActionPassive,
+	kActionTrade,
+	kActionUse,
+	kActionSelect,
+	kActionScrollDown,
+	kActionScrollUp,
+	kActionExitSubMenu,
+	kActionOption1,
+	kActionOption2,
+	kActionOption3,
+	kActionOption4,
+	kActionOption5,
+	kActionOption6,
+	kActionOption7,
+	kActionOption8,
+	kActionOption9,
+	kActionOption10,
+	kActionOption11,
+	kActionOption12,
+	kActionOption13,
+	kActionOption14,
+	kActionSound13,
+	kActionSound14,
+	kActionSound15,
+	kActionSound5,
+	kActionSound10,
+	kActionSound9,
+	kActionSound16,
+};
+
+struct EfhSelectionAction {
+	EFHAction _action;
+	int8 _id;
+};
+
+static const EfhSelectionAction _efhEnemySelectionCodes[] = {
+	{ kActionEnemy1, 0 },
+	{ kActionEnemy2, 1 },
+	{ kActionEnemy3, 2 },
+	{ kActionEnemy4, 3 },
+	{ kActionEnemy5, 4 },
+};
+
+static const EfhSelectionAction _efhTeamSelectionCodes[] = {
+	{ kActionCharacter1, 0 },
+	{ kActionCharacter2, 1 },
+	{ kActionCharacter3, 2 },
+};
+
+static const EfhSelectionAction _efhStatusMenuSubMenuCodes[] = {
+	{ kActionOption1, 0 },
+	{ kActionOption2, 1 },
+	{ kActionOption3, 2 },
+	{ kActionOption4, 3 },
+	{ kActionOption5, 4 },
+	{ kActionOption6, 5 },
+	{ kActionOption7, 6 },
+	{ kActionOption8, 7 },
+	{ kActionOption9, 8 },
+	{ kActionOption10, 9 },
+	{ kActionOption11, 10 },
+	{ kActionOption12, 11 },
+	{ kActionOption13, 12 },
+	{ kActionOption14, 13 },
+};
+
+enum EfhKeymapCode {
+	kKeymapDefault,
+	kKeymapMenu,
+	kKeymapSkipVideo,
+	kKeymapSkipSong,
+	kKeymapStatusMenu,
+	kKeymapStatusMenuNavigation,
+	kKeymapStatusMenuSubMenu,
+	kKeymapInteraction,
+	kKeymapFight,
+	kKeymapCharacterSelection,
+	kKeymapEnemySelection,
+	kKeymapDeathMenu,
+};
+
+struct EfhKeymap {
+	EfhKeymapCode _keymap;
+	Common::String _id;
+};
+
+static const EfhKeymap _efhKeymaps[] = {
+	{ kKeymapDefault, "efh-default" },
+	{ kKeymapMenu, "menu" },
+	{ kKeymapSkipVideo, "skip-video" },
+	{ kKeymapSkipSong, "skip-song" },
+	{ kKeymapStatusMenu, "status-menu" },
+	{ kKeymapStatusMenuNavigation, "status-menu-navigation" },
+	{ kKeymapStatusMenuSubMenu, "status-menu-submenu" },
+	{ kKeymapInteraction, "interaction" },
+	{ kKeymapFight, "fight" },
+	{ kKeymapCharacterSelection, "character-selection" },
+	{ kKeymapEnemySelection, "enemy-selection" },
+	{ kKeymapDeathMenu, "death-menu" },
 };
 
 class EfhEngine : public Engine {
@@ -316,7 +447,6 @@ private:
 	Common::Platform _platform;
 	int _loadSaveSlot;
 	bool _saveAuthorized;
-	Common::CustomEventType _customAction = kActionNone;
 
 	void initialize();
 	void playIntro();
@@ -515,7 +645,7 @@ private:
 	// Sound
 	void songDelay(int delay);
 	void playNote(int frequencyIndex, int totalDelay);
-	Common::KeyCode playSong(uint8 *buffer);
+	Common::CustomEventType playSong(uint8 *buffer);
 	void generateSound1(int lowFreq, int highFreq, int duration);
 	void generateSound2(int startFreq, int endFreq, int speed);
 	void generateSound3();
@@ -531,13 +661,14 @@ private:
 	void loadImageSet(int16 imageSetId, uint8 *buffer, uint8 **subFilesArray, uint8 *destBuffer);
 	uint32 uncompressBuffer(uint8 *compressedBuf, uint8 *destBuf);
 	int16 getRandom(int16 maxVal);
-	Common::KeyCode getLastCharAfterAnimCount(int16 delay, bool waitForTTS = true);
-	Common::KeyCode getInput(int16 delay);
-	Common::KeyCode waitForKey();
-	Common::KeyCode handleAndMapInput(bool animFl);
+	Common::CustomEventType getLastCharAfterAnimCount(int16 delay, bool waitForTTS = true);
+	Common::CustomEventType getInput(int16 delay);
+	Common::CustomEventType waitForKey();
+	Common::CustomEventType handleAndMapInput(bool animFl);
 	bool getValidationFromUser();
 	uint32 ROR(uint32 val, uint8 shiftVal);
 	Common::String getArticle(int pronoun);
+	void setKeymap(EfhKeymapCode keymapCode);
 
 	// Actions
 	void handleActionSave();
diff --git a/engines/efh/fight.cpp b/engines/efh/fight.cpp
index 26c219cb7cc..dd271f7d4a5 100644
--- a/engines/efh/fight.cpp
+++ b/engines/efh/fight.cpp
@@ -1050,29 +1050,34 @@ bool EfhEngine::getTeamAttackRoundPlans() {
 		retVal = true;
 		do {
 			drawCombatScreen(_teamChar[charId]._id, false, true);
-			switch (handleAndMapInput(true)) {
-			case Common::KEYCODE_a: // Attack
+
+			setKeymap(kKeymapFight);
+			Common::CustomEventType input = handleAndMapInput(true);
+			setKeymap(kKeymapDefault);
+
+			switch (input) {
+			case kActionAttack: // Attack
 				sayText("Attack", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_teamChar[charId]._lastAction = 'A';
 				_teamChar[charId]._nextAttack = determineTeamTarget(_teamChar[charId]._id, 9, true);
 				if (_teamChar[charId]._nextAttack == -1)
 					_teamChar[charId]._lastAction = 0;
 				break;
-			case Common::KEYCODE_d: // Defend
+			case kActionDefend: // Defend
 				sayText("Defend", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_teamChar[charId]._lastAction = 'D';
 				break;
-			case Common::KEYCODE_h: // Hide
+			case kActionHide: // Hide
 				sayText("Hide", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_teamChar[charId]._lastAction = 'H';
 				break;
-			case Common::KEYCODE_r: // Run
+			case kActionRun: // Run
 				sayText("Run", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				for (int counter2 = 0; counter2 < _teamSize; ++counter2) {
 					_teamChar[counter2]._lastAction = 'R';
 				}
 				return true;
-			case Common::KEYCODE_s: { // Status
+			case kActionTeamStatus: { // Status
 				sayText("Status", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				_sayMenu = true;
 				int16 lastInvId = handleStatusMenu(2, _teamChar[charId]._id);
@@ -1134,7 +1139,7 @@ bool EfhEngine::getTeamAttackRoundPlans() {
 				}
 
 			} break;
-			case Common::KEYCODE_t: // Terrain
+			case kActionTerrain: // Terrain
 				redrawScreenForced();
 				sayText("Terrain", kNoRestriction, Common::TextToSpeechManager::INTERRUPT);
 				waitForKey();
@@ -1699,23 +1704,21 @@ int16 EfhEngine::selectMonsterGroup() {
 
 	int16 retVal = -1;
 
+	setKeymap(kKeymapEnemySelection);
+
 	while (retVal == -1 && !shouldQuit()) {
-		Common::KeyCode input = handleAndMapInput(true);
-		switch (input) {
-		case Common::KEYCODE_ESCAPE:
+		Common::CustomEventType input = handleAndMapInput(true);
+		if (input == kActionCancelEnemySelection) {
 			retVal = 27;
-			break;
-		case Common::KEYCODE_a:
-		case Common::KEYCODE_b:
-		case Common::KEYCODE_c:
-		case Common::KEYCODE_d:
-		case Common::KEYCODE_e:
-			retVal = input - Common::KEYCODE_a;
-			if (_teamMonster[retVal]._id == -1)
-				retVal = -1;
-			break;
-		default:
-			break;
+		} else {
+			for (int i = 0; i < ARRAYSIZE(_efhEnemySelectionCodes); ++i) {
+				if (input == _efhEnemySelectionCodes[i]._action) {
+					retVal = _efhEnemySelectionCodes[i]._id;
+					if (_teamMonster[retVal]._id == -1)
+						retVal = -1;
+					break;
+				}
+			}
 		}
 	}
 
@@ -1725,6 +1728,8 @@ int16 EfhEngine::selectMonsterGroup() {
 		sayText(Common::String::format("%c", retVal + Common::KEYCODE_a), kNoRestriction);
 	}
 
+	setKeymap(kKeymapDefault);
+
 	return retVal;
 }
 
diff --git a/engines/efh/menu.cpp b/engines/efh/menu.cpp
index 08e789dfea1..b802433f08c 100644
--- a/engines/efh/menu.cpp
+++ b/engines/efh/menu.cpp
@@ -21,6 +21,8 @@
 
 #include "efh/efh.h"
 
+#include "backends/keymapper/keymapper.h"
+
 namespace Efh {
 
 int16 EfhEngine::displayBoxWithText(const Common::String &str, int16 menuType, int16 displayOption, bool displayTeamWindowFl, bool voiceText) {
@@ -141,21 +143,23 @@ bool EfhEngine::handleDeathMenu() {
 			displayFctFullScreen();
 	}
 
+	setKeymap(kKeymapDeathMenu);
+
 	for (bool found = false; !found && !shouldQuit();) {
-		Common::KeyCode input = waitForKey();
+		Common::CustomEventType input = waitForKey();
 		switch (input) {
-		case Common::KEYCODE_l:
+		case kActionLoad:
 			// If the user actually loads a savegame, it'll get _saveAuthorized from the savegame (always true) and will set 'found' to true.
 			// If 'found' remains false, it means the user cancelled the loading and still needs to take a decision
 			// Original is calling loadEfhGame() because there's only one savegame, so it's not ambiguous
 			loadGameDialog();
 			found = _saveAuthorized;
 			break;
-		case Common::KEYCODE_q:
+		case kActionQuit:
 			quitGame();
 			return true;
 			break;
-		case Common::KEYCODE_r:
+		case kActionreset:
 			loadEfhGame();
 			resetGame();
 			found = true;
@@ -169,6 +173,8 @@ bool EfhEngine::handleDeathMenu() {
 		}
 	}
 
+	setKeymap(kKeymapDefault);
+
 	displayAnimFrames(0xFE, true);
 	return false;
 }
@@ -419,7 +425,7 @@ void EfhEngine::displayCharacterInformationOrSkills(int16 curMenuLine, int16 cha
 	buffer = "Name: " + buffer;
 	setTextPos(146, 27);
 	displayStringAtTextPos(buffer);
-	
+
 	sayText(buffer, kMenu);
 
 	if (_menuItemCounter <= 0) {
@@ -593,6 +599,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 	_statusMenuActive = true;
 	_menuDepth = 0;
 
+	Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
+
 	displayWindowAndStatusMenu(charId, windowId, menuId, curMenuLine);
 
 	for (;;) {
@@ -601,47 +609,52 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 		else
 			windowId = kEfhMenuEquip;
 
+		keymapper->disableAllGameKeymaps();
+		keymapper->getKeymap("status-menu-navigation")->setEnabled(true);
+		if (_menuDepth == 0)
+			keymapper->getKeymap("status-menu")->setEnabled(true);
+		else
+			keymapper->getKeymap("status-menu-submenu")->setEnabled(true);
 		do {
-			Common::KeyCode input = handleAndMapInput(false);
+			Common::CustomEventType input = handleAndMapInput(false);
 			if (_menuDepth == 0) {
 				switch (input) {
-				case Common::KEYCODE_a:
+				case kActionActive:
 					windowId = kEfhMenuActive;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_d:
+				case kActionDrop:
 					windowId = kEfhMenuDrop;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_e:
+				case kActionEquip:
 					windowId = kEfhMenuEquip;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_g:
+				case kActionGive:
 					windowId = kEfhMenuGive;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_i:
+				case kActionInfo:
 					windowId = kEfhMenuInfo;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_ESCAPE:
-				case Common::KEYCODE_l:
+				case kActionExitStatusMenu:
 					stopTextToSpeech();
 					windowId = kEfhMenuLeave;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_p:
+				case kActionPassive:
 					windowId = kEfhMenuPassive;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_t:
+				case kActionTrade:
 					windowId = kEfhMenuTrade;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
-				case Common::KEYCODE_u:
+				case kActionUse:
 					windowId = kEfhMenuUse;
-					input = Common::KEYCODE_RETURN;
+					input = kActionSelect;
 					break;
 				default:
 					debugC(9, kDebugEngine, "handleStatusMenu - unhandled keys");
@@ -653,17 +666,18 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 				}
 			} else if (_menuDepth == 1) {
 				// in the sub-menus, only a list of selectable items is displayed
-				if (input >= Common::KEYCODE_a && input <= Common::KEYCODE_z) {
-					int16 var8 = input - Common::KEYCODE_a;
-					if (var8 < _menuItemCounter) {
-						curMenuLine = var8;
-						input = Common::KEYCODE_RETURN;
+				for (int i = 0; i < ARRAYSIZE(_efhStatusMenuSubMenuCodes); ++i) {
+					if (input == _efhStatusMenuSubMenuCodes[i]._action) {
+						if (_efhStatusMenuSubMenuCodes[i]._id < _menuItemCounter) {
+							curMenuLine = _efhStatusMenuSubMenuCodes[i]._id;
+							input = kActionSelect;
+						}
 					}
 				}
 			}
 
 			switch (input) {
-			case Common::KEYCODE_RETURN:
+			case kActionSelect:
 				// case 0xFA: Joystick button 1
 				if (_menuDepth == 0) {
 					menuId = windowId;
@@ -673,6 +687,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 						_sayMenu = true;
 						_menuDepth = 1;
 						curMenuLine = 0;
+						keymapper->getKeymap("status-menu")->setEnabled(false);
+						keymapper->getKeymap("status-menu-submenu")->setEnabled(true);
 					}
 				} else if (_menuDepth == 1) {
 					if (_menuItemCounter == 0) {
@@ -681,27 +697,25 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 						menuId = kEfhMenuInvalid;
 						_sayMenu = true;
 						prepareStatusMenu(windowId, menuId, curMenuLine, charId, true);
+						keymapper->getKeymap("status-menu-submenu")->setEnabled(false);
+						keymapper->getKeymap("status-menu")->setEnabled(true);
 					} else {
 						selectedLine = curMenuLine;
 						selectionDoneFl = true;
 					}
 				}
 				break;
-			case Common::KEYCODE_ESCAPE:
+			case kActionExitSubMenu:
 				_menuDepth = 0;
 				curMenuLine = -1;
 				menuId = kEfhMenuInvalid;
 				stopTextToSpeech();
 				_sayMenu = true;
 				prepareStatusMenu(windowId, menuId, curMenuLine, charId, true);
+				keymapper->getKeymap("status-menu-submenu")->setEnabled(false);
+				keymapper->getKeymap("status-menu")->setEnabled(true);
 				break;
-			case Common::KEYCODE_2:
-			case Common::KEYCODE_6:
-			// Added for ScummVM
-			case Common::KEYCODE_DOWN:
-			case Common::KEYCODE_RIGHT:
-			case Common::KEYCODE_KP2:
-			case Common::KEYCODE_KP6:
+			case kActionScrollDown:
 				// Original checks joystick axis: case 0xCC, 0xCF
 				if (_menuDepth == 0) {
 					if (++windowId > kEfhMenuLeave)
@@ -714,13 +728,7 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 					}
 				}
 				break;
-			case Common::KEYCODE_4:
-			case Common::KEYCODE_8:
-			// Added for ScummVM
-			case Common::KEYCODE_LEFT:
-			case Common::KEYCODE_UP:
-			case Common::KEYCODE_KP4:
-			case Common::KEYCODE_KP8:
+			case kActionScrollUp:
 				// Original checks joystick axis: case 0xC7, 0xCA
 				if (_menuDepth == 0) {
 					if (--windowId < kEfhMenuEquip)
@@ -741,6 +749,8 @@ int16 EfhEngine::handleStatusMenu(int16 gameMode, int16 charId) {
 
 		} while (!selectionDoneFl && !shouldQuit()); // Loop until a menu entry is confirmed by the user by pressing the enter key
 
+		setKeymap(kKeymapDefault);
+
 		bool validationFl = true;
 
 		int16 objectId;
diff --git a/engines/efh/metaengine.cpp b/engines/efh/metaengine.cpp
index 14e9da986a5..7b07e0c1b95 100644
--- a/engines/efh/metaengine.cpp
+++ b/engines/efh/metaengine.cpp
@@ -224,97 +224,476 @@ bool EfhMetaEngine::removeSaveState(const char *target, int slot) const {
 	return g_system->getSavefileManager()->removeSavefile(fileName);
 }
 
+struct EfhSubMenuOption {
+	EFHAction _action;
+	const char *_id;
+	const char *_inputKey;
+	const char *_desc;
+};
+
+static const EfhSubMenuOption _efhSubMenuOptions[] = {
+	{ kActionOption1, "OPTION1", "a", _s("Select option 1") },
+	{ kActionOption2, "OPTION2", "b", _s("Select option 2") },
+	{ kActionOption3, "OPTION3", "c", _s("Select option 3") },
+	{ kActionOption4, "OPTION4", "d", _s("Select option 4") },
+	{ kActionOption5, "OPTION5", "e", _s("Select option 5") },
+	{ kActionOption6, "OPTION6", "f", _s("Select option 6") },
+	{ kActionOption7, "OPTION7", "g", _s("Select option 7") },
+	{ kActionOption8, "OPTION8", "h", _s("Select option 8") },
+	{ kActionOption9, "OPTION9", "i", _s("Select option 9") },
+	{ kActionOption10, "OPTION10", "j", _s("Select option 10") },
+	{ kActionOption11, "OPTION11", "k", _s("Select option 11") },
+	{ kActionOption12, "OPTION12", "l", _s("Select option 12") },
+	{ kActionOption13, "OPTION13", "m", _s("Select option 13") },
+	{ kActionOption14, "OPTION14", "n", _s("Select option 14") },
+
+	{ kActionNone, nullptr, nullptr, nullptr }
+};
+
 Common::KeymapArray EfhMetaEngine::initKeymaps(const char *target) const {
 	using namespace Common;
 
-	Keymap *keymap = new Keymap(Keymap::kKeymapTypeGame, "efh", _("Game keymappings"));
+	Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "efh-default", _("Default keymappings"));
+	Keymap *menuKeymap = new Keymap(Keymap::kKeymapTypeGame, "menu", _("Menu keymappings"));
+	Keymap *quitKeymap = new Keymap(Keymap::kKeymapTypeGame, "efh-quit", _("Quit keymappings"));
+	Keymap *skipVideoKeymap = new Keymap(Keymap::kKeymapTypeGame, "skip-video", _("Skip video keymappings"));
+	Keymap *skipSongKeymap = new Keymap(Keymap::kKeymapTypeGame, "skip-song", _("Skip song keymappings"));
+	Keymap *statusMenuNavigationKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu-navigation", _("Status menu navigation keymappings"));
+	Keymap *statusMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu", _("Status menu keymappings"));
+	Keymap *statusMenuSubMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "status-menu-submenu", _("Status menu submenu keymappings"));
+	Keymap *interactionKeymap = new Keymap(Keymap::kKeymapTypeGame, "interaction", _("Interaction keymappings"));
+	Keymap *fightKeymap = new Keymap(Keymap::kKeymapTypeGame, "fight", _("Fight keymappings"));
+	Keymap *characterSelectionKeymap = new Keymap(Keymap::kKeymapTypeGame, "character-selection", _("Character selection keymappings"));
+	Keymap *enemySelectionKeymap = new Keymap(Keymap::kKeymapTypeGame, "enemy-selection", _("Enemy selection keymappings"));
+	Keymap *deathMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "death-menu", _("Death menu keymappings"));
 
 	Action *act;
 
-	act = new Action(kStandardActionLeftClick, _("Left click"));
-	act->setLeftClickEvent();
-	act->addDefaultInputMapping("MOUSE_LEFT");
-	act->addDefaultInputMapping("JOY_A");
-	keymap->addAction(act);
-
-	act = new Action(kStandardActionRightClick, _("Right click"));
-	act->setRightClickEvent();
-	act->addDefaultInputMapping("MOUSE_RIGHT");
-	act->addDefaultInputMapping("JOY_B");
-	keymap->addAction(act);
-
 	act = new Action(kStandardActionSave, _("Save game"));
 	act->setCustomEngineActionEvent(kActionSave);
 	act->addDefaultInputMapping("F5");
-	act->addDefaultInputMapping("JOY_LEFT_SHOULDER");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("C+s");
+	act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
+	engineKeymap->addAction(act);
 
 	act = new Action(kStandardActionLoad, _("Load game"));
 	act->setCustomEngineActionEvent(kActionLoad);
 	act->addDefaultInputMapping("F7");
-	act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("C+l");
+	act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEUP", _("Move up"));
 	act->setCustomEngineActionEvent(kActionMoveUp);
 	act->addDefaultInputMapping("UP");
+	act->addDefaultInputMapping("KP8");
 	act->addDefaultInputMapping("JOY_UP");
-	keymap->addAction(act);
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEDOWN", _("Move down"));
 	act->setCustomEngineActionEvent(kActionMoveDown);
 	act->addDefaultInputMapping("DOWN");
+	act->addDefaultInputMapping("KP2");
 	act->addDefaultInputMapping("JOY_DOWN");
-	keymap->addAction(act);
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVELEFT", _("Move left"));
 	act->setCustomEngineActionEvent(kActionMoveLeft);
 	act->addDefaultInputMapping("LEFT");
+	act->addDefaultInputMapping("KP4");
 	act->addDefaultInputMapping("JOY_LEFT");
-	keymap->addAction(act);
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVERIGHT", _("Move right"));
 	act->setCustomEngineActionEvent(kActionMoveRight);
 	act->addDefaultInputMapping("RIGHT");
+	act->addDefaultInputMapping("KP6");
 	act->addDefaultInputMapping("JOY_RIGHT");
-	keymap->addAction(act);
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEUPLEFT", _("Move up-left"));
 	act->setCustomEngineActionEvent(kActionMoveUpLeft);
 	act->addDefaultInputMapping("HOME");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("KP7");
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEUPRIGHT", _("Move up-right"));
 	act->setCustomEngineActionEvent(kActionMoveUpRight);
 	act->addDefaultInputMapping("PAGEUP");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("KP9");
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEDOWNLEFT", _("Move down-left"));
 	act->setCustomEngineActionEvent(kActionMoveDownLeft);
 	act->addDefaultInputMapping("END");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("KP1");
+	engineKeymap->addAction(act);
 
 	act = new Action("MOVEDOWNRIGHT", _("Move down-right"));
 	act->setCustomEngineActionEvent(kActionMoveDownRight);
 	act->addDefaultInputMapping("PAGEDOWN");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("KP3");
+	engineKeymap->addAction(act);
 
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
 	act = new Action("CHARACTER1STATUS", _("Character 1 status"));
 	act->setCustomEngineActionEvent(kActionCharacter1Status);
+	act->addDefaultInputMapping("1");
 	act->addDefaultInputMapping("F1");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("JOY_A");
+	engineKeymap->addAction(act);
 
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
 	act = new Action("CHARACTER2STATUS", _("Character 2 status"));
 	act->setCustomEngineActionEvent(kActionCharacter2Status);
+	act->addDefaultInputMapping("2");
 	act->addDefaultInputMapping("F2");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("JOY_X");
+	engineKeymap->addAction(act);
 
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
 	act = new Action("CHARACTER3STATUS", _("Character 3 status"));
 	act->setCustomEngineActionEvent(kActionCharacter3Status);
+	act->addDefaultInputMapping("3");
 	act->addDefaultInputMapping("F3");
-	keymap->addAction(act);
+	act->addDefaultInputMapping("JOY_Y");
+	engineKeymap->addAction(act);
+
+	act = new Action("YES", _("Yes"));
+	act->setCustomEngineActionEvent(kActionYes);
+	act->addDefaultInputMapping("y");
+	act->addDefaultInputMapping("JOY_A");
+	menuKeymap->addAction(act);
+
+	act = new Action("NO", _("No"));
+	act->setCustomEngineActionEvent(kActionNo);
+	act->addDefaultInputMapping("JOY_B");
+	menuKeymap->addAction(act);
+
+	act = new Action("QUIT", _("Quit game"));
+	act->setCustomEngineActionEvent(kActionQuit);
+	act->addDefaultInputMapping("C+q");
+	act->addDefaultInputMapping("C+x");
+	quitKeymap->addAction(act);
+
+	act = new Action("SKIP", _("Skip"));
+	act->setCustomEngineActionEvent(kActionSkipVideo);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("JOY_A");
+	skipVideoKeymap->addAction(act);
+
+	act = new Action("SKIPSONG", _("Skip song"));
+	act->setCustomEngineActionEvent(kActionSkipSong);
+	act->addDefaultInputMapping("RETURN");
+	act->addDefaultInputMapping("JOY_A");
+	skipSongKeymap->addAction(act);
+
+	act = new Action("SKIPSONGANDINTRO", _("Skip song and intro"));
+	act->setCustomEngineActionEvent(kActionSkipSongAndIntro);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("JOY_B");
+	skipSongKeymap->addAction(act);
+
+	act = new Action("SELECT", _("Select"));
+	act->setCustomEngineActionEvent(kActionSelect);
+	act->addDefaultInputMapping("RETURN");
+	act->addDefaultInputMapping("JOY_A");
+	statusMenuNavigationKeymap->addAction(act);
+
+	act = new Action("SCROLLDOWN", _("Scroll down"));
+	act->setCustomEngineActionEvent(kActionScrollDown);
+	act->addDefaultInputMapping("DOWN");
+	act->addDefaultInputMapping("RIGHT");
+	act->addDefaultInputMapping("2");
+	act->addDefaultInputMapping("6");
+	act->addDefaultInputMapping("KP2");
+	act->addDefaultInputMapping("KP6");
+	act->addDefaultInputMapping("JOY_DOWN");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	statusMenuNavigationKeymap->addAction(act);
+
+	act = new Action("SCROLLUP", _("Scroll up"));
+	act->setCustomEngineActionEvent(kActionScrollUp);
+	act->addDefaultInputMapping("UP");
+	act->addDefaultInputMapping("LEFT");
+	act->addDefaultInputMapping("8");
+	act->addDefaultInputMapping("4");
+	act->addDefaultInputMapping("KP8");
+	act->addDefaultInputMapping("KP4");
+	act->addDefaultInputMapping("JOY_UP");
+	act->addDefaultInputMapping("JOY_LEFT");
+	statusMenuNavigationKeymap->addAction(act);
+
+	act = new Action("ACTIVE", _("Active skills"));
+	act->setCustomEngineActionEvent(kActionActive);
+	act->addDefaultInputMapping("a");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("DROP", _("Drop"));
+	act->setCustomEngineActionEvent(kActionDrop);
+	act->addDefaultInputMapping("d");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("EQUIP", _("Equip"));
+	act->setCustomEngineActionEvent(kActionEquip);
+	act->addDefaultInputMapping("e");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("GIVE", _("Give"));
+	act->setCustomEngineActionEvent(kActionGive);
+	act->addDefaultInputMapping("g");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("INFO", _("Info"));
+	act->setCustomEngineActionEvent(kActionInfo);
+	act->addDefaultInputMapping("i");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("PASSIVE", _("Passive skills"));
+	act->setCustomEngineActionEvent(kActionPassive);
+	act->addDefaultInputMapping("p");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("TRADE", _("Trade"));
+	act->setCustomEngineActionEvent(kActionTrade);
+	act->addDefaultInputMapping("t");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("USE", _("Use"));
+	act->setCustomEngineActionEvent(kActionUse);
+	act->addDefaultInputMapping("u");
+	statusMenuKeymap->addAction(act);
+
+	act = new Action("EXIT", _("Exit status menu"));
+	act->setCustomEngineActionEvent(kActionExitStatusMenu);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("l");
+	act->addDefaultInputMapping("JOY_B");
+	statusMenuKeymap->addAction(act);
+
+	for (const EfhSubMenuOption *i = _efhSubMenuOptions; i->_id; ++i) {
+		act = new Action(i->_id, _(i->_desc));
+		act->setCustomEngineActionEvent(i->_action);
+		act->addDefaultInputMapping(i->_inputKey);
+		statusMenuSubMenuKeymap->addAction(act);
+	}
+
+	act = new Action("EXIT", _("Exit submenu"));
+	act->setCustomEngineActionEvent(kActionExitSubMenu);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("JOY_B");
+	statusMenuSubMenuKeymap->addAction(act);
+
+	act = new Action("STARTFIGHT", _("Attack"));
+	act->setCustomEngineActionEvent(kActionStartFight);
+	act->addDefaultInputMapping("a");
+	act->addDefaultInputMapping("JOY_UP");
+	interactionKeymap->addAction(act);
+
+	act = new Action("LEAVE", _("Leave"));
+	act->setCustomEngineActionEvent(kActionLeave);
+	act->addDefaultInputMapping("l");
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("JOY_DOWN");
+	interactionKeymap->addAction(act);
+
+	act = new Action("STATUS", _("Status"));
+	act->setCustomEngineActionEvent(kActionStatus);
+	act->addDefaultInputMapping("s");
+	act->addDefaultInputMapping("JOY_LEFT");
+	interactionKeymap->addAction(act);
+
+	act = new Action("TALK", _("Talk"));
+	act->setCustomEngineActionEvent(kActionTalk);
+	act->addDefaultInputMapping("t");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	interactionKeymap->addAction(act);
+
+	act = new Action("ATTACK", _("Attack"));
+	act->setCustomEngineActionEvent(kActionAttack);
+	act->addDefaultInputMapping("a");
+	act->addDefaultInputMapping("JOY_UP");
+	fightKeymap->addAction(act);
+
+	act = new Action("DEFEND", _("Defend"));
+	act->setCustomEngineActionEvent(kActionDefend);
+	act->addDefaultInputMapping("d");
+	act->addDefaultInputMapping("JOY_DOWN");
+	fightKeymap->addAction(act);
+
+	act = new Action("HIDE", _("Hide"));
+	act->setCustomEngineActionEvent(kActionHide);
+	act->addDefaultInputMapping("h");
+	act->addDefaultInputMapping("JOY_LEFT");
+	fightKeymap->addAction(act);
+
+	act = new Action("RUN", _("Run"));
+	act->setCustomEngineActionEvent(kActionRun);
+	act->addDefaultInputMapping("r");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	fightKeymap->addAction(act);
+
+	act = new Action("STATUS", _("Status"));
+	act->setCustomEngineActionEvent(kActionTeamStatus);
+	act->addDefaultInputMapping("s");
+	act->addDefaultInputMapping("JOY_Y");
+	fightKeymap->addAction(act);
+
+	// I18N: (Game name: Escape from hell) This action is used to view the terrain during a fight so that the player can see where they can move if they decide to run.
+	act = new Action("TERRAIN", _("View terrain"));
+	act->setCustomEngineActionEvent(kActionTerrain);
+	act->addDefaultInputMapping("t");
+	act->addDefaultInputMapping("JOY_X");
+	fightKeymap->addAction(act);
+
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
+	act = new Action("CHARACTER1", _("Select character 1"));
+	act->setCustomEngineActionEvent(kActionCharacter1);
+	act->addDefaultInputMapping("1");
+	act->addDefaultInputMapping("JOY_UP");
+	characterSelectionKeymap->addAction(act);
+
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
+	act = new Action("CHARACTER2", _("Select character 2"));
+	act->setCustomEngineActionEvent(kActionCharacter2);
+	act->addDefaultInputMapping("2");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	characterSelectionKeymap->addAction(act);
+
+	// I18N: (Game name: Escape from hell) Character is a hero in-game
+	act = new Action("CHARACTER3", _("Select character 3"));
+	act->setCustomEngineActionEvent(kActionCharacter3);
+	act->addDefaultInputMapping("3");
+	act->addDefaultInputMapping("JOY_DOWN");
+	characterSelectionKeymap->addAction(act);
+
+	act = new Action("CHARACTERSELECTIONCANCEL", _("Cancel character selection"));
+	act->setCustomEngineActionEvent(kActionCancelCharacterSelection);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("0");
+	act->addDefaultInputMapping("JOY_B");
+	characterSelectionKeymap->addAction(act);
+
+	act = new Action("ENEMY1", _("Select enemy 1"));
+	act->setCustomEngineActionEvent(kActionEnemy1);
+	act->addDefaultInputMapping("a");
+	act->addDefaultInputMapping("JOY_UP");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action("ENEMY2", _("Select enemy 2"));
+	act->setCustomEngineActionEvent(kActionEnemy2);
+	act->addDefaultInputMapping("b");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action("ENEMY3", _("Select enemy 3"));
+	act->setCustomEngineActionEvent(kActionEnemy3);
+	act->addDefaultInputMapping("c");
+	act->addDefaultInputMapping("JOY_DOWN");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action("ENEMY4", _("Select enemy 4"));
+	act->setCustomEngineActionEvent(kActionEnemy4);
+	act->addDefaultInputMapping("d");
+	act->addDefaultInputMapping("JOY_LEFT");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action("ENEMY5", _("Select enemy 5"));
+	act->setCustomEngineActionEvent(kActionEnemy5);
+	act->addDefaultInputMapping("e");
+	act->addDefaultInputMapping("JOY_Y");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action("CANCEL", _("Cancel enemy selection"));
+	act->setCustomEngineActionEvent(kActionCancelEnemySelection);
+	act->addDefaultInputMapping("ESCAPE");
+	act->addDefaultInputMapping("JOY_B");
+	enemySelectionKeymap->addAction(act);
+
+	act = new Action(kStandardActionLoad, _("Load game"));
+	act->setCustomEngineActionEvent(kActionLoad);
+	act->addDefaultInputMapping("l");
+	act->addDefaultInputMapping("JOY_LEFT");
+	deathMenuKeymap->addAction(act);
+
+	act = new Action(kStandardActionSave, _("Quit game"));
+	act->setCustomEngineActionEvent(kActionQuit);
+	act->addDefaultInputMapping("q");
+	act->addDefaultInputMapping("JOY_RIGHT");
+	deathMenuKeymap->addAction(act);
+
+	act = new Action("RESET", _("Restart game"));
+	act->setCustomEngineActionEvent(kActionreset);
+	act->addDefaultInputMapping("r");
+	act->addDefaultInputMapping("JOY_UP");
+	deathMenuKeymap->addAction(act);
+
+	if (ConfMan.getBool("dump_scripts")) {
+		act = new Action("SOUND13", _("Play sound type 13"));
+		act->setCustomEngineActionEvent(kActionSound13);
+		act->addDefaultInputMapping("4");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND14", _("Play sound type 14"));
+		act->setCustomEngineActionEvent(kActionSound14);
+		act->addDefaultInputMapping("5");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND15", _("Play sound type 15"));
+		act->setCustomEngineActionEvent(kActionSound15);
+		act->addDefaultInputMapping("6");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND5", _("Play sound type 5"));
+		act->setCustomEngineActionEvent(kActionSound5);
+		act->addDefaultInputMapping("7");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND10", _("Play sound type 10"));
+		act->setCustomEngineActionEvent(kActionSound10);
+		act->addDefaultInputMapping("8");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND9", _("Play sound type 9"));
+		act->setCustomEngineActionEvent(kActionSound9);
+		act->addDefaultInputMapping("9");
+		engineKeymap->addAction(act);
+
+		act = new Action("SOUND16", _("Play sound type 16"));
+		act->setCustomEngineActionEvent(kActionSound16);
+		act->addDefaultInputMapping("0");
+		engineKeymap->addAction(act);
+	}
 
-	return Keymap::arrayOf(keymap);
+	KeymapArray keymap(13);
+
+	keymap[0] = engineKeymap;
+	keymap[1] = menuKeymap;
+	keymap[2] = quitKeymap;
+	keymap[3] = skipVideoKeymap;
+	keymap[4] = skipSongKeymap;
+	keymap[5] = statusMenuNavigationKeymap;
+	keymap[6] = statusMenuKeymap;
+	keymap[7] = statusMenuSubMenuKeymap;
+	keymap[8] = interactionKeymap;
+	keymap[9] = fightKeymap;
+	keymap[10] = characterSelectionKeymap;
+	keymap[11] = enemySelectionKeymap;
+	keymap[12] = deathMenuKeymap;
+
+	menuKeymap->setEnabled(false);
+	skipVideoKeymap->setEnabled(false);
+	skipSongKeymap->setEnabled(false);
+	statusMenuNavigationKeymap->setEnabled(false);
+	statusMenuKeymap->setEnabled(false);
+	statusMenuSubMenuKeymap->setEnabled(false);
+	interactionKeymap->setEnabled(false);
+	fightKeymap->setEnabled(false);
+	characterSelectionKeymap->setEnabled(false);
+	enemySelectionKeymap->setEnabled(false);
+	deathMenuKeymap->setEnabled(false);
+
+	return keymap;
 }
 
 } // End of namespace Efh
diff --git a/engines/efh/sound.cpp b/engines/efh/sound.cpp
index e440f48f08b..e8e7cef628b 100644
--- a/engines/efh/sound.cpp
+++ b/engines/efh/sound.cpp
@@ -44,13 +44,13 @@ void EfhEngine::playNote(int frequencyIndex, int totalDelay) {
 	}
 }
 
-Common::KeyCode EfhEngine::playSong(uint8 *buffer) {
+Common::CustomEventType EfhEngine::playSong(uint8 *buffer) {
 	debugC(3, kDebugEngine, "playSong");
 
 	_speaker = new Audio::PCSpeaker();
 	_speaker->init();
 
-	Common::KeyCode inputChar = Common::KEYCODE_INVALID;
+	Common::CustomEventType inputAction = kActionNone;
 	int totalDelay = 0;
 
 	int8 stopFl;
@@ -83,10 +83,10 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) {
 
 		songDelay(10);
 		_system->getEventManager()->pollEvent(event);
-		if (event.type == Common::EVENT_KEYUP) {
-			inputChar = event.kbd.keycode;
+		if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
+			inputAction = event.customType;
 			// Hack, sometimes there's a ghost event after the 2nd note
-			if (inputChar == Common::KEYCODE_ESCAPE || inputChar == Common::KEYCODE_RETURN)
+			if (inputAction == kActionSkipSong || inputAction == kActionSkipSongAndIntro)
 				stopFl = 0;
 		}
 	} while (stopFl != 0 && !shouldQuit());
@@ -94,7 +94,7 @@ Common::KeyCode EfhEngine::playSong(uint8 *buffer) {
 	delete _speaker;
 	_speaker = nullptr;
 
-	return inputChar;
+	return inputAction;
 }
 
 void EfhEngine::generateSound1(int lowFreq, int highFreq, int duration) {
diff --git a/engines/efh/utils.cpp b/engines/efh/utils.cpp
index 78dd45b68d6..19de01d307f 100644
--- a/engines/efh/utils.cpp
+++ b/engines/efh/utils.cpp
@@ -24,6 +24,8 @@
 #include "common/random.h"
 #include "efh/efh.h"
 
+#include "backends/keymapper/keymapper.h"
+
 namespace Efh {
 
 void EfhEngine::decryptImpFile(bool techMapFl) {
@@ -134,17 +136,16 @@ int16 EfhEngine::getRandom(int16 maxVal) {
 	return 1 + _rnd->getRandomNumber(maxVal - 1);
 }
 
-Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay, bool waitForTTS) {
+Common::CustomEventType EfhEngine::getLastCharAfterAnimCount(int16 delay, bool waitForTTS) {
 	debugC(1, kDebugUtils, "getLastCharAfterAnimCount %d", delay);
 	if (delay == 0)
-		return Common::KEYCODE_INVALID;
+		return kActionNone;
 
-	Common::KeyCode lastChar = Common::KEYCODE_INVALID;
-	_customAction = kActionNone;
+	Common::CustomEventType action = kActionNone;
 
 	uint32 lastMs = _system->getMillis();
 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
-	while ((delay > 0 || (waitForTTS && ttsMan && ttsMan->isSpeaking())) && lastChar == Common::KEYCODE_INVALID && _customAction == kActionNone && !shouldQuit()) {
+	while ((delay > 0 || (waitForTTS && ttsMan && ttsMan->isSpeaking())) && action == kActionNone && !shouldQuit()) {
 		_system->delayMillis(20);
 		uint32 newMs = _system->getMillis();
 
@@ -154,24 +155,23 @@ Common::KeyCode EfhEngine::getLastCharAfterAnimCount(int16 delay, bool waitForTT
 			handleAnimations();
 		}
 
-		lastChar = handleAndMapInput(false);
+		action = handleAndMapInput(false);
 	}
 
 	if (waitForTTS) {
 		stopTextToSpeech();
 	}
 
-	return lastChar;
+	return action;
 }
 
-Common::KeyCode EfhEngine::getInput(int16 delay) {
+Common::CustomEventType EfhEngine::getInput(int16 delay) {
 	debugC(1, kDebugUtils, "getInput %d", delay);
 	if (delay == 0)
-		return Common::KEYCODE_INVALID;
-
-	Common::KeyCode lastChar = Common::KEYCODE_INVALID;
-	Common::KeyCode retVal = Common::KEYCODE_INVALID;
+		return kActionNone;
 
+	Common::CustomEventType lastAction = kActionNone;
+	Common::CustomEventType retVal = kActionNone;
 	uint32 lastMs = _system->getMillis();
 	Common::TextToSpeechManager *ttsMan = g_system->getTextToSpeechManager();
 	while ((delay > 0 || (ttsMan && ttsMan->isSpeaking())) && !shouldQuit()) {
@@ -184,21 +184,20 @@ Common::KeyCode EfhEngine::getInput(int16 delay) {
 			handleAnimations();
 		}
 
-		lastChar = handleAndMapInput(false);
-		if (lastChar != Common::KEYCODE_INVALID)
-			retVal = lastChar;
+		lastAction = handleAndMapInput(false);
+		if (lastAction != kActionNone)
+			retVal = lastAction;
 	}
-
 	return retVal;
 }
 
-Common::KeyCode EfhEngine::waitForKey() {
+Common::CustomEventType EfhEngine::waitForKey() {
 	debugC(1, kDebugUtils, "waitForKey");
-	Common::KeyCode retVal = Common::KEYCODE_INVALID;
+	Common::CustomEventType retVal = kActionNone;
 	Common::Event event;
 
 	uint32 lastMs = _system->getMillis();
-	while (retVal == Common::KEYCODE_INVALID && !shouldQuit()) {
+	while (retVal == kActionNone && !shouldQuit()) {
 		_system->delayMillis(20);
 		uint32 newMs = _system->getMillis();
 
@@ -208,39 +207,42 @@ Common::KeyCode EfhEngine::waitForKey() {
 		}
 
 		_system->getEventManager()->pollEvent(event);
-		if (event.type == Common::EVENT_KEYUP) {
-			if ((event.kbd.flags & Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_q)
+		switch (event.type) {
+		case Common::EVENT_KEYUP:
+			retVal = kActionNo;
+			break;
+		case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
+			if (event.customType == kActionQuit) {
 				quitGame();
-			if (!event.kbd.flags)
-				retVal = event.kbd.keycode;
+			} else
+				retVal = event.customType;
+			break;
+		default:
+			break;
 		}
 	}
 
 	return retVal;
 }
 
-Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) {
+Common::CustomEventType EfhEngine::handleAndMapInput(bool animFl) {
 	debugC(1, kDebugUtils, "handleAndMapInput %s", animFl ? "True" : "False");
 	// The original checks for the joystick input
 	Common::Event event;
 	_system->getEventManager()->pollEvent(event);
-	Common::KeyCode retVal = Common::KEYCODE_INVALID;
-	_customAction = kActionNone;
+	Common::CustomEventType retVal = kActionNone;
 
 	uint32 lastMs = _system->getMillis();
-	while (retVal == Common::KEYCODE_INVALID && _customAction == kActionNone && !shouldQuit()) {
+	while (retVal == kActionNone && !shouldQuit()) {
 		_system->getEventManager()->pollEvent(event);
 
-		if (event.type == Common::EVENT_KEYUP) {
-			if ((event.kbd.flags & Common::KBD_CTRL) && event.kbd.keycode == Common::KEYCODE_q)
+		if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_END) {
+			if (event.customType == kActionQuit)
 				quitGame();
-			if (!event.kbd.flags)
-				retVal = event.kbd.keycode;
+			else
+				retVal = event.customType;
 		}
 
-		if (event.type == Common::EVENT_CUSTOM_ENGINE_ACTION_START)
-			_customAction = event.customType;
-
 		if (animFl) {
 			_system->delayMillis(20);
 			uint32 newMs = _system->getMillis();
@@ -257,8 +259,14 @@ Common::KeyCode EfhEngine::handleAndMapInput(bool animFl) {
 
 bool EfhEngine::getValidationFromUser() {
 	debugC(1, kDebugUtils, "getValidationFromUser");
-	Common::KeyCode input = handleAndMapInput(true);
-	if (input == Common::KEYCODE_y) // or if joystick button 1
+
+	setKeymap(kKeymapMenu);
+
+	Common::CustomEventType action = handleAndMapInput(true);
+
+	setKeymap(kKeymapDefault);
+
+	if (action == kActionYes) // or if joystick button 1
 		return true;
 
 	return false;
@@ -274,4 +282,16 @@ Common::String EfhEngine::getArticle(int pronoun) {
 
 	return "";
 }
+
+void EfhEngine::setKeymap(EfhKeymapCode keymapCode) {
+	Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
+	keymapper->disableAllGameKeymaps();
+	keymapper->getKeymap("efh-quit")->setEnabled(true);
+	for(int i = 0;i < ARRAYSIZE(_efhKeymaps); ++i) {
+		if (_efhKeymaps[i]._keymap == keymapCode) {
+			keymapper->getKeymap(_efhKeymaps[i]._id)->setEnabled(true);
+			break;
+		}
+	}
+}
 } // End of namespace Efh




More information about the Scummvm-git-logs mailing list