2019-05-09 21:31:43 +02:00
# include " stdafx.h "
2017-12-23 22:25:51 +01:00
# include "PadHandler.h"
2018-11-20 16:35:06 +01:00
# include "pad_thread.h"
2017-12-23 22:25:51 +01:00
cfg_input g_cfg_input ;
PadHandlerBase : : PadHandlerBase ( pad_handler type ) : m_type ( type )
{
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase : : FindKeyCode ( std : : unordered_map < u32 , std : : string > map , const cfg : : string & name , bool fallback )
{
std : : string def = name . def ;
std : : string nam = name . to_string ( ) ;
int def_code = - 1 ;
for ( auto it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it - > second = = nam )
return it - > first ;
if ( fallback & & it - > second = = def )
def_code = it - > first ;
}
if ( fallback )
{
LOG_ERROR ( HLE , " int FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s] " , nam , def_code , def ) ;
if ( def_code < 0 )
def_code = 0 ;
}
return def_code ;
}
long PadHandlerBase : : FindKeyCode ( std : : unordered_map < u64 , std : : string > map , const cfg : : string & name , bool fallback )
{
std : : string def = name . def ;
std : : string nam = name . to_string ( ) ;
long def_code = - 1 ;
for ( auto it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it - > second = = nam )
return static_cast < long > ( it - > first ) ;
if ( fallback & & it - > second = = def )
def_code = static_cast < long > ( it - > first ) ;
}
if ( fallback )
{
LOG_ERROR ( HLE , " long FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s] " , nam , def_code , def ) ;
if ( def_code < 0 )
def_code = 0 ;
}
return def_code ;
}
// Search an unordered map for a string value and return found keycode
int PadHandlerBase : : FindKeyCodeByString ( std : : unordered_map < u32 , std : : string > map , const std : : string & name , bool fallback )
{
for ( auto it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it - > second = = name )
return it - > first ;
}
if ( fallback )
{
LOG_ERROR ( HLE , " long FindKeyCodeByString fohr [name = %s] returned with 0 " , name ) ;
return 0 ;
}
return - 1 ;
}
// Search an unordered map for a string value and return found keycode
long PadHandlerBase : : FindKeyCodeByString ( std : : unordered_map < u64 , std : : string > map , const std : : string & name , bool fallback )
{
for ( auto it = map . begin ( ) ; it ! = map . end ( ) ; + + it )
{
if ( it - > second = = name )
return static_cast < long > ( it - > first ) ;
}
if ( fallback )
{
LOG_ERROR ( HLE , " long FindKeyCodeByString fohr [name = %s] returned with 0 " , name ) ;
return 0 ;
}
return - 1 ;
}
// Get new scaled value between 0 and 255 based on its minimum and maximum
float PadHandlerBase : : ScaleStickInput ( s32 raw_value , int minimum , int maximum )
{
// value based on max range converted to [0, 1]
2018-09-05 22:52:30 +02:00
float val = float ( std : : clamp ( raw_value , minimum , maximum ) - minimum ) / float ( abs ( maximum ) + abs ( minimum ) ) ;
2017-12-23 22:25:51 +01:00
return 255.0f * val ;
}
// Get new scaled value between -255 and 255 based on its minimum and maximum
float PadHandlerBase : : ScaleStickInput2 ( s32 raw_value , int minimum , int maximum )
{
// value based on max range converted to [0, 1]
2018-09-05 22:52:30 +02:00
float val = float ( std : : clamp ( raw_value , minimum , maximum ) - minimum ) / float ( abs ( maximum ) + abs ( minimum ) ) ;
2017-12-23 22:25:51 +01:00
return ( 510.0f * val ) - 255.0f ;
}
// Get normalized trigger value based on the range defined by a threshold
u16 PadHandlerBase : : NormalizeTriggerInput ( u16 value , int threshold )
{
if ( value < = threshold | | threshold > = trigger_max )
{
return static_cast < u16 > ( 0 ) ;
}
else if ( threshold < = trigger_min )
{
return value ;
}
else
{
return ( u16 ) ( float ( trigger_max ) * float ( value - threshold ) / float ( trigger_max - threshold ) ) ;
}
}
// normalizes a directed input, meaning it will correspond to a single "button" and not an axis with two directions
// the input values must lie in 0+
2019-05-16 21:14:33 +02:00
u16 PadHandlerBase : : NormalizeDirectedInput ( s32 raw_value , s32 threshold , s32 maximum )
2017-12-23 22:25:51 +01:00
{
if ( threshold > = maximum | | maximum < = 0 )
{
return static_cast < u16 > ( 0 ) ;
}
2019-05-16 21:14:33 +02:00
float val = float ( std : : clamp ( raw_value , 0 , maximum ) ) / float ( maximum ) ; // value based on max range converted to [0, 1]
2017-12-23 22:25:51 +01:00
if ( threshold < = 0 )
{
return static_cast < u16 > ( 255.0f * val ) ;
}
else
{
float thresh = float ( threshold ) / float ( maximum ) ; // threshold converted to [0, 1]
return static_cast < u16 > ( 255.0f * std : : min ( 1.0f , ( val - thresh ) / ( 1.0f - thresh ) ) ) ;
}
}
2019-05-16 21:14:33 +02:00
u16 PadHandlerBase : : NormalizeStickInput ( u16 raw_value , int threshold , int multiplier , bool ignore_threshold )
2017-12-23 22:25:51 +01:00
{
2019-05-16 21:14:33 +02:00
const s32 scaled_value = ( multiplier * raw_value ) / 100 ;
2017-12-23 22:25:51 +01:00
if ( ignore_threshold )
{
2019-05-16 21:14:33 +02:00
return static_cast < u16 > ( ScaleStickInput ( scaled_value , 0 , thumb_max ) ) ;
2017-12-23 22:25:51 +01:00
}
else
{
2019-05-16 21:14:33 +02:00
return NormalizeDirectedInput ( scaled_value , threshold , thumb_max ) ;
2017-12-23 22:25:51 +01:00
}
}
// This function normalizes stick deadzone based on the DS3's deadzone, which is ~13%
// X and Y is expected to be in (-255) to 255 range, deadzone should be in terms of thumb stick range
// return is new x and y values in 0-255 range
std : : tuple < u16 , u16 > PadHandlerBase : : NormalizeStickDeadzone ( s32 inX , s32 inY , u32 deadzone )
{
const float dzRange = deadzone / float ( ( std : : abs ( thumb_max ) + std : : abs ( thumb_min ) ) ) ;
float X = inX / 255.0f ;
float Y = inY / 255.0f ;
if ( dzRange > 0.f )
{
const float mag = std : : min ( sqrtf ( X * X + Y * Y ) , 1.f ) ;
if ( mag < = 0 )
{
return std : : tuple < u16 , u16 > ( ConvertAxis ( X ) , ConvertAxis ( Y ) ) ;
}
if ( mag > dzRange ) {
float pos = lerp ( 0.13f , 1.f , ( mag - dzRange ) / ( 1 - dzRange ) ) ;
float scale = pos / mag ;
X = X * scale ;
Y = Y * scale ;
}
else {
float pos = lerp ( 0.f , 0.13f , mag / dzRange ) ;
float scale = pos / mag ;
X = X * scale ;
Y = Y * scale ;
}
}
return std : : tuple < u16 , u16 > ( ConvertAxis ( X ) , ConvertAxis ( Y ) ) ;
}
// get clamped value between 0 and 255
u16 PadHandlerBase : : Clamp0To255 ( f32 input )
{
2018-09-05 22:52:30 +02:00
return static_cast < u16 > ( std : : clamp ( input , 0.0f , 255.0f ) ) ;
2017-12-23 22:25:51 +01:00
}
// get clamped value between 0 and 1023
u16 PadHandlerBase : : Clamp0To1023 ( f32 input )
{
2018-09-05 22:52:30 +02:00
return static_cast < u16 > ( std : : clamp ( input , 0.0f , 1023.0f ) ) ;
2017-12-23 22:25:51 +01:00
}
// input has to be [-1,1]. result will be [0,255]
u16 PadHandlerBase : : ConvertAxis ( float value )
{
return static_cast < u16 > ( ( value + 1.0 ) * ( 255.0 / 2.0 ) ) ;
}
// The DS3, (and i think xbox controllers) give a 'square-ish' type response, so that the corners will give (almost)max x/y instead of the ~30x30 from a perfect circle
// using a simple scale/sensitivity increase would *work* although it eats a chunk of our usable range in exchange
// this might be the best for now, in practice it seems to push the corners to max of 20x20, with a squircle_factor of 8000
// This function assumes inX and inY is already in 0-255
std : : tuple < u16 , u16 > PadHandlerBase : : ConvertToSquirclePoint ( u16 inX , u16 inY , int squircle_factor )
{
// convert inX and Y to a (-1, 1) vector;
const f32 x = ( ( f32 ) inX - 127.5f ) / 127.5f ;
const f32 y = ( ( f32 ) inY - 127.5f ) / 127.5f ;
// compute angle and len of given point to be used for squircle radius
const f32 angle = std : : atan2 ( y , x ) ;
const f32 r = std : : sqrt ( std : : pow ( x , 2.f ) + std : : pow ( y , 2.f ) ) ;
// now find len/point on the given squircle from our current angle and radius in polar coords
// https://thatsmaths.com/2016/07/14/squircles/
const f32 newLen = ( 1 + std : : pow ( std : : sin ( 2 * angle ) , 2.f ) / ( float ( squircle_factor ) / 1000.f ) ) * r ;
2018-04-29 08:41:51 +02:00
// we now have len and angle, convert to cartesian
2017-12-23 22:25:51 +01:00
const int newX = Clamp0To255 ( ( ( newLen * std : : cos ( angle ) ) + 1 ) * 127.5f ) ;
const int newY = Clamp0To255 ( ( ( newLen * std : : sin ( angle ) ) + 1 ) * 127.5f ) ;
return std : : tuple < u16 , u16 > ( newX , newY ) ;
}
2018-01-17 02:23:50 +01:00
std : : string PadHandlerBase : : name_string ( )
{
return m_name_string ;
}
2018-01-16 14:07:57 +01:00
int PadHandlerBase : : max_devices ( )
{
return m_max_devices ;
}
2017-12-23 22:25:51 +01:00
bool PadHandlerBase : : has_config ( )
{
return b_has_config ;
}
bool PadHandlerBase : : has_rumble ( )
{
return b_has_rumble ;
}
bool PadHandlerBase : : has_deadzones ( )
{
return b_has_deadzones ;
}
2019-05-09 21:31:43 +02:00
bool PadHandlerBase : : has_led ( )
{
return b_has_led ;
}
2018-11-20 16:35:06 +01:00
std : : string PadHandlerBase : : get_config_dir ( pad_handler type , const std : : string & title_id )
2017-12-23 22:25:51 +01:00
{
2018-11-20 16:35:06 +01:00
if ( ! title_id . empty ( ) )
{
2019-06-01 15:52:39 +02:00
return Emulator : : GetCustomInputConfigDir ( title_id ) + fmt : : format ( " %s " , type ) + " / " ;
2018-11-20 16:35:06 +01:00
}
2017-12-23 22:25:51 +01:00
return fs : : get_config_dir ( ) + " /InputConfigs/ " + fmt : : format ( " %s " , type ) + " / " ;
}
2018-11-20 16:35:06 +01:00
std : : string PadHandlerBase : : get_config_filename ( int i , const std : : string & title_id )
2017-12-23 22:25:51 +01:00
{
2019-06-01 15:52:39 +02:00
if ( ! title_id . empty ( ) & & fs : : is_file ( Emulator : : GetCustomInputConfigPath ( title_id ) ) )
2018-11-20 16:35:06 +01:00
{
2019-06-01 15:52:39 +02:00
const std : : string path = Emulator : : GetCustomInputConfigDir ( title_id ) + g_cfg_input . player [ i ] - > handler . to_string ( ) + " / " + g_cfg_input . player [ i ] - > profile . to_string ( ) + " .yml " ;
2018-11-20 16:35:06 +01:00
if ( fs : : is_file ( path ) )
{
return path ;
}
}
2017-12-23 22:25:51 +01:00
return fs : : get_config_dir ( ) + " /InputConfigs/ " + g_cfg_input . player [ i ] - > handler . to_string ( ) + " / " + g_cfg_input . player [ i ] - > profile . to_string ( ) + " .yml " ;
}
void PadHandlerBase : : init_configs ( )
{
int index = 0 ;
for ( int i = 0 ; i < MAX_GAMEPADS ; i + + )
{
if ( g_cfg_input . player [ i ] - > handler = = m_type )
{
2018-11-20 16:35:06 +01:00
init_config ( & m_pad_configs [ index ] , get_config_filename ( i , pad : : g_title_id ) ) ;
2017-12-23 22:25:51 +01:00
index + + ;
}
}
}