diff --git a/backends/events/sdl/legacy-sdl-events.cpp b/backends/events/sdl/legacy-sdl-events.cpp new file mode 100644 index 00000000000..5dfa87673c7 --- /dev/null +++ b/backends/events/sdl/legacy-sdl-events.cpp @@ -0,0 +1,314 @@ +/* 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)); + + ConfMan.registerDefault("kbdmouse_speed", 3); + ConfMan.registerDefault("joystick_deadzone", 3); +} + +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); +} + +#if SDL_VERSION_ATLEAST(2, 0, 0) +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 + +#endif diff --git a/backends/events/sdl/legacy-sdl-events.h b/backends/events/sdl/legacy-sdl-events.h new file mode 100644 index 00000000000..f4a437e7a42 --- /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/graphics/windowed.h b/backends/graphics/windowed.h index 203e69d833a..0420751885c 100644 --- a/backends/graphics/windowed.h +++ b/backends/graphics/windowed.h @@ -28,7 +28,7 @@ #include "common/rect.h" #include "common/config-manager.h" #include "common/textconsole.h" -//#include "graphics/scaler/aspect.h" // ResidualVM: not use +#include "graphics/scaler/aspect.h" enum { STRETCH_CENTER = 0, diff --git a/backends/graphics3d/graphics3d.h b/backends/graphics3d/graphics3d.h index e34f750920f..b9791c98313 100644 --- a/backends/graphics3d/graphics3d.h +++ b/backends/graphics3d/graphics3d.h @@ -26,6 +26,7 @@ #include "common/system.h" #include "common/noncopyable.h" #include "common/keyboard.h" +#include "common/config-manager.h" #include "graphics/mode.h" #include "graphics/palette.h" @@ -59,6 +60,8 @@ public: virtual void clearFocusRectangle() {} virtual void setMouseCursor(const void *buf, uint w, uint h, int hotspotX, int hotspotY, uint32 keycolor, bool dontScale = false, const Graphics::PixelFormat *format = NULL) {} virtual void setCursorPalette(const byte *colors, uint start, uint num) {} + int getWindowWidth() const { return 0; } + int getWindowHeight() const { return 0; } }; #endif diff --git a/backends/module.mk b/backends/module.mk index 4c68118da92..d9c2cb2b76c 100644 --- a/backends/module.mk +++ b/backends/module.mk @@ -117,6 +117,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 \ events/sdl/resvm-sdl-events.o \ graphics3d/sdl/sdl-graphics3d.o \ diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp index 24f70584a41..b114b5c4f99 100644 --- a/backends/platform/sdl/sdl.cpp +++ b/backends/platform/sdl/sdl.cpp @@ -44,11 +44,8 @@ #endif #include "backends/events/default/default-events.h" -// ResidualVM: -// #include "backends/events/sdl/sdl-events.h" -// ResidualVM: -// #include "backends/events/sdl/legacy-sdl-events.h" -#include "backends/events/sdl/resvm-sdl-events.h" +#include "backends/events/sdl/resvm-sdl-events.h" // ResidualVM +#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"