[Scummvm-git-logs] scummvm master -> 7cc2f23da62928e8403cfebc5749ea7858d1e523

neuromancer noreply at scummvm.org
Sat Jun 13 10:20:11 UTC 2026


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

Summary:
60b2f4b28e HYPNO: improved gamepad support
7cc2f23da6 HYPNO: make sure keyboard navigation of level selection is correct


Commit: 60b2f4b28e217f1d9ff5b2a98ac95c6d3ac1f2e0
    https://github.com/scummvm/scummvm/commit/60b2f4b28e217f1d9ff5b2a98ac95c6d3ac1f2e0
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-13T12:20:01+02:00

Commit Message:
HYPNO: improved gamepad support

Changed paths:
    engines/hypno/arcade.cpp
    engines/hypno/hypno.cpp
    engines/hypno/hypno.h
    engines/hypno/metaengine.cpp
    engines/hypno/spider/arcade.cpp
    engines/hypno/wet/arcade.cpp


diff --git a/engines/hypno/arcade.cpp b/engines/hypno/arcade.cpp
index 4197c518711..6652223b902 100644
--- a/engines/hypno/arcade.cpp
+++ b/engines/hypno/arcade.cpp
@@ -19,8 +19,9 @@
  *
  */
 
-#include "common/tokenizer.h"
+#include "common/config-manager.h"
 #include "common/events.h"
+#include "common/tokenizer.h"
 #include "graphics/cursorman.h"
 #include "graphics/framelimiter.h"
 
@@ -182,6 +183,126 @@ void HypnoEngine::runAfterArcade(ArcadeShooting *arc) {}
 
 void HypnoEngine::pressedKey(const int keycode) {}
 
