Browse Source

Merge pull request #3866 from IvanSavenko/input_config

More configurable input settings
Ivan Savenko 1 year ago
parent
commit
45e35f357d

+ 41 - 14
client/eventsSDL/InputHandler.cpp

@@ -38,6 +38,9 @@ InputHandler::InputHandler()
 	, fingerHandler(std::make_unique<InputSourceTouch>())
 	, textHandler(std::make_unique<InputSourceText>())
 	, gameControllerHandler(std::make_unique<InputSourceGameController>())
+	, enableMouse(settings["input"]["enableMouse"].Bool())
+	, enableTouch(settings["input"]["enableTouch"].Bool())
+	, enableController(settings["input"]["enableController"].Bool())
 {
 }
 
@@ -48,35 +51,59 @@ void InputHandler::handleCurrentEvent(const SDL_Event & current)
 	switch (current.type)
 	{
 		case SDL_KEYDOWN:
-			return keyboardHandler->handleEventKeyDown(current.key);
+			keyboardHandler->handleEventKeyDown(current.key);
+			return;
 		case SDL_KEYUP:
-			return keyboardHandler->handleEventKeyUp(current.key);
+			keyboardHandler->handleEventKeyUp(current.key);
+			return;
 #ifndef VCMI_EMULATE_TOUCHSCREEN_WITH_MOUSE
 		case SDL_MOUSEMOTION:
-			return mouseHandler->handleEventMouseMotion(current.motion);
+			if (enableMouse)
+				mouseHandler->handleEventMouseMotion(current.motion);
+			return;
 		case SDL_MOUSEBUTTONDOWN:
-			return mouseHandler->handleEventMouseButtonDown(current.button);
+			if (enableMouse)
+				mouseHandler->handleEventMouseButtonDown(current.button);
+			return;
 		case SDL_MOUSEBUTTONUP:
-			return mouseHandler->handleEventMouseButtonUp(current.button);
+			if (enableMouse)
+				mouseHandler->handleEventMouseButtonUp(current.button);
+			return;
 		case SDL_MOUSEWHEEL:
-			return mouseHandler->handleEventMouseWheel(current.wheel);
+			if (enableMouse)
+				mouseHandler->handleEventMouseWheel(current.wheel);
+			return;
 #endif
 		case SDL_TEXTINPUT:
-			return textHandler->handleEventTextInput(current.text);
+			textHandler->handleEventTextInput(current.text);
+			return;
 		case SDL_TEXTEDITING:
-			return textHandler->handleEventTextEditing(current.edit);
+			textHandler->handleEventTextEditing(current.edit);
+			return;
 		case SDL_FINGERMOTION:
-			return fingerHandler->handleEventFingerMotion(current.tfinger);
+			if (enableTouch)
+				fingerHandler->handleEventFingerMotion(current.tfinger);
+			return;
 		case SDL_FINGERDOWN:
-			return fingerHandler->handleEventFingerDown(current.tfinger);
+			if (enableTouch)
+				fingerHandler->handleEventFingerDown(current.tfinger);
+			return;
 		case SDL_FINGERUP:
-			return fingerHandler->handleEventFingerUp(current.tfinger);
+			if (enableTouch)
+				fingerHandler->handleEventFingerUp(current.tfinger);
+			return;
 		case SDL_CONTROLLERAXISMOTION:
-			return gameControllerHandler->handleEventAxisMotion(current.caxis);
+			if (enableController)
+				gameControllerHandler->handleEventAxisMotion(current.caxis);
+			return;
 		case SDL_CONTROLLERBUTTONDOWN:
-			return gameControllerHandler->handleEventButtonDown(current.cbutton);
+			if (enableController)
+				gameControllerHandler->handleEventButtonDown(current.cbutton);
+			return;
 		case SDL_CONTROLLERBUTTONUP:
-			return gameControllerHandler->handleEventButtonUp(current.cbutton);
+			if (enableController)
+				gameControllerHandler->handleEventButtonUp(current.cbutton);
+			return;
 	}
 }
 

+ 4 - 0
client/eventsSDL/InputHandler.h

@@ -30,6 +30,10 @@ class InputHandler
 
 	Point cursorPosition;
 
+	const bool enableMouse;
+	const bool enableTouch;
+	const bool enableController;
+
 	std::vector<SDL_Event> acquireEvents();
 
 	void preprocessEvent(const SDL_Event & event);

+ 33 - 15
client/eventsSDL/InputSourceGameController.cpp

@@ -19,6 +19,8 @@
 #include "../gui/EventDispatcher.h"
 #include "../gui/ShortcutHandler.h"
 
