2021-07-08 22:39:17 +02:00
# include <algorithm>
2023-03-31 20:12:48 +02:00
# include <sstream>
2021-07-08 22:39:17 +02:00
2021-07-08 21:30:23 +02:00
# include "Common/Math/math_util.h"
2021-07-09 16:14:32 +02:00
# include "Common/TimeUtil.h"
2023-03-31 20:12:48 +02:00
# include "Common/StringUtils.h"
2021-08-28 15:12:10 +02:00
# include "Common/Log.h"
2021-07-09 16:14:32 +02:00
2023-03-26 11:35:42 +02:00
# include "Core/HLE/sceCtrl.h"
2021-07-08 21:30:23 +02:00
# include "Core/KeyMap.h"
# include "Core/ControlMapper.h"
# include "Core/Config.h"
2022-07-04 13:10:42 -07:00
# include "Core/CoreParameter.h"
# include "Core/System.h"
2021-07-08 21:30:23 +02:00
2023-04-01 00:12:14 +02:00
using KeyMap : : MultiInputMapping ;
2023-03-30 15:15:33 +02:00
// TODO: Possibly make these thresholds configurable?
2023-03-29 13:50:57 +02:00
static float GetDeviceAxisThreshold ( int device ) {
return device = = DEVICE_ID_MOUSE ? AXIS_BIND_THRESHOLD_MOUSE : AXIS_BIND_THRESHOLD ;
}
static int GetOppositeVKey ( int vkey ) {
switch ( vkey ) {
case VIRTKEY_AXIS_X_MIN : return VIRTKEY_AXIS_X_MAX ; break ;
case VIRTKEY_AXIS_X_MAX : return VIRTKEY_AXIS_X_MIN ; break ;
case VIRTKEY_AXIS_Y_MIN : return VIRTKEY_AXIS_Y_MAX ; break ;
case VIRTKEY_AXIS_Y_MAX : return VIRTKEY_AXIS_Y_MIN ; break ;
case VIRTKEY_AXIS_RIGHT_X_MIN : return VIRTKEY_AXIS_RIGHT_X_MAX ; break ;
case VIRTKEY_AXIS_RIGHT_X_MAX : return VIRTKEY_AXIS_RIGHT_X_MIN ; break ;
case VIRTKEY_AXIS_RIGHT_Y_MIN : return VIRTKEY_AXIS_RIGHT_Y_MAX ; break ;
case VIRTKEY_AXIS_RIGHT_Y_MAX : return VIRTKEY_AXIS_RIGHT_Y_MIN ; break ;
default :
return 0 ;
}
}
2023-03-31 20:12:48 +02:00
static bool IsAxisVKey ( int vkey ) {
// Little hacky but works, of course.
return GetOppositeVKey ( vkey ) ! = 0 ;
}
2023-03-30 21:25:49 +02:00
static bool IsUnsignedMapping ( int vkey ) {
return vkey = = VIRTKEY_SPEED_ANALOG ;
}
static bool IsSignedAxis ( int axis ) {
switch ( axis ) {
case JOYSTICK_AXIS_X :
case JOYSTICK_AXIS_Y :
case JOYSTICK_AXIS_Z :
case JOYSTICK_AXIS_RX :
case JOYSTICK_AXIS_RY :
case JOYSTICK_AXIS_RZ :
return true ;
default :
return false ;
}
}
2023-03-29 13:50:57 +02:00
// This is applied on the circular radius, not directly on the axes.
2021-07-08 21:30:23 +02:00
static float MapAxisValue ( float v ) {
const float deadzone = g_Config . fAnalogDeadzone ;
const float invDeadzone = g_Config . fAnalogInverseDeadzone ;
const float sensitivity = g_Config . fAnalogSensitivity ;
const float sign = v > = 0.0f ? 1.0f : - 1.0f ;
2022-11-23 12:22:59 +01:00
2023-04-15 10:13:57 +02:00
return sign * Clamp ( invDeadzone + ( fabsf ( v ) - deadzone ) / ( 1.0f - deadzone ) * ( sensitivity - invDeadzone ) , 0.0f , 1.0f ) ;
2021-07-08 21:30:23 +02:00
}
2023-03-30 14:42:11 +02:00
void ConvertAnalogStick ( float x , float y , float * outX , float * outY ) {
2021-07-08 21:30:23 +02:00
const bool isCircular = g_Config . bAnalogIsCircular ;
float norm = std : : max ( fabsf ( x ) , fabsf ( y ) ) ;
2023-03-30 14:42:11 +02:00
if ( norm = = 0.0f ) {
* outX = x ;
* outY = y ;
2021-07-08 21:30:23 +02:00
return ;
2023-03-30 14:42:11 +02:00
}
2021-07-08 21:30:23 +02:00
if ( isCircular ) {
float newNorm = sqrtf ( x * x + y * y ) ;
float factor = newNorm / norm ;
x * = factor ;
y * = factor ;
norm = newNorm ;
}
float mappedNorm = MapAxisValue ( norm ) ;
2023-03-30 14:42:11 +02:00
* outX = Clamp ( x / norm * mappedNorm , - 1.0f , 1.0f ) ;
* outY = Clamp ( y / norm * mappedNorm , - 1.0f , 1.0f ) ;
2021-07-08 21:30:23 +02:00
}
2023-03-30 10:47:28 +02:00
void ControlMapper : : SetCallbacks (
std : : function < void ( int , bool ) > onVKey ,
2023-03-29 13:50:57 +02:00
std : : function < void ( int , float ) > onVKeyAnalog ,
2023-04-01 08:57:42 +02:00
std : : function < void ( uint32_t , uint32_t ) > updatePSPButtons ,
2023-03-31 11:11:46 +02:00
std : : function < void ( int , float , float ) > setPSPAnalog ,
std : : function < void ( int , float , float ) > setRawAnalog ) {
2023-03-30 10:47:28 +02:00
onVKey_ = onVKey ;
2023-03-30 15:03:41 +02:00
onVKeyAnalog_ = onVKeyAnalog ;
2023-04-01 08:57:42 +02:00
updatePSPButtons_ = updatePSPButtons ;
2021-07-09 11:01:56 +02:00
setPSPAnalog_ = setPSPAnalog ;
2021-07-09 13:10:16 +02:00
setRawAnalog_ = setRawAnalog ;
}
2023-03-29 13:50:57 +02:00
void ControlMapper : : SetPSPAxis ( int device , int stick , char axis , float value ) {
2021-07-09 11:01:56 +02:00
int axisId = axis = = ' X ' ? 0 : 1 ;
2022-11-23 12:22:59 +01:00
float position [ 2 ] ;
2023-03-26 18:04:40 +02:00
position [ 0 ] = history_ [ stick ] [ 0 ] ;
position [ 1 ] = history_ [ stick ] [ 1 ] ;
2021-07-09 11:01:56 +02:00
2022-11-23 12:22:59 +01:00
position [ axisId ] = value ;
float x = position [ 0 ] ;
float y = position [ 1 ] ;
2021-07-09 11:01:56 +02:00
2021-07-09 13:10:16 +02:00
if ( setRawAnalog_ ) {
setRawAnalog_ ( stick , x , y ) ;
}
2022-11-23 12:22:59 +01:00
// NOTE: We need to use single-axis checks, since the other axis might be from another device,
// so we'll add a little leeway.
bool inDeadZone = fabsf ( value ) < g_Config . fAnalogDeadzone * 0.7f ;
bool ignore = false ;
if ( inDeadZone & & lastNonDeadzoneDeviceID_ [ stick ] ! = device ) {
// Ignore this event! See issue #15465
2023-04-01 09:01:27 +02:00
ignore = true ;
2022-11-23 12:22:59 +01:00
}
if ( ! inDeadZone ) {
lastNonDeadzoneDeviceID_ [ stick ] = device ;
}
if ( ! ignore ) {
2023-03-26 18:04:40 +02:00
history_ [ stick ] [ axisId ] = value ;
2023-04-15 17:36:55 +02:00
UpdateAnalogOutput ( stick ) ;
2022-11-23 12:22:59 +01:00
}
2021-07-08 21:30:23 +02:00
}
2023-04-15 17:36:55 +02:00
void ControlMapper : : UpdateAnalogOutput ( int stick ) {
float x , y ;
ConvertAnalogStick ( history_ [ stick ] [ 0 ] , history_ [ stick ] [ 1 ] , & x , & y ) ;
if ( virtKeyOn_ [ VIRTKEY_ANALOG_LIGHTLY - VIRTKEY_FIRST ] ) {
x * = g_Config . fAnalogLimiterDeadzone ;
y * = g_Config . fAnalogLimiterDeadzone ;
}
converted_ [ stick ] [ 0 ] = x ;
converted_ [ stick ] [ 1 ] = y ;
setPSPAnalog_ ( stick , x , y ) ;
}
2023-05-02 21:36:17 +02:00
void ControlMapper : : ForceReleaseVKey ( int vkey ) {
std : : vector < KeyMap : : MultiInputMapping > multiMappings ;
if ( KeyMap : : InputMappingsFromPspButton ( vkey , & multiMappings , true ) ) {
2023-08-23 17:52:30 +02:00
double now = time_now_d ( ) ;
2023-05-02 21:36:17 +02:00
for ( const auto & entry : multiMappings ) {
for ( const auto & mapping : entry . mappings ) {
2023-08-23 17:52:30 +02:00
curInput_ [ mapping ] = { 0.0f , now } ;
2023-05-02 23:51:40 +02:00
// Different logic for signed axes?
2023-08-23 18:42:20 +02:00
UpdatePSPState ( mapping , now ) ;
2023-05-02 21:36:17 +02:00
}
}
}
}
2023-03-29 10:21:49 +02:00
static int RotatePSPKeyCode ( int x ) {
switch ( x ) {
case CTRL_UP : return CTRL_RIGHT ;
case CTRL_RIGHT : return CTRL_DOWN ;
case CTRL_DOWN : return CTRL_LEFT ;
case CTRL_LEFT : return CTRL_UP ;
default :
return x ;
}
}
2023-03-31 20:27:30 +02:00
// Used to decay analog values when clashing with digital ones.
2023-08-23 18:42:20 +02:00
static ControlMapper : : InputSample ReduceMagnitude ( ControlMapper : : InputSample sample , double now ) {
float reduction = std : : min ( std : : max ( 0.0f , ( float ) ( now - sample . timestamp ) - 2.0f ) , 1.0f ) ;
if ( reduction > 0.0f ) {
sample . value * = ( 1.0f - reduction ) ;
}
2023-08-23 17:52:30 +02:00
if ( ( sample . value > 0.0f & & sample . value < 0.05f ) | | ( sample . value < 0.0f & & sample . value > - 0.05f ) ) {
sample . value = 0.0f ;
2023-03-31 20:27:30 +02:00
}
2023-08-23 17:52:30 +02:00
return sample ;
2023-03-31 20:27:30 +02:00
}
2023-04-01 09:07:29 +02:00
float ControlMapper : : MapAxisValue ( float value , int vkId , const InputMapping & mapping , const InputMapping & changedMapping , bool * oppositeTouched ) {
if ( IsUnsignedMapping ( vkId ) ) {
// If a signed axis is mapped to an unsigned mapping,
// convert it. This happens when mapping DirectInput triggers to analog speed,
// for example.
int direction ;
if ( IsSignedAxis ( mapping . Axis ( & direction ) ) ) {
// The value has been split up into two curInput values, so we need to go fetch the other
// and put them back together again. Kind of awkward, but at least makes the regular case simple...
InputMapping other = mapping . FlipDirection ( ) ;
if ( other = = changedMapping ) {
* oppositeTouched = true ;
}
2023-08-23 17:52:30 +02:00
float valueOther = curInput_ [ other ] . value ;
2023-04-01 09:07:29 +02:00
float signedValue = value - valueOther ;
float ranged = ( signedValue + 1.0f ) * 0.5f ;
if ( direction = = - 1 ) {
ranged = 1.0f - ranged ;
}
// NOTICE_LOG(SYSTEM, "rawValue: %f other: %f signed: %f ranged: %f", iter->second, valueOther, signedValue, ranged);
return ranged ;
} else {
return value ;
}
} else {
return value ;
}
}
2023-04-20 00:00:46 +02:00
static bool IsSwappableVKey ( uint32_t vkey ) {
switch ( vkey ) {
case CTRL_UP :
case CTRL_LEFT :
case CTRL_DOWN :
case CTRL_RIGHT :
case VIRTKEY_AXIS_X_MIN :
case VIRTKEY_AXIS_X_MAX :
case VIRTKEY_AXIS_Y_MIN :
case VIRTKEY_AXIS_Y_MAX :
return true ;
default :
return false ;
}
}
void ControlMapper : : SwapMappingIfEnabled ( uint32_t * vkey ) {
if ( swapAxes_ ) {
switch ( * vkey ) {
case CTRL_UP : * vkey = VIRTKEY_AXIS_Y_MAX ; break ;
case VIRTKEY_AXIS_Y_MAX : * vkey = CTRL_UP ; break ;
case CTRL_DOWN : * vkey = VIRTKEY_AXIS_Y_MIN ; break ;
case VIRTKEY_AXIS_Y_MIN : * vkey = CTRL_DOWN ; break ;
case CTRL_LEFT : * vkey = VIRTKEY_AXIS_X_MIN ; break ;
case VIRTKEY_AXIS_X_MIN : * vkey = CTRL_LEFT ; break ;
case CTRL_RIGHT : * vkey = VIRTKEY_AXIS_X_MAX ; break ;
case VIRTKEY_AXIS_X_MAX : * vkey = CTRL_RIGHT ; break ;
}
}
}
2023-03-30 15:28:08 +02:00
// Can only be called from Key or Axis.
2023-09-11 11:10:00 +02:00
// mutex_ should be locked.
2023-08-23 18:42:20 +02:00
// TODO: We should probably make a batched version of this.
bool ControlMapper : : UpdatePSPState ( const InputMapping & changedMapping , double now ) {
2023-03-29 10:21:49 +02:00
// Instead of taking an input key and finding what it outputs, we loop through the OUTPUTS and
// see if the input that corresponds to it has a value. That way we can easily implement all sorts
// of crazy input combos if needed.
int rotations = 0 ;
switch ( g_Config . iInternalScreenRotation ) {
case ROTATION_LOCKED_HORIZONTAL180 : rotations = 2 ; break ;
case ROTATION_LOCKED_VERTICAL : rotations = 1 ; break ;
case ROTATION_LOCKED_VERTICAL180 : rotations = 3 ; break ;
}
2023-03-29 12:30:55 +02:00
// For the PSP's button inputs, we just go through and put the flags together.
uint32_t buttonMask = 0 ;
2023-03-29 13:50:57 +02:00
uint32_t changedButtonMask = 0 ;
2023-03-29 10:21:49 +02:00
for ( int i = 0 ; i < 32 ; i + + ) {
uint32_t mask = 1 < < i ;
if ( ! ( mask & CTRL_MASK_USER ) ) {
// Not a mappable button bit
continue ;
}
2023-03-29 13:50:57 +02:00
uint32_t mappingBit = mask ;
2023-03-29 10:21:49 +02:00
for ( int i = 0 ; i < rotations ; i + + ) {
2023-03-29 13:50:57 +02:00
mappingBit = RotatePSPKeyCode ( mappingBit ) ;
2023-03-29 10:21:49 +02:00
}
2023-04-20 00:00:46 +02:00
SwapMappingIfEnabled ( & mappingBit ) ;
2023-04-01 00:12:14 +02:00
std : : vector < MultiInputMapping > inputMappings ;
2023-03-29 13:50:57 +02:00
if ( ! KeyMap : : InputMappingsFromPspButton ( mappingBit , & inputMappings , false ) )
2023-03-29 10:21:49 +02:00
continue ;
2023-03-29 12:30:55 +02:00
// If a mapping could consist of a combo, we could trivially check it here.
2023-04-01 00:12:14 +02:00
for ( auto & multiMapping : inputMappings ) {
2023-03-29 13:50:57 +02:00
// Check if the changed mapping was involved in this PSP key.
2023-04-01 00:12:14 +02:00
if ( multiMapping . mappings . contains ( changedMapping ) ) {
2023-03-29 13:50:57 +02:00
changedButtonMask | = mask ;
}
2023-04-01 00:12:14 +02:00
// Check if all inputs are "on".
bool all = true ;
for ( auto mapping : multiMapping . mappings ) {
auto iter = curInput_ . find ( mapping ) ;
2023-08-23 17:52:30 +02:00
bool down = iter ! = curInput_ . end ( ) & & iter - > second . value > GetDeviceAxisThreshold ( iter - > first . deviceId ) ;
2023-04-01 00:12:14 +02:00
if ( ! down )
all = false ;
}
if ( all ) {
2023-03-29 10:21:49 +02:00
buttonMask | = mask ;
}
}
}
2023-03-29 13:50:57 +02:00
// We only request changing the buttons where the mapped input was involved.
2023-04-01 08:57:42 +02:00
updatePSPButtons_ ( buttonMask & changedButtonMask , ( ~ buttonMask ) & changedButtonMask ) ;
2023-03-29 10:21:49 +02:00
2023-04-02 10:41:26 +02:00
bool keyInputUsed = changedButtonMask ! = 0 ;
2023-04-15 17:36:55 +02:00
bool updateAnalogSticks = false ;
2023-04-02 10:41:26 +02:00
2023-03-29 10:21:49 +02:00
// OK, handle all the virtual keys next. For these we need to do deltas here and send events.
2023-08-23 17:52:30 +02:00
// Note that virtual keys include the analog directions, as they are driven by them.
2023-03-29 12:30:55 +02:00
for ( int i = 0 ; i < VIRTKEY_COUNT ; i + + ) {
int vkId = i + VIRTKEY_FIRST ;
2023-04-01 00:12:14 +02:00
std : : vector < MultiInputMapping > inputMappings ;
2023-04-20 00:00:46 +02:00
uint32_t idForMapping = vkId ;
SwapMappingIfEnabled ( & idForMapping ) ;
if ( ! KeyMap : : InputMappingsFromPspButton ( idForMapping , & inputMappings , false ) )
2023-03-29 12:30:55 +02:00
continue ;
2021-07-08 21:30:23 +02:00
2023-03-29 12:30:55 +02:00
// If a mapping could consist of a combo, we could trivially check it here.
2023-03-29 13:50:57 +02:00
// Save the first device ID so we can pass it into onVKeyDown, which in turn needs it for the analog
// mapping which gets a little hacky.
float threshold = 1.0f ;
bool touchedByMapping = false ;
2023-03-30 15:03:41 +02:00
float value = 0.0f ;
2023-04-01 00:12:14 +02:00
for ( auto & multiMapping : inputMappings ) {
if ( multiMapping . mappings . contains ( changedMapping ) ) {
2023-03-29 13:50:57 +02:00
touchedByMapping = true ;
}
2023-04-01 00:12:14 +02:00
float product = 1.0f ; // We multiply the various inputs in a combo mapping with each other.
for ( auto mapping : multiMapping . mappings ) {
auto iter = curInput_ . find ( mapping ) ;
if ( iter ! = curInput_ . end ( ) ) {
if ( mapping . IsAxis ( ) ) {
threshold = GetDeviceAxisThreshold ( iter - > first . deviceId ) ;
2023-08-23 17:52:30 +02:00
product * = MapAxisValue ( iter - > second . value , idForMapping , mapping , changedMapping , & touchedByMapping ) ;
2023-04-01 00:12:14 +02:00
} else {
2023-08-23 17:52:30 +02:00
product * = iter - > second . value ;
2023-04-01 00:12:14 +02:00
}
2023-03-30 21:25:49 +02:00
} else {
2023-04-01 00:12:14 +02:00
product = 0.0f ;
2023-03-29 13:50:57 +02:00
}
2023-03-29 12:30:55 +02:00
}
2023-04-01 00:12:14 +02:00
value + = product ;
2023-03-29 12:30:55 +02:00
}
2023-03-29 10:21:49 +02:00
2023-03-29 13:50:57 +02:00
if ( ! touchedByMapping ) {
continue ;
2023-03-29 12:30:55 +02:00
}
2023-03-29 10:21:49 +02:00
2023-04-02 10:41:26 +02:00
keyInputUsed = true ;
2023-03-31 20:27:30 +02:00
// Small values from analog inputs like gamepad sticks can linger around, which is bad here because we sum
// up before applying deadzone etc. This means that it can be impossible to reach the min/max values with digital input!
// So if non-analog events clash with analog ones mapped to the same input, decay the analog input,
// which will quickly get things back to normal, while if it's intentional to use both at the same time for some reason,
// that still works, though a bit weaker. We could also zero here, but you never know who relies on such strange tricks..
// Note: This is an old problem, it didn't appear with the refactoring.
if ( ! changedMapping . IsAxis ( ) ) {
2023-04-01 00:12:14 +02:00
for ( auto & multiMapping : inputMappings ) {
for ( auto & mapping : multiMapping . mappings ) {
2023-08-23 18:42:20 +02:00
if ( mapping ! = changedMapping & & curInput_ [ mapping ] . value > 0.0f ) {
// Note that this takes the time into account now - values will
// decay after a while, not immediately.
curInput_ [ mapping ] = ReduceMagnitude ( curInput_ [ mapping ] , now ) ;
}
2023-03-31 20:27:30 +02:00
}
}
}
2023-03-29 13:50:57 +02:00
value = clamp_value ( value , 0.0f , 1.0f ) ;
2023-03-29 12:30:55 +02:00
2023-03-29 13:50:57 +02:00
// Derive bools from the floats using the device's threshold.
2023-03-30 21:25:49 +02:00
// NOTE: This must be before the equality check below.
2023-03-29 13:50:57 +02:00
bool bPrevValue = virtKeys_ [ i ] > = threshold ;
bool bValue = value > = threshold ;
2023-03-30 21:25:49 +02:00
2023-03-29 13:50:57 +02:00
if ( virtKeys_ [ i ] ! = value ) {
// INFO_LOG(G3D, "vkeyanalog %s : %f", KeyMap::GetVirtKeyName(vkId), value);
onVKeyAnalog ( changedMapping . deviceId , vkId , value ) ;
2023-03-30 15:03:41 +02:00
virtKeys_ [ i ] = value ;
2023-03-29 13:50:57 +02:00
}
2023-03-30 21:25:49 +02:00
2023-03-29 13:50:57 +02:00
if ( ! bPrevValue & & bValue ) {
2023-03-30 15:03:41 +02:00
// INFO_LOG(G3D, "vkeyon %s", KeyMap::GetVirtKeyName(vkId));
2023-03-29 13:50:57 +02:00
onVKey ( vkId , true ) ;
2023-04-15 17:36:55 +02:00
virtKeyOn_ [ vkId - VIRTKEY_FIRST ] = true ;
if ( vkId = = VIRTKEY_ANALOG_LIGHTLY ) {
updateAnalogSticks = true ;
}
2023-03-29 13:50:57 +02:00
} else if ( bPrevValue & & ! bValue ) {
2023-03-30 15:03:41 +02:00
// INFO_LOG(G3D, "vkeyoff %s", KeyMap::GetVirtKeyName(vkId));
2023-03-29 13:50:57 +02:00
onVKey ( vkId , false ) ;
2023-04-15 17:36:55 +02:00
virtKeyOn_ [ vkId - VIRTKEY_FIRST ] = false ;
if ( vkId = = VIRTKEY_ANALOG_LIGHTLY ) {
updateAnalogSticks = true ;
}
2023-03-29 13:50:57 +02:00
}
}
2023-03-29 12:30:55 +02:00
2023-04-15 17:36:55 +02:00
if ( updateAnalogSticks ) {
// If "lightly" (analog limiter) was toggled, we need to update both computed stick outputs.
UpdateAnalogOutput ( 0 ) ;
UpdateAnalogOutput ( 1 ) ;
}
2023-04-02 10:41:26 +02:00
return keyInputUsed ;
2023-03-29 10:21:49 +02:00
}
bool ControlMapper : : Key ( const KeyInput & key , bool * pauseTrigger ) {
if ( key . flags & KEY_IS_REPEAT ) {
2021-07-08 21:30:23 +02:00
// Claim that we handled this. Prevents volume key repeats from popping up the volume control on Android.
return true ;
}
2023-08-23 18:42:20 +02:00
double now = time_now_d ( ) ;
if ( key . deviceId < DEVICE_ID_COUNT ) {
deviceTimestamps_ [ ( int ) key . deviceId ] = now ;
}
2023-03-30 15:28:08 +02:00
2023-03-29 10:21:49 +02:00
InputMapping mapping ( key . deviceId , key . keyCode ) ;
2023-08-23 18:42:20 +02:00
std : : lock_guard < std : : mutex > guard ( mutex_ ) ;
2023-03-29 10:21:49 +02:00
if ( key . flags & KEY_DOWN ) {
2023-08-23 18:42:20 +02:00
curInput_ [ mapping ] = { 1.0f , now } ;
2023-03-29 10:21:49 +02:00
} else if ( key . flags & KEY_UP ) {
2023-08-23 18:42:20 +02:00
curInput_ [ mapping ] = { 0.0f , now } ;
2021-07-08 21:30:23 +02:00
}
2023-03-30 15:28:08 +02:00
// TODO: See if this can be simplified further somehow.
2023-04-01 09:01:27 +02:00
if ( ( key . flags & KEY_DOWN ) & & key . keyCode = = NKCODE_BACK ) {
bool mappingFound = KeyMap : : InputMappingToPspButton ( mapping , nullptr ) ;
DEBUG_LOG ( SYSTEM , " Key: %d DeviceId: %d " , key . keyCode , key . deviceId ) ;
if ( ! mappingFound | | key . deviceId = = DEVICE_ID_DEFAULT ) {
2021-07-08 21:30:23 +02:00
* pauseTrigger = true ;
return true ;
}
}
2023-08-23 18:42:20 +02:00
return UpdatePSPState ( mapping , now ) ;
2021-07-08 21:30:23 +02:00
}
2023-04-20 00:00:46 +02:00
void ControlMapper : : ToggleSwapAxes ( ) {
swapAxes_ = ! swapAxes_ ;
updatePSPButtons_ ( 0 , CTRL_LEFT | CTRL_RIGHT | CTRL_UP | CTRL_DOWN ) ;
for ( uint32_t vkey = VIRTKEY_FIRST ; vkey < VIRTKEY_LAST ; vkey + + ) {
if ( IsSwappableVKey ( vkey ) ) {
if ( virtKeyOn_ [ vkey - VIRTKEY_FIRST ] ) {
onVKey_ ( vkey , false ) ;
virtKeyOn_ [ vkey - VIRTKEY_FIRST ] = false ;
}
if ( virtKeys_ [ vkey - VIRTKEY_FIRST ] > 0.0f ) {
onVKeyAnalog_ ( vkey , 0.0f ) ;
virtKeys_ [ vkey - VIRTKEY_FIRST ] = 0.0f ;
}
}
}
history_ [ 0 ] [ 0 ] = 0.0f ;
history_ [ 0 ] [ 1 ] = 0.0f ;
UpdateAnalogOutput ( 0 ) ;
UpdateAnalogOutput ( 1 ) ;
}
2022-12-31 21:44:52 +01:00
void ControlMapper : : Axis ( const AxisInput & axis ) {
2023-08-23 17:52:30 +02:00
double now = time_now_d ( ) ;
2023-08-23 18:42:20 +02:00
std : : lock_guard < std : : mutex > guard ( mutex_ ) ;
2023-09-27 17:36:05 +02:00
size_t deviceIndex = ( size_t ) axis . deviceId ; // this'll wrap around ANY (-1) to max, which will eliminate it on the next line, if such an event appears by mistake.
if ( deviceIndex < ( size_t ) DEVICE_ID_COUNT ) {
deviceTimestamps_ [ deviceIndex ] = now ;
2023-08-23 18:42:20 +02:00
}
2023-03-31 20:12:48 +02:00
if ( axis . value > = 0.0f ) {
2023-03-29 10:21:49 +02:00
InputMapping mapping ( axis . deviceId , axis . axisId , 1 ) ;
2023-03-31 20:12:48 +02:00
InputMapping opposite ( axis . deviceId , axis . axisId , - 1 ) ;
2023-08-23 17:52:30 +02:00
curInput_ [ mapping ] = { axis . value , now } ;
curInput_ [ opposite ] = { 0.0f , now } ;
2023-08-23 18:42:20 +02:00
UpdatePSPState ( mapping , now ) ;
UpdatePSPState ( opposite , now ) ;
2023-03-31 20:12:48 +02:00
} else if ( axis . value < 0.0f ) {
2023-03-29 10:21:49 +02:00
InputMapping mapping ( axis . deviceId , axis . axisId , - 1 ) ;
2023-03-31 20:12:48 +02:00
InputMapping opposite ( axis . deviceId , axis . axisId , 1 ) ;
2023-08-23 17:52:30 +02:00
curInput_ [ mapping ] = { - axis . value , now } ;
curInput_ [ opposite ] = { 0.0f , now } ;
2023-08-23 18:42:20 +02:00
UpdatePSPState ( mapping , now ) ;
UpdatePSPState ( opposite , now ) ;
2021-07-08 21:30:23 +02:00
}
}
2023-08-23 18:42:20 +02:00
void ControlMapper : : Update ( double now ) {
2021-07-09 16:14:32 +02:00
if ( autoRotatingAnalogCW_ ) {
// Clamp to a square
float x = std : : min ( 1.0f , std : : max ( - 1.0f , 1.42f * ( float ) cos ( now * - g_Config . fAnalogAutoRotSpeed ) ) ) ;
float y = std : : min ( 1.0f , std : : max ( - 1.0f , 1.42f * ( float ) sin ( now * - g_Config . fAnalogAutoRotSpeed ) ) ) ;
setPSPAnalog_ ( 0 , x , y ) ;
} else if ( autoRotatingAnalogCCW_ ) {
float x = std : : min ( 1.0f , std : : max ( - 1.0f , 1.42f * ( float ) cos ( now * g_Config . fAnalogAutoRotSpeed ) ) ) ;
float y = std : : min ( 1.0f , std : : max ( - 1.0f , 1.42f * ( float ) sin ( now * g_Config . fAnalogAutoRotSpeed ) ) ) ;
setPSPAnalog_ ( 0 , x , y ) ;
}
}
2023-03-26 18:04:40 +02:00
void ControlMapper : : PSPKey ( int deviceId , int pspKeyCode , int flags ) {
2023-03-30 15:28:08 +02:00
std : : lock_guard < std : : mutex > guard ( mutex_ ) ;
2021-07-08 21:30:23 +02:00
if ( pspKeyCode > = VIRTKEY_FIRST ) {
int vk = pspKeyCode - VIRTKEY_FIRST ;
if ( flags & KEY_DOWN ) {
2023-03-29 13:50:57 +02:00
virtKeys_ [ vk ] = 1.0f ;
onVKey ( pspKeyCode , true ) ;
2023-05-08 10:46:28 +02:00
onVKeyAnalog ( deviceId , pspKeyCode , 1.0f ) ;
2021-07-08 21:30:23 +02:00
}
if ( flags & KEY_UP ) {
2023-03-29 13:50:57 +02:00
virtKeys_ [ vk ] = 0.0f ;
onVKey ( pspKeyCode , false ) ;
2023-05-08 10:46:28 +02:00
onVKeyAnalog ( deviceId , pspKeyCode , 0.0f ) ;
2021-07-08 21:30:23 +02:00
}
} else {
2023-03-26 18:04:40 +02:00
// INFO_LOG(SYSTEM, "pspKey %d %d", pspKeyCode, flags);
2021-07-08 21:30:23 +02:00
if ( flags & KEY_DOWN )
2023-04-01 08:57:42 +02:00
updatePSPButtons_ ( pspKeyCode , 0 ) ;
2021-07-08 21:30:23 +02:00
if ( flags & KEY_UP )
2023-04-01 08:57:42 +02:00
updatePSPButtons_ ( 0 , pspKeyCode ) ;
2021-07-08 21:30:23 +02:00
}
}
2023-03-29 13:50:57 +02:00
void ControlMapper : : onVKeyAnalog ( int deviceId , int vkey , float value ) {
// Unfortunately, for digital->analog inputs to work sanely, we need to sum up
// with the opposite value too.
int stick = 0 ;
int axis = ' X ' ;
2023-03-31 20:12:48 +02:00
int oppositeVKey = GetOppositeVKey ( vkey ) ;
2023-03-29 13:50:57 +02:00
float sign = 1.0f ;
2021-07-08 21:30:23 +02:00
switch ( vkey ) {
2023-03-29 13:50:57 +02:00
case VIRTKEY_AXIS_X_MIN : sign = - 1.0f ; break ;
case VIRTKEY_AXIS_X_MAX : break ;
case VIRTKEY_AXIS_Y_MIN : axis = ' Y ' ; sign = - 1.0f ; break ;
case VIRTKEY_AXIS_Y_MAX : axis = ' Y ' ; break ;
case VIRTKEY_AXIS_RIGHT_X_MIN : stick = CTRL_STICK_RIGHT ; sign = - 1.0f ; break ;
case VIRTKEY_AXIS_RIGHT_X_MAX : stick = CTRL_STICK_RIGHT ; break ;
case VIRTKEY_AXIS_RIGHT_Y_MIN : stick = CTRL_STICK_RIGHT ; axis = ' Y ' ; sign = - 1.0f ; break ;
case VIRTKEY_AXIS_RIGHT_Y_MAX : stick = CTRL_STICK_RIGHT ; axis = ' Y ' ; break ;
default :
if ( onVKeyAnalog_ )
onVKeyAnalog_ ( vkey , value ) ;
return ;
}
2023-03-31 20:12:48 +02:00
if ( oppositeVKey ! = 0 ) {
float oppVal = virtKeys_ [ oppositeVKey - VIRTKEY_FIRST ] ;
if ( oppVal ! = 0.0f ) {
value - = oppVal ;
// NOTICE_LOG(SCECTRL, "Reducing %f by %f (from %08x : %s)", value, oppVal, oppositeVKey, KeyMap::GetPspButtonName(oppositeVKey).c_str());
}
2023-03-30 21:25:49 +02:00
}
2023-03-29 13:50:57 +02:00
SetPSPAxis ( deviceId , stick , axis , sign * value ) ;
}
2021-07-08 21:30:23 +02:00
2023-03-29 13:50:57 +02:00
void ControlMapper : : onVKey ( int vkey , bool down ) {
switch ( vkey ) {
2021-07-09 16:14:32 +02:00
case VIRTKEY_ANALOG_ROTATE_CW :
2023-03-30 10:47:28 +02:00
if ( down ) {
autoRotatingAnalogCW_ = true ;
autoRotatingAnalogCCW_ = false ;
} else {
autoRotatingAnalogCW_ = false ;
setPSPAnalog_ ( 0 , 0.0f , 0.0f ) ;
}
2021-07-09 16:14:32 +02:00
break ;
case VIRTKEY_ANALOG_ROTATE_CCW :
2023-03-30 10:47:28 +02:00
if ( down ) {
autoRotatingAnalogCW_ = false ;
autoRotatingAnalogCCW_ = true ;
} else {
autoRotatingAnalogCCW_ = false ;
setPSPAnalog_ ( 0 , 0.0f , 0.0f ) ;
}
2021-07-09 16:14:32 +02:00
break ;
2021-07-08 21:30:23 +02:00
default :
2023-03-30 10:47:28 +02:00
if ( onVKey_ )
onVKey_ ( vkey , down ) ;
2021-07-08 21:30:23 +02:00
break ;
}
}
2023-03-31 20:12:48 +02:00
void ControlMapper : : GetDebugString ( char * buffer , size_t bufSize ) const {
std : : stringstream str ;
for ( auto iter : curInput_ ) {
char temp [ 256 ] ;
iter . first . FormatDebug ( temp , sizeof ( temp ) ) ;
2023-08-23 17:52:30 +02:00
str < < temp < < " : " < < iter . second . value < < std : : endl ;
2023-03-31 20:12:48 +02:00
}
for ( int i = 0 ; i < ARRAY_SIZE ( virtKeys_ ) ; i + + ) {
int vkId = VIRTKEY_FIRST + i ;
2023-03-31 20:27:30 +02:00
if ( ( vkId > = VIRTKEY_AXIS_X_MIN & & vkId < = VIRTKEY_AXIS_Y_MAX ) | | vkId = = VIRTKEY_ANALOG_LIGHTLY | | vkId = = VIRTKEY_SPEED_ANALOG ) {
2023-03-31 20:12:48 +02:00
str < < KeyMap : : GetPspButtonName ( vkId ) < < " : " < < virtKeys_ [ i ] < < std : : endl ;
}
}
str < < " Lstick: " < < converted_ [ 0 ] [ 0 ] < < " , " < < converted_ [ 0 ] [ 1 ] < < std : : endl ;
truncate_cpy ( buffer , bufSize , str . str ( ) . c_str ( ) ) ;
}