+void HypnoEngine::resetGamepadAim(const Common::Rect &mouseBox) {
+	Common::Point mousePos = g_system->getEventManager()->getMousePos();
+	_gamepadAimPosition.x = CLIP<int>(mousePos.x, mouseBox.left, mouseBox.right - 1);
+	_gamepadAimPosition.y = CLIP<int>(mousePos.y, mouseBox.top, mouseBox.bottom - 1);
+	_gamepadAxisX = 0;
+	_gamepadAxisY = 0;
+	_gamepadAimActive = false;
+	_gamepadAimLeft = false;
+	_gamepadAimDown = false;
+	_gamepadAimRight = false;
+	_gamepadAimUp = false;
+}
+
+void HypnoEngine::setGamepadAimActive(bool active) {
+	_gamepadAimActive = active;
+}
+
+bool HypnoEngine::isGamepadAimActive() const {
+	return _gamepadAimActive;
+}
+
+bool HypnoEngine::handleGamepadAimAction(const int action, bool pressed) {
+	switch (action) {
+	case kActionAimLeft:
+		_gamepadAimLeft = pressed;
+		break;
+	case kActionAimDown:
+		_gamepadAimDown = pressed;
+		break;
+	case kActionAimRight:
+		_gamepadAimRight = pressed;
+		break;
+	case kActionAimUp:
+		_gamepadAimUp = pressed;
+		break;
+	default:
+		return false;
+	}
+
+	if (pressed)
+		_gamepadAimActive = true;
+	return true;
+}
+
+bool HypnoEngine::handleGamepadAxisAction(const int action, int16 position) {
+	const int16 axisPosition = (position == Common::JOYAXIS_MIN) ? Common::JOYAXIS_MAX : position;
+
+	switch (action) {
+	case kActionAimLeft:
+		if (position == 0 && _gamepadAxisX > 0)
+			return true;
+		_gamepadAxisX = -axisPosition;
+		break;
+	case kActionAimDown:
+		if (position == 0 && _gamepadAxisY < 0)
+			return true;
+		_gamepadAxisY = axisPosition;
+		break;
+	case kActionAimRight:
+		if (position == 0 && _gamepadAxisX < 0)
+			return true;
+		_gamepadAxisX = axisPosition;
+		break;
+	case kActionAimUp:
+		if (position == 0 && _gamepadAxisY > 0)
+			return true;
+		_gamepadAxisY = -axisPosition;
+		break;
+	default:
+		return false;
+	}
+
+	return true;
+}
+
+bool HypnoEngine::updateGamepadAim(const Common::Rect &mouseBox) {
+	const int dpadX = (_gamepadAimRight ? 1 : 0) - (_gamepadAimLeft ? 1 : 0);
+	const int dpadY = (_gamepadAimDown ? 1 : 0) - (_gamepadAimUp ? 1 : 0);
+
+	int deltaX = 0;
+	int deltaY = 0;
+
+	if (dpadX || dpadY) {
+		const int kDigitalStep = 4;
+		deltaX = dpadX * kDigitalStep;
+		deltaY = dpadY * kDigitalStep;
+	} else {
+		const int deadZone = MAX(0, ConfMan.getInt("joystick_deadzone")) * 1000;
+		const int16 axisX = (ABS((int)_gamepadAxisX) <= deadZone) ? 0 : _gamepadAxisX;
+		const int16 axisY = (ABS((int)_gamepadAxisY) <= deadZone) ? 0 : _gamepadAxisY;
+		if (axisX || axisY) {
+			const int kAnalogMaxStep = 8;
+			deltaX = (int)axisX * kAnalogMaxStep / Common::JOYAXIS_MAX;
+			deltaY = (int)axisY * kAnalogMaxStep / Common::JOYAXIS_MAX;
+			if (axisX && deltaX == 0)
+				deltaX = (axisX > 0) ? 1 : -1;
+			if (axisY && deltaY == 0)
+				deltaY = (axisY > 0) ? 1 : -1;
+		}
+	}
+
+	if (deltaX == 0 && deltaY == 0)
+		return false;
+
+	if (!_gamepadAimActive) {
+		Common::Point mousePos = g_system->getEventManager()->getMousePos();
+		_gamepadAimPosition.x = CLIP<int>(mousePos.x, mouseBox.left, mouseBox.right - 1);
+		_gamepadAimPosition.y = CLIP<int>(mousePos.y, mouseBox.top, mouseBox.bottom - 1);
+	}
+
+	_gamepadAimActive = true;
+	Common::Point oldPos = _gamepadAimPosition;
+	_gamepadAimPosition.x = CLIP<int>(_gamepadAimPosition.x + deltaX, mouseBox.left, mouseBox.right - 1);
+	_gamepadAimPosition.y = CLIP<int>(_gamepadAimPosition.y + deltaY, mouseBox.top, mouseBox.bottom - 1);
+
+	if (oldPos.x != _gamepadAimPosition.x || oldPos.y != _gamepadAimPosition.y)
+		g_system->warpMouse(_gamepadAimPosition.x, _gamepadAimPosition.y);
+	return true;
+}
+
 void HypnoEngine::initSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
 void HypnoEngine::findNextSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
 
@@ -242,6 +363,8 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 	arc->mouseBox.moveTo(anchor.x, anchor.y);
 	_background = new MVideo(arc->backgroundVideo, anchor, false, false, false);
 
+	resetGamepadAim(arc->mouseBox);
+	mousePos = getPlayerPosition(false);
 	drawCursorArcade(mousePos);
 	playVideo(*_background);
 
@@ -292,6 +415,32 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 	limiter.startFrame();
 
 	Common::Event event;