+#include "../../lib/CConfigHandler.h"
+
 void InputSourceGameController::gameControllerDeleter(SDL_GameController * gameController)
 {
 	if(gameController)
@@ -26,6 +28,13 @@ void InputSourceGameController::gameControllerDeleter(SDL_GameController * gameC
 }
 
 InputSourceGameController::InputSourceGameController():
+	configTriggerTreshold(settings["input"]["controllerTriggerTreshold"].Float()),
+	configAxisDeadZone(settings["input"]["controllerAxisDeadZone"].Float()),
+	configAxisFullZone(settings["input"]["controllerAxisFullZone"].Float()),
+	configPointerSpeed(settings["input"]["controllerPointerSpeed"].Float()),
+	configPointerScale(settings["input"]["controllerPointerScale"].Float()),
+	configPanningSpeed(settings["input"]["controllerPanningSpeed"].Float()),
+	configPanningScale(settings["input"]["controllerPanningScale"].Float()),
 	cursorAxisValueX(0),
 	cursorAxisValueY(0),
 	cursorPlanDisX(0.0),
@@ -120,21 +129,22 @@ void InputSourceGameController::handleEventDeviceRemapped(const SDL_ControllerDe
 	openGameController(device.which);
 }
 
-int InputSourceGameController::getRealAxisValue(int value)
+double InputSourceGameController::getRealAxisValue(int value)
 {
-	if(value < AXIS_DEAD_ZOOM && value > -AXIS_DEAD_ZOOM)
+	double ratio = static_cast<double>(value) / SDL_JOYSTICK_AXIS_MAX;
+	double greenZone = configAxisFullZone - configAxisDeadZone;
+
+	if (std::abs(ratio) < configAxisDeadZone)
 		return 0;
-	if(value > AXIS_MAX_ZOOM)
-		return AXIS_MAX_ZOOM;
-	if(value < -AXIS_MAX_ZOOM)
-		return -AXIS_MAX_ZOOM;
-	int base = value > 0 ? AXIS_DEAD_ZOOM : -AXIS_DEAD_ZOOM;
-	return (value - base) * AXIS_MAX_ZOOM / (AXIS_MAX_ZOOM - AXIS_DEAD_ZOOM);
+
+	double scaledValue = (ratio - configAxisDeadZone) / greenZone;
+	double clampedValue = std::clamp(scaledValue, -1.0, +1.0);
+	return clampedValue;
 }
 
 void InputSourceGameController::dispatchAxisShortcuts(const std::vector<EShortcut> & shortcutsVector, SDL_GameControllerAxis axisID, int axisValue)
 {
-	if(axisValue >= TRIGGER_PRESS_THRESHOLD)
+	if(getRealAxisValue(axisValue) > configTriggerTreshold)
 	{
 		if(!pressedAxes.count(axisID))
 		{
@@ -249,19 +259,27 @@ void InputSourceGameController::handleUpdate()
 	lastCheckTime = nowMs;
 }
 
+static double scaleAxis(double value, double power)
+{
+	if (value > 0)
+		return std::pow(value, power);
+	else
+		return -std::pow(-value, power);
+}
+
 void InputSourceGameController::handleCursorUpdate(int32_t deltaTimeMs)
 {
 	float deltaTimeSeconds = static_cast<float>(deltaTimeMs) / 1000;
 
-	if(cursorAxisValueX == 0)
+	if(vstd::isAlmostZero(cursorAxisValueX))
 		cursorPlanDisX = 0;
 	else
-		cursorPlanDisX += deltaTimeSeconds * AXIS_MOVE_SPEED * cursorAxisValueX / AXIS_MAX_ZOOM;
+		cursorPlanDisX += deltaTimeSeconds * configPointerSpeed * scaleAxis(cursorAxisValueX, configPointerScale);
 
-	if(cursorAxisValueY == 0)
+	if (vstd::isAlmostZero(cursorAxisValueY))
 		cursorPlanDisY = 0;
 	else
-		cursorPlanDisY += deltaTimeSeconds * AXIS_MOVE_SPEED * cursorAxisValueY / AXIS_MAX_ZOOM;
+		cursorPlanDisY += deltaTimeSeconds * configPointerSpeed * scaleAxis(cursorAxisValueY, configPointerScale);
 
 	int moveDisX = getMoveDis(cursorPlanDisX);
 	int moveDisY = getMoveDis(cursorPlanDisY);
@@ -290,8 +308,8 @@ void InputSourceGameController::handleScrollUpdate(int32_t deltaTimeMs)
 		return;
 	}
 	float deltaTimeSeconds = static_cast<float>(deltaTimeMs) / 1000;
-	scrollPlanDisX += deltaTimeSeconds * AXIS_MOVE_SPEED * scrollAxisValueX / AXIS_MAX_ZOOM;
-	scrollPlanDisY += deltaTimeSeconds * AXIS_MOVE_SPEED * scrollAxisValueY / AXIS_MAX_ZOOM;
+	scrollPlanDisX += deltaTimeSeconds * configPanningSpeed * scaleAxis(scrollAxisValueX, configPanningScale);
+	scrollPlanDisY += deltaTimeSeconds * configPanningSpeed * scaleAxis(scrollAxisValueY, configPanningScale);
 	int moveDisX = getMoveDis(scrollPlanDisX);
 	int moveDisY = getMoveDis(scrollPlanDisY);
 	if(moveDisX != 0 || moveDisY != 0)

+ 17 - 14
client/eventsSDL/InputSourceGameController.h

@@ -16,11 +16,6 @@
 #include "../../lib/Point.h"
 #include "../gui/Shortcut.h"
 
-constexpr int AXIS_DEAD_ZOOM = 6000;
-constexpr int AXIS_MAX_ZOOM = 32000;
-constexpr int AXIS_MOVE_SPEED = 500;
-constexpr int TRIGGER_PRESS_THRESHOLD = 8000;
-
 /// Class that handles game controller input from SDL events
 class InputSourceGameController
 {
@@ -31,22 +26,30 @@ class InputSourceGameController
 	std::set<SDL_GameControllerAxis> pressedAxes;
 
 	std::chrono::steady_clock::time_point lastCheckTime;
-	int cursorAxisValueX;
-	int cursorAxisValueY;
-	float cursorPlanDisX;
-	float cursorPlanDisY;
+	double cursorAxisValueX;
+	double cursorAxisValueY;
+	double cursorPlanDisX;
+	double cursorPlanDisY;
 
 	bool scrollAxisMoved;
 	Point scrollStart;
 	Point scrollCurrent;
-	int scrollAxisValueX;
-	int scrollAxisValueY;
-	float scrollPlanDisX;
-	float scrollPlanDisY;
+	double scrollAxisValueX;
+	double scrollAxisValueY;
+	double scrollPlanDisX;
+	double scrollPlanDisY;
+
+	const double configTriggerTreshold;
+	const double configAxisDeadZone;
+	const double configAxisFullZone;
+	const double configPointerSpeed;
+	const double configPointerScale;
+	const double configPanningSpeed;
+	const double configPanningScale;
 
 	void openGameController(int index);
 	int getJoystickIndex(SDL_GameController * controller);
-	int getRealAxisValue(int value);
+	double getRealAxisValue(int value);
 	void dispatchAxisShortcuts(const std::vector<EShortcut> & shortcutsVector, SDL_GameControllerAxis axisID, int axisValue);
 	void tryToConvertCursor();
 	void doCursorMove(int deltaX, int deltaY);

+ 8 - 5
client/eventsSDL/InputSourceMouse.cpp

@@ -12,15 +12,18 @@
 #include "InputSourceMouse.h"
 #include "InputHandler.h"
 
-#include "../../lib/Point.h"
 #include "../gui/CGuiHandler.h"
 #include "../gui/EventDispatcher.h"
 #include "../gui/MouseButton.h"
 
+#include "../../lib/Point.h"
+#include "../../lib/CConfigHandler.h"
+
 #include <SDL_events.h>
 #include <SDL_hints.h>
 
 InputSourceMouse::InputSourceMouse()
+	:mouseToleranceDistance(settings["input"]["mouseToleranceDistance"].Integer())
 {
 	SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1");
 }
@@ -48,12 +51,12 @@ void InputSourceMouse::handleEventMouseButtonDown(const SDL_MouseButtonEvent & b
 	{
 		case SDL_BUTTON_LEFT:
 			if(button.clicks > 1)
-				GH.events().dispatchMouseDoubleClick(position, 0);
+				GH.events().dispatchMouseDoubleClick(position, mouseToleranceDistance);
 			else
-				GH.events().dispatchMouseLeftButtonPressed(position, 0);
+				GH.events().dispatchMouseLeftButtonPressed(position, mouseToleranceDistance);
 			break;
 		case SDL_BUTTON_RIGHT:
-			GH.events().dispatchShowPopup(position, 0);
+			GH.events().dispatchShowPopup(position, mouseToleranceDistance);
 			break;
 		case SDL_BUTTON_MIDDLE:
 			middleClickPosition = position;
@@ -74,7 +77,7 @@ void InputSourceMouse::handleEventMouseButtonUp(const SDL_MouseButtonEvent & but
 	switch(button.button)
 	{
 		case SDL_BUTTON_LEFT:
-			GH.events().dispatchMouseLeftButtonReleased(position, 0);
+			GH.events().dispatchMouseLeftButtonReleased(position, mouseToleranceDistance);
 			break;
 		case SDL_BUTTON_RIGHT:
 			GH.events().dispatchClosePopup(position);

+ 1 - 0
client/eventsSDL/InputSourceMouse.h

@@ -23,6 +23,7 @@ class InputSourceMouse
 {
 	Point middleClickPosition;
 	int mouseButtonsMask = 0;
+	const int mouseToleranceDistance;
 public:
 	InputSourceMouse();
 

+ 5 - 4
client/gui/EventDispatcher.cpp

@@ -17,6 +17,7 @@
 #include "WindowHandler.h"
 #include "gui/Shortcut.h"
 
+#include "../../lib/CConfigHandler.h"
 #include "../../lib/Rect.h"
 
 template<typename Functor>
@@ -76,10 +77,10 @@ void EventDispatcher::dispatchShortcutPressed(const std::vector<EShortcut> & sho
 	bool keysCaptured = false;
 
 	if (vstd::contains(shortcutsVector, EShortcut::MOUSE_LEFT))
-		dispatchMouseLeftButtonPressed(GH.getCursorPosition(), 0);
+		dispatchMouseLeftButtonPressed(GH.getCursorPosition(), settings["input"]["shortcutToleranceDistance"].Integer());
 
 	if (vstd::contains(shortcutsVector, EShortcut::MOUSE_RIGHT))
-		dispatchShowPopup(GH.getCursorPosition(), 0);
+		dispatchShowPopup(GH.getCursorPosition(), settings["input"]["shortcutToleranceDistance"].Integer());
 
 	for(auto & i : keyinterested)
 		for(EShortcut shortcut : shortcutsVector)
@@ -105,7 +106,7 @@ void EventDispatcher::dispatchShortcutReleased(const std::vector<EShortcut> & sh
 	bool keysCaptured = false;
 
 	if (vstd::contains(shortcutsVector, EShortcut::MOUSE_LEFT))
-		dispatchMouseLeftButtonReleased(GH.getCursorPosition(), 0);
+		dispatchMouseLeftButtonReleased(GH.getCursorPosition(), settings["input"]["shortcutToleranceDistance"].Integer());
 
 	if (vstd::contains(shortcutsVector, EShortcut::MOUSE_RIGHT))
 		dispatchClosePopup(GH.getCursorPosition());
@@ -164,7 +165,7 @@ AEventsReceiver * EventDispatcher::findElementInToleranceRange(const EventReceiv
 		if (distance.lengthSquared() == 0)
 			continue;
 
-		Point moveDelta = distance * tolerance / distance.length();
+		Point moveDelta = distance * std::min(1.0, static_cast<double>(tolerance) / distance.length());
 		Point testPosition = position + moveDelta;
 
 		if( !i->receiveEvent(testPosition, eventToTest))

+ 64 - 1
config/schemas/settings.json

@@ -236,7 +236,22 @@
 			"type" : "object",
 			"additionalProperties" : false,
 			"default" : {},
-			"required" : [ "radialWheelGarrisonSwipe", "touchToleranceDistance" ],
+			"required" : [ 
+				"radialWheelGarrisonSwipe",
+				"touchToleranceDistance",
+				"mouseToleranceDistance",
+				"shortcutToleranceDistance",
+				"enableMouse",
+				"enableTouch",
+				"enableController",
+				"controllerTriggerTreshold",
+				"controllerAxisDeadZone",
+				"controllerAxisFullZone",
+				"controllerPointerSpeed",
+				"controllerPointerScale",
+				"controllerPanningSpeed",
+				"controllerPanningScale",
+			],
 			"properties" : {
 				"radialWheelGarrisonSwipe" : {
 					"type" : "boolean",
@@ -245,6 +260,54 @@
 				"touchToleranceDistance" : {
 					"type" : "number",
 					"default" : 20
+				},
+				"mouseToleranceDistance" : {
+					"type" : "number",
+					"default" : 0
+				},
+				"shortcutToleranceDistance" : {
+					"type" : "number",
+					"default" : 0
+				},
+				"enableMouse" : {
+					"type" : "boolean",
+					"default" : true
+				},
+				"enableTouch" : {
+					"type" : "boolean",
+					"default" : true
+				},
+				"enableController" : {
+					"type" : "boolean",
+					"default" : true
+				},
+				"controllerTriggerTreshold" : {
+					"type" : "number",
+					"default" : 0.3
+				},
+				"controllerAxisDeadZone" : {
+					"type" : "number",
+					"default" : 0.2
+				},
+				"controllerAxisFullZone" : {
+					"type" : "number",
+					"default" : 1.0
+				},
+				"controllerPointerSpeed" : {
+					"type" : "number",
+					"default" : 1000
+				},
+				"controllerPointerScale" : {
+					"type" : "number",
+					"default" : 2
+				},
+				"controllerPanningSpeed" : {
+					"type" : "number",
+					"default" : 1000
+				},
+				"controllerPanningScale" : {
+					"type" : "number",
+					"default" : 2
 				}
 			}
 		},