[Scummvm-git-logs] scummvm master -> cd173c8739668108c664c220244ae5e83238c87d

bgK bastien.bouclet at gmail.com
Mon Mar 9 19:00:37 UTC 2020


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

Summary:
d94c7c3bcc SDL: Move the keyboard mouse to a subclass of SdlEventSource
e66e35a3fd COMMON: Move isMouseEvent from Keymapper to Common
568d882e80 KEYMAPPER: Introduce a Virtual Mouse event source
cd173c8739 3DS: Use the shared virtual mouse


Commit: d94c7c3bcc7ea0dee89bd167c037a422d0c31989
    https://github.com/scummvm/scummvm/commit/d94c7c3bcc7ea0dee89bd167c037a422d0c31989
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-03-09T20:00:31+01:00

Commit Message:
SDL: Move the keyboard mouse to a subclass of SdlEventSource

And deprecate it. The new Virtual Mouse system is expected to replace
it.

Changed paths:
  A backends/events/sdl/legacy-sdl-events.cpp
  A backends/events/sdl/legacy-sdl-events.h
    backends/events/dinguxsdl/dinguxsdl-events.h
    backends/events/gph/gph-events.h
    backends/events/openpandora/op-events.cpp
    backends/events/psp2sdl/psp2sdl-events.cpp
    backends/events/psp2sdl/psp2sdl-events.h
    backends/events/samsungtvsdl/samsungtvsdl-events.h
    backends/events/sdl/sdl-events.cpp
    backends/events/sdl/sdl-events.h
    backends/events/switchsdl/switchsdl-events.cpp
    backends/events/switchsdl/switchsdl-events.h
    backends/events/symbiansdl/symbiansdl-events.h
    backends/events/webossdl/webossdl-events.cpp
    backends/graphics/sdl/sdl-graphics.cpp
    backends/graphics/windowed.h
    backends/module.mk
    backends/platform/sdl/sdl.cpp


diff --git a/backends/events/dinguxsdl/dinguxsdl-events.h b/backends/events/dinguxsdl/dinguxsdl-events.h
index 0ed0a9923e..b7928b84d9 100644
--- a/backends/events/dinguxsdl/dinguxsdl-events.h
+++ b/backends/events/dinguxsdl/dinguxsdl-events.h
@@ -23,9 +23,9 @@
 #ifndef BACKENDS_EVENTS_SDL_DINGUX_H
 #define BACKENDS_EVENTS_SDL_DINGUX_H
 
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/events/sdl/legacy-sdl-events.h"
 