+	auto handlePointerMotion = [&]() {
+		drawCursorArcade(mousePos);
+		if (mousePos.x >= arc->mouseBox.right - 1) {
+			g_system->warpMouse(arc->mouseBox.right - 1, mousePos.y);
+		} else if (mousePos.y < arc->mouseBox.top) { // Usually top is zero
+			g_system->warpMouse(mousePos.x, arc->mouseBox.top + 1);
+		} else if (mousePos.y >= arc->mouseBox.bottom - 1) {
+			g_system->warpMouse(mousePos.x, arc->mouseBox.bottom - 1);
+		} else if (mousePos.x <= 40 && offset.x < 0) {
+			for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
+				if (it->video && it->video->decoder)
+					it->video->position.x = it->video->position.x + 1;
+			}
+			offset.x = offset.x + 1;
+			needsUpdate = true;
+		} else if (mousePos.x >= 280 && offset.x > 320 - _background->decoder->getWidth()) {
+			for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
+				if (it->video && it->video->decoder)
+					it->video->position.x = it->video->position.x - 1;
+			}
+			offset.x = offset.x - 1;
+			needsUpdate = true;
+		}
+		_background->position.x = offset.x;
+	};
+
 	while (!shouldQuit()) {
 		if (_timerStarted) {
 			if (_countdown <= 0) {
@@ -303,8 +452,6 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 		}
 		needsUpdate = _background->decoder->needsUpdate();
 		while (g_system->getEventManager()->pollEvent(event)) {
-			mousePos = getPlayerPosition(false);
-
 			// Events
 			switch (event.type) {
 
@@ -312,54 +459,66 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 			case Common::EVENT_RETURN_TO_LAUNCHER:
 				break;
 			case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
-				pressedKey(event.customType);
-				if (event.customType == kActionPrimaryShoot)
+				mousePos = getPlayerPosition(false);
+				if (handleGamepadAimAction(event.customType, true)) {
+					needsUpdate = true;
+				} else if (event.customType == kActionPrimaryShoot) {
 					if (clickedPrimaryShoot(mousePos))
 						shootingPrimary = true;
+				} else if (event.customType == kActionSecondaryShoot) {
+					setRButtonUp(false);
+					if (clickedSecondaryShoot(mousePos))
+						shootingSecondary = true;
+				} else {
+					pressedKey(event.customType);
+				}
+				break;
+
+			case Common::EVENT_CUSTOM_ENGINE_ACTION_END:
+				if (handleGamepadAimAction(event.customType, false)) {
+					needsUpdate = true;
+				} else if (event.customType == kActionSecondaryShoot) {
+					setRButtonUp(true);
+					shootingSecondary = false;
+				}
+				break;
+
+			case Common::EVENT_CUSTOM_BACKEND_ACTION_AXIS:
+				if (handleGamepadAxisAction(event.customType, event.joystick.position))
+					needsUpdate = true;
 				break;
 
 			case Common::EVENT_KEYDOWN:
+				mousePos = getPlayerPosition(false);
 				pressedKey(event.kbd.keycode);
 				break;
 
 			case Common::EVENT_LBUTTONDOWN:
+				setGamepadAimActive(false);
+				mousePos = g_system->getEventManager()->getMousePos();
 				if (clickedPrimaryShoot(mousePos))
 					shootingPrimary = true;
 				break;
 
 			case Common::EVENT_RBUTTONDOWN:
+				setGamepadAimActive(false);
+				setRButtonUp(false);
+				mousePos = g_system->getEventManager()->getMousePos();
 				if (clickedSecondaryShoot(mousePos))
 					shootingSecondary = true;
 				break;
 
 			case Common::EVENT_RBUTTONUP:
+				setRButtonUp(true);
 				shootingSecondary = false;
 				break;
 
 			case Common::EVENT_MOUSEMOVE:
-				drawCursorArcade(mousePos);
-				if (mousePos.x >= arc->mouseBox.right-1) {
-					g_system->warpMouse(arc->mouseBox.right-1, mousePos.y);
-				} else if (mousePos.y < arc->mouseBox.top) { // Usually top is zero
-					g_system->warpMouse(mousePos.x, arc->mouseBox.top + 1);
-				} else if (mousePos.y >= arc->mouseBox.bottom-1) {
-					g_system->warpMouse(mousePos.x, arc->mouseBox.bottom-1);
-				} else if (mousePos.x <= 40 && offset.x < 0) {
-					for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
-						if (it->video && it->video->decoder)
-							it->video->position.x = it->video->position.x + 1;
-					}
-					offset.x = offset.x + 1;
-					needsUpdate = true;
-				} else if (mousePos.x >= 280 && offset.x > 320 - _background->decoder->getWidth()) {
-					for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
-						if (it->video && it->video->decoder)
-							it->video->position.x = it->video->position.x - 1;
-					}
-					offset.x = offset.x - 1;
-					needsUpdate = true;
-				}
-				_background->position.x = offset.x;
+				setGamepadAimActive(false);
+				mousePos = g_system->getEventManager()->getMousePos();
+				_gamepadAimPosition.x = CLIP<int>(mousePos.x, arc->mouseBox.left, arc->mouseBox.right - 1);
+				_gamepadAimPosition.y = CLIP<int>(mousePos.y, arc->mouseBox.top, arc->mouseBox.bottom - 1);
+				handlePointerMotion();
 				break;
 
 			default:
@@ -367,8 +526,14 @@ void HypnoEngine::runArcade(ArcadeShooting *arc) {
 			}
 		}
 
+		if (updateGamepadAim(arc->mouseBox)) {
+			mousePos = getPlayerPosition(false);
+			handlePointerMotion();
+			needsUpdate = true;
+		}
+
 		if (needsUpdate) {
-			getPlayerPosition(true);
+			mousePos = getPlayerPosition(true);
 			if (_background->decoder->getCurFrame() > firstFrame)
 				drawScreen();
 			updateScreen(*_background);
@@ -614,6 +779,8 @@ Common::Point HypnoEngine::computeTargetPosition(const Common::Point &mousePos)
 }
 
 Common::Point HypnoEngine::getPlayerPosition(bool needsUpdate) {
+	if (_gamepadAimActive)
+		return _gamepadAimPosition;
 	return g_system->getEventManager()->getMousePos();
 }
 
@@ -833,4 +1000,3 @@ void HypnoEngine::enableGameKeymaps() {
 }
 
 } // End of namespace Hypno
