beetle-psx-libretro/input.cpp

1153 lines
43 KiB
C++
Raw Normal View History

2017-11-19 10:45:16 +00:00
#include "libretro.h"
#include "mednafen/mednafen-types.h"
#include <math.h>
#include <stdio.h>
2017-12-07 14:09:42 +00:00
#include <algorithm>
2017-11-19 10:45:16 +00:00
#include "mednafen/git.h"
#include "mednafen/psx/frontio.h"
#include "input.h"
2017-11-19 10:45:16 +00:00
//------------------------------------------------------------------------------
// Locals
//------------------------------------------------------------------------------
static retro_environment_t environ_cb; // cached during input_init_env
2017-11-19 10:45:16 +00:00
static retro_rumble_interface rumble; // acquired during input_init_env
static FrontIO* FIO; // cached in input_set_fio
#define MAX_CONTROLLERS 8
static unsigned players = 2;
static bool enable_analog_calibration = false;
2017-11-22 23:53:59 +00:00
static float mouse_sensitivity = 1.0f;
2017-11-23 13:08:26 +00:00
static int gun_cursor = FrontIO::SETTING_GUN_CROSSHAIR_CROSS;
2017-11-19 10:45:16 +00:00
int gun_input_mode = SETTING_GUN_INPUT_LIGHTGUN;
// Touchscreen Lightgun Sensitivity
static int pointer_pressed = 0;
static const int POINTER_PRESSED_CYCLES = 4;
static int pointer_cycles_after_released = 0;
static int pointer_pressed_last_x = 0;
static int pointer_pressed_last_y = 0;
2018-08-21 16:07:54 +00:00
// NegCon adjustment parameters
// > The NegCon 'twist' action is somewhat awkward when mapped
// to a standard analog stick -> user should be able to tweak
// response/deadzone for comfort
// > When response is linear, 'additional' deadzone (set here)
// may be left at zero, since this is normally handled via in-game
// options menus
// > When response is non-linear, deadzone should be set to match the
// controller being used (otherwise precision may be lost)
// > negcon_linearity:
// - 1: Response is linear - recommended when using racing wheel
// peripherals, not recommended for standard gamepads
// - 2: Response is quadratic - optimal setting for gamepads
// - 3: Response is cubic - enables precise fine control, but
// difficult to use...
#define NEGCON_RANGE 0x7FFF
static int negcon_deadzone = 0;
static int negcon_linearity = 1;
2017-11-19 10:45:16 +00:00
typedef union
{
2017-11-19 11:30:09 +00:00
uint8_t u8[ 10 * sizeof( uint32_t ) ];
uint32_t u32[ 10 ]; /* 1 + 8 + 1 */
2017-11-19 17:40:40 +00:00
uint16_t gun_pos[ 2 ];
2017-11-19 11:30:09 +00:00
uint16_t buttons;
2017-11-19 10:45:16 +00:00
}
INPUT_DATA;
// Controller state buffer (per player)
static INPUT_DATA input_data[ MAX_CONTROLLERS ] = {0};
2017-11-19 11:30:09 +00:00
struct analog_calibration
2017-11-19 10:45:16 +00:00
{
2017-11-19 11:30:09 +00:00
float left;
float right;
2017-11-19 14:14:05 +00:00
float twist;
2017-11-19 10:45:16 +00:00
};
static struct analog_calibration analog_calibration[MAX_CONTROLLERS];
// Controller type (per player)
static uint32_t input_type[ MAX_CONTROLLERS ] = {0};
//------------------------------------------------------------------------------
// Supported Devices
//------------------------------------------------------------------------------
#define RETRO_DEVICE_PS_CONTROLLER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_JOYPAD, 0)
#define RETRO_DEVICE_PS_DUALSHOCK RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 1)
#define RETRO_DEVICE_PS_ANALOG RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 0)
#define RETRO_DEVICE_PS_ANALOG_JOYSTICK RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 2)
2017-11-19 17:40:40 +00:00
#define RETRO_DEVICE_PS_GUNCON RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 0)
2017-11-20 00:31:37 +00:00
#define RETRO_DEVICE_PS_JUSTIFIER RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_LIGHTGUN, 1)
2017-11-19 10:45:16 +00:00
#define RETRO_DEVICE_PS_MOUSE RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_MOUSE, 0)
2017-11-19 14:14:05 +00:00
#define RETRO_DEVICE_PS_NEGCON RETRO_DEVICE_SUBCLASS(RETRO_DEVICE_ANALOG, 3)
2017-11-19 10:45:16 +00:00
2017-11-20 00:31:37 +00:00
enum { INPUT_DEVICE_TYPES_COUNT = 1 /*none*/ + 8 }; // <-- update me!
2017-11-19 10:45:16 +00:00
static const struct retro_controller_description input_device_types[ INPUT_DEVICE_TYPES_COUNT ] =
{
{ "PlayStation Controller", RETRO_DEVICE_JOYPAD },
{ "DualShock", RETRO_DEVICE_PS_DUALSHOCK },
{ "Analog Controller", RETRO_DEVICE_PS_ANALOG },
{ "Analog Joystick", RETRO_DEVICE_PS_ANALOG_JOYSTICK },
2017-11-19 17:40:40 +00:00
{ "Guncon / G-Con 45", RETRO_DEVICE_PS_GUNCON },
2017-11-20 00:31:37 +00:00
{ "Justifier", RETRO_DEVICE_PS_JUSTIFIER },
2017-11-19 11:45:58 +00:00
{ "Mouse", RETRO_DEVICE_PS_MOUSE },
2017-11-19 14:14:05 +00:00
{ "neGcon", RETRO_DEVICE_PS_NEGCON },
2017-11-19 10:45:16 +00:00
{ NULL, 0 },
};
static const struct retro_controller_info ports8[ 8 + 1 ] =
{
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ 0 },
};
static const struct retro_controller_info ports5[ 5 + 1 ] =
{
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ 0 },
};
static const struct retro_controller_info ports2[ 2 + 1 ] =
{
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ input_device_types, INPUT_DEVICE_TYPES_COUNT },
{ 0 },
};
2017-11-19 10:45:16 +00:00
2017-11-19 11:30:09 +00:00
//------------------------------------------------------------------------------
// Mapping Helpers
//------------------------------------------------------------------------------
/* Controller (default) */
enum { INPUT_MAP_CONTROLLER_SIZE = 16 };
static const unsigned input_map_controller[ INPUT_MAP_CONTROLLER_SIZE ] =
{
// libretro input at position || maps to PS1 on bit
//-----------------------------------------------------------------------------
#ifdef MSB_FIRST
RETRO_DEVICE_ID_JOYPAD_L2, // L-trigger -> L2
RETRO_DEVICE_ID_JOYPAD_R2, // R-trigger -> R2
RETRO_DEVICE_ID_JOYPAD_L, // L-shoulder -> L1
RETRO_DEVICE_ID_JOYPAD_R, // R-shoulder -> R1
RETRO_DEVICE_ID_JOYPAD_X, // X(top) -> Triangle
RETRO_DEVICE_ID_JOYPAD_A, // A(right) -> Circle
RETRO_DEVICE_ID_JOYPAD_B, // B(down) -> Cross
RETRO_DEVICE_ID_JOYPAD_Y, // Y(left) -> Square
RETRO_DEVICE_ID_JOYPAD_SELECT, // Select -> Select
RETRO_DEVICE_ID_JOYPAD_L3, // L-thumb -> L3
RETRO_DEVICE_ID_JOYPAD_R3, // R-thumb -> R3
RETRO_DEVICE_ID_JOYPAD_START, // Start -> Start
RETRO_DEVICE_ID_JOYPAD_UP, // Pad-Up -> Pad-Up
2017-11-19 14:14:05 +00:00
RETRO_DEVICE_ID_JOYPAD_RIGHT, // Pad-Right -> Pad-Right
RETRO_DEVICE_ID_JOYPAD_DOWN, // Pad-Down -> Pad-Down
RETRO_DEVICE_ID_JOYPAD_LEFT, // Pad-Left -> Pad-Left
2017-11-19 11:30:09 +00:00
#else
RETRO_DEVICE_ID_JOYPAD_SELECT, // Select -> Select 0
RETRO_DEVICE_ID_JOYPAD_L3, // L-thumb -> L3 1
RETRO_DEVICE_ID_JOYPAD_R3, // R-thumb -> R3 2
RETRO_DEVICE_ID_JOYPAD_START, // Start -> Start 3
RETRO_DEVICE_ID_JOYPAD_UP, // Pad-Up -> Pad-Up 4
2017-11-19 14:14:05 +00:00
RETRO_DEVICE_ID_JOYPAD_RIGHT, // Pad-Right -> Pad-Right 5
RETRO_DEVICE_ID_JOYPAD_DOWN, // Pad-Down -> Pad-Down 6
RETRO_DEVICE_ID_JOYPAD_LEFT, // Pad-Left -> Pad-Left 7
2017-11-19 11:30:09 +00:00
RETRO_DEVICE_ID_JOYPAD_L2, // L-trigger -> L2 8
RETRO_DEVICE_ID_JOYPAD_R2, // R-trigger -> R2 9
RETRO_DEVICE_ID_JOYPAD_L, // L-shoulder -> L1 10
RETRO_DEVICE_ID_JOYPAD_R, // R-shoulder -> R1 11
RETRO_DEVICE_ID_JOYPAD_X, // X(top) -> Triangle 12
RETRO_DEVICE_ID_JOYPAD_A, // A(right) -> Circle 13
RETRO_DEVICE_ID_JOYPAD_B, // B(down) -> Cross 14
RETRO_DEVICE_ID_JOYPAD_Y, // Y(left) -> Square 15
#endif
};
2017-11-19 14:14:05 +00:00
2017-11-19 10:45:16 +00:00
//------------------------------------------------------------------------------
// Local Functions
//------------------------------------------------------------------------------
// Return the normalized distance between the origin and the current
// (x,y) analog stick position
static float analog_radius(int x, int y) {
float fx = ((float)x) / 0x8000;
float fy = ((float)y) / 0x8000;
return sqrtf(fx * fx + fy * fy);
}
2017-11-19 14:14:05 +00:00
static float analog_deflection(int x) {
float fx = ((float)x) / 0x8000;
return fabsf(fx);
}
2017-11-19 10:45:16 +00:00
static void analog_scale(uint32_t *v, float s) {
*v *= s;
if (*v > 0x7fff) {
*v = 0x7fff;
}
}
static void SetInput(int port, const char *type, void *ptr)
{
FIO->SetInput(port, type, ptr);
}
2017-11-19 14:14:05 +00:00
static uint16_t get_analog_button( retro_input_state_t input_state_cb,
int player_index,
int id )
{
uint16_t button;
// NOTE: Analog buttons were added Nov 2017. Not all front-ends support this
// feature (or pre-date it) so we need to handle this in a graceful way.
// First, try and get an analog value using the new libretro API constant
button = input_state_cb( player_index,
RETRO_DEVICE_ANALOG,
RETRO_DEVICE_INDEX_ANALOG_BUTTON,
id );
if ( button == 0 )
{
// If we got exactly zero, we're either not pressing the button, or the front-end
// is not reporting analog values. We need to do a second check using the classic
// digital API method, to at least get some response - better than nothing.
// NOTE: If we're really just not holding the button, we're still going to get zero.
button = input_state_cb( player_index,
RETRO_DEVICE_JOYPAD,
0,
id ) ? 0x7FFF : 0;
}
return button;
}
2017-11-19 10:45:16 +00:00
//------------------------------------------------------------------------------
// Global Functions
//------------------------------------------------------------------------------
void input_init_env( retro_environment_t _environ_cb )
{
// Cache this
environ_cb = _environ_cb;
struct retro_input_descriptor desc[] =
{
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 1, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 1, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 2, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 2, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 3, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 3, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 4, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 4, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 5, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 5, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 6, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 6, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT, "D-Pad Left" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP, "D-Pad Up" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN, "D-Pad Down" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT, "D-Pad Right" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_B, "Cross" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A, "Circle" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X, "Triangle" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_Y, "Square" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L, "L1" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2, "L2" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L3, "L3" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R, "R1" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2, "R2" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R3, "R3" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_SELECT, "Select" },
{ 7, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START, "Start" },
{ 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X, "Left Analog X" },
{ 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y, "Left Analog Y" },
{ 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X, "Right Analog X" },
{ 7, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y, "Right Analog Y" },
{ 0 },
};
environ_cb( RETRO_ENVIRONMENT_SET_INPUT_DESCRIPTORS, desc );
if ( environ_cb( RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE, &rumble ) && log_cb )
log_cb(RETRO_LOG_INFO, "Rumble interface supported!\n");
}
void input_set_env( retro_environment_t environ_cb )
{
switch ( players )
2017-11-19 10:45:16 +00:00
{
case 8:
environ_cb( RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports8 );
break;
case 5:
environ_cb( RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports5 );
break;
default:
case 2:
environ_cb( RETRO_ENVIRONMENT_SET_CONTROLLER_INFO, (void*)ports2 );
break;
} /* switch ( players ) */
2017-11-19 10:45:16 +00:00
}
void input_init()
{
// Initialise to default and bind input buffers to PS1 emulation.
for ( unsigned i = 0; i < MAX_CONTROLLERS; ++i )
{
input_type[ i ] = RETRO_DEVICE_JOYPAD;
SetInput( i, "gamepad", (uint8*)&input_data[ i ] );
}
}
void input_set_fio( FrontIO* fio )
{
FIO = fio;
}
void input_init_calibration()
{
for ( unsigned i = 0; i < MAX_CONTROLLERS; i++ )
{
analog_calibration[ i ].left = 0.7f;
analog_calibration[ i ].right = 0.7f;
2017-11-19 14:14:05 +00:00
analog_calibration[ i ].twist = 0.7f;
2017-11-19 10:45:16 +00:00
}
}
void input_enable_calibration( bool enable )
{
enable_analog_calibration = enable;
}
void input_set_player_count( unsigned _players )
{
players = _players;
input_set_env( environ_cb );
2017-11-19 10:45:16 +00:00
}
2017-11-22 23:53:59 +00:00
void input_set_mouse_sensitivity( int percent )
{
if ( percent > 0 && percent <= 200 ) {
mouse_sensitivity = (float)percent / 100.0f;
}
}
2017-11-23 13:08:26 +00:00
void input_set_gun_cursor( int cursor )
{
gun_cursor = cursor;
if ( FIO ) {
// todo -- support multiple guns.
for ( int port = 0; port < 8; ++port ) {
FIO->SetCrosshairsCursor( port, gun_cursor );
}
}
}
2018-08-21 16:07:54 +00:00
void input_set_negcon_deadzone( int deadzone )
{
negcon_deadzone = deadzone;
}
void input_set_negcon_linearity( int linearity )
{
negcon_linearity = linearity;
}
2017-11-19 10:45:16 +00:00
unsigned input_get_player_count()
{
return players;
}
void input_handle_lightgun_touchscreen( INPUT_DATA *p_input, int iplayer, retro_input_state_t input_state_cb )
{
int gun_x, gun_y, gun_x_raw, gun_y_raw;
gun_x_raw = input_state_cb( iplayer, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X);
gun_y_raw = input_state_cb( iplayer, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y);
// .. scale into screen space:
// NOTE: the scaling here is semi-guesswork, need to re-write.
// TODO: Test with PAL games.
const int scale_x = 2800;
const int scale_y = 240;
gun_x = ( ( gun_x_raw + 0x7fff ) * scale_x ) / (0x7fff << 1);
gun_y = ( ( gun_y_raw + 0x7fff ) * scale_y ) / (0x7fff << 1);
int is_offscreen = 0;
// Handle offscreen by checking corrected x and y values
if ( gun_x == 0 || gun_y == 0 )
{
is_offscreen = 1;
gun_x = -16384; // magic position to disable cross-hair drawing.
gun_y = -16384;
}
// Touch sensitivity: Keep the gun position held for a fixed number of cycles after touch is released
// because a very light touch can result in a misfire
if ( pointer_cycles_after_released > 0 && pointer_cycles_after_released < POINTER_PRESSED_CYCLES ) {
pointer_cycles_after_released++;
p_input->gun_pos[ 0 ] = pointer_pressed_last_x;
p_input->gun_pos[ 1 ] = pointer_pressed_last_y;
return;
}
// trigger
if ( input_state_cb( iplayer, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED ) )
{
pointer_pressed = 1;
pointer_cycles_after_released = 0;
pointer_pressed_last_x = gun_x;
pointer_pressed_last_y = gun_y;
} else if ( pointer_pressed ) {
pointer_cycles_after_released++;
pointer_pressed = 0;
p_input->gun_pos[ 0 ] = pointer_pressed_last_x;
p_input->gun_pos[ 1 ] = pointer_pressed_last_y;
p_input->u8[4] &= ~0x1;
return;
}
// position
p_input->gun_pos[ 0 ] = gun_x;
p_input->gun_pos[ 1 ] = gun_y;
// buttons
p_input->u8[ 4 ] = 0;
// use multi-touch to support different button inputs:
// 3-finger touch: START button
// 2-finger touch: Reload
// offscreen touch: Reload
int touch_count = input_state_cb( iplayer, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_COUNT );
if ( touch_count == 1 ) {
p_input->u8[ 4 ] |= 0x1;
}
if ( input_type[ iplayer ] == RETRO_DEVICE_PS_JUSTIFIER )
{
// Justifier 'Aux'
if ( touch_count == 2 ) {
p_input->u8[ 4 ] |= 0x2;
}
// Justifier 'Start'
if ( touch_count == 3 ) {
p_input->u8[ 4 ] |= 0x4;
}
}
else
{
// Guncon 'A'
if ( touch_count == 2 ) {
p_input->u8[ 4 ] |= 0x2;
}
// Guncon 'B'
if ( touch_count == 3 ) {
p_input->u8[ 4 ] |= 0x4;
}
// Guncon 'A' + 'B'
if ( touch_count == 4 ) {
p_input->u8[ 4 ] |= 0x2;
p_input->u8[ 4 ] |= 0x4;
}
}
}
void input_handle_lightgun( INPUT_DATA *p_input, int iplayer, retro_input_state_t input_state_cb )
{
uint8_t shot_type;
int gun_x, gun_y;
int forced_reload;
forced_reload = input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_RELOAD );
// off-screen?
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN ) || forced_reload )
{
shot_type = 0x8; // off-screen shot
gun_x = -16384; // magic position to disable cross-hair drawing.
gun_y = -16384;
}
else
{
shot_type = 0x1; // on-screen shot
int gun_x_raw, gun_y_raw;
gun_x_raw = input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X );
gun_y_raw = input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y );
// .. scale into screen space:
// NOTE: the scaling here is semi-guesswork, need to re-write.
// TODO: Test with PAL games.
const int scale_x = 2800;
const int scale_y = 240;
gun_x = ( ( gun_x_raw + 0x7fff ) * scale_x ) / (0x7fff << 1);
gun_y = ( ( gun_y_raw + 0x7fff ) * scale_y ) / (0x7fff << 1);
}
// position
p_input->gun_pos[ 0 ] = gun_x;
p_input->gun_pos[ 1 ] = gun_y;
// buttons
p_input->u8[ 4 ] = 0;
// trigger
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_TRIGGER ) || forced_reload ) {
p_input->u8[ 4 ] |= shot_type;
}
if ( input_type[ iplayer ] == RETRO_DEVICE_PS_JUSTIFIER )
{
// Justifier 'Aux'
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_A ) ) {
p_input->u8[ 4 ] |= 0x2;
}
// Justifier 'Start'
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_START ) ) {
p_input->u8[ 4 ] |= 0x4;
}
}
else
{
// Guncon 'A'
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_A ) ) {
p_input->u8[ 4 ] |= 0x2;
}
// Guncon 'B'
if ( input_state_cb( iplayer, RETRO_DEVICE_LIGHTGUN, 0, RETRO_DEVICE_ID_LIGHTGUN_AUX_B ) ) {
p_input->u8[ 4 ] |= 0x4;
}
}
}
2017-11-19 10:45:16 +00:00
void input_update( retro_input_state_t input_state_cb )
{
2017-11-19 11:30:09 +00:00
// For each player (logical controller)
for ( unsigned iplayer = 0; iplayer < players; ++iplayer )
{
INPUT_DATA* p_input = &(input_data[ iplayer ]);
2017-11-19 10:45:16 +00:00
2017-11-19 11:30:09 +00:00
switch ( input_type[ iplayer ] )
{
2017-11-19 11:45:58 +00:00
default:
p_input->buttons = 0;
break;
2017-11-19 11:30:09 +00:00
case RETRO_DEVICE_JOYPAD:
case RETRO_DEVICE_PS_CONTROLLER:
case RETRO_DEVICE_PS_DUALSHOCK:
case RETRO_DEVICE_PS_ANALOG:
case RETRO_DEVICE_PS_ANALOG_JOYSTICK:
// Use fixed lookup table to map RetroPad inputs to PlayStation input bitmap.
2017-11-19 11:45:58 +00:00
p_input->buttons = 0;
2017-11-19 11:30:09 +00:00
for ( unsigned i = 0; i < INPUT_MAP_CONTROLLER_SIZE; i++ )
{
p_input->buttons |=
input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, input_map_controller[ i ] )
? ( 1 << i ) : 0;
}
break;
2017-11-19 17:40:40 +00:00
case RETRO_DEVICE_PS_GUNCON:
2017-11-20 00:31:37 +00:00
case RETRO_DEVICE_PS_JUSTIFIER:
2017-11-19 17:40:40 +00:00
{
if ( gun_input_mode == SETTING_GUN_INPUT_POINTER ) {
input_handle_lightgun_touchscreen( p_input, iplayer, input_state_cb );
} else {
// RETRO_DEVICE_LIGHTGUN is default
input_handle_lightgun( p_input, iplayer, input_state_cb );
}
// allow guncon buttons to be pressed by gamepad while using lightgun
// Joypad L/R/A buttons are mapped to Guncon 'A'
// The idea is to be able to use the controller in tandem with some games
// like Time Crisis where you need to hold a button down and fire
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A ) ||
input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L ) ||
input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R ) )
2017-11-20 00:31:37 +00:00
{
// Guncon 'A'
p_input->u8[ 4 ] |= 0x2;
}
2017-11-19 17:40:40 +00:00
}
break;
2017-11-19 11:45:58 +00:00
case RETRO_DEVICE_PS_MOUSE:
// Simple two-button mouse.
{
p_input->u32[ 2 ] = 0;
if ( input_state_cb( iplayer, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT ) ) {
p_input->u32[ 2 ] |= ( 1 << 1 ); // Left
}
if ( input_state_cb( iplayer, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT ) ) {
p_input->u32[ 2 ] |= ( 1 << 0 ); // Right
}
}
// Relative input.
{
// mouse input
int dx_raw, dy_raw;
dx_raw = input_state_cb( iplayer, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X );
dy_raw = input_state_cb( iplayer, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y );
2017-11-22 23:53:59 +00:00
p_input->u32[ 0 ] = (int)roundf( dx_raw * mouse_sensitivity );
p_input->u32[ 1 ] = (int)roundf( dy_raw * mouse_sensitivity );
2017-11-19 11:45:58 +00:00
}
break;
2017-11-19 14:14:05 +00:00
case RETRO_DEVICE_PS_NEGCON:
// Analog Inputs
{
2017-11-19 14:27:52 +00:00
uint16_t button_ii, button_i, left_shoulder;
2017-11-19 14:14:05 +00:00
2017-11-19 14:27:52 +00:00
button_ii = std::max(
get_analog_button( input_state_cb, iplayer, RETRO_DEVICE_ID_JOYPAD_L2 ),
get_analog_button( input_state_cb, iplayer, RETRO_DEVICE_ID_JOYPAD_Y )
);
button_i = std::max(
get_analog_button( input_state_cb, iplayer, RETRO_DEVICE_ID_JOYPAD_R2 ),
get_analog_button( input_state_cb, iplayer, RETRO_DEVICE_ID_JOYPAD_B )
);
left_shoulder = get_analog_button( input_state_cb, iplayer, RETRO_DEVICE_ID_JOYPAD_L );
2017-11-19 14:14:05 +00:00
p_input->u32[ 3 ] = button_i; // Analog button I
p_input->u32[ 4 ] = button_ii; // Analog button II
p_input->u32[ 5 ] = left_shoulder; // Analog shoulder (left only!)
}
// Twist
{
int analog_left_x = input_state_cb( iplayer, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT,
RETRO_DEVICE_ID_ANALOG_X);
2018-08-21 16:07:54 +00:00
// Account for deadzone
if (analog_left_x > negcon_deadzone){
analog_left_x = analog_left_x - negcon_deadzone;
} else if (analog_left_x < -negcon_deadzone){
analog_left_x = analog_left_x + negcon_deadzone;
} else {
analog_left_x = 0;
}
// Convert to an 'amplitude' [-1.0,1.0]
float analog_left_x_amplitude = (float)analog_left_x / (float)(NEGCON_RANGE - negcon_deadzone);
// Handle 'analog self-calibration'...
// NB: This seems pointless, since all it does is arbitrarily
// reduce the precision of 'twist' input (making games rather
// unplayable). Someone, however, must have thought it was a
// good idea at some point, so we'll leave the basic functionality
// in place...
struct analog_calibration *calibration = &analog_calibration[ iplayer ];
2017-11-19 14:14:05 +00:00
if ( enable_analog_calibration )
{
// Compute the current stick deflection
2018-08-21 16:07:54 +00:00
float twist = fabsf(analog_left_x_amplitude);
2017-11-19 14:14:05 +00:00
// We recalibrate when we find a new max value for the sticks
if ( twist > analog_calibration->twist ) {
analog_calibration->twist = twist;
log_cb(RETRO_LOG_DEBUG, "Recalibrating twist, deflection: %f\n", twist);
}
2018-08-21 16:07:54 +00:00
2017-11-19 14:14:05 +00:00
// NOTE: This value was copied from the DualShock code below. Needs confirmation.
static const float neGcon_analog_deflection = 1.35f;
2018-08-21 16:07:54 +00:00
2017-11-19 14:14:05 +00:00
// Now compute the scaling factor to apply to convert the
// emulator's controller coordinates to a native neGcon range.
float twist_scaling = neGcon_analog_deflection / analog_calibration->twist;
2018-08-21 16:07:54 +00:00
analog_left_x_amplitude = analog_left_x_amplitude * twist_scaling;
2017-11-19 14:14:05 +00:00
}
else
{
// Reset the calibration. Since we only increase the
// calibration coordinates we can start with a reasonably
// small value.
analog_calibration->twist = 0.7;
}
2018-08-21 16:07:54 +00:00
// Safety check
// (also fixes range when above 'analog self-calibration' twist_scaling
// is applied)
analog_left_x_amplitude = analog_left_x_amplitude < -1.0f ? -1.0f : analog_left_x_amplitude;
analog_left_x_amplitude = analog_left_x_amplitude > 1.0f ? 1.0f : analog_left_x_amplitude;
// Adjust response
if (negcon_linearity == 2) {
if (analog_left_x_amplitude < 0.0) {
analog_left_x_amplitude = -(analog_left_x_amplitude * analog_left_x_amplitude);
} else {
analog_left_x_amplitude = analog_left_x_amplitude * analog_left_x_amplitude;
}
} else if (negcon_linearity == 3) {
analog_left_x_amplitude = analog_left_x_amplitude * analog_left_x_amplitude * analog_left_x_amplitude;
}
// Convert back from an 'amplitude' [-1.0,1.0] to a 'range' [-0x7FFF,0x7FFF]
analog_left_x = (int)(analog_left_x_amplitude * NEGCON_RANGE);
uint32_t twist_left = analog_left_x < 0 ? -analog_left_x : 0;
uint32_t twist_right = analog_left_x > 0 ? analog_left_x : 0;
2017-11-19 14:14:05 +00:00
p_input->u32[ 1 ] = twist_right; // Twist Right
p_input->u32[ 2 ] = twist_left; // Twist Left
}
// Digital Buttons
{
p_input->u8[ 0 ] = 0;
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_UP ) ) {
p_input->u8[ 0 ] |= ( 1 << 4 ); // Pad-Up
}
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_RIGHT ) ) {
p_input->u8[ 0 ] |= ( 1 << 5 ); // Pad-Right
}
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_DOWN ) ) {
p_input->u8[ 0 ] |= ( 1 << 6 ); // Pad-Down
}
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_LEFT ) ) {
p_input->u8[ 0 ] |= ( 1 << 7 ); // Pad-Left
}
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_START ) ) {
p_input->u8[ 0 ] |= ( 1 << 3 ); // Start
}
p_input->u8[ 1 ] = 0;
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_A ) ) {
p_input->u8[ 1 ] |= ( 1 << 5 ); // neGcon A
}
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_X ) ) {
p_input->u8[ 1 ] |= ( 1 << 4 ); // neGcon B
}
/*if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L ) ) {
p_input->u8[ 1 ] |= ( 1 << 2 ); // neGcon L shoulder (digital - non-standard?)
}*/
if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R ) ) {
p_input->u8[ 1 ] |= ( 1 << 3 ); // neGcon R shoulder (digital)
}
/*if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2 ) ) {
p_input->u8[ 1 ] |= ( 1 << 0 ); // neGcon L2 (non-standard?)
}*/
/*if ( input_state_cb( iplayer, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2 ) ) {
p_input->u8[ 1 ] |= ( 1 << 1 ); // neGcon R2 (non-standard?)
}*/
}
break;
2017-11-19 11:30:09 +00:00
}; // switch ( input_type[ iplayer ] )
2017-11-19 11:45:58 +00:00
2017-11-19 11:30:09 +00:00
//
2017-11-19 14:14:05 +00:00
// -- Dual Analog Sticks
2017-11-19 11:30:09 +00:00
switch ( input_type[ iplayer ] )
{
case RETRO_DEVICE_PS_DUALSHOCK:
case RETRO_DEVICE_PS_ANALOG:
case RETRO_DEVICE_PS_ANALOG_JOYSTICK:
{
int analog_left_x = input_state_cb( iplayer, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT,
RETRO_DEVICE_ID_ANALOG_X);
int analog_left_y = input_state_cb( iplayer, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT,
RETRO_DEVICE_ID_ANALOG_Y);
int analog_right_x = input_state_cb( iplayer, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT,
RETRO_DEVICE_ID_ANALOG_X);
int analog_right_y = input_state_cb( iplayer, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT,
RETRO_DEVICE_ID_ANALOG_Y);
struct analog_calibration *calibration = &analog_calibration[ iplayer ];
uint32_t r_right = analog_right_x > 0 ? analog_right_x : 0;
uint32_t r_left = analog_right_x < 0 ? -analog_right_x : 0;
uint32_t r_down = analog_right_y > 0 ? analog_right_y : 0;
uint32_t r_up = analog_right_y < 0 ? -analog_right_y : 0;
uint32_t l_right = analog_left_x > 0 ? analog_left_x : 0;
uint32_t l_left = analog_left_x < 0 ? -analog_left_x : 0;
uint32_t l_down = analog_left_y > 0 ? analog_left_y : 0;
uint32_t l_up = analog_left_y < 0 ? -analog_left_y : 0;
if ( enable_analog_calibration )
{
// Compute the "radius" (distance from 0, 0) of the current
// stick position, using the same normalized values
float l = analog_radius(analog_left_x, analog_left_y);
float r = analog_radius(analog_right_x, analog_right_y);
// We recalibrate when we find a new max value for the sticks
if ( l > analog_calibration->left ) {
analog_calibration->left = l;
log_cb(RETRO_LOG_DEBUG, "Recalibrating left stick, radius: %f\n", l);
}
if ( r > analog_calibration->right ) {
analog_calibration->right = r;
log_cb(RETRO_LOG_DEBUG, "Recalibrating right stick, radius: %f\n", r);
}
// This represents the maximal value the DualShock sticks can
// reach, where 1.0 would be the maximum value along the X or
// Y axis. XXX I need to measure this value more precisely,
// it's a rough estimate at the moment.
static const float dualshock_analog_radius = 1.35;
// Now compute the scaling factor to apply to convert the
// emulator's controller coordinates to a native DualShock's
// ones
float l_scaling = dualshock_analog_radius / analog_calibration->left;
float r_scaling = dualshock_analog_radius / analog_calibration->right;
analog_scale(&l_left, l_scaling);
analog_scale(&l_right, l_scaling);
analog_scale(&l_up, l_scaling);
analog_scale(&l_down, l_scaling);
analog_scale(&r_left, r_scaling);
analog_scale(&r_right, r_scaling);
analog_scale(&r_up, r_scaling);
analog_scale(&r_down, r_scaling);
}
else
{
// Reset the calibration. Since we only increase the
// calibration coordinates we can start with a reasonably
// small value.
analog_calibration->left = 0.7;
analog_calibration->right = 0.7;
}
p_input->u32[1] = r_right;
p_input->u32[2] = r_left;
p_input->u32[3] = r_down;
p_input->u32[4] = r_up;
p_input->u32[5] = l_right;
p_input->u32[6] = l_left;
p_input->u32[7] = l_down;
p_input->u32[8] = l_up;
}
break;
}; // switch ( input_type[ iplayer ] )
2017-11-19 11:45:58 +00:00
2017-11-19 11:30:09 +00:00
//
// -- Rumble
if ( rumble.set_rumble_state )
{
switch ( input_type[ iplayer ] )
{
case RETRO_DEVICE_PS_DUALSHOCK:
{
// Appears to be correct.
rumble.set_rumble_state( iplayer, RETRO_RUMBLE_WEAK, p_input->u8[9 * 4] * 0x101);
rumble.set_rumble_state( iplayer, RETRO_RUMBLE_STRONG, p_input->u8[9 * 4 + 1] * 0x101);
/*log_cb( RETRO_LOG_INFO, "Controller %u: Rumble: %d %d\n",
iplayer,
p_input->u8[9 * 4] * 0x101,
p_input->u8[9 * 4 + 1] * 0x101
);*/
}
break;
}; // switch ( input_type[ iplayer ] )
}; // can we rumble?
}; // for each player
2017-11-19 10:45:16 +00:00
}
//------------------------------------------------------------------------------
// Libretro Interface
//------------------------------------------------------------------------------
void retro_set_controller_port_device( unsigned in_port, unsigned device )
{
if ( in_port < MAX_CONTROLLERS )
{
// Store input type
input_type[ in_port ] = device;
switch ( device )
{
case RETRO_DEVICE_NONE:
log_cb( RETRO_LOG_INFO, "Controller %u: Unplugged\n", (in_port+1) );
SetInput( in_port, "none", (uint8*)&input_data[ in_port ] );
break;
case RETRO_DEVICE_JOYPAD:
case RETRO_DEVICE_PS_CONTROLLER:
log_cb( RETRO_LOG_INFO, "Controller %u: PlayStation Controller\n", (in_port+1) );
SetInput( in_port, "gamepad", (uint8*)&input_data[ in_port ] );
break;
case RETRO_DEVICE_PS_DUALSHOCK:
log_cb( RETRO_LOG_INFO, "Controller %u: DualShock\n", (in_port+1) );
SetInput( in_port, "dualshock", (uint8*)&input_data[ in_port ] );
break;
case RETRO_DEVICE_PS_ANALOG:
log_cb( RETRO_LOG_INFO, "Controller %u: Analog Controller\n", (in_port+1) );
SetInput( in_port, "dualanalog", (uint8*)&input_data[ in_port ] );
break;
case RETRO_DEVICE_PS_ANALOG_JOYSTICK:
log_cb( RETRO_LOG_INFO, "Controller %u: Analog Joystick\n", (in_port+1) );
SetInput( in_port, "analogjoy", (uint8*)&input_data[ in_port ] );
break;
2017-11-19 17:40:40 +00:00
case RETRO_DEVICE_PS_GUNCON:
log_cb( RETRO_LOG_INFO, "Controller %u: Guncon / G-Con 45\n", (in_port+1) );
SetInput( in_port, "guncon", (uint8*)&input_data[ in_port ] );
2017-11-23 13:08:26 +00:00
if ( FIO ) {
FIO->SetCrosshairsCursor( in_port, gun_cursor );
}
2017-11-19 17:40:40 +00:00
break;
2017-11-20 00:31:37 +00:00
case RETRO_DEVICE_PS_JUSTIFIER:
log_cb( RETRO_LOG_INFO, "Controller %u: Justifier\n", (in_port+1) );
SetInput( in_port, "justifier", (uint8*)&input_data[ in_port ] );
2017-11-23 13:08:26 +00:00
if ( FIO ) {
FIO->SetCrosshairsCursor( in_port, gun_cursor );
}
2017-11-20 00:31:37 +00:00
break;
2017-11-19 11:45:58 +00:00
case RETRO_DEVICE_PS_MOUSE:
log_cb( RETRO_LOG_INFO, "Controller %u: Mouse\n", (in_port+1) );
SetInput( in_port, "mouse", (uint8*)&input_data[ in_port ] );
break;
2017-11-19 14:14:05 +00:00
case RETRO_DEVICE_PS_NEGCON:
log_cb( RETRO_LOG_INFO, "Controller %u: neGcon\n", (in_port+1) );
SetInput( in_port, "negcon", (uint8*)&input_data[ in_port ] );
break;
2017-11-19 10:45:16 +00:00
default:
log_cb( RETRO_LOG_WARN, "Controller %u: Unsupported Device (%u)\n", (in_port+1), device );
SetInput( in_port, "none", (uint8*)&input_data[ in_port ] );
break;
}; // switch ( device )
2017-11-19 11:30:09 +00:00
// Clear rumble.
2017-11-19 10:45:16 +00:00
if ( rumble.set_rumble_state )
{
rumble.set_rumble_state(in_port, RETRO_RUMBLE_STRONG, 0);
rumble.set_rumble_state(in_port, RETRO_RUMBLE_WEAK, 0);
}
2017-11-19 11:30:09 +00:00
input_data[ in_port ].u32[ 9 ] = 0;
2017-11-19 10:45:16 +00:00
}; // valid port?
}
//==============================================================================