-class DINGUXSdlEventSource : public SdlEventSource {
+class DINGUXSdlEventSource : public LegacySdlEventSource {
 protected:
 	bool remapKey(SDL_Event &ev, Common::Event &event);
 };
diff --git a/backends/events/gph/gph-events.h b/backends/events/gph/gph-events.h
index bdcb62d8c2..b9bcf1332d 100644
--- a/backends/events/gph/gph-events.h
+++ b/backends/events/gph/gph-events.h
@@ -23,13 +23,13 @@
 #if !defined(BACKEND_EVENTS_GPH_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
 #define BACKEND_EVENTS_GPH_H
 
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/events/sdl/legacy-sdl-events.h"
 
 /*
  * SDL Events manager for GPH devices.
  */
 
-class GPHEventSource : public SdlEventSource {
+class GPHEventSource : public LegacySdlEventSource {
 public:
 	GPHEventSource();
 
diff --git a/backends/events/openpandora/op-events.cpp b/backends/events/openpandora/op-events.cpp
index bcc2bd8190..7a196dbfb1 100644
--- a/backends/events/openpandora/op-events.cpp
+++ b/backends/events/openpandora/op-events.cpp
@@ -82,10 +82,6 @@ bool OPEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
 	else
 		event.type = Common::EVENT_LBUTTONDOWN; /* For normal mice etc. */
 
-	// update KbdMouse
-	_km.x = ev.button.x * MULTIPLIER;
-	_km.y = ev.button.y * MULTIPLIER;
-
 	return processMouseEvent(event, ev.button.x, ev.button.y);
 }
 
@@ -113,9 +109,6 @@ bool OPEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
 		return false;
 
 	processMouseEvent(event, ev.button.x, ev.button.y);
-	// update KbdMouse
-	_km.x = ev.button.x * MULTIPLIER;
-	_km.y = ev.button.y * MULTIPLIER;
 
 	return true;
 }
@@ -130,18 +123,18 @@ bool OPEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
 		switch (ev.key.keysym.sym) {
 		case SDLK_LEFT:
 			event.type = (ev.type == SDL_KEYDOWN) ? Common::EVENT_LBUTTONDOWN : Common::EVENT_LBUTTONUP;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseY, _mouseY);
 			return true;
 			break;
 		case SDLK_RIGHT:
 			event.type = (ev.type == SDL_KEYDOWN) ? Common::EVENT_RBUTTONDOWN : Common::EVENT_RBUTTONUP;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 #if defined(SDL_BUTTON_MIDDLE)
 		case SDLK_UP:
 			event.type = (ev.type == SDL_KEYDOWN) ? Common::EVENT_MBUTTONDOWN : Common::EVENT_MBUTTONUP;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 #endif
@@ -154,12 +147,12 @@ bool OPEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
 		switch (ev.key.keysym.sym) {
 		case SDLK_HOME:
 			event.type = Common::EVENT_LBUTTONDOWN;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 		case SDLK_END:
 			event.type = Common::EVENT_RBUTTONDOWN;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 		case SDLK_PAGEDOWN:
@@ -192,12 +185,12 @@ bool OPEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
 		switch (ev.key.keysym.sym) {
 		case SDLK_HOME:
 			event.type = Common::EVENT_LBUTTONUP;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 		case SDLK_END:
 			event.type = Common::EVENT_RBUTTONUP;
-			processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+			processMouseEvent(event, _mouseX, _mouseY);
 			return true;
 			break;
 		case SDLK_PAGEDOWN:
diff --git a/backends/events/psp2sdl/psp2sdl-events.cpp b/backends/events/psp2sdl/psp2sdl-events.cpp
index b14493c345..38a0ee0932 100644
--- a/backends/events/psp2sdl/psp2sdl-events.cpp
+++ b/backends/events/psp2sdl/psp2sdl-events.cpp
@@ -103,8 +103,8 @@ void PSP2EventSource::preprocessFingerDown(SDL_Event *event) {
 	// id (for multitouch)
 	SDL_FingerID id = event->tfinger.fingerId;
 
-	int x = _km.x / MULTIPLIER;
-	int y = _km.y / MULTIPLIER;
+	int x = _mouseX;
+	int y = _mouseY;
 
 	if (port == 0 && !ConfMan.getBool("frontpanel_touchpad_mode")) {
 		convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y);
@@ -147,8 +147,8 @@ void PSP2EventSource::preprocessFingerUp(SDL_Event *event) {
 		}
 	}
 
-	int x = _km.x / MULTIPLIER;
-	int y = _km.y / MULTIPLIER;
+	int x = _mouseX;
+	int y = _mouseY;
 
 	for (int i = 0; i < MAX_NUM_FINGERS; i++) {
 		if (_finger[port][i].id == id) {
@@ -219,8 +219,10 @@ void PSP2EventSource::preprocessFingerMotion(SDL_Event *event) {
 	}
 
 	if (numFingersDown >= 1) {
-		int x = _km.x / MULTIPLIER;
-		int y = _km.y / MULTIPLIER;
+		int x = _mouseX;
+		int y = _mouseY;
+		int xMax = _graphicsManager->getWindowWidth()  - 1;
+		int yMax = _graphicsManager->getWindowHeight() - 1;
 
 		if (port == 0 && !ConfMan.getBool("frontpanel_touchpad_mode")) {
 			convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y);
@@ -267,23 +269,23 @@ void PSP2EventSource::preprocessFingerMotion(SDL_Event *event) {
 
 			// convert touch events to relative mouse pointer events
 			// track sub-pixel relative finger motion using the MULTIPLIER
-			_hiresDX += (event->tfinger.dx * 1.25 * speedFactor * _km.x_max * MULTIPLIER);
-			_hiresDY += (event->tfinger.dy * 1.25 * speedFactor * _km.y_max * MULTIPLIER);
+			_hiresDX += (event->tfinger.dx * 1.25 * speedFactor * xMax * MULTIPLIER);
+			_hiresDY += (event->tfinger.dy * 1.25 * speedFactor * yMax * MULTIPLIER);
 			int xRel = _hiresDX / MULTIPLIER;
 			int yRel = _hiresDY / MULTIPLIER;
-			x = (_km.x / MULTIPLIER) + xRel;
-			y = (_km.y / MULTIPLIER) + yRel;
+			x = _mouseX + xRel;
+			y = _mousey + yRel;
 			_hiresDX %= MULTIPLIER;
 			_hiresDY %= MULTIPLIER;
 		}
 
-		if (x > _km.x_max) {
-			x = _km.x_max;
+		if (x > xMax) {
+			x = xMax;
 		} else if (x < 0) {
 			x = 0;
 		}
-		if (y > _km.y_max) {
-			y = _km.y_max;
+		if (y > yMax) {
+			y = yMax;
 		} else if (y < 0) {
 			y = 0;
 		}
@@ -311,8 +313,8 @@ void PSP2EventSource::preprocessFingerMotion(SDL_Event *event) {
 				if (numFingersDownLong >= 2) {
 					// starting drag, so push mouse down at current location (back) 
 					// or location of "oldest" finger (front)
-					int mouseDownX = _km.x / MULTIPLIER;
-					int mouseDownY = _km.y / MULTIPLIER;
+					int mouseDownX = _mouseX;
+					int mouseDownY = _mousey;
 					if (port == 0 && !ConfMan.getBool("frontpanel_touchpad_mode")) {
 						for (int i = 0; i < MAX_NUM_FINGERS; i++) {
 							if (_finger[port][i].id == id) {
@@ -372,8 +374,8 @@ void PSP2EventSource::preprocessFingerMotion(SDL_Event *event) {
 }
 
 void PSP2EventSource::convertTouchXYToGameXY(float touchX, float touchY, int *gameX, int *gameY) {
-	int screenH = _km.y_max;
-	int screenW = _km.x_max;
+	int screenH = _graphicsManager->getWindowHeight();
+	int screenW = _graphicsManager->getWindowWidth();
 
 	const int dispW = TOUCHSCREEN_WIDTH;
 	const int dispH = TOUCHSCREEN_HEIGHT;
@@ -395,8 +397,8 @@ void PSP2EventSource::convertTouchXYToGameXY(float touchX, float touchY, int *ga
 	float dispTouchX = (touchX * (float)dispW);
 	float dispTouchY = (touchY * (float)dispH);
 
-	*gameX = CLIP((int)((dispTouchX - x) / sx), 0, (int)_km.x_max);
-	*gameY = CLIP((int)((dispTouchY - y) / sy), 0, (int)_km.y_max);
+	*gameX = CLIP((int)((dispTouchX - x) / sx), 0, screenW - 1);
+	*gameY = CLIP((int)((dispTouchY - y) / sy), 0, screenH - 1);
 }
 
 void PSP2EventSource::finishSimulatedMouseClicks() {
@@ -414,8 +416,8 @@ void PSP2EventSource::finishSimulatedMouseClicks() {
 					SDL_Event ev;
 					ev.type = SDL_MOUSEBUTTONUP;
 					ev.button.button = simulatedButton;
-					ev.button.x = _km.x / MULTIPLIER;
-					ev.button.y = _km.y / MULTIPLIER;
+					ev.button.x = _mouseX;
+					ev.button.y = _mousey;
 					SDL_PushEvent(&ev);
 
 					_simulatedClickStartTime[port][i] = 0;
diff --git a/backends/events/psp2sdl/psp2sdl-events.h b/backends/events/psp2sdl/psp2sdl-events.h
index f37d51c46b..11e97ec5b9 100644
--- a/backends/events/psp2sdl/psp2sdl-events.h
+++ b/backends/events/psp2sdl/psp2sdl-events.h
@@ -42,7 +42,8 @@ private:
 		MAX_TAP_TIME = 250, // taps longer than this will not result in mouse click events
 		MAX_TAP_MOTION_DISTANCE = 10, // max distance finger motion in Vita screen pixels to be considered a tap
 		SIMULATED_CLICK_DURATION = 50, // time in ms how long simulated mouse clicks should be
-	}; // track three fingers per panel
+		MULTIPLIER = 16 // multiplier for sub-pixel resolution
+	};
 
 	typedef struct {
 		int id; // -1: no touch
diff --git a/backends/events/samsungtvsdl/samsungtvsdl-events.h b/backends/events/samsungtvsdl/samsungtvsdl-events.h
index be3dfef8fd..a831992061 100644
--- a/backends/events/samsungtvsdl/samsungtvsdl-events.h
+++ b/backends/events/samsungtvsdl/samsungtvsdl-events.h
@@ -23,12 +23,12 @@
 #if !defined(BACKEND_EVENTS_SDL_SAMSUNGTV_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
 #define BACKEND_EVENTS_SDL_SAMSUNGTV_H
 
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/events/sdl/legacy-sdl-events.h"
 
 /**
  * SDL events manager for Samsung TV
  */
-class SamsungTVSdlEventSource : public SdlEventSource {
+class SamsungTVSdlEventSource : public LegacySdlEventSource {
 protected:
 	virtual bool remapKey(SDL_Event &ev, Common::Event &event);
 };
diff --git a/backends/events/sdl/legacy-sdl-events.cpp b/backends/events/sdl/legacy-sdl-events.cpp
new file mode 100644
index 0000000000..5cc061c317
--- /dev/null
+++ b/backends/events/sdl/legacy-sdl-events.cpp
@@ -0,0 +1,309 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "common/scummsys.h"
+
+#if defined(SDL_BACKEND)
+
+#include "backends/events/sdl/legacy-sdl-events.h"
+
+// #define JOY_INVERT_Y
+#define JOY_XAXIS 0
+#define JOY_YAXIS 1
+
+LegacySdlEventSource::LegacySdlEventSource() {
+	// Reset mouse state
+	memset(&_km, 0, sizeof(_km));
+}
+
+void LegacySdlEventSource::updateKbdMouse() {
+	uint32 curTime = g_system->getMillis(true);
+	if (curTime < _km.last_time + _km.delay_time) {
+		return;
+	}
+
+	_km.last_time = curTime;
+	if (_km.x_down_count == 1) {
+		_km.x_down_time = curTime;
+		_km.x_down_count = 2;
+	}
+	if (_km.y_down_count == 1) {
+		_km.y_down_time = curTime;
+		_km.y_down_count = 2;
+	}
+
+	if (_km.x_vel || _km.y_vel) {
+		if (_km.x_down_count) {
+			if (curTime > _km.x_down_time + 300) {
+				if (_km.x_vel > 0)
+					_km.x_vel += MULTIPLIER;
+				else
+					_km.x_vel -= MULTIPLIER;
+			} else if (curTime > _km.x_down_time + 200) {
+				if (_km.x_vel > 0)
+					_km.x_vel = 5 * MULTIPLIER;
+				else
+					_km.x_vel = -5 * MULTIPLIER;
+			}
+		}
+		if (_km.y_down_count) {
+			if (curTime > _km.y_down_time + 300) {
+				if (_km.y_vel > 0)
+					_km.y_vel += MULTIPLIER;
+				else
+					_km.y_vel -= MULTIPLIER;
+			} else if (curTime > _km.y_down_time + 200) {
+				if (_km.y_vel > 0)
+					_km.y_vel = 5 * MULTIPLIER;
+				else
+					_km.y_vel = -5 * MULTIPLIER;
+			}
+		}
+
+		int16 speedFactor = computeJoystickMouseSpeedFactor();
+
+		// - The modifier key makes the mouse movement slower
+		// - The extra factor "delay/speedFactor" ensures velocities
+		// are independent of the kbdMouse update rate
+		// - all velocities were originally chosen
+		// at a delay of 25, so that is the reference used here
+		// - note: operator order is important to avoid overflow
+		if (_km.modifier) {
+			_km.x += ((_km.x_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
+			_km.y += ((_km.y_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
+		} else {
+			_km.x += (_km.x_vel * ((int16)_km.delay_time)) / speedFactor;
+			_km.y += (_km.y_vel * ((int16)_km.delay_time)) / speedFactor;
+		}
+
+		if (_km.x < 0) {
+			_km.x = 0;
+			_km.x_vel = -1 * MULTIPLIER;
+			_km.x_down_count = 1;
+		} else if (_km.x > _km.x_max * MULTIPLIER) {
+			_km.x = _km.x_max * MULTIPLIER;
+			_km.x_vel = 1 * MULTIPLIER;
+			_km.x_down_count = 1;
+		}
+
+		if (_km.y < 0) {
+			_km.y = 0;
+			_km.y_vel = -1 * MULTIPLIER;
+			_km.y_down_count = 1;
+		} else if (_km.y > _km.y_max * MULTIPLIER) {
+			_km.y = _km.y_max * MULTIPLIER;
+			_km.y_vel = 1 * MULTIPLIER;
+			_km.y_down_count = 1;
+		}
+	}
+}
+
+bool LegacySdlEventSource::handleKbdMouse(Common::Event &event) {
+	int32 oldKmX = _km.x;
+	int32 oldKmY = _km.y;
+
+	updateKbdMouse();
+
+	if (_km.x != oldKmX || _km.y != oldKmY) {
+		if (_graphicsManager) {
+			_graphicsManager->getWindow()->warpMouseInWindow((Uint16)(_km.x / MULTIPLIER), (Uint16)(_km.y / MULTIPLIER));
+		}
+
+		event.type = Common::EVENT_MOUSEMOVE;
+		return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
+	}
+
+	return false;
+}
+
+bool LegacySdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
+	if (ev.jaxis.axis == JOY_XAXIS) {
+		_km.joy_x = ev.jaxis.value;
+		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
+	} else if (ev.jaxis.axis == JOY_YAXIS) {
+		_km.joy_y = ev.jaxis.value;
+		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
+	}
+
+	return SdlEventSource::handleJoyAxisMotion(ev, event);
+}
+
+int16 LegacySdlEventSource::computeJoystickMouseSpeedFactor() const {
+	int16 speedFactor;
+
+	switch (ConfMan.getInt("kbdmouse_speed")) {
+	// 0.25 keyboard pointer speed
+	case 0:
+		speedFactor = 100;
+		break;
+	// 0.5 speed
+	case 1:
+		speedFactor = 50;
+		break;
+	// 0.75 speed
+	case 2:
+		speedFactor = 33;
+		break;
+	// 1.0 speed
+	case 3:
+		speedFactor = 25;
+		break;
+	// 1.25 speed
+	case 4:
+		speedFactor = 20;
+		break;
+	// 1.5 speed
+	case 5:
+		speedFactor = 17;
+		break;
+	// 1.75 speed
+	case 6:
+		speedFactor = 14;
+		break;
+	// 2.0 speed
+	case 7:
+		speedFactor = 12;
+		break;
+	default:
+		speedFactor = 25;
+	}
+
+	// Scale the mouse cursor speed with the display size so moving across
+	// the screen takes a reasonable amount of time at higher resolutions.
+	return speedFactor * 480 / _km.y_max;
+}
+
+bool LegacySdlEventSource::handleAxisToMouseMotion(int16 xAxis, int16 yAxis) {
+#ifdef JOY_INVERT_Y
+	yAxis = -yAxis;
+#endif
+
+	// conversion factor between keyboard mouse and joy axis value
+	int vel_to_axis = (1500 / MULTIPLIER);
+
+	// radial and scaled deadzone
+
+	float analogX = (float)xAxis;
+	float analogY = (float)yAxis;
+	float deadZone = (float)ConfMan.getInt("joystick_deadzone") * 1000.0f;
+
+	float magnitude = sqrt(analogX * analogX + analogY * analogY);
+
+	if (magnitude >= deadZone) {
+		_km.x_down_count = 0;
+		_km.y_down_count = 0;
+		float scalingFactor = 1.0f / magnitude * (magnitude - deadZone) / (32769.0f - deadZone);
+		_km.x_vel = (int16)(analogX * scalingFactor * 32768.0f / vel_to_axis);
+		_km.y_vel = (int16)(analogY * scalingFactor * 32768.0f / vel_to_axis);
+	} else {
+		_km.x_vel = 0;
+		_km.y_vel = 0;
+	}
+
+	return false;
+}
+
+void LegacySdlEventSource::resetKeyboardEmulation(int16 x_max, int16 y_max) {
+	_km.x_max = x_max;
+	_km.y_max = y_max;
+	_km.delay_time = 12;
+	_km.last_time = 0;
+	_km.modifier = false;
+	_km.joy_x = 0;
+	_km.joy_y = 0;
+}
+
+void LegacySdlEventSource::checkScreenChange() {
+	if (!_graphicsManager) {
+		return;
+	}
+
+	int newMaxX = _graphicsManager->getWindowWidth()  - 1;
+	int newMaxY = _graphicsManager->getWindowHeight() - 1;
+
+	if (_km.x_max != newMaxX || _km.y_max != newMaxY) {
+		resetKeyboardEmulation(newMaxX, newMaxY);
+	}
+}
+
+bool LegacySdlEventSource::pollEvent(Common::Event &event) {
+	checkScreenChange();
+
+	bool handled = SdlEventSource::pollEvent(event);
+	if (handled) {
+		return true;
+	}
+
+	// Handle mouse control via analog joystick and keyboard
+	if (handleKbdMouse(event)) {
+		return true;
+	}
+
+	return false;
+}
+
+bool LegacySdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
+	// update KbdMouse
+	_km.x = ev.motion.x * MULTIPLIER;
+	_km.y = ev.motion.y * MULTIPLIER;
+
+	return SdlEventSource::handleMouseMotion(ev, event);
+}
+
+bool LegacySdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event) {
+	// update KbdMouse
+	_km.x = ev.motion.x * MULTIPLIER;
+	_km.y = ev.motion.y * MULTIPLIER;
+
+	return SdlEventSource::handleMouseButtonDown(ev, event);
+}
+
+bool LegacySdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
+	// update KbdMouse
+	_km.x = ev.motion.x * MULTIPLIER;
+	_km.y = ev.motion.y * MULTIPLIER;
+
+	return SdlEventSource::handleMouseButtonUp(ev, event);
+}
+
+bool LegacySdlEventSource::handleControllerButton(const SDL_Event &ev, Common::Event &event, bool buttonUp) {
+	if (event.joystick.button == Common::JOYSTICK_BUTTON_RIGHT_SHOULDER) {
+		// Right shoulder is the modifier button that makes the mouse go slower.
+		_km.modifier = !buttonUp;
+	}
+
+	return 	SdlEventSource::handleControllerButton(ev, event, buttonUp);
+}
+
+bool LegacySdlEventSource::handleControllerAxisMotion(const SDL_Event &ev, Common::Event &event) {
+	if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX) {
+		_km.joy_x = ev.caxis.value;
+		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
+	} else if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) {
+		_km.joy_y = ev.caxis.value;
+		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
+	}
+
+	return SdlEventSource::handleControllerAxisMotion(ev, event);
+}
+
+#endif
diff --git a/backends/events/sdl/legacy-sdl-events.h b/backends/events/sdl/legacy-sdl-events.h
new file mode 100644
index 0000000000..f4a437e7a4
--- /dev/null
+++ b/backends/events/sdl/legacy-sdl-events.h
@@ -0,0 +1,88 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKEND_EVENTS_SDL_LEGACY_H
+#define BACKEND_EVENTS_SDL_LEGACY_H
+
+#include "backends/events/sdl/sdl-events.h"
+
+// multiplier used to increase resolution for keyboard/joystick mouse
+#define MULTIPLIER 16
+
+class LegacySdlEventSource : public SdlEventSource {
+public:
+	LegacySdlEventSource();
+
+	bool pollEvent(Common::Event &event) override;
+
+	void checkScreenChange();
+
+protected:
+	/** @name Keyboard mouse emulation
+	 * Disabled by fingolfin 2004-12-18.
+	 * I am keeping the rest of the code in for now, since the joystick
+	 * code (or rather, "hack") uses it, too.
+	 */
+	//@{
+
+	struct KbdMouse {
+		int32 x, y;
+		int16 x_vel, y_vel, x_max, y_max, x_down_count, y_down_count, joy_x, joy_y;
+		uint32 last_time, delay_time, x_down_time, y_down_time;
+		bool modifier;
+	};
+	KbdMouse _km;
+
+	virtual void updateKbdMouse();
+	virtual bool handleKbdMouse(Common::Event &event);
+
+	//@}
+
+	bool handleMouseMotion(SDL_Event &ev, Common::Event &event) override;
+	bool handleMouseButtonDown(SDL_Event &ev, Common::Event &event) override;
+	bool handleMouseButtonUp(SDL_Event &ev, Common::Event &event) override;
+	bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) override;
+
+#if SDL_VERSION_ATLEAST(2, 0, 0)
+	bool handleControllerButton(const SDL_Event &ev, Common::Event &event, bool buttonUp) override;
+	bool handleControllerAxisMotion(const SDL_Event &ev, Common::Event &event) override;
+#endif
+
+	/**
+	 * Update the virtual mouse according to a joystick or game controller axis position change
+	 */
+	virtual bool handleAxisToMouseMotion(int16 xAxis, int16 yAxis);
+
+	/**
+	 * Compute the virtual mouse movement speed factor according to the 'kbdmouse_speed' setting.
+	 * The speed factor is scaled with the display size.
+	 */
+	int16 computeJoystickMouseSpeedFactor() const;
+
+	/**
+	 * Resets keyboard emulation after a video screen change
+	 */
+	void resetKeyboardEmulation(int16 x_max, int16 y_max);
+
+};
+
+#endif
diff --git a/backends/events/sdl/sdl-events.cpp b/backends/events/sdl/sdl-events.cpp
index 1f6e56b660..a218457248 100644
--- a/backends/events/sdl/sdl-events.cpp
+++ b/backends/events/sdl/sdl-events.cpp
@@ -33,10 +33,6 @@
 #include "engines/engine.h"
 #include "gui/gui-manager.h"
 
-// #define JOY_INVERT_Y
-#define JOY_XAXIS 0
-#define JOY_YAXIS 1
-
 #if SDL_VERSION_ATLEAST(2, 0, 0)
 #define GAMECONTROLLERDB_FILE "gamecontrollerdb.txt"
 
@@ -87,14 +83,12 @@ void SdlEventSource::loadGameControllerMappingFile() {
 #endif
 
 SdlEventSource::SdlEventSource()
-    : EventSource(), _scrollLock(false), _joystick(0), _lastScreenID(0), _graphicsManager(0), _queuedFakeMouseMove(false), _lastHatPosition(SDL_HAT_CENTERED)
+    : EventSource(), _scrollLock(false), _joystick(0), _lastScreenID(0), _graphicsManager(0), _queuedFakeMouseMove(false),
+      _lastHatPosition(SDL_HAT_CENTERED), _mouseX(0), _mouseY(0)
 #if SDL_VERSION_ATLEAST(2, 0, 0)
       , _queuedFakeKeyUp(false), _fakeKeyUp(), _controller(nullptr)
 #endif
       {
-	// Reset mouse state
-	memset(&_km, 0, sizeof(_km));
-
 	int joystick_num = ConfMan.getInt("joystick_num");
 	if (joystick_num >= 0) {
 		// Initialize SDL joystick subsystem
@@ -182,6 +176,9 @@ int SdlEventSource::mapKey(SDL_Keycode sdlKey, SDL_Keymod mod, Uint16 unicode) {
 }
 
 bool SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) {
+	_mouseX = x;
+	_mouseY = y;
+
 	event.mouse.x = x;
 	event.mouse.y = y;
 
@@ -192,151 +189,6 @@ bool SdlEventSource::processMouseEvent(Common::Event &event, int x, int y) {
 	return true;
 }
 
-void SdlEventSource::updateKbdMouse() {
-	uint32 curTime = g_system->getMillis(true);
-	if (curTime < _km.last_time + _km.delay_time) {
-		return;
-	}
-
-	_km.last_time = curTime;
-	if (_km.x_down_count == 1) {
-		_km.x_down_time = curTime;
-		_km.x_down_count = 2;
-	}
-	if (_km.y_down_count == 1) {
-		_km.y_down_time = curTime;
-		_km.y_down_count = 2;
-	}
-
-	if (_km.x_vel || _km.y_vel) {
-		if (_km.x_down_count) {
-			if (curTime > _km.x_down_time + 300) {
-				if (_km.x_vel > 0)
-					_km.x_vel += MULTIPLIER;
-				else
-					_km.x_vel -= MULTIPLIER;
-			} else if (curTime > _km.x_down_time + 200) {
-				if (_km.x_vel > 0)
-					_km.x_vel = 5 * MULTIPLIER;
-				else
-					_km.x_vel = -5 * MULTIPLIER;
-			}
-		}
-		if (_km.y_down_count) {
-			if (curTime > _km.y_down_time + 300) {
-				if (_km.y_vel > 0)
-					_km.y_vel += MULTIPLIER;
-				else
-					_km.y_vel -= MULTIPLIER;
-			} else if (curTime > _km.y_down_time + 200) {
-				if (_km.y_vel > 0)
-					_km.y_vel = 5 * MULTIPLIER;
-				else
-					_km.y_vel = -5 * MULTIPLIER;
-			}
-		}
-
-		int16 speedFactor = computeJoystickMouseSpeedFactor();
-
-		// - The modifier key makes the mouse movement slower
-		// - The extra factor "delay/speedFactor" ensures velocities
-		// are independent of the kbdMouse update rate
-		// - all velocities were originally chosen
-		// at a delay of 25, so that is the reference used here
-		// - note: operator order is important to avoid overflow
-		if (_km.modifier) {
-			_km.x += ((_km.x_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
-			_km.y += ((_km.y_vel / 10) * ((int16)_km.delay_time)) / speedFactor;
-		} else {
-			_km.x += (_km.x_vel * ((int16)_km.delay_time)) / speedFactor;
-			_km.y += (_km.y_vel * ((int16)_km.delay_time)) / speedFactor;
-		}
-
-		if (_km.x < 0) {
-			_km.x = 0;
-			_km.x_vel = -1 * MULTIPLIER;
-			_km.x_down_count = 1;
-		} else if (_km.x > _km.x_max * MULTIPLIER) {
-			_km.x = _km.x_max * MULTIPLIER;
-			_km.x_vel = 1 * MULTIPLIER;
-			_km.x_down_count = 1;
-		}
-
-		if (_km.y < 0) {
-			_km.y = 0;
-			_km.y_vel = -1 * MULTIPLIER;
-			_km.y_down_count = 1;
-		} else if (_km.y > _km.y_max * MULTIPLIER) {
-			_km.y = _km.y_max * MULTIPLIER;
-			_km.y_vel = 1 * MULTIPLIER;
-			_km.y_down_count = 1;
-		}
-	}
-}
-
-bool SdlEventSource::handleKbdMouse(Common::Event &event) {
-	int32 oldKmX = _km.x;
-	int32 oldKmY = _km.y;
-
-	updateKbdMouse();
-
-	if (_km.x != oldKmX || _km.y != oldKmY) {
-		if (_graphicsManager) {
-			_graphicsManager->getWindow()->warpMouseInWindow((Uint16)(_km.x / MULTIPLIER), (Uint16)(_km.y / MULTIPLIER));
-		}
-
-		event.type = Common::EVENT_MOUSEMOVE;
-		return processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER);
-	}
-
-	return false;
-}
-
-int16 SdlEventSource::computeJoystickMouseSpeedFactor() const {
-	int16 speedFactor;
-
-	switch (ConfMan.getInt("kbdmouse_speed")) {
-	// 0.25 keyboard pointer speed
-	case 0:
-		speedFactor = 100;
-		break;
-	// 0.5 speed
-	case 1:
-		speedFactor = 50;
-		break;
-	// 0.75 speed
-	case 2:
-		speedFactor = 33;
-		break;
-	// 1.0 speed
-	case 3:
-		speedFactor = 25;
-		break;
-	// 1.25 speed
-	case 4:
-		speedFactor = 20;
-		break;
-	// 1.5 speed
-	case 5:
-		speedFactor = 17;
-		break;
-	// 1.75 speed
-	case 6:
-		speedFactor = 14;
-		break;
-	// 2.0 speed
-	case 7:
-		speedFactor = 12;
-		break;
-	default:
-		speedFactor = 25;
-	}
-
-	// Scale the mouse cursor speed with the display size so moving across
-	// the screen takes a reasonable amount of time at higher resolutions.
-	return speedFactor * 480 / _km.y_max;
-}
-
 void SdlEventSource::SDLModToOSystemKeyFlags(SDL_Keymod mod, Common::Event &event) {
 
 	event.kbd.flags = 0;
@@ -590,11 +442,6 @@ bool SdlEventSource::pollEvent(Common::Event &event) {
 			return true;
 	}
 
-	// Handle mouse control via analog joystick and keyboard
-	if (handleKbdMouse(event)) {
-		return true;
-	}
-
 	return false;
 }
 
@@ -616,11 +463,10 @@ bool SdlEventSource::dispatchSDLEvent(SDL_Event &ev, Common::Event &event) {
 #if SDL_VERSION_ATLEAST(2, 0, 0)
 	case SDL_MOUSEWHEEL: {
 		Sint32 yDir = ev.wheel.y;
-		// HACK: It seems we want the mouse coordinates supplied
-		// with a mouse wheel event. However, SDL2 does not supply
-		// these, thus we use whatever we got last time. It seems
-		// these are always stored in _km.x, _km.y.
-		if (!processMouseEvent(event, _km.x / MULTIPLIER, _km.y / MULTIPLIER)) {
+		// We want the mouse coordinates supplied with a mouse wheel event.
+		// However, SDL2 does not supply these, thus we use whatever we got
+		// last time.
+		if (!processMouseEvent(event, _mouseX, _mouseY)) {
 			return false;
 		}
 		if (yDir < 0) {
@@ -798,10 +644,6 @@ bool SdlEventSource::handleKeyUp(SDL_Event &ev, Common::Event &event) {
 bool SdlEventSource::handleMouseMotion(SDL_Event &ev, Common::Event &event) {
 	event.type = Common::EVENT_MOUSEMOVE;
 
-	// update KbdMouse
-	_km.x = ev.motion.x * MULTIPLIER;
-	_km.y = ev.motion.y * MULTIPLIER;
-
 	return processMouseEvent(event, ev.motion.x, ev.motion.y);
 }
 
@@ -831,10 +673,6 @@ bool SdlEventSource::handleMouseButtonDown(SDL_Event &ev, Common::Event &event)
 	else
 		return false;
 
-	// update KbdMouse
-	_km.x = ev.button.x * MULTIPLIER;
-	_km.y = ev.button.y * MULTIPLIER;
-
 	return processMouseEvent(event, ev.button.x, ev.button.y);
 }
 
@@ -858,10 +696,6 @@ bool SdlEventSource::handleMouseButtonUp(SDL_Event &ev, Common::Event &event) {
 	else
 		return false;
 
-	// update KbdMouse
-	_km.x = ev.button.x * MULTIPLIER;
-	_km.y = ev.button.y * MULTIPLIER;
-
 	return processMouseEvent(event, ev.button.x, ev.button.y);
 }
 
@@ -951,16 +785,6 @@ bool SdlEventSource::handleJoyButtonUp(SDL_Event &ev, Common::Event &event) {
 }
 
 bool SdlEventSource::handleJoyAxisMotion(SDL_Event &ev, Common::Event &event) {
-
-	// TODO: Move hardcoded axis to mouse motion code to the keymapper
-	if (ev.jaxis.axis == JOY_XAXIS) {
-		_km.joy_x = ev.jaxis.value;
-		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
-	} else if (ev.jaxis.axis == JOY_YAXIS) {
-		_km.joy_y = ev.jaxis.value;
-		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
-	}
-
 	event.type = Common::EVENT_JOYAXIS_MOTION;
 	event.joystick.axis = ev.jaxis.axis;
 	event.joystick.position = ev.jaxis.value;
@@ -1071,25 +895,10 @@ bool SdlEventSource::handleControllerButton(const SDL_Event &ev, Common::Event &
 	event.type = buttonUp ? Common::EVENT_JOYBUTTON_UP : Common::EVENT_JOYBUTTON_DOWN;
 	event.joystick.button = button;
 
-	if (event.joystick.button == Common::JOYSTICK_BUTTON_RIGHT_SHOULDER) {
-		// Right shoulder is the modifier button that makes the mouse go slower.
-		_km.modifier = !buttonUp;
-	}
-
 	return true;
 }
 
 bool SdlEventSource::handleControllerAxisMotion(const SDL_Event &ev, Common::Event &event) {
-
-	// TODO: Move hardcoded axis to mouse motion code to the keymapper
-	if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX) {
-		_km.joy_x = ev.caxis.value;
-		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
-	} else if (ev.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY) {
-		_km.joy_y = ev.caxis.value;
-		return handleAxisToMouseMotion(_km.joy_x, _km.joy_y);
-	}
-
 	event.type = Common::EVENT_JOYAXIS_MOTION;
 	event.joystick.axis = ev.caxis.axis;
 	event.joystick.position = ev.caxis.value;
@@ -1098,50 +907,10 @@ bool SdlEventSource::handleControllerAxisMotion(const SDL_Event &ev, Common::Eve
 }
 #endif
 
-bool SdlEventSource::handleAxisToMouseMotion(int16 xAxis, int16 yAxis) {
-#ifdef JOY_INVERT_Y
-	yAxis = -yAxis;
-#endif
-
-	// conversion factor between keyboard mouse and joy axis value
-	int vel_to_axis = (1500 / MULTIPLIER);
-
-	// radial and scaled deadzone
-
-	float analogX = (float)xAxis;
-	float analogY = (float)yAxis;
-	float deadZone = (float)ConfMan.getInt("joystick_deadzone") * 1000.0f;
-
-	float magnitude = sqrt(analogX * analogX + analogY * analogY);
-
-	if (magnitude >= deadZone) {
-		_km.x_down_count = 0;
-		_km.y_down_count = 0;
-		float scalingFactor = 1.0f / magnitude * (magnitude - deadZone) / (32769.0f - deadZone);
-		_km.x_vel = (int16)(analogX * scalingFactor * 32768.0f / vel_to_axis);
-		_km.y_vel = (int16)(analogY * scalingFactor * 32768.0f / vel_to_axis);
-	} else {
-		_km.x_vel = 0;
-		_km.y_vel = 0;
-	}
-
-	return false;
-}
-
 bool SdlEventSource::remapKey(SDL_Event &ev, Common::Event &event) {
 	return false;
 }
 
-void SdlEventSource::resetKeyboardEmulation(int16 x_max, int16 y_max) {
-	_km.x_max = x_max;
-	_km.y_max = y_max;
-	_km.delay_time = 12;
-	_km.last_time = 0;
-	_km.modifier = false;
-	_km.joy_x = 0;
-	_km.joy_y = 0;
-}
-
 void SdlEventSource::fakeWarpMouse(const int x, const int y) {
 	_queuedFakeMouseMove = true;
 	_fakeMouseMove.type = Common::EVENT_MOUSEMOVE;
diff --git a/backends/events/sdl/sdl-events.h b/backends/events/sdl/sdl-events.h
index 54a7d5ef01..746e7f8d59 100644
--- a/backends/events/sdl/sdl-events.h
+++ b/backends/events/sdl/sdl-events.h
@@ -28,9 +28,6 @@
 
 #include "common/events.h"
 
-// multiplier used to increase resolution for keyboard/joystick mouse
-#define MULTIPLIER 16
-
 // Type names which changed between SDL 1.2 and SDL 2.
 #if !SDL_VERSION_ATLEAST(2, 0, 0)
 typedef SDLKey     SDL_Keycode;
@@ -53,11 +50,6 @@ public:
 	 */
 	virtual bool pollEvent(Common::Event &event);
 
-	/**
-	 * Resets keyboard emulation after a video screen change
-	 */
-	virtual void resetKeyboardEmulation(int16 x_max, int16 y_max);
-
 	/**
 	 * Emulates a mouse movement that would normally be caused by a mouse warp
 	 * of the system mouse.
@@ -65,26 +57,12 @@ public:
 	void fakeWarpMouse(const int x, const int y);
 
 protected:
-	/** @name Keyboard mouse emulation
-	 * Disabled by fingolfin 2004-12-18.
-	 * I am keeping the rest of the code in for now, since the joystick
-	 * code (or rather, "hack") uses it, too.
-	 */
-	//@{
-
-	struct KbdMouse {
-		int32 x, y;
-		int16 x_vel, y_vel, x_max, y_max, x_down_count, y_down_count, joy_x, joy_y;
-		uint32 last_time, delay_time, x_down_time, y_down_time;
-		bool modifier;
-	};
-	KbdMouse _km;
-
-	//@}
-
 	/** Scroll lock state - since SDL doesn't track it */
 	bool _scrollLock;
 
+	int _mouseX;
+	int _mouseY;
+
 	/** Joystick */
 	SDL_Joystick *_joystick;
 
@@ -151,8 +129,6 @@ protected:
 	virtual bool handleJoyButtonUp(SDL_Event &ev, Common::Event &event);
 	virtual bool handleJoyAxisMotion(SDL_Event &ev, Common::Event &event);
 	virtual bool handleJoyHatMotion(SDL_Event &ev, Common::Event &event);
-	virtual void updateKbdMouse();
-	virtual bool handleKbdMouse(Common::Event &event);
 
 #if SDL_VERSION_ATLEAST(2, 0, 0)
 	virtual bool handleJoystickAdded(const SDL_JoyDeviceEvent &event);
@@ -164,17 +140,6 @@ protected:
 
 	//@}
 
-	/**
-	 * Update the virtual mouse according to a joystick or game controller axis position change
-	 */
-	virtual bool handleAxisToMouseMotion(int16 xAxis, int16 yAxis);
-
-	/**
-	 * Compute the virtual mouse movement speed factor according to the 'kbdmouse_speed' setting.
-	 * The speed factor is scaled with the display size.
-	 */
-	int16 computeJoystickMouseSpeedFactor() const;
-
 	/**
 	 * Assigns the mouse coords to the mouse event. Furthermore notify the
 	 * graphics manager about the position change.
diff --git a/backends/events/switchsdl/switchsdl-events.cpp b/backends/events/switchsdl/switchsdl-events.cpp
index 54f6784f4b..ff750b20d8 100644
--- a/backends/events/switchsdl/switchsdl-events.cpp
+++ b/backends/events/switchsdl/switchsdl-events.cpp
@@ -97,8 +97,8 @@ void SwitchEventSource::preprocessFingerDown(SDL_Event *event) {
 	// id (for multitouch)
 	SDL_FingerID id = event->tfinger.fingerId;
 
-	int x = _km.x / MULTIPLIER;
-	int y = _km.y / MULTIPLIER;
+	int x = _mouseX;
+	int y = _mouseY;
 
 	if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) {
 		convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y);
@@ -141,8 +141,8 @@ void SwitchEventSource::preprocessFingerUp(SDL_Event *event) {
 		}
 	}
 
-	int x = _km.x / MULTIPLIER;
-	int y = _km.y / MULTIPLIER;
+	int x = _mouseX;
+	int y = _mouseY;
 
 	for (int i = 0; i < MAX_NUM_FINGERS; i++) {
 		if (_finger[port][i].id == id) {
@@ -213,8 +213,10 @@ void SwitchEventSource::preprocessFingerMotion(SDL_Event *event) {
 	}
 
 	if (numFingersDown >= 1) {
-		int x = _km.x / MULTIPLIER;
-		int y = _km.y / MULTIPLIER;
+		int x = _mouseX;
+		int y = _mouseY;
+		int xMax = _graphicsManager->getWindowWidth()  - 1;
+		int yMax = _graphicsManager->getWindowHeight() - 1;
 
 		if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) {
 			convertTouchXYToGameXY(event->tfinger.x, event->tfinger.y, &x, &y);
@@ -253,14 +255,14 @@ void SwitchEventSource::preprocessFingerMotion(SDL_Event *event) {
 
 			// convert touch events to relative mouse pointer events
 			// Whenever an SDL_event involving the mouse is processed,
-			// _km.x/y are truncated from subpixel precision to regular pixel precision.
-			// Therefore, there's no need here to deal with subpixel precision in _km.x/y.
-			x = (_km.x / MULTIPLIER + (event->tfinger.dx * 1.25 * speedFactor * _km.x_max));
-			y = (_km.y / MULTIPLIER + (event->tfinger.dy * 1.25 * speedFactor * _km.y_max));
+			// _mouseX/Y are truncated from subpixel precision to regular pixel precision.
+			// Therefore, there's no need here to deal with subpixel precision in _mouseX/Y.
+			x = (_mouseX + (event->tfinger.dx * 1.25 * speedFactor * xMax));
+			y = (_mouseY + (event->tfinger.dy * 1.25 * speedFactor * yMax));
 		}
 
-		x = CLIP(x, 0, (int)_km.x_max);
-		y = CLIP(y, 0, (int)_km.y_max);
+		x = CLIP(x, 0, xMax);
+		y = CLIP(y, 0, yMax);
 
 		// update the current finger's coordinates so we can track it later
 		for (int i = 0; i < MAX_NUM_FINGERS; i++) {
@@ -285,8 +287,8 @@ void SwitchEventSource::preprocessFingerMotion(SDL_Event *event) {
 				if (numFingersDownLong >= 2) {
 					// starting drag, so push mouse down at current location (back) 
 					// or location of "oldest" finger (front)
-					int mouseDownX = _km.x / MULTIPLIER;
-					int mouseDownY = _km.y / MULTIPLIER;
+					int mouseDownX = _mouseX;
+					int mouseDownY = _mouseY;
 					if (port == 0 && !ConfMan.getBool("touchpad_mouse_mode")) {
 						for (int i = 0; i < MAX_NUM_FINGERS; i++) {
 							if (_finger[port][i].id == id) {
@@ -346,8 +348,8 @@ void SwitchEventSource::preprocessFingerMotion(SDL_Event *event) {
 }
 
 void SwitchEventSource::convertTouchXYToGameXY(float touchX, float touchY, int *gameX, int *gameY) {
-	int screenH = _km.y_max;
-	int screenW = _km.x_max;
+	int screenH = _graphicsManager->getWindowHeight();
+	int screenW = _graphicsManager->getWindowWidth();
 
 	const int dispW = TOUCHSCREEN_WIDTH;
 	const int dispH = TOUCHSCREEN_HEIGHT;
@@ -369,8 +371,8 @@ void SwitchEventSource::convertTouchXYToGameXY(float touchX, float touchY, int *
 	float dispTouchX = (touchX * (float)dispW);
 	float dispTouchY = (touchY * (float)dispH);
 
-	*gameX = CLIP((int)((dispTouchX - x) / sx), 0, (int)_km.x_max);
-	*gameY = CLIP((int)((dispTouchY - y) / sy), 0, (int)_km.y_max);
+	*gameX = CLIP((int)((dispTouchX - x) / sx), 0, screenW);
+	*gameY = CLIP((int)((dispTouchY - y) / sy), 0, screenH);
 }
 
 void SwitchEventSource::finishSimulatedMouseClicks() {
@@ -388,8 +390,8 @@ void SwitchEventSource::finishSimulatedMouseClicks() {
 					SDL_Event ev;
 					ev.type = SDL_MOUSEBUTTONUP;
 					ev.button.button = simulatedButton;
-					ev.button.x = _km.x / MULTIPLIER;
-					ev.button.y = _km.y / MULTIPLIER;
+					ev.button.x = _mouseX;
+					ev.button.y = _mouseY;
 					SDL_PushEvent(&ev);
 
 					_simulatedClickStartTime[port][i] = 0;
diff --git a/backends/events/switchsdl/switchsdl-events.h b/backends/events/switchsdl/switchsdl-events.h
index 6a5076bac3..8aa41b2301 100644
--- a/backends/events/switchsdl/switchsdl-events.h
+++ b/backends/events/switchsdl/switchsdl-events.h
@@ -45,7 +45,8 @@ private:
 		MAX_TAP_TIME = 250, // taps longer than this will not result in mouse click events
 		MAX_TAP_MOTION_DISTANCE = 10, // max distance finger motion in Vita screen pixels to be considered a tap
 		SIMULATED_CLICK_DURATION = 50, // time in ms how long simulated mouse clicks should be
-	}; // track three fingers per panel
+		MULTIPLIER = 16 // multiplier for sub-pixel resolution
+	};
 
 	typedef struct {
 		int id; // -1: no touch
diff --git a/backends/events/symbiansdl/symbiansdl-events.h b/backends/events/symbiansdl/symbiansdl-events.h
index 0393e398f0..9b107dc0f4 100644
--- a/backends/events/symbiansdl/symbiansdl-events.h
+++ b/backends/events/symbiansdl/symbiansdl-events.h
@@ -23,14 +23,14 @@
 #if !defined(BACKEND_EVENTS_SYMBIAN_SDL_H) && !defined(DISABLE_DEFAULT_EVENTMANAGER)
 #define BACKEND_EVENTS_SYMBIAN_SDL_H
 
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/events/sdl/legacy-sdl-events.h"
 
 #define TOTAL_ZONES 3
 
 /**
  * SDL events manager for Symbian
  */
-class SymbianSdlEventSource : public SdlEventSource {
+class SymbianSdlEventSource : public LegacySdlEventSource {
 public:
 	SymbianSdlEventSource();
 
diff --git a/backends/events/webossdl/webossdl-events.cpp b/backends/events/webossdl/webossdl-events.cpp
index 643276a8e9..ad94891c6a 100644
--- a/backends/events/webossdl/webossdl-events.cpp
+++ b/backends/events/webossdl/webossdl-events.cpp
@@ -150,9 +150,6 @@ bool WebOSSdlEventSource::handleMouseButtonDown(SDL_Event &ev,
 			_dragging = true;
 			event.type = Common::EVENT_LBUTTONDOWN;
 			processMouseEvent(event, _curX, _curY);
-			// update KbdMouse
-			_km.x = _curX * MULTIPLIER;
-			_km.y = _curY * MULTIPLIER;
 		}
 		// If we're not in trackpad mode, move the cursor to the tap
 		if (!_trackpadMode) {
@@ -161,17 +158,11 @@ bool WebOSSdlEventSource::handleMouseButtonDown(SDL_Event &ev,
 			// If we're already clicking, hold it until after the move.
 			if (event.type == Common::EVENT_LBUTTONDOWN) {
 				processMouseEvent(event, _curX, _curY);
-				// update KbdMouse
-				_km.x = _curX * MULTIPLIER;
-				_km.y = _curY * MULTIPLIER;
 				g_system->getEventManager()->pushEvent(event);
 			}
 			// Move the mouse
 			event.type = Common::EVENT_MOUSEMOVE;
 			processMouseEvent(event, _curX, _curY);
-			// update KbdMouse
-			_km.x = _curX * MULTIPLIER;
-			_km.y = _curY * MULTIPLIER;
 		}
 		// Watch for a double-tap-triggered drag
 		_dragStartTime = g_system->getMillis();
@@ -200,9 +191,6 @@ bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev,
 		if (ev.button.which == 0 && _dragging) {
 			event.type = Common::EVENT_LBUTTONUP;
 			processMouseEvent(event, _curX, _curY);
-			// update KbdMouse
-			_km.x = _curX * MULTIPLIER;
-			_km.y = _curY * MULTIPLIER;
 			_dragging = false;
 		} else {
 			// If it was the first finger and the click hasn't been
@@ -211,9 +199,6 @@ bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev,
 					!_fingerDown[1] && !_fingerDown[2]) {
 				event.type = Common::EVENT_LBUTTONUP;
 				processMouseEvent(event, _curX, _curY);
-				// update KbdMouse
-				_km.x = _curX * MULTIPLIER;
-				_km.y = _curY * MULTIPLIER;
 				g_system->getEventManager()->pushEvent(event);
 				event.type = Common::EVENT_LBUTTONDOWN;
 				if (_queuedDragTime > 0)
@@ -224,9 +209,6 @@ bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev,
 				// right mouse click.
 				event.type = Common::EVENT_RBUTTONDOWN;
 				processMouseEvent(event, _curX, _curY);
-				// update KbdMouse
-				_km.x = _curX * MULTIPLIER;
-				_km.y = _curY * MULTIPLIER;
 				_queuedRUpTime = g_system->getMillis() + QUEUED_RUP_DELAY;
 			} else if (ev.button.which == 2 &&
 					_fingerDown[0] && _fingerDown[1]) {
@@ -235,9 +217,6 @@ bool WebOSSdlEventSource::handleMouseButtonUp(SDL_Event &ev,
 				// as a right click.
 				event.type = Common::EVENT_MBUTTONUP;
 				processMouseEvent(event, _curX, _curY);
-				// update KbdMouse
-				_km.x = _curX * MULTIPLIER;
-				_km.y = _curY * MULTIPLIER;
 				g_system->getEventManager()->pushEvent(event);
 				event.type = Common::EVENT_MBUTTONDOWN;
 				_fingerDown[1] = false;
@@ -284,9 +263,6 @@ bool WebOSSdlEventSource::handleMouseMotion(SDL_Event &ev,
 				}
 				event.type = Common::EVENT_MOUSEMOVE;
 				processMouseEvent(event, _curX, _curY);
-				// update KbdMouse
-				_km.x = _curX * MULTIPLIER;
-				_km.y = _curY * MULTIPLIER;
 			}
 			break;
 		case 1:
@@ -431,18 +407,12 @@ bool WebOSSdlEventSource::pollEvent(Common::Event &event) {
 	} else if (_queuedRUpTime != 0 && curTime >= _queuedRUpTime) {
 		event.type = Common::EVENT_RBUTTONUP;
 		processMouseEvent(event, _curX, _curY);
-		// update KbdMouse
-		_km.x = _curX * MULTIPLIER;
-		_km.y = _curY * MULTIPLIER;
 		_queuedRUpTime = 0;
 		return true;
 	} else if (_queuedDragTime != 0 && curTime >= _queuedDragTime) {
 		event.type = Common::EVENT_LBUTTONDOWN;
 		_dragging = true;
 		processMouseEvent(event, _curX, _curY);
-		// update KbdMouse
-		_km.x = _curX * MULTIPLIER;
-		_km.y = _curY * MULTIPLIER;
 		_queuedDragTime = 0;
 		return true;
 	}
diff --git a/backends/graphics/sdl/sdl-graphics.cpp b/backends/graphics/sdl/sdl-graphics.cpp
index b45b229d31..36dde9a26e 100644
--- a/backends/graphics/sdl/sdl-graphics.cpp
+++ b/backends/graphics/sdl/sdl-graphics.cpp
@@ -235,7 +235,6 @@ void SdlGraphicsManager::setSystemMousePosition(const int x, const int y) {
 }
 
 void SdlGraphicsManager::handleResizeImpl(const int width, const int height, const int xdpi, const int ydpi) {
-	_eventSource->resetKeyboardEmulation(width - 1, height - 1);
 	_forceRedraw = true;
 }
 
diff --git a/backends/graphics/windowed.h b/backends/graphics/windowed.h
index 99115275de..b85124e78a 100644
--- a/backends/graphics/windowed.h
+++ b/backends/graphics/windowed.h
@@ -86,6 +86,9 @@ public:
 		}
 	}
 
+	int getWindowWidth() const { return _windowWidth; }
+	int getWindowHeight() const { return _windowHeight; }
+
 protected:
 	/**
 	 * @returns whether or not the game screen must have aspect ratio correction
diff --git a/backends/module.mk b/backends/module.mk
index 5c914d07f8..b5d7736698 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -137,6 +137,7 @@ endif
 # derive from the SDL backend, and they all need the following files.
 ifdef SDL_BACKEND
 MODULE_OBJS += \
+	events/sdl/legacy-sdl-events.o \
 	events/sdl/sdl-events.o \
 	graphics/sdl/sdl-graphics.o \
 	graphics/surfacesdl/surfacesdl-graphics.o \
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 20b488aa84..de1fd3380e 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -40,7 +40,7 @@
 #endif
 
 #include "backends/events/default/default-events.h"
-#include "backends/events/sdl/sdl-events.h"
+#include "backends/events/sdl/legacy-sdl-events.h"
 #include "backends/keymapper/hardware-input.h"
 #include "backends/mutex/sdl/sdl-mutex.h"
 #include "backends/timer/sdl/sdl-timer.h"
@@ -203,7 +203,7 @@ void OSystem_SDL::initBackend() {
 	// Create the default event source, in case a custom backend
 	// manager didn't provide one yet.
 	if (_eventSource == 0)
-		_eventSource = new SdlEventSource();
+		_eventSource = new LegacySdlEventSource();
 
 	if (_eventManager == nullptr) {
 		DefaultEventManager *eventManager = new DefaultEventManager(_eventSource);


Commit: e66e35a3fd4b4a3c3b6dafcd7453433f44bfde01
    https://github.com/scummvm/scummvm/commit/e66e35a3fd4b4a3c3b6dafcd7453433f44bfde01
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-03-09T20:00:31+01:00

Commit Message:
COMMON: Move isMouseEvent from Keymapper to Common

Changed paths:
  A common/events.cpp
  R common/EventDispatcher.cpp
    backends/keymapper/keymapper.cpp
    backends/keymapper/keymapper.h
    common/events.h
    common/module.mk


diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 869c7969f8..6dc5f36659 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -257,22 +257,6 @@ Keymapper::IncomingEventType Keymapper::convertToIncomingEventType(const Event &
 	}
 }
 
-bool Keymapper::isMouseEvent(const Event &event) {
-	return event.type == EVENT_LBUTTONDOWN
-	        || event.type == EVENT_LBUTTONUP
-	        || event.type == EVENT_RBUTTONDOWN
-	        || event.type == EVENT_RBUTTONUP
-	        || event.type == EVENT_MBUTTONDOWN
-	        || event.type == EVENT_MBUTTONUP
-	        || event.type == EVENT_WHEELDOWN
-	        || event.type == EVENT_WHEELUP
-	        || event.type == EVENT_X1BUTTONDOWN
-	        || event.type == EVENT_X1BUTTONUP
-	        || event.type == EVENT_X2BUTTONDOWN
-	        || event.type == EVENT_X2BUTTONUP
-	        || event.type == EVENT_MOUSEMOVE;
-}
-
 Event Keymapper::executeAction(const Action *action, const Event &incomingEvent) {
 	Event outgoingEvent = Event(action->event);
 
diff --git a/backends/keymapper/keymapper.h b/backends/keymapper/keymapper.h
index 708732a85f..6f1cf1cb88 100644
--- a/backends/keymapper/keymapper.h
+++ b/backends/keymapper/keymapper.h
@@ -160,7 +160,6 @@ private:
 	Event executeAction(const Action *act, const Event &incomingEvent);
 	EventType convertStartToEnd(EventType eventType);
 	IncomingEventType convertToIncomingEventType(const Event &ev) const;
-	static bool isMouseEvent(const Event &event);
 
 	void hardcodedEventMapping(Event ev);
 	void resetInputState();
diff --git a/common/EventDispatcher.cpp b/common/events.cpp
similarity index 85%
rename from common/EventDispatcher.cpp
rename to common/events.cpp
index 3f7da512b0..529ef7ff26 100644
--- a/common/EventDispatcher.cpp
+++ b/common/events.cpp
@@ -24,6 +24,30 @@
 
 namespace Common {
 
+bool isMouseEvent(const Event &event) {
+	return event.type == EVENT_LBUTTONDOWN
+	        || event.type == EVENT_LBUTTONUP
+	        || event.type == EVENT_RBUTTONDOWN
+	        || event.type == EVENT_RBUTTONUP
+	        || event.type == EVENT_MBUTTONDOWN
+	        || event.type == EVENT_MBUTTONUP
+	        || event.type == EVENT_X1BUTTONDOWN
+	        || event.type == EVENT_X1BUTTONUP
+	        || event.type == EVENT_X2BUTTONDOWN
+	        || event.type == EVENT_X2BUTTONUP
+	        || event.type == EVENT_WHEELDOWN
+	        || event.type == EVENT_WHEELUP
+	        || event.type == EVENT_MOUSEMOVE;
+}
+
+EventSource::~EventSource() {}
+
+EventObserver::~EventObserver() {}
+
+EventMapper::~EventMapper() {}
+
+EventManager::~EventManager() {}
+
 EventDispatcher::EventDispatcher() : _mapper(nullptr) {
 }
 
diff --git a/common/events.h b/common/events.h
index d7a39d52d4..b781f35cca 100644
--- a/common/events.h
+++ b/common/events.h
@@ -221,6 +221,13 @@ struct Event {
 	}
 };
 
+/**
+ * Determinates whether an event is a mouse event
+ *
+ * Mouse events have valid mouse coordinates
+ */
+bool isMouseEvent(const Event &event);
+
 /**
  * A source of Events.
  *
@@ -229,7 +236,7 @@ struct Event {
  */
 class EventSource {
 public:
-	virtual ~EventSource() {}
+	virtual ~EventSource();
 
 	/**
 	 * Queries a event from the source.
@@ -287,7 +294,7 @@ public:
  */
 class EventObserver {
 public:
-	virtual ~EventObserver() {}
+	virtual ~EventObserver();
 
 	/**
 	 * Notifies the observer of an incoming event.
@@ -317,7 +324,7 @@ public:
  */
 class EventMapper {
 public:
-	virtual ~EventMapper() {}
+	virtual ~EventMapper();
 
 	/**
 	 * Map an incoming event to one or more action events
@@ -423,8 +430,7 @@ class Keymapper;
  */
 class EventManager : NonCopyable {
 public:
-	EventManager() {}
-	virtual ~EventManager() {}
+	virtual ~EventManager();
 
 	enum {
 		LBUTTON = 1 << MOUSE_BUTTON_LEFT,
diff --git a/common/module.mk b/common/module.mk
index 717d37a7f1..6769ce3f3b 100644
--- a/common/module.mk
+++ b/common/module.mk
@@ -7,7 +7,7 @@ MODULE_OBJS := \
 	dcl.o \
 	debug.o \
 	error.o \
-	EventDispatcher.o \
+	events.o \
 	file.o \
 	fs.o \
 	gui_options.o \


Commit: 568d882e80dc41066943b3bb5e1742ca41b5c99a
    https://github.com/scummvm/scummvm/commit/568d882e80dc41066943b3bb5e1742ca41b5c99a
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-03-09T20:00:31+01:00

Commit Message:
KEYMAPPER: Introduce a Virtual Mouse event source

The Virtual Mouse is meant to provide a way to control the mouse cursor
on system without a physical mouse. It provides keymapper actions that
are expected to be bound to game controller axes or buttons.

Changed paths:
  A backends/keymapper/virtual-mouse.cpp
  A backends/keymapper/virtual-mouse.h
    backends/events/default/default-events.cpp
    backends/events/default/default-events.h
    backends/keymapper/action.h
    backends/keymapper/keymap.cpp
    backends/keymapper/keymapper.cpp
    backends/module.mk
    backends/platform/sdl/sdl.cpp
    common/events.h
    po/POTFILES


diff --git a/backends/events/default/default-events.cpp b/backends/events/default/default-events.cpp
index e29d9c3da5..8781b1ce7f 100644
--- a/backends/events/default/default-events.cpp
+++ b/backends/events/default/default-events.cpp
@@ -30,7 +30,7 @@
 #include "backends/events/default/default-events.h"
 #include "backends/keymapper/action.h"
 #include "backends/keymapper/keymapper.h"
-#include "backends/keymapper/remap-widget.h"
+#include "backends/keymapper/virtual-mouse.h"
 #include "backends/vkeybd/virtual-keyboard.h"
 
 #include "engines/engine.h"
@@ -58,13 +58,15 @@ DefaultEventManager::DefaultEventManager(Common::EventSource *boss) :
 #ifdef ENABLE_VKEYBD
 	_vk = nullptr;
 #endif
+
+	_virtualMouse = new Common::VirtualMouse(&_dispatcher);
+
 	_keymapper = new Common::Keymapper(this);
-	// EventDispatcher will automatically free the keymapper
 	_dispatcher.registerMapper(_keymapper);
-	_remap = false;
 }
 
 DefaultEventManager::~DefaultEventManager() {
+	delete _virtualMouse;
 #ifdef ENABLE_VKEYBD
 	delete _vk;
 #endif
@@ -372,6 +374,8 @@ Common::Keymap *DefaultEventManager::getGlobalKeymap() {
 	act->setEvent(EVENT_DEBUGGER);
 	globalKeymap->addAction(act);
 
+	_virtualMouse->addActionsToKeymap(globalKeymap);
+
 	return globalKeymap;
 }
 
diff --git a/backends/events/default/default-events.h b/backends/events/default/default-events.h
index 11d523af04..7696c08303 100644
--- a/backends/events/default/default-events.h
+++ b/backends/events/default/default-events.h
@@ -31,6 +31,7 @@ class Keymapper;
 #ifdef ENABLE_VKEYBD
 class VirtualKeyboard;
 #endif
+class VirtualMouse;
 }
 
 
@@ -39,8 +40,9 @@ class DefaultEventManager : public Common::EventManager, Common::EventObserver {
 	Common::VirtualKeyboard *_vk;
 #endif
 
+	Common::VirtualMouse *_virtualMouse;
+
 	Common::Keymapper *_keymapper;
-	bool _remap;
 
 	Common::ArtificialEventSource _artificialEventSource;
 
diff --git a/backends/keymapper/action.h b/backends/keymapper/action.h
index a8e46e8d9c..f798d2f50a 100644
--- a/backends/keymapper/action.h
+++ b/backends/keymapper/action.h
@@ -68,6 +68,12 @@ public:
 		event.customType = evtType;
 	}
 
+	void setCustomBackendActionAxisEvent(const CustomEventType evtType) {
+		event = Event();
+		event.type = EVENT_CUSTOM_BACKEND_ACTION_AXIS;
+		event.customType = evtType;
+	}
+
 	void setCustomEngineActionEvent(const CustomEventType evtType) {
 		event = Event();
 		event.type = EVENT_CUSTOM_ENGINE_ACTION_START;
diff --git a/backends/keymapper/keymap.cpp b/backends/keymapper/keymap.cpp
index 409aff6a2c..64b8c3ddaa 100644
--- a/backends/keymapper/keymap.cpp
+++ b/backends/keymapper/keymap.cpp
@@ -171,9 +171,19 @@ Keymap::ActionArray Keymap::getMappedActions(const Event &event) const {
 		return _hwActionMap[hardwareInput];
 	}
 	case EVENT_JOYAXIS_MOTION: {
-		bool positiveHalf = event.joystick.position >= 0;
-		HardwareInput hardwareInput = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, positiveHalf, "");
-		return _hwActionMap[hardwareInput];
+		if (event.joystick.position != 0) {
+			bool positiveHalf = event.joystick.position >= 0;
+			HardwareInput hardwareInput = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, positiveHalf, "");
+			return _hwActionMap[hardwareInput];
+		} else {
+			// Axis position zero is part of both half axes, and triggers actions bound to both
+			Keymap::ActionArray actions;
+			HardwareInput hardwareInputPos = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, true, "");
+			HardwareInput hardwareInputNeg = HardwareInput::createJoystickHalfAxis("", event.joystick.axis, false, "");
+			actions.push_back(_hwActionMap[hardwareInputPos]);
+			actions.push_back(_hwActionMap[hardwareInputNeg]);
+			return actions;
+		}
 	}
 	case EVENT_CUSTOM_BACKEND_HARDWARE: {
 		HardwareInput hardwareInput = HardwareInput::createCustom("", event.customType, "");
diff --git a/backends/keymapper/keymapper.cpp b/backends/keymapper/keymapper.cpp
index 6dc5f36659..c3d5b9ed0c 100644
--- a/backends/keymapper/keymapper.cpp
+++ b/backends/keymapper/keymapper.cpp
@@ -261,6 +261,23 @@ Event Keymapper::executeAction(const Action *action, const Event &incomingEvent)
 	Event outgoingEvent = Event(action->event);
 
 	IncomingEventType incomingType = convertToIncomingEventType(incomingEvent);
+
+	if (outgoingEvent.type == EVENT_JOYAXIS_MOTION
+	        || outgoingEvent.type == EVENT_CUSTOM_BACKEND_ACTION_AXIS) {
+		if (incomingEvent.type == EVENT_JOYAXIS_MOTION) {
+			// At the moment only half-axes can be bound to actions, hence taking
+			//  the absolute value. If full axes were to be mappable, the action
+			//  could carry the information allowing to distinguish cases here.
+			outgoingEvent.joystick.position = ABS(incomingEvent.joystick.position);
+		} else if (incomingType == kIncomingEventStart) {
+			outgoingEvent.joystick.position = JOYAXIS_MAX;
+		} else if (incomingType == kIncomingEventEnd) {
+			outgoingEvent.joystick.position = 0;
+		}
+
+		return outgoingEvent;
+	}
+
 	if (incomingType == kIncomingEventIgnored) {
 		outgoingEvent.type = EVENT_INVALID;
 		return outgoingEvent;
diff --git a/backends/keymapper/virtual-mouse.cpp b/backends/keymapper/virtual-mouse.cpp
new file mode 100644
index 0000000000..0adf3a2a92
--- /dev/null
+++ b/backends/keymapper/virtual-mouse.cpp
@@ -0,0 +1,219 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "backends/keymapper/virtual-mouse.h"
+
+#include "backends/keymapper/action.h"
+#include "backends/keymapper/keymap.h"
+
+#include "common/config-manager.h"
+#include "common/system.h"
+#include "common/translation.h"
+
+#include "gui/gui-manager.h"
+
+namespace Common {
+
+VirtualMouse::VirtualMouse(EventDispatcher *eventDispatcher) :
+		_eventDispatcher(eventDispatcher),
+		_inputAxisPositionX(0),
+		_inputAxisPositionY(0),
+		_mouseVelocityX(0.f),
+		_mouseVelocityY(0.f),
+		_slowModifier(1.f),
+		_subPixelRemainderX(0.f),
+		_subPixelRemainderY(0.f),
+		_lastUpdateMillis(0) {
+	_eventDispatcher->registerSource(this, false);
+	_eventDispatcher->registerObserver(this, 10, false);
+}
+
+VirtualMouse::~VirtualMouse() {
+	_eventDispatcher->unregisterObserver(this);
+	_eventDispatcher->unregisterSource(this);
+}
+
+bool VirtualMouse::pollEvent(Event &event) {
+	// Update the virtual mouse once per frame (assuming 60Hz)
+	uint32 curTime = g_system->getMillis(true);
+	if (curTime < _lastUpdateMillis + kUpdateDelay) {
+		return false;
+	}
+	_lastUpdateMillis = curTime;
+
+	// Adjust the speed of the cursor according to the virtual screen resolution
+	Common::Rect screenSize;
+	if (g_gui.isActive()) {
+		screenSize = Common::Rect(g_system->getOverlayWidth(), g_system->getOverlayHeight());
+	} else {
+		screenSize = Common::Rect(g_system->getWidth(), g_system->getHeight());
+	}
+
+	float screenSizeSpeedModifier = screenSize.width() / (float)kDefaultScreenWidth;
+
+	// Compute the movement delta when compared to the previous update
+	float deltaX = _subPixelRemainderX + _mouseVelocityX * _slowModifier * screenSizeSpeedModifier * 10.f;
+	float deltaY = _subPixelRemainderY + _mouseVelocityY * _slowModifier * screenSizeSpeedModifier * 10.f;
+
+	Common::Point delta;
+	delta.x = deltaX;
+	delta.y = deltaY;
+
+	// Keep track of sub-pixel movement so the cursor ultimately moves,
+	// even when configured at very low speeds.
+	_subPixelRemainderX = deltaX - delta.x;
+	_subPixelRemainderY = deltaY - delta.y;
+
+	if (delta.x == 0 && delta.y == 0) {
+		return false;
+	}
+
+	// Send a mouse event
+	Common::Point oldPos = g_system->getEventManager()->getMousePos();
+
+	event.type = Common::EVENT_MOUSEMOVE;
+	event.mouse = oldPos + delta;
+
+	event.mouse.x = CLIP<int16>(event.mouse.x, 0, screenSize.width());
+	event.mouse.y = CLIP<int16>(event.mouse.y, 0, screenSize.height());
+
+	g_system->warpMouse(event.mouse.x, event.mouse.y);
+
+	return true;
+}
+
+bool VirtualMouse::notifyEvent(const Event &event) {
+	if (event.type != EVENT_CUSTOM_BACKEND_ACTION_AXIS) {
+		return false;
+	}
+
+	switch (event.customType) {
+	case kCustomActionVirtualAxisUp:
+		if (event.joystick.position == 0 && _inputAxisPositionY > 0) {
+			return true; // Ignore axis reset events if we are already going in the other direction
+		}
+
+		handleAxisMotion(_inputAxisPositionX, -event.joystick.position);
+		return true;
+	case kCustomActionVirtualAxisDown:
+		if (event.joystick.position == 0 && _inputAxisPositionY < 0) {
+			return true;
+		}
+
+		handleAxisMotion(_inputAxisPositionX, event.joystick.position);
+		return true;
+	case kCustomActionVirtualAxisLeft:
+		if (event.joystick.position == 0 && _inputAxisPositionX > 0) {
+			return true;
+		}
+
+		handleAxisMotion(-event.joystick.position, _inputAxisPositionY);
+		return true;
+	case kCustomActionVirtualAxisRight:
+		if (event.joystick.position == 0 && _inputAxisPositionX < 0) {
+			return true;
+		}
+
+		handleAxisMotion(event.joystick.position, _inputAxisPositionY);
+		return true;
+	case kCustomActionVirtualMouseSlow:
+		_slowModifier = 0.9f * (1.f - event.joystick.position / (float)JOYAXIS_MAX) + 0.1f;
+		return true;
+	}
+
+	return false;
+}
+
+void VirtualMouse::addActionsToKeymap(Keymap *keymap) {
+	Action *act;
+
+	act = new Action("VMOUSEUP", _("Virtual mouse up"));
+	act->addDefaultInputMapping("JOY_LEFT_STICK_Y-");
+	act->setCustomBackendActionAxisEvent(VirtualMouse::kCustomActionVirtualAxisUp);
+	keymap->addAction(act);
+
+	act = new Action("VMOUSEDOWN", _("Virtual mouse down"));
+	act->addDefaultInputMapping("JOY_LEFT_STICK_Y+");
+	act->setCustomBackendActionAxisEvent(VirtualMouse::kCustomActionVirtualAxisDown);
+	keymap->addAction(act);
+
+	act = new Action("VMOUSELEFT", _("Virtual mouse left"));
+	act->addDefaultInputMapping("JOY_LEFT_STICK_X-");
+	act->setCustomBackendActionAxisEvent(VirtualMouse::kCustomActionVirtualAxisLeft);
+	keymap->addAction(act);
+
+	act = new Action("VMOUSERIGHT", _("Virtual mouse right"));
+	act->addDefaultInputMapping("JOY_LEFT_STICK_X+");
+	act->setCustomBackendActionAxisEvent(VirtualMouse::kCustomActionVirtualAxisRight);
+	keymap->addAction(act);
+
+	act = new Action("VMOUSESLOW", _("Slow down virtual mouse"));
+	act->addDefaultInputMapping("JOY_RIGHT_SHOULDER");
+	act->setCustomBackendActionAxisEvent(VirtualMouse::kCustomActionVirtualMouseSlow);
+	keymap->addAction(act);
+}
+
+void VirtualMouse::handleAxisMotion(int16 axisPositionX, int16 axisPositionY) {
+	_inputAxisPositionX = axisPositionX;
+	_inputAxisPositionY = axisPositionY;
+
+	float analogX  = (float)_inputAxisPositionX;
+	float analogY  = (float)_inputAxisPositionY;
+	float deadZone = (float)ConfMan.getInt("joystick_deadzone") * 1000.0f;
+
+	float magnitude = sqrtf(analogX * analogX + analogY * analogY);
+
+	if (magnitude >= deadZone) {
+		float scalingFactor = 1.0f / magnitude * (magnitude - deadZone) / (JOYAXIS_MAX - deadZone);
+		float speedFactor = computeJoystickMouseSpeedFactor();
+		_mouseVelocityX = analogX * scalingFactor * speedFactor;
+		_mouseVelocityY = analogY * scalingFactor * speedFactor;
+	} else {
+		_mouseVelocityX = 0.f;
+		_mouseVelocityY = 0.f;
+	}
+}
+
+float VirtualMouse::computeJoystickMouseSpeedFactor() const {
+	switch (ConfMan.getInt("kbdmouse_speed")) {
+	case 0:
+		return 0.25; // 0.25 keyboard pointer speed
+	case 1:
+		return 0.5;  // 0.5 speed
+	case 2:
+		return 0.75; // 0.75 speed
+	case 3:
+		return 1.0;  // 1.0 speed
+	case 4:
+		return 1.25; // 1.25 speed
+	case 5:
+		return 1.5;  // 1.5 speed
+	case 6:
+		return 1.75; // 1.75 speed
+	case 7:
+		return 2.0;  // 2.0 speed
+	default:
+		return 1.0;
+	}
+}
+
+} // End of namespace Common
diff --git a/backends/keymapper/virtual-mouse.h b/backends/keymapper/virtual-mouse.h
new file mode 100644
index 0000000000..58c0f29799
--- /dev/null
+++ b/backends/keymapper/virtual-mouse.h
@@ -0,0 +1,91 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef BACKENDS_KEYMAPPER_VIRTUAL_MOUSE_H
+#define BACKENDS_KEYMAPPER_VIRTUAL_MOUSE_H
+
+#include "common/scummsys.h"
+
+#include "common/events.h"
+
+namespace Common {
+
+class EventDispatcher;
+class Keymap;
+
+/**
+ * The Virtual Mouse can produce mouse move events on systems without a physical mouse.
+ *
+ * It is useful for moving the mouse cursor using a gamepad or a keyboard.
+ *
+ * This class defines a keymap with actions for moving the cursor in all four directions.
+ * The keymapper produces custom backend events whenever keys bound to these actions are
+ * pressed. This class handles the events through its EventObserver interface and produces
+ * mouse move events when necesssary through its EventSource interface.
+ */
+class VirtualMouse : public EventSource, public EventObserver {
+public:
+	VirtualMouse(EventDispatcher *eventDispatcher);
+	~VirtualMouse() override;
+
+	// EventSource API
+	bool pollEvent(Event &event) override;
+
+	// EventObserver API
+	bool notifyEvent(const Event &event) override;
+
+	/** Add the virtual mouse keymapper actions to a keymap */
+	void addActionsToKeymap(Keymap *keymap);
+
+private:
+	static const int32 kUpdateDelay = 12;
+	static const int32 kDefaultScreenWidth = 640;
+
+	enum {
+		kCustomActionVirtualAxisUp    = 10000,
+		kCustomActionVirtualAxisDown  = 10001,
+		kCustomActionVirtualAxisLeft  = 10002,
+		kCustomActionVirtualAxisRight = 10003,
+		kCustomActionVirtualMouseSlow = 10004
+	};
+
+	void handleAxisMotion(int16 axisPositionX, int16 axisPositionY);
+	float computeJoystickMouseSpeedFactor() const;
+
+	EventDispatcher *_eventDispatcher;
+
+	int16 _inputAxisPositionX;
+	int16 _inputAxisPositionY;
+
+	float _mouseVelocityX;
+	float _mouseVelocityY;
+	float _slowModifier;
+
+	float _subPixelRemainderX;
+	float _subPixelRemainderY;
+
+	uint32 _lastUpdateMillis;
+};
+
+} // End of namespace Common
+
+#endif // #ifndef BACKENDS_KEYMAPPER_VIRTUAL_MOUSE_H
diff --git a/backends/module.mk b/backends/module.mk
index b5d7736698..caea5bb11c 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -15,6 +15,7 @@ MODULE_OBJS := \
 	keymapper/keymapper.o \
 	keymapper/remap-widget.o \
 	keymapper/standard-actions.o \
+	keymapper/virtual-mouse.o \
 	log/log.o \
 	midi/alsa.o \
 	midi/dmedia.o \
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index de1fd3380e..79b9ae5006 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -203,7 +203,7 @@ void OSystem_SDL::initBackend() {
 	// Create the default event source, in case a custom backend
 	// manager didn't provide one yet.
 	if (_eventSource == 0)
-		_eventSource = new LegacySdlEventSource();
+		_eventSource = new SdlEventSource();
 
 	if (_eventManager == nullptr) {
 		DefaultEventManager *eventManager = new DefaultEventManager(_eventSource);
diff --git a/common/events.h b/common/events.h
index b781f35cca..d314acf0d2 100644
--- a/common/events.h
+++ b/common/events.h
@@ -76,6 +76,7 @@ enum EventType {
 
 	EVENT_CUSTOM_BACKEND_ACTION_START = 18,
 	EVENT_CUSTOM_BACKEND_ACTION_END   = 19,
+	EVENT_CUSTOM_BACKEND_ACTION_AXIS  = 34,
 	EVENT_CUSTOM_ENGINE_ACTION_START  = 20,
 	EVENT_CUSTOM_ENGINE_ACTION_END    = 21,
 
diff --git a/po/POTFILES b/po/POTFILES
index b72a56ae46..abdef12d73 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -65,6 +65,7 @@ backends/graphics/surfacesdl/surfacesdl-graphics.cpp
 backends/graphics/sdl/sdl-graphics.cpp
 backends/keymapper/hardware-input.cpp
 backends/keymapper/remap-widget.cpp
+backends/keymapper/virtual-mouse.cpp
 backends/midi/windows.cpp
 backends/networking/sdl_net/handlers/createdirectoryhandler.cpp
 backends/networking/sdl_net/handlers/downloadfilehandler.cpp


Commit: cd173c8739668108c664c220244ae5e83238c87d
    https://github.com/scummvm/scummvm/commit/cd173c8739668108c664c220244ae5e83238c87d
Author: Bastien Bouclet (bastien.bouclet at gmail.com)
Date: 2020-03-09T20:00:31+01:00

Commit Message:
3DS: Use the shared virtual mouse

Changed paths:
    backends/platform/3ds/config.cpp
    backends/platform/3ds/config.h
    backends/platform/3ds/options-dialog.cpp
    backends/platform/3ds/options-dialog.h
    backends/platform/3ds/osystem-events.cpp
    backends/platform/3ds/osystem-graphics.cpp


diff --git a/backends/platform/3ds/config.cpp b/backends/platform/3ds/config.cpp
index 4c567c2920..a160ac9950 100644
--- a/backends/platform/3ds/config.cpp
+++ b/backends/platform/3ds/config.cpp
@@ -58,7 +58,6 @@ void loadConfig() {
 	config.showCursor = confGetBool("showcursor", true);
 	config.snapToBorder = confGetBool("snaptoborder", true);
 	config.stretchToFit = confGetBool("stretchtofit", false);
-	config.sensitivity = confGetInt("sensitivity", -5);
 	config.screen = confGetInt("screen", kScreenBoth);
 
 	// Turn off the backlight of any screen not used
@@ -83,7 +82,6 @@ void saveConfig() {
 	confSetBool("showcursor", config.showCursor);
 	confSetBool("snaptoborder", config.snapToBorder);
 	confSetBool("stretchtofit", config.stretchToFit);
-	confSetInt("sensitivity", config.sensitivity);
 	confSetInt("screen", config.screen);
 	ConfMan.flushToDisk();
 }
diff --git a/backends/platform/3ds/config.h b/backends/platform/3ds/config.h
index 02560b2040..346cf19ca4 100644
--- a/backends/platform/3ds/config.h
+++ b/backends/platform/3ds/config.h
@@ -31,7 +31,6 @@ struct Config {
 	bool showCursor;
 	bool snapToBorder;
 	bool stretchToFit;
-	int sensitivity;
 	int screen;
 };
 
diff --git a/backends/platform/3ds/options-dialog.cpp b/backends/platform/3ds/options-dialog.cpp
index a6155e0f70..e83ec34db7 100644
--- a/backends/platform/3ds/options-dialog.cpp
+++ b/backends/platform/3ds/options-dialog.cpp
@@ -59,13 +59,6 @@ OptionsDialog::OptionsDialog() : GUI::Dialog(20, 20, 280, 200) {
 	_screenBottomRadioWidget = new GUI::RadiobuttonWidget(this, 190, 50, 80, 20, _screenRadioGroup, kScreenBottom, _c("Bottom", "3ds-screen"));
 	_screenBothRadioWidget = new GUI::RadiobuttonWidget(this, 155, 70, 80, 20, _screenRadioGroup, kScreenBoth, _c("Both", "3ds-screen"));
 	_screenRadioGroup->setValue(config.screen);
-
-	new GUI::StaticTextWidget(this, 0, 100, 110, 15, _("C-Pad Sensitivity:"), Graphics::kTextAlignRight);
-	_sensitivity = new GUI::SliderWidget(this, 115, 100, 160, 15);
-	_sensitivity->setMinValue(-15);
-	_sensitivity->setMaxValue(30);
-	_sensitivity->setValue(config.sensitivity);
-	_sensitivity->setFlags(GUI::WIDGET_CLEARBG);
 }
 
 OptionsDialog::~OptionsDialog() {
@@ -84,10 +77,6 @@ bool OptionsDialog::getStretchToFit() const {
 	return _stretchToFitCheckbox->getState();
 }
 
-int OptionsDialog::getSensitivity() const {
-	return _sensitivity->getValue();
-}
-
 int OptionsDialog::getScreen() const {
 	return _screenRadioGroup->getValue();
 }
diff --git a/backends/platform/3ds/options-dialog.h b/backends/platform/3ds/options-dialog.h
index 68ff75e242..1922791c75 100644
--- a/backends/platform/3ds/options-dialog.h
+++ b/backends/platform/3ds/options-dialog.h
@@ -61,7 +61,6 @@ public:
 protected:
 	void handleCommand(GUI::CommandSender *sender, uint32 cmd, uint32 data) override;
 
-	GUI::SliderWidget *_sensitivity;
 	GUI::CheckboxWidget *_showCursorCheckbox;
 	GUI::CheckboxWidget *_snapToBorderCheckbox;
 	GUI::CheckboxWidget *_stretchToFitCheckbox;
diff --git a/backends/platform/3ds/osystem-events.cpp b/backends/platform/3ds/osystem-events.cpp
index d4d47f3e0e..87e7a033f8 100644
--- a/backends/platform/3ds/osystem-events.cpp
+++ b/backends/platform/3ds/osystem-events.cpp
@@ -73,6 +73,8 @@ const Common::HardwareInputTableEntry ctrMouseButtons[] = {
     { nullptr,        0,                           nullptr     }
 };
 
+static const int16 CIRCLE_MAX = 160;
+
 static void pushEventQueue(Common::Queue<Common::Event> *queue, Common::Event &event) {
 	Common::StackLock lock(*eventMutex);
 	queue->push(event);
@@ -93,10 +95,8 @@ static void eventThreadFunc(void *arg) {
 	auto eventQueue = (Common::Queue<Common::Event> *)arg;
 
 	uint32 touchStartTime = osys->getMillis();
-	touchPosition lastTouch = {0, 0};
-	float cursorDeltaX = 0;
-	float cursorDeltaY = 0;
-	int circleDeadzone = 20;
+	touchPosition  lastTouch  = {0, 0};
+	circlePosition lastCircle = {0, 0};
 	int borderSnapZone = 6;
 	Common::Event event;
 
@@ -106,25 +106,13 @@ static void eventThreadFunc(void *arg) {
 		} while (osys->sleeping && !osys->exiting);
 
 		hidScanInput();
-		touchPosition touch;
-		circlePosition circle;
 		u32 held = hidKeysHeld();
 		u32 keysPressed = hidKeysDown();
 		u32 keysReleased = hidKeysUp();
 
-		// C-Pad used to control the cursor
-		hidCircleRead(&circle);
-		if (circle.dx < circleDeadzone && circle.dx > -circleDeadzone) {
-			circle.dx = 0;
-		}
-		if (circle.dy < circleDeadzone && circle.dy > -circleDeadzone) {
-			circle.dy = 0;
-		}
-		cursorDeltaX = (0.0002f + config.sensitivity / 100000.f) * circle.dx * abs(circle.dx);
-		cursorDeltaY = (0.0002f + config.sensitivity / 100000.f) * circle.dy * abs(circle.dy);
-
 		// Touch screen events
 		if (held & KEY_TOUCH) {
+			touchPosition touch;
 			hidTouchRead(&touch);
 			if (config.snapToBorder) {
 				if (touch.px < borderSnapZone) {
@@ -143,7 +131,6 @@ static void eventThreadFunc(void *arg) {
 
 			osys->transformPoint(touch);
 
-			osys->warpMouse(touch.px, touch.py);
 			event.mouse.x = touch.px;
 			event.mouse.y = touch.py;
 
@@ -174,21 +161,28 @@ static void eventThreadFunc(void *arg) {
 				event.type = Common::EVENT_LBUTTONUP;
 				pushEventQueue(eventQueue, event);
 			}
-		} else if (cursorDeltaX != 0 || cursorDeltaY != 0) {
-			float scaleRatio = osys->getScaleRatio();
+		}
 
-			lastTouch.px += cursorDeltaX / scaleRatio;
-			lastTouch.py -= cursorDeltaY / scaleRatio;
+		// C-Pad events
+		circlePosition circle;
+		hidCircleRead(&circle);
 
-			osys->clipPoint(lastTouch);
-			osys->warpMouse(lastTouch.px, lastTouch.py);
+		if (circle.dx != lastCircle.dx) {
+			event.type              = Common::EVENT_JOYAXIS_MOTION;
+			event.joystick.axis     = Common::JOYSTICK_AXIS_LEFT_STICK_X;
+			event.joystick.position = (int32)circle.dx * Common::JOYAXIS_MAX / CIRCLE_MAX;
+			pushEventQueue(eventQueue, event);
+		}
 
-			event.mouse.x = lastTouch.px;
-			event.mouse.y = lastTouch.py;
-			event.type = Common::EVENT_MOUSEMOVE;
+		if (circle.dy != lastCircle.dy) {
+			event.type              = Common::EVENT_JOYAXIS_MOTION;
+			event.joystick.axis     = Common::JOYSTICK_AXIS_LEFT_STICK_Y;
+			event.joystick.position = -(int32)circle.dy * Common::JOYAXIS_MAX / CIRCLE_MAX;
 			pushEventQueue(eventQueue, event);
 		}
 
+		lastCircle = circle;
+
 		// Button events
 		doJoyEvent(eventQueue, keysPressed, keysReleased, KEY_L,      Common::JOYSTICK_BUTTON_LEFT_SHOULDER);
 		doJoyEvent(eventQueue, keysPressed, keysReleased, KEY_R,      Common::JOYSTICK_BUTTON_RIGHT_SHOULDER);
@@ -367,6 +361,11 @@ bool OSystem_3DS::pollEvent(Common::Event &event) {
 	}
 
 	event = _eventQueue.pop();
+
+	if (Common::isMouseEvent(event)) {
+		warpMouse(event.mouse.x, event.mouse.y);
+	}
+
 	return true;
 }
 
@@ -458,7 +457,6 @@ void OSystem_3DS::runOptionsDialog() {
 		config.showCursor   = dialog.getShowCursor();
 		config.snapToBorder = dialog.getSnapToBorder();
 		config.stretchToFit = dialog.getStretchToFit();
-		config.sensitivity  = dialog.getSensitivity();
 		config.screen       = dialog.getScreen();
 
 		saveConfig();
diff --git a/backends/platform/3ds/osystem-graphics.cpp b/backends/platform/3ds/osystem-graphics.cpp
index b4ff84cbca..ad2b1d3ca0 100644
--- a/backends/platform/3ds/osystem-graphics.cpp
+++ b/backends/platform/3ds/osystem-graphics.cpp
@@ -123,7 +123,9 @@ void OSystem_3DS::destroy3DSGraphics() {
 
 bool OSystem_3DS::hasFeature(OSystem::Feature f) {
 	return (f == OSystem::kFeatureCursorPalette ||
-	        f == OSystem::kFeatureOverlaySupportsAlpha);
+	        f == OSystem::kFeatureOverlaySupportsAlpha ||
+	        f == OSystem::kFeatureKbdMouseSpeed ||
+	        f == OSystem::kFeatureJoystickDeadzone);
 }
 
 void OSystem_3DS::setFeatureState(OSystem::Feature f, bool enable) {




More information about the Scummvm-git-logs mailing list