-
diff --git a/engines/hypno/hypno.cpp b/engines/hypno/hypno.cpp
index f12bba6a6c7..14826226562 100644
--- a/engines/hypno/hypno.cpp
+++ b/engines/hypno/hypno.cpp
@@ -94,6 +94,15 @@ HypnoEngine::HypnoEngine(OSystem *syst, const ADGameDescription *gd)
 	if (!Common::parseBool(ConfMan.get("subtitles"), _useSubtitles))
 		warning("Failed to parse bool from subtitles options");
 
+	_gamepadAimPosition = Common::Point(0, 0);
+	_gamepadAxisX = 0;
+	_gamepadAxisY = 0;
+	_gamepadAimActive = false;
+	_gamepadAimLeft = false;
+	_gamepadAimDown = false;
+	_gamepadAimRight = false;
+	_gamepadAimUp = false;
+
 	// Add quit level
 	Hotspot q(MakeMenu);
 	Action *a = new Quit();
diff --git a/engines/hypno/hypno.h b/engines/hypno/hypno.h
index 43f6d93bb77..ac7de039d2d 100644
--- a/engines/hypno/hypno.h
+++ b/engines/hypno/hypno.h
@@ -107,6 +107,11 @@ enum HYPNOActions {
 	kActionQuit,
 	kActionCredits,
 	kActionSelect,
+	kActionSecondaryShoot,
+	kActionAimLeft,
+	kActionAimDown,
+	kActionAimRight,
+	kActionAimUp,
 };
 
 class HypnoEngine;
@@ -316,6 +321,12 @@ public:
 	virtual void pressedKey(const int keycode);
 	virtual bool clickedPrimaryShoot(const Common::Point &mousePos);
 	virtual bool clickedSecondaryShoot(const Common::Point &mousePos);
+	void resetGamepadAim(const Common::Rect &mouseBox);
+	void setGamepadAimActive(bool active);
+	bool isGamepadAimActive() const;
+	bool handleGamepadAimAction(const int action, bool pressed);
+	bool handleGamepadAxisAction(const int action, int16 position);
+	bool updateGamepadAim(const Common::Rect &mouseBox);
 	virtual void drawShoot(const Common::Point &mousePos);
 	virtual bool shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary);
 	virtual void hitPlayer();
@@ -361,6 +372,14 @@ public:
 	bool _loseLevel;
 	bool _skipDefeatVideo;
 	bool _skipNextVideo;
+	Common::Point _gamepadAimPosition;
+	int16 _gamepadAxisX;
+	int16 _gamepadAxisY;
+	bool _gamepadAimActive;
+	bool _gamepadAimLeft;
+	bool _gamepadAimDown;
+	bool _gamepadAimRight;
+	bool _gamepadAimUp;
 
 	virtual void drawCursorArcade(const Common::Point &mousePos);
 	virtual void drawPlayer();
diff --git a/engines/hypno/metaengine.cpp b/engines/hypno/metaengine.cpp
index 4b3ce6f641a..0b75135dfe6 100644
--- a/engines/hypno/metaengine.cpp
+++ b/engines/hypno/metaengine.cpp
@@ -134,25 +134,84 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 	act = new Common::Action(kStandardActionLeftClick, _("Primary shoot"));
 	act->setLeftClickEvent();
 	act->addDefaultInputMapping("MOUSE_LEFT");
-	act->addDefaultInputMapping("JOY_A");
 	engineKeymap->addAction(act);
 
 	act = new Common::Action(kStandardActionRightClick, _("Secondary shoot"));
 	act->setRightClickEvent();
 	act->addDefaultInputMapping("MOUSE_RIGHT");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("PRIMARYSHOOT", _("Primary shoot"));
+	act->setCustomEngineActionEvent(kActionPrimaryShoot);
+	act->addDefaultInputMapping("JOY_A");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("SECONDARYSHOOT", _("Rapid fire / secondary action"));
+	act->setCustomEngineActionEvent(kActionSecondaryShoot);
 	act->addDefaultInputMapping("JOY_B");
+	act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("AIMLEFT", _("Aim left"));
+	act->setCustomEngineActionEvent(kActionAimLeft);
+	act->addDefaultInputMapping("JOY_LEFT");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("AIMDOWN", _("Aim down"));
+	act->setCustomEngineActionEvent(kActionAimDown);
+	act->addDefaultInputMapping("JOY_DOWN");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("AIMRIGHT", _("Aim right"));
+	act->setCustomEngineActionEvent(kActionAimRight);
+	act->addDefaultInputMapping("JOY_RIGHT");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("AIMUP", _("Aim up"));
+	act->setCustomEngineActionEvent(kActionAimUp);
+	act->addDefaultInputMapping("JOY_UP");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("STICKLEFT", _("Stick left"));
+	act->setCustomBackendActionAxisEvent(kActionAimLeft);
+	act->addDefaultInputMapping("JOY_LEFT_STICK_X-");
+	act->addDefaultInputMapping("JOY_RIGHT_STICK_X-");
+	act->addDefaultInputMapping("JOY_HAT_X-");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("STICKDOWN", _("Stick down"));
+	act->setCustomBackendActionAxisEvent(kActionAimDown);
+	act->addDefaultInputMapping("JOY_LEFT_STICK_Y+");
+	act->addDefaultInputMapping("JOY_RIGHT_STICK_Y+");
+	act->addDefaultInputMapping("JOY_HAT_Y+");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("STICKRIGHT", _("Stick right"));
+	act->setCustomBackendActionAxisEvent(kActionAimRight);
+	act->addDefaultInputMapping("JOY_LEFT_STICK_X+");
+	act->addDefaultInputMapping("JOY_RIGHT_STICK_X+");
+	act->addDefaultInputMapping("JOY_HAT_X+");
+	engineKeymap->addAction(act);
+
+	act = new Common::Action("STICKUP", _("Stick up"));
+	act->setCustomBackendActionAxisEvent(kActionAimUp);
+	act->addDefaultInputMapping("JOY_LEFT_STICK_Y-");
+	act->addDefaultInputMapping("JOY_RIGHT_STICK_Y-");
+	act->addDefaultInputMapping("JOY_HAT_Y-");
 	engineKeymap->addAction(act);
 
 	act = new Common::Action("SKIPINTRO", _("Skip intro"));
 	act->setCustomEngineActionEvent(kActionSkipIntro);
 	act->addDefaultInputMapping("ESCAPE");
-	act->addDefaultInputMapping("JOY_Y");
+	act->addDefaultInputMapping("JOY_B");
+	act->addDefaultInputMapping("JOY_START");
 	introKeymap->addAction(act);
 
 	act = new Common::Action("SKIPCUTSCENE", _("Skip cutscene"));
 	act->setCustomEngineActionEvent(kActionSkipCutscene);
 	act->addDefaultInputMapping("ESCAPE");
-	act->addDefaultInputMapping("JOY_Y");
+	act->addDefaultInputMapping("JOY_B");
+	act->addDefaultInputMapping("JOY_START");
 	cutsceneKeymap->addAction(act);
 
 	keymaps.push_back(engineKeymap);
@@ -172,7 +231,6 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 			act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
 			act->setCustomEngineActionEvent(kActionSkipLevel);
 			act->addDefaultInputMapping("c");
-			act->addDefaultInputMapping("JOY_X");
 			gameKeymap->addAction(act);
 		}
 
@@ -180,13 +238,12 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 		act = new Common::Action("KILLPLAYER", _("Kill player"));
 		act->setCustomEngineActionEvent(kActionKillPlayer);
 		act->addDefaultInputMapping("k");
-		act->addDefaultInputMapping("JOY_LEFT");
 		gameKeymap->addAction(act);
 
 		act = new Common::Action("PAUSE", _("Pause"));
 		act->setCustomEngineActionEvent(kActionPause);
 		act->addDefaultInputMapping("ESCAPE");
-		act->addDefaultInputMapping("JOY_UP");
+		act->addDefaultInputMapping("JOY_START");
 		gameKeymap->addAction(act);
 
 		act = new Common::Action("YES", _("Yes"));
@@ -270,7 +327,6 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 			act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
 			act->setCustomEngineActionEvent(kActionSkipLevel);
 			act->addDefaultInputMapping("c");
-			act->addDefaultInputMapping("JOY_X");
 			gameKeymap->addAction(act);
 		}
 
@@ -278,7 +334,12 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 		act = new Common::Action("KILLPLAYER", _("Kill player"));
 		act->setCustomEngineActionEvent(kActionKillPlayer);
 		act->addDefaultInputMapping("k");
-		act->addDefaultInputMapping("JOY_Y");
+		gameKeymap->addAction(act);
+
+		act = new Common::Action("PAUSE", _("Pause"));
+		act->setCustomEngineActionEvent(kActionPause);
+		act->addDefaultInputMapping("ESCAPE");
+		act->addDefaultInputMapping("JOY_START");
 		gameKeymap->addAction(act);
 
 		act = new Common::Action("LEFT", _("Move left"));
@@ -316,60 +377,86 @@ Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
 		act = new Common::Action("CREDITS", _("Show credits"));
 		act->setCustomEngineActionEvent(kActionCredits);
 		act->addDefaultInputMapping("c");
-		act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
 		gameKeymap->addAction(act);
 
 		act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
 		act->setCustomEngineActionEvent(kActionSkipLevel);
 		act->addDefaultInputMapping("s");
-		act->addDefaultInputMapping("JOY_X");
 		gameKeymap->addAction(act);
 
 		// I18N: (Game name: Wetlands) player refers to the users own character.
 		act = new Common::Action("KILLPLAYER", _("Kill player"));
 		act->setCustomEngineActionEvent(kActionKillPlayer);
 		act->addDefaultInputMapping("k");
-		act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
 		gameKeymap->addAction(act);
 
 		act = new Common::Action("LEFT", _("Move left"));
 		act->setCustomEngineActionEvent(kActionLeft);
 		act->allowKbdRepeats();
 		act->addDefaultInputMapping("LEFT");
-		act->addDefaultInputMapping("JOY_LEFT");
 		directionKeymap->addAction(act);
 
 		act = new Common::Action("DOWN", _("Move down"));
 		act->setCustomEngineActionEvent(kActionDown);
 		act->allowKbdRepeats();
 		act->addDefaultInputMapping("DOWN");
-		act->addDefaultInputMapping("JOY_DOWN");
 		directionKeymap->addAction(act);
 
 		act = new Common::Action("RIGHT", _("Move right"));
 		act->setCustomEngineActionEvent(kActionRight);
 		act->allowKbdRepeats();
 		act->addDefaultInputMapping("RIGHT");
-		act->addDefaultInputMapping("JOY_RIGHT");
 		directionKeymap->addAction(act);
 
 		act = new Common::Action("UP", _("Move up"));
 		act->setCustomEngineActionEvent(kActionUp);
 		act->allowKbdRepeats();
 		act->addDefaultInputMapping("UP");
-		act->addDefaultInputMapping("JOY_UP");
 		directionKeymap->addAction(act);
 
+		act = new Common::Action("MENULEFT", _("Menu left"));
+		act->setCustomEngineActionEvent(kActionLeft);
+		act->addDefaultInputMapping("LEFT");
+		act->addDefaultInputMapping("JOY_LEFT");
+		act->addDefaultInputMapping("JOY_LEFT_STICK_X-");
+		act->addDefaultInputMapping("JOY_HAT_X-");
+		menuKeymap->addAction(act);
+
+		act = new Common::Action("MENUDOWN", _("Menu down"));
+		act->setCustomEngineActionEvent(kActionDown);
+		act->addDefaultInputMapping("DOWN");
+		act->addDefaultInputMapping("JOY_DOWN");
+		act->addDefaultInputMapping("JOY_LEFT_STICK_Y+");
+		act->addDefaultInputMapping("JOY_HAT_Y+");
+		menuKeymap->addAction(act);
+
+		act = new Common::Action("MENURIGHT", _("Menu right"));
+		act->setCustomEngineActionEvent(kActionRight);
+		act->addDefaultInputMapping("RIGHT");
+		act->addDefaultInputMapping("JOY_RIGHT");
+		act->addDefaultInputMapping("JOY_LEFT_STICK_X+");
+		act->addDefaultInputMapping("JOY_HAT_X+");
+		menuKeymap->addAction(act);
+
+		act = new Common::Action("MENUUP", _("Menu up"));
+		act->setCustomEngineActionEvent(kActionUp);
+		act->addDefaultInputMapping("UP");
+		act->addDefaultInputMapping("JOY_UP");
+		act->addDefaultInputMapping("JOY_LEFT_STICK_Y-");
+		act->addDefaultInputMapping("JOY_HAT_Y-");
+		menuKeymap->addAction(act);
+
 		act = new Common::Action("SELECT", _("Select"));
 		act->setCustomEngineActionEvent(kActionSelect);
 		act->addDefaultInputMapping("RETURN");
+		act->addDefaultInputMapping("JOY_A");
 		act->addDefaultInputMapping("JOY_X");
 		menuKeymap->addAction(act);
 
 		act = new Common::Action("PAUSE", _("Pause"));
 		act->setCustomEngineActionEvent(kActionPause);
 		act->addDefaultInputMapping("ESCAPE");
-		act->addDefaultInputMapping("JOY_Y");
+		act->addDefaultInputMapping("JOY_START");
 		pauseKeymap->addAction(act);
 
 		keymaps.push_back(gameKeymap);
@@ -396,4 +483,3 @@ REGISTER_PLUGIN_DYNAMIC(HYPNO, PLUGIN_TYPE_ENGINE, HypnoMetaEngine);
 #else
 REGISTER_PLUGIN_STATIC(HYPNO, PLUGIN_TYPE_ENGINE, HypnoMetaEngine);
 #endif
-
diff --git a/engines/hypno/spider/arcade.cpp b/engines/hypno/spider/arcade.cpp
index 736ae2b4424..888040896b4 100644
--- a/engines/hypno/spider/arcade.cpp
+++ b/engines/hypno/spider/arcade.cpp
@@ -106,16 +106,18 @@ void SpiderEngine::pressedKey(const int keycode) {
 		return;
 	} else if (keycode == kActionKillPlayer) { // Added for testing
 		_health = 0;
-	} else if (keycode == kActionLeft) {
+	} else if (keycode == kActionPause) {
+		openMainMenuDialog();
+	} else if (keycode == kActionLeft && (_arcadeMode == "YC" || _arcadeMode == "YD")) {
 		_lastPlayerPosition = _currentPlayerPosition;
 		_currentPlayerPosition = kPlayerLeft;
-	} else if (keycode == kActionDown) {
+	} else if (keycode == kActionDown && (_arcadeMode == "YC" || _arcadeMode == "YD")) {
 		_lastPlayerPosition = _currentPlayerPosition;
 		_currentPlayerPosition = kPlayerBottom;
-	} else if (keycode == kActionRight) {
+	} else if (keycode == kActionRight && (_arcadeMode == "YC" || _arcadeMode == "YD")) {
 		_lastPlayerPosition = _currentPlayerPosition;
 		_currentPlayerPosition = kPlayerRight;
-	} else if (keycode == kActionUp) {
+	} else if (keycode == kActionUp && (_arcadeMode == "YC" || _arcadeMode == "YD")) {
 		_lastPlayerPosition = _currentPlayerPosition;
 		_currentPlayerPosition = kPlayerTop;
 	}
