PSP2: More settings for touch (direct touch on/off, pointer speed)

This commit is contained in:
rsn8887 2018-01-23 14:37:04 -06:00
parent b785f4a290
commit 5551241c51
4 changed files with 281 additions and 83 deletions

View File

@ -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) {
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);
}
}
}
}
} 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);
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;
}
event->type = SDL_MOUSEMOTION;
event->motion.x = mouse_x;
event->motion.y = mouse_y;
switch (event->type) {
case SDL_FINGERDOWN:
preprocessFingerDown(event);
break;
case SDL_FINGERUP:
preprocessFingerUp(event);
break;
case SDL_FINGERMOTION:
preprocessFingerMotion(event);
break;
}
}
}
}
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;
}
event->type = SDL_MOUSEBUTTONDOWN;
event->button.button = simulatedButton;
event->button.x = x;
event->button.y = y;
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) {
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

View File

@ -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 */

View File

@ -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);

View File

@ -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