339 lines
11 KiB
C++
339 lines
11 KiB
C++
/* Copyright (C) 2023 Giovanni Cascione <ing.cascione@gmail.com>
|
|
*
|
|
* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
|
|
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
|
|
|
|
#include "backends/platform/libretro/include/libretro-defs.h"
|
|
#include "backends/platform/libretro/include/libretro-os.h"
|
|
#include "backends/platform/libretro/include/libretro-mapper.h"
|
|
#include "backends/platform/libretro/include/libretro-core.h"
|
|
#include "backends/platform/libretro/include/libretro-graphics-surface.h"
|
|
#ifdef USE_OPENGL
|
|
#include "backends/platform/libretro/include/libretro-graphics-opengl.h"
|
|
#endif
|
|
|
|
void OSystem_libretro::updateMouseXY(float deltaAcc, float *cumulativeXYAcc, int doing_x) {
|
|
int *mouseXY;
|
|
int16 screen_wh;
|
|
int *relMouseXY;
|
|
int cumulativeXYAcc_int;
|
|
|
|
if (! deltaAcc)
|
|
return;
|
|
|
|
if (_cursorStatus & CURSOR_STATUS_DOING_SLOWER)
|
|
deltaAcc /= retro_setting_get_mouse_fine_control_speed_reduction();
|
|
|
|
if (doing_x) {
|
|
_cursorStatus |= CURSOR_STATUS_DOING_X;
|
|
mouseXY = &_mouseX;
|
|
screen_wh = getScreenWidth();
|
|
relMouseXY = &_relMouseX;
|
|
} else {
|
|
_cursorStatus |= CURSOR_STATUS_DOING_Y;
|
|
mouseXY = &_mouseY;
|
|
screen_wh = getScreenHeight();
|
|
relMouseXY = &_relMouseY;
|
|
}
|
|
*cumulativeXYAcc += deltaAcc;
|
|
cumulativeXYAcc_int = (int) * cumulativeXYAcc;
|
|
if (cumulativeXYAcc_int != 0) {
|
|
// Set mouse position
|
|
*mouseXY += cumulativeXYAcc_int;
|
|
*mouseXY = (*mouseXY < 0) ? 0 : *mouseXY;
|
|
*mouseXY = (*mouseXY >= screen_wh) ? (screen_wh ? screen_wh - 1 : 0) : *mouseXY;
|
|
// Update accumulator
|
|
*cumulativeXYAcc -= (float)cumulativeXYAcc_int;
|
|
}
|
|
*relMouseXY = (int)deltaAcc;
|
|
}
|
|
|
|
void OSystem_libretro::getMouseXYFromAnalog(bool is_x, int16 coor) {
|
|
|
|
int16 sign = (coor > 0) - (coor < 0);
|
|
uint16 abs_coor = abs(coor);
|
|
float *mouseAcc;
|
|
|
|
if (abs_coor < retro_setting_get_analog_deadzone()) return;
|
|
|
|
_cursorStatus |= CURSOR_STATUS_DOING_JOYSTICK;
|
|
|
|
if (is_x) {
|
|
mouseAcc = &_mouseXAcc;
|
|
} else {
|
|
mouseAcc = &_mouseYAcc;
|
|
}
|
|
|
|
*mouseAcc = ((*mouseAcc > 0) - (*mouseAcc < 0)) == sign ? *mouseAcc : 0;
|
|
float analog_amplitude = (float)(abs_coor - retro_setting_get_analog_deadzone()) / (float)(ANALOG_RANGE - retro_setting_get_analog_deadzone());
|
|
|
|
if (retro_setting_get_analog_response_is_quadratic())
|
|
analog_amplitude *= analog_amplitude;
|
|
|
|
updateMouseXY(sign * analog_amplitude * _adjusted_cursor_speed, mouseAcc, is_x);
|
|
}
|
|
|
|
void OSystem_libretro::getMouseXYFromButton(bool is_x, int16 sign) {
|
|
float *dpadVel;
|
|
float *dpadAcc;
|
|
|
|
if (is_x) {
|
|
dpadVel = &_dpadXVel;
|
|
dpadAcc = &_dpadXAcc;
|
|
} else {
|
|
dpadVel = &_dpadYVel;
|
|
dpadAcc = &_dpadYAcc;
|
|
}
|
|
|
|
if ((*dpadAcc && ((*dpadAcc > 0) - (*dpadAcc < 0)) != sign) || ! sign) {
|
|
*dpadVel = 0.0f;
|
|
*dpadAcc = 0.0f;
|
|
}
|
|
|
|
if (! sign)
|
|
return;
|
|
|
|
_cursorStatus |= CURSOR_STATUS_DOING_JOYSTICK;
|
|
|
|
*dpadVel = MIN(*dpadVel + _inverse_acceleration_time, 1.0f);
|
|
|
|
updateMouseXY(sign * *dpadVel * _adjusted_cursor_speed, dpadAcc, is_x);
|
|
}
|
|
|
|
void OSystem_libretro::processInputs(void) {
|
|
int16 x, y;
|
|
float deltaAcc;
|
|
int key_modifiers [3][2] = {{RETROKE_SHIFT_MOD, RETROKMOD_SHIFT}, {RETROKE_CTRL_MOD, RETROKMOD_CTRL}, {RETROKE_ALT_MOD, RETROKMOD_ALT}};
|
|
int key_flags = 0;
|
|
int retropad_value = 0;
|
|
|
|
static const uint32 retroButtons[2] = {RETRO_DEVICE_ID_MOUSE_LEFT, RETRO_DEVICE_ID_MOUSE_RIGHT};
|
|
static const Common::EventType eventID[2][2] = {{Common::EVENT_LBUTTONDOWN, Common::EVENT_LBUTTONUP}, {Common::EVENT_RBUTTONDOWN, Common::EVENT_RBUTTONUP}};
|
|
|
|
_cursorStatus = 0;
|
|
|
|
// Process input from RetroPad
|
|
mapper_poll_device();
|
|
|
|
// Reduce cursor speed, if required
|
|
if (retro_get_input_device() == RETRO_DEVICE_JOYPAD && mapper_get_mapper_key_status(RETROKE_FINE_CONTROL)) {
|
|
_cursorStatus |= CURSOR_STATUS_DOING_SLOWER;
|
|
} else {
|
|
_cursorStatus &= ~CURSOR_STATUS_DOING_SLOWER;
|
|
}
|
|
|
|
// Handle x,y
|
|
int x_coor_cursor = mapper_get_mapper_key_value(RETROKE_RIGHT) - mapper_get_mapper_key_value(RETROKE_LEFT);
|
|
int y_coor_cursor = mapper_get_mapper_key_value(RETROKE_DOWN) - mapper_get_mapper_key_value(RETROKE_UP);
|
|
|
|
if (abs(x_coor_cursor) > 1) {
|
|
getMouseXYFromAnalog(true, x_coor_cursor);
|
|
} else
|
|
getMouseXYFromButton(true, x_coor_cursor);
|
|
|
|
if (abs(y_coor_cursor) > 1)
|
|
getMouseXYFromAnalog(false, y_coor_cursor);
|
|
else
|
|
getMouseXYFromButton(false, y_coor_cursor);
|
|
|
|
if (_cursorStatus & CURSOR_STATUS_DOING_JOYSTICK) {
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_MOUSEMOVE;
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
ev.relMouse.x = _cursorStatus & CURSOR_STATUS_DOING_X ? _relMouseX : 0;
|
|
ev.relMouse.y = _cursorStatus & CURSOR_STATUS_DOING_Y ? _relMouseY : 0;
|
|
_events.push_back(ev);
|
|
setMousePosition(_mouseX, _mouseY);
|
|
}
|
|
|
|
// Handle special functions
|
|
if (mapper_get_mapper_key_value(RETROKE_SCUMMVM_GUI)) {
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_MAINMENU;
|
|
_events.push_back(ev);
|
|
}
|
|
|
|
if ((mapper_get_mapper_key_status(RETROKE_VKBD) & ((1 << RETRO_DEVICE_KEY_STATUS) | (1 << RETRO_DEVICE_KEY_CHANGED))) == ((1 << RETRO_DEVICE_KEY_STATUS) | (1 << RETRO_DEVICE_KEY_CHANGED))) {
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_VIRTUAL_KEYBOARD;
|
|
_events.push_back(ev);
|
|
}
|
|
|
|
|
|
// Handle mouse buttons
|
|
retropad_value = mapper_get_mapper_key_status(RETROKE_LEFT_BUTTON);
|
|
if (retropad_value & (1 << RETRO_DEVICE_KEY_CHANGED)) {
|
|
Common::Event ev;
|
|
ev.type = eventID[0][(retropad_value & (1 << RETRO_DEVICE_KEY_STATUS)) ? 0 : 1];
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
}
|
|
|
|
retropad_value = mapper_get_mapper_key_status(RETROKE_RIGHT_BUTTON);
|
|
if (retropad_value & (1 << RETRO_DEVICE_KEY_CHANGED)) {
|
|
Common::Event ev;
|
|
ev.type = eventID[1][(retropad_value & (1 << RETRO_DEVICE_KEY_STATUS)) ? 0 : 1];
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
}
|
|
|
|
// Handle keyboard buttons
|
|
for (uint8 i = 0; i < sizeof(key_modifiers) / sizeof(key_modifiers[0]); i++) {
|
|
if (mapper_get_mapper_key_value(key_modifiers[i][0]))
|
|
key_flags |= key_modifiers[i][1];
|
|
}
|
|
|
|
for (uint8 i = 0; i < RETRO_DEVICE_ID_JOYPAD_LAST; i++) {
|
|
if (mapper_get_device_key_retro_id(i) <= 0)
|
|
continue;
|
|
retropad_value = mapper_get_device_key_status(i);
|
|
|
|
if (retropad_value & (1 << RETRO_DEVICE_KEY_CHANGED)) {
|
|
processKeyEvent((retropad_value & (1 << RETRO_DEVICE_KEY_STATUS)), mapper_get_device_key_scummvm_id(i), 0, key_flags);
|
|
}
|
|
}
|
|
|
|
if (retro_setting_get_gamepad_cursor_only())
|
|
return;
|
|
|
|
#if defined(WIIU) || defined(__SWITCH__)
|
|
int p_x = retro_input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
|
|
int p_y = retro_input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
|
|
int p_press = retro_input_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED);
|
|
int px = (int)((p_x + 0x7fff) * getScreenWidth() / 0xffff);
|
|
int py = (int)((p_y + 0x7fff) * getScreenHeight() / 0xffff);
|
|
|
|
static int ptrhold = 0;
|
|
|
|
if (p_press)
|
|
ptrhold++;
|
|
else
|
|
ptrhold = 0;
|
|
|
|
if (ptrhold > 0) {
|
|
_mouseX = px;
|
|
_mouseY = py;
|
|
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_MOUSEMOVE;
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
setMousePosition(_mouseX, _mouseY);
|
|
}
|
|
|
|
if (ptrhold > 10 && _ptrmouseButton == 0) {
|
|
_ptrmouseButton = 1;
|
|
Common::Event ev;
|
|
ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
} else if (ptrhold == 0 && _ptrmouseButton == 1) {
|
|
_ptrmouseButton = 0;
|
|
Common::Event ev;
|
|
ev.type = eventID[0][_ptrmouseButton ? 0 : 1];
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
}
|
|
|
|
#endif
|
|
|
|
// Process input from physical mouse
|
|
x = retro_input_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X);
|
|
y = retro_input_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y);
|
|
|
|
// > X Axis
|
|
if (x != 0) {
|
|
_cursorStatus |= (CURSOR_STATUS_DOING_MOUSE | CURSOR_STATUS_DOING_X);
|
|
if (x > 0) {
|
|
// Reset accumulator when changing direction
|
|
_mouseXAcc = (_mouseXAcc < 0.0) ? 0.0 : _mouseXAcc;
|
|
}
|
|
if (x < 0) {
|
|
// Reset accumulator when changing direction
|
|
_mouseXAcc = (_mouseXAcc > 0.0) ? 0.0 : _mouseXAcc;
|
|
}
|
|
deltaAcc = (float)x * retro_setting_get_mouse_speed();
|
|
updateMouseXY(deltaAcc, &_mouseXAcc, 1);
|
|
}
|
|
// > Y Axis
|
|
if (y != 0) {
|
|
_cursorStatus |= (CURSOR_STATUS_DOING_MOUSE | CURSOR_STATUS_DOING_Y);
|
|
if (y > 0) {
|
|
// Reset accumulator when changing direction
|
|
_mouseYAcc = (_mouseYAcc < 0.0) ? 0.0 : _mouseYAcc;
|
|
}
|
|
if (y < 0) {
|
|
// Reset accumulator when changing direction
|
|
_mouseYAcc = (_mouseYAcc > 0.0) ? 0.0 : _mouseYAcc;
|
|
}
|
|
deltaAcc = (float)y * retro_setting_get_mouse_speed();
|
|
updateMouseXY(deltaAcc, &_mouseYAcc, 0);
|
|
}
|
|
|
|
if (_cursorStatus & CURSOR_STATUS_DOING_MOUSE) {
|
|
Common::Event ev;
|
|
ev.type = Common::EVENT_MOUSEMOVE;
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
ev.relMouse.x = _cursorStatus & CURSOR_STATUS_DOING_X ? _relMouseX : 0;
|
|
ev.relMouse.y = _cursorStatus & CURSOR_STATUS_DOING_Y ? _relMouseY : 0;
|
|
_events.push_back(ev);
|
|
setMousePosition(_mouseX, _mouseY);
|
|
}
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
Common::Event ev;
|
|
bool down = retro_input_cb(0, RETRO_DEVICE_MOUSE, 0, retroButtons[i]);
|
|
if (down != _mouseButtons[i]) {
|
|
_mouseButtons[i] = down;
|
|
ev.type = eventID[i][down ? 0 : 1];
|
|
ev.mouse.x = _mouseX;
|
|
ev.mouse.y = _mouseY;
|
|
_events.push_back(ev);
|
|
}
|
|
}
|
|
}
|
|
|
|
void OSystem_libretro::processKeyEvent(bool down, unsigned keycode, uint32 character, uint16 key_modifiers) {
|
|
int _keyflags = 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_CTRL) ? Common::KBD_CTRL : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_ALT) ? Common::KBD_ALT : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_SHIFT) ? Common::KBD_SHIFT : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_META) ? Common::KBD_META : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_CAPSLOCK) ? Common::KBD_CAPS : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_NUMLOCK) ? Common::KBD_NUM : 0;
|
|
_keyflags |= (key_modifiers & RETROKMOD_SCROLLOCK) ? Common::KBD_SCRL : 0;
|
|
|
|
Common::Event ev;
|
|
ev.type = down ? Common::EVENT_KEYDOWN : Common::EVENT_KEYUP;
|
|
ev.kbd.keycode = (Common::KeyCode)keycode;
|
|
ev.kbd.flags = _keyflags;
|
|
ev.kbd.ascii = keycode;
|
|
|
|
/* If shift was down then send upper case letter to engine */
|
|
if (ev.kbd.ascii >= 97 && ev.kbd.ascii <= 122 && (_keyflags & Common::KBD_SHIFT))
|
|
ev.kbd.ascii = ev.kbd.ascii & ~0x20;
|
|
|
|
_events.push_back(ev);
|
|
}
|