diff --git a/engines/hypno/wet/arcade.cpp b/engines/hypno/wet/arcade.cpp
index 8b68763d3f0..74be3622e4e 100644
--- a/engines/hypno/wet/arcade.cpp
+++ b/engines/hypno/wet/arcade.cpp
@@ -772,9 +772,12 @@ void WetEngine::pressedKey(const int keycode) {
 }
 
 Common::Point WetEngine::getPlayerPosition(bool needsUpdate) {
-	Common::Point mousePos = g_system->getEventManager()->getMousePos();
+	Common::Point mousePos = HypnoEngine::getPlayerPosition(false);
 	if (_arcadeMode == "YT") {
 		if (needsUpdate) {
+			if (isGamepadAimActive() && _c33PlayerDirection.empty())
+				_c33UseMouse = true;
+
 			if (!_c33UseMouse) {
 				disableCursor();
 				if (_c33PlayerDirection.size() == 0)
@@ -805,7 +808,7 @@ Common::Point WetEngine::getPlayerPosition(bool needsUpdate) {
 					diff.x = (diff.x / abs(diff.x)) * 10;
 
 				if (abs(diff.y) >= 10)
-					diff.y = (diff.x / abs(diff.x)) * 10;
+					diff.y = (diff.y / abs(diff.y)) * 10;
 
 				_c33PlayerPosition = _c33PlayerPosition + diff;
 
@@ -819,6 +822,8 @@ Common::Point WetEngine::getPlayerPosition(bool needsUpdate) {
 					drawImage(*_c33PlayerCursor[10], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
 			}
 		}
+		_c33PlayerPosition.x = CLIP<int>(_c33PlayerPosition.x, 0, _screenW - 1);
+		_c33PlayerPosition.y = CLIP<int>(_c33PlayerPosition.y, 0, _screenH - 1);
 		uint32 c = _compositeSurface->getPixel(_c33PlayerPosition.x, _c33PlayerPosition.y);
 		if (c >= 225 && c <= 231) {
 			if (!_infiniteHealthCheat)
@@ -827,7 +832,7 @@ Common::Point WetEngine::getPlayerPosition(bool needsUpdate) {
 		}
 		return _c33PlayerPosition;
 	}
-	return mousePos;
+	return HypnoEngine::getPlayerPosition(needsUpdate);
 }
 
 void WetEngine::drawCursorArcade(const Common::Point &mousePos) {


Commit: 7cc2f23da62928e8403cfebc5749ea7858d1e523
    https://github.com/scummvm/scummvm/commit/7cc2f23da62928e8403cfebc5749ea7858d1e523
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2026-06-13T12:20:01+02:00

Commit Message:
HYPNO: make sure keyboard navigation of level selection is correct

Changed paths:
    engines/hypno/wet/hard.cpp


diff --git a/engines/hypno/wet/hard.cpp b/engines/hypno/wet/hard.cpp
index 09dbb664748..9ff212713a9 100644
--- a/engines/hypno/wet/hard.cpp
+++ b/engines/hypno/wet/hard.cpp
@@ -91,6 +91,7 @@ void WetEngine::runLevelMenu(Code *code) {
 
 	Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
 	keymapper->getKeymap("game-shortcuts")->setEnabled(false);
+	keymapper->getKeymap("direction")->setEnabled(false);
 	keymapper->getKeymap("menu")->setEnabled(true);
 
 	while (!shouldQuit() && cont) {
@@ -137,6 +138,7 @@ void WetEngine::runLevelMenu(Code *code) {
 	}
 
 	keymapper->getKeymap("menu")->setEnabled(false);
+	keymapper->getKeymap("direction")->setEnabled(true);
 	keymapper->getKeymap("game-shortcuts")->setEnabled(true);
 
 	menu->free();
@@ -276,6 +278,7 @@ void WetEngine::runMainMenu(Code *code) {
 
 	keymapper->getKeymap("game-shortcuts")->setEnabled(false);
 	keymapper->getKeymap("pause")->setEnabled(false);
+	keymapper->getKeymap("direction")->setEnabled(false);
 	keymapper->getKeymap("menu")->setEnabled(true);
 
 	while (!shouldQuit() && cont) {
@@ -336,6 +339,7 @@ void WetEngine::runMainMenu(Code *code) {
 	}
 
 	keymapper->getKeymap("menu")->setEnabled(false);
+	keymapper->getKeymap("direction")->setEnabled(true);
 	keymapper->getKeymap("game-shortcuts")->setEnabled(true);
 	keymapper->getKeymap("pause")->setEnabled(true);
 




More information about the Scummvm-git-logs mailing list