diff options
-rw-r--r-- | backends/events/psp2sdl/psp2sdl-events.cpp | 296 | ||||
-rw-r--r-- | backends/events/psp2sdl/psp2sdl-events.h | 13 | ||||
-rw-r--r-- | backends/platform/sdl/psp2/psp2.cpp | 27 | ||||
-rw-r--r-- | backends/platform/sdl/psp2/psp2.h | 14 |
4 files changed, 274 insertions, 76 deletions
diff --git a/backends/events/psp2sdl/psp2sdl-events.cpp b/backends/events/psp2sdl/psp2sdl-events.cpp index b774b9eda1..81f057f2e0 100644 --- a/backends/events/psp2sdl/psp2sdl-events.cpp +++ b/backends/events/psp2sdl/psp2sdl-events.cpp @@ -25,6 +25,7 @@ #if defined(PSP2) #include <psp2/kernel/processmgr.h> +#include <psp2/touch.h> #include "backends/platform/sdl/psp2/psp2.h" #include "backends/events/psp2sdl/psp2sdl-events.h" #include "backends/platform/sdl/sdl.h" @@ -38,97 +39,256 @@ PSP2EventSource::PSP2EventSource() { for (int i = 0; i < SCE_TOUCH_PORT_MAX_NUM; i++) { - for (int j = 0; j < 2; j++) { + for (int j = 0; j < MAX_NUM_FINGERS; j++) { _finger[i][j].id = -1; } } + // need specs of front panel for accurate direct touch + sceTouchGetPanelInfo(0, &panelInfo); } void PSP2EventSource::preprocessEvents(SDL_Event *event) { - // prevent suspend (scummvm games contains a lot of cutscenes..) + // prevent suspend (scummvm games contain a lot of cutscenes..) sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_AUTO_SUSPEND); sceKernelPowerTick(SCE_KERNEL_POWER_TICK_DISABLE_OLED_OFF); - // left mouse click gesture: single finger short tap - // right mouse click gesture: second finger short tap while first finger is still down + // Supported touch gestures: + // left mouse click: single finger short tap + // right mouse click: second finger short tap while first finger is still down + // pointer motion: single finger drag if (event->type == SDL_FINGERDOWN || event->type == SDL_FINGERUP || event->type == SDL_FINGERMOTION) { - // front (0) or back (1) panel? + // front (0) or back (1) panel SDL_TouchID port = event->tfinger.touchId; - // which touchID (for multitouch)? - SDL_FingerID id = event->tfinger.fingerId; - - int numFingersDown = 0; - for (int j = 0; j < 2; j++) { - if (_finger[port][j].id >= 0) { - numFingersDown++; + if (port < SCE_TOUCH_PORT_MAX_NUM && port >= 0) { + switch (event->type) { + case SDL_FINGERDOWN: + preprocessFingerDown(event); + break; + case SDL_FINGERUP: + preprocessFingerUp(event); + break; + case SDL_FINGERMOTION: + preprocessFingerMotion(event); + break; } } + } +} - if (port < SCE_TOUCH_PORT_MAX_NUM && port >= 0) { - if (event->type == SDL_FINGERDOWN) { - for (int i = 0; i < 2; i++) { - if (_finger[port][i].id == -1 || i == 1) { - _finger[port][i].id = id; - _finger[port][i].timeLastDown = event->tfinger.timestamp; - break; - } - } - } else if (event->type == SDL_FINGERUP) { - // 250 ms long tap is interpreted as right/left mouse click depending on number of fingers down - for (int i = 0; i < 2; i++) { - if (_finger[port][i].id == id) { - - _finger[port][i].id = -1; - - if ((event->tfinger.timestamp - _finger[port][i].timeLastDown) <= 250) { - if (numFingersDown == 2 || numFingersDown == 1) { - Uint8 simulatedButton = 0; - if (numFingersDown == 2) { - simulatedButton = SDL_BUTTON_RIGHT; - } else if (numFingersDown == 1) { - simulatedButton = SDL_BUTTON_LEFT; - } - - // simulate button click due to tap gesture - event->type = SDL_MOUSEBUTTONDOWN; - event->button.button = simulatedButton; - event->button.x = _km.x / MULTIPLIER; - event->button.y = _km.y / MULTIPLIER; - - SDL_Event ev; - ev.type = SDL_MOUSEBUTTONUP; - ev.button.button = simulatedButton; - ev.button.x = _km.x / MULTIPLIER; - ev.button.y = _km.y / MULTIPLIER; - SDL_PushEvent(&ev); - } - } +void PSP2EventSource::preprocessFingerDown(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + // id (for multitouch) + SDL_FingerID id = event->tfinger.fingerId; + + // find out how many fingers were down before this event + int numFingersDown = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + numFingersDown++; + } + } + + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == -1) { + _finger[port][i].id = id; + _finger[port][i].timeLastDown = event->tfinger.timestamp; + break; + } + } +} + +void PSP2EventSource::preprocessFingerUp(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + // id (for multitouch) + SDL_FingerID id = event->tfinger.fingerId; + + // find out how many fingers were down before this event + int numFingersDown = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + numFingersDown++; + } + } + + int x = _km.x / MULTIPLIER; + int y = _km.y / MULTIPLIER; + + if (!ConfMan.getBool("touchpad_mouse_mode") && port == 0) { + convertTouchToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } + + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id == id) { + _finger[port][i].id = -1; + if ((event->tfinger.timestamp - _finger[port][i].timeLastDown) <= 250) { + // short (<250 ms) tap is interpreted as right/left mouse click depending on # fingers already down + if (numFingersDown == 2 || numFingersDown == 1) { + Uint8 simulatedButton = 0; + if (numFingersDown == 2) { + simulatedButton = SDL_BUTTON_RIGHT; + } else if (numFingersDown == 1) { + simulatedButton = SDL_BUTTON_LEFT; } - } - } else if (event->type == SDL_FINGERMOTION && numFingersDown == 1) { - // convert touch events to relative mouse pointer events - Sint32 mouse_x = _km.x / MULTIPLIER + (event->tfinger.dx * _km.x_max); - Sint32 mouse_y = _km.y / MULTIPLIER + (event->tfinger.dy * _km.y_max); + event->type = SDL_MOUSEBUTTONDOWN; + event->button.button = simulatedButton; + event->button.x = x; + event->button.y = y; - if (mouse_x > _km.x_max) { - mouse_x = _km.x_max; - } else if (mouse_x < 0) { - mouse_x = 0; - } - if (mouse_y > _km.y_max) { - mouse_y = _km.y_max; - } else if (mouse_y < 0) { - mouse_y = 0; + SDL_Event ev; + ev.type = SDL_MOUSEBUTTONUP; + ev.button.button = simulatedButton; + ev.button.x = x; + ev.button.y = y; + SDL_PushEvent(&ev); } + } + } + } +} + +void PSP2EventSource::preprocessFingerMotion(SDL_Event *event) { + // front (0) or back (1) panel + SDL_TouchID port = event->tfinger.touchId; + + // find out how many fingers were down before this event + int numFingersDown = 0; + for (int i = 0; i < MAX_NUM_FINGERS; i++) { + if (_finger[port][i].id >= 0) { + numFingersDown++; + } + } + + if (numFingersDown == 1) { - event->type = SDL_MOUSEMOTION; - event->motion.x = mouse_x; - event->motion.y = mouse_y; + int x = _km.x / MULTIPLIER;; + int y = _km.y / MULTIPLIER; + + if (!ConfMan.getBool("touchpad_mouse_mode") && port == 0) { + convertTouchToGameXY(event->tfinger.x, event->tfinger.y, &x, &y); + } else { + // for relative mode, use the pointer speed setting + float speedFactor = 1.0; + + switch (ConfMan.getInt("kbdmouse_speed")) { + // 0.25 keyboard pointer speed + case 0: + speedFactor = 0.25; + break; + // 0.5 speed + case 1: + speedFactor = 0.5; + break; + // 0.75 speed + case 2: + speedFactor = 0.75; + break; + // 1.0 speed + case 3: + speedFactor = 1.0; + break; + // 1.25 speed + case 4: + speedFactor = 1.25; + break; + // 1.5 speed + case 5: + speedFactor = 1.5; + break; + // 1.75 speed + case 6: + speedFactor = 1.75; + break; + // 2.0 speed + case 7: + speedFactor = 2.0; + break; + default: + speedFactor = 1.0; } + + // 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)); + } + + if (x > _km.x_max) { + x = _km.x_max; + } else if (x < 0) { + x = 0; + } + if (y > _km.y_max) { + y = _km.y_max; + } else if (y < 0) { + y = 0; } + + event->type = SDL_MOUSEMOTION; + event->motion.x = x; + event->motion.y = y; + } +} + +void PSP2EventSource::convertTouchToGameXY(float touchX, float touchY, int *gameX, int *gameY) { + // Find touch coordinates in terms of Vita screen pixels + float aaTouchX = touchX * (panelInfo.maxAaX - panelInfo.minAaX) + panelInfo.minAaX; + float aaTouchY = touchY * (panelInfo.maxAaY - panelInfo.minAaY) + panelInfo.minAaY; + + float screenTouchX = (aaTouchX - panelInfo.minDispX) * 960 / panelInfo.maxDispX; + float screenTouchY = (aaTouchY - panelInfo.minDispY) * 544 / panelInfo.maxDispY; + + // Find four corners of game screen in Vita screen coordinates + // This depends on the fullscreen and aspect ratio correction settings (at least on Vita) + + float gameXMin = 0; + float gameXMax = 0; + float gameYMin = 0; + float gameYMax = 0; + float aspectRatio = 4.0 / 3.0; + + // vertical + if (ConfMan.getBool("fullscreen")) { + gameYMin = 0.0; + gameYMax = 544.0; + } else { + if (_km.y_max <= 272) { + gameYMin = (544.0 - (_km.y_max * 2.0)) / 2.0; + gameYMax = 544.0 - gameYMin; + } else { + gameYMin = (544.0 - (_km.y_max)) / 2.0; + gameYMax = 544 - gameYMin; + } + } + // horizontal + if (ConfMan.getBool("aspect_ratio")) { + aspectRatio = 4.0/3.0; + } else { + aspectRatio = (float)_km.x_max / (float)_km.y_max; + } + gameXMin = (960 - (gameYMax - gameYMin) * aspectRatio) / 2.0; + gameXMax = 960.0 - gameXMin; + + // find game pixel coordinates corresponding to front panel touch coordinates + int x = (screenTouchX - gameXMin) / (gameXMax - gameXMin) * _km.x_max; + int y = (screenTouchY - gameYMin) / (gameYMax - gameYMin) * _km.y_max; + + if (x < 0) { + x = 0; + } else if (x > _km.x_max) { + x = _km.x_max; + } else if (y < 0) { + y = 0; + } else if (y > _km.y_max) { + y = _km.y_max; } + *gameX = x; + *gameY = y; } #endif diff --git a/backends/events/psp2sdl/psp2sdl-events.h b/backends/events/psp2sdl/psp2sdl-events.h index a71553681a..a4143af157 100644 --- a/backends/events/psp2sdl/psp2sdl-events.h +++ b/backends/events/psp2sdl/psp2sdl-events.h @@ -34,11 +34,22 @@ public: PSP2EventSource(); protected: void preprocessEvents(SDL_Event *event) override; +private: typedef struct { int id; // -1: no touch int timeLastDown; } Touch; - Touch _finger[SCE_TOUCH_PORT_MAX_NUM][2]; // track only two fingers per panel + + enum { + MAX_NUM_FINGERS = 3, + }; // track three fingers per panel + Touch _finger[SCE_TOUCH_PORT_MAX_NUM][MAX_NUM_FINGERS]; // keep track of finger status + + void preprocessFingerDown(SDL_Event *event); + void preprocessFingerUp(SDL_Event *event); + void preprocessFingerMotion(SDL_Event *event); + void convertTouchToGameXY(float touchX, float touchY, int *gameX, int *gameY); + SceTouchPanelInfo panelInfo; }; #endif /* BACKEND_EVENTS_PSP2_H */ diff --git a/backends/platform/sdl/psp2/psp2.cpp b/backends/platform/sdl/psp2/psp2.cpp index f959bbaf49..62b0a68320 100644 --- a/backends/platform/sdl/psp2/psp2.cpp +++ b/backends/platform/sdl/psp2/psp2.cpp @@ -80,6 +80,7 @@ void OSystem_PSP2::initBackend() { ConfMan.registerDefault("kbdmouse_speed", 3); ConfMan.registerDefault("joystick_deadzone", 2); ConfMan.registerDefault("shader", 0); + ConfMan.registerDefault("touchpad_mouse_mode", true); if (!ConfMan.hasKey("fullscreen")) { ConfMan.setBool("fullscreen", true); @@ -96,7 +97,10 @@ void OSystem_PSP2::initBackend() { if (!ConfMan.hasKey("shader")) { ConfMan.setInt("shader", 2); } - + if (!ConfMan.hasKey("touchpad_mouse_mode")) { + ConfMan.setBool("touchpad_mouse_mode", false); + } + // Create the savefile manager if (_savefileManager == 0) _savefileManager = new DefaultSaveFileManager("ux0:data/scummvm/saves"); @@ -125,9 +129,30 @@ bool OSystem_PSP2::hasFeature(Feature f) { return (f == kFeatureKbdMouseSpeed || f == kFeatureJoystickDeadzone || f == kFeatureShader || + f == kFeatureTouchpadMode || OSystem_SDL::hasFeature(f)); } +void OSystem_PSP2::setFeatureState(Feature f, bool enable) { + switch (f) { + case kFeatureTouchpadMode: + ConfMan.setBool("touchpad_mouse_mode", enable); + break; + } + OSystem_SDL::setFeatureState(f, enable); +} + +bool OSystem_PSP2::getFeatureState(Feature f) { + switch (f) { + case kFeatureTouchpadMode: + return ConfMan.getBool("touchpad_mouse_mode"); + break; + default: + return OSystem_SDL::getFeatureState(f); + break; + } +} + void OSystem_PSP2::logMessage(LogMessageType::Type type, const char *message) { #if __PSP2_DEBUG__ psp2shell_print(message); diff --git a/backends/platform/sdl/psp2/psp2.h b/backends/platform/sdl/psp2/psp2.h index 65d98098be..db9140e4c1 100644 --- a/backends/platform/sdl/psp2/psp2.h +++ b/backends/platform/sdl/psp2/psp2.h @@ -34,19 +34,21 @@ public: OSystem_PSP2(Common::String baseConfigName = "scummvm.ini"); virtual ~OSystem_PSP2() {} - virtual void init(); - virtual void initBackend(); - virtual bool hasFeature(Feature f); - virtual void logMessage(LogMessageType::Type type, const char *message); + virtual void init() override; + virtual void initBackend() override; + virtual bool hasFeature(Feature f) override; + virtual void setFeatureState(Feature f, bool enable) override; + virtual bool getFeatureState(Feature f) override; + virtual void logMessage(LogMessageType::Type type, const char *message) override; protected: // Base string for creating the default path and filename // for the configuration file Common::String _baseConfigName; - virtual Common::String getDefaultConfigFileName(); + virtual Common::String getDefaultConfigFileName() override; - virtual Common::WriteStream *createLogFile(); + virtual Common::WriteStream *createLogFile() override; }; #endif |