2020-12-05 13:08:24 +01:00
# pragma once
2012-11-15 00:39:56 +01:00
2020-02-22 20:42:49 +01:00
# include "pad_types.h"
2020-02-15 23:36:20 +01:00
# include "pad_config.h"
2020-02-22 20:42:49 +01:00
# include "pad_config_types.h"
2020-12-12 13:01:29 +01:00
# include "util/types.hpp"
2012-11-15 00:39:56 +01:00
2020-12-22 16:04:08 +01:00
# include <cmath>
# include <functional>
# include <string>
# include <vector>
# include <memory>
# include <unordered_map>
2021-02-11 22:13:21 +01:00
class PadDevice
2019-09-20 16:28:55 +02:00
{
2021-02-11 22:13:21 +01:00
public :
2019-09-20 16:28:55 +02:00
pad_config * config { nullptr } ;
} ;
2020-03-05 21:20:57 +01:00
using pad_preview_values = std : : array < int , 6 > ;
using pad_callback = std : : function < void ( u16 /*button_value*/ , std : : string /*button_name*/ , std : : string /*pad_name*/ , u32 /*battery_level*/ , pad_preview_values /*preview_values*/ ) > ;
using pad_fail_callback = std : : function < void ( std : : string /*pad_name*/ ) > ;
2012-11-15 00:39:56 +01:00
class PadHandlerBase
{
protected :
2019-09-20 16:28:55 +02:00
enum button
{
up ,
down ,
left ,
right ,
cross ,
square ,
circle ,
triangle ,
l1 ,
l2 ,
l3 ,
r1 ,
r2 ,
r3 ,
start ,
select ,
ps ,
//reserved,
ls_left ,
ls_right ,
ls_down ,
ls_up ,
rs_left ,
rs_right ,
rs_down ,
rs_up ,
button_count
} ;
enum connection
{
no_data ,
connected ,
disconnected
} ;
2017-11-27 22:31:15 +01:00
static const u32 MAX_GAMEPADS = 7 ;
2017-12-10 10:41:55 +01:00
std : : array < bool , MAX_GAMEPADS > last_connection_status { { false , false , false , false , false , false , false } } ;
2018-01-17 02:23:50 +01:00
std : : string m_name_string ;
2021-02-09 02:24:33 +01:00
u32 m_player_id = 0 ;
2020-12-18 08:39:54 +01:00
usz m_max_devices = 0 ;
2017-11-27 22:31:15 +01:00
int m_trigger_threshold = 0 ;
int m_thumb_threshold = 0 ;
2019-05-09 21:31:43 +02:00
bool b_has_led = false ;
2021-02-28 04:50:23 +01:00
bool b_has_rgb = false ;
2020-03-05 19:02:28 +01:00
bool b_has_battery = false ;
2017-11-27 22:31:15 +01:00
bool b_has_deadzones = false ;
bool b_has_rumble = false ;
2017-08-15 14:03:07 +02:00
bool b_has_config = false ;
2017-12-23 22:25:51 +01:00
std : : array < pad_config , MAX_GAMEPADS > m_pad_configs ;
2019-09-20 16:28:55 +02:00
std : : vector < std : : pair < std : : shared_ptr < PadDevice > , std : : shared_ptr < Pad > > > bindings ;
std : : unordered_map < u32 , std : : string > button_list ;
std : : vector < u32 > blacklist ;
2017-11-27 22:31:15 +01:00
// Search an unordered map for a string value and return found keycode
2020-02-23 11:32:32 +01:00
static int FindKeyCode ( const std : : unordered_map < u32 , std : : string > & map , const cfg : : string & name , bool fallback = true ) ;
2017-11-27 22:31:15 +01:00
2017-12-01 16:03:17 +01:00
// Search an unordered map for a string value and return found keycode
2020-02-23 11:32:32 +01:00
static long FindKeyCode ( const std : : unordered_map < u64 , std : : string > & map , const cfg : : string & name , bool fallback = true ) ;
2017-12-01 16:03:17 +01:00
2017-12-01 14:21:27 +01:00
// Search an unordered map for a string value and return found keycode
2020-02-23 11:32:32 +01:00
static int FindKeyCodeByString ( const std : : unordered_map < u32 , std : : string > & map , const std : : string & name , bool fallback = true ) ;
2017-12-01 14:21:27 +01:00
2017-12-23 22:25:51 +01:00
// Search an unordered map for a string value and return found keycode
2020-02-23 11:32:32 +01:00
static long FindKeyCodeByString ( const std : : unordered_map < u64 , std : : string > & map , const std : : string & name , bool fallback = true ) ;
2017-11-27 22:31:15 +01:00
// Get new scaled value between 0 and 255 based on its minimum and maximum
2020-05-04 16:02:43 +02:00
static float ScaledInput ( s32 raw_value , int minimum , int maximum ) ;
2017-11-27 22:31:15 +01:00
2017-12-01 10:16:48 +01:00
// Get new scaled value between -255 and 255 based on its minimum and maximum
2020-05-04 16:02:43 +02:00
static float ScaledInput2 ( s32 raw_value , int minimum , int maximum ) ;
2017-12-23 22:25:51 +01:00
// Get normalized trigger value based on the range defined by a threshold
u16 NormalizeTriggerInput ( u16 value , int threshold ) ;
2017-12-01 10:16:48 +01:00
2017-11-27 22:31:15 +01:00
// 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+
2020-07-03 21:16:01 +02:00
u16 NormalizeDirectedInput ( s32 raw_value , s32 threshold , s32 maximum ) const ;
2017-11-27 22:31:15 +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
2020-07-12 19:30:45 +02:00
std : : tuple < u16 , u16 > NormalizeStickDeadzone ( s32 inX , s32 inY , u32 deadzone ) const ;
2017-11-27 22:31:15 +01:00
// get clamped value between 0 and 255
2020-02-23 11:32:32 +01:00
static u16 Clamp0To255 ( f32 input ) ;
2017-11-27 22:31:15 +01:00
// get clamped value between 0 and 1023
2020-02-23 11:32:32 +01:00
static u16 Clamp0To1023 ( f32 input ) ;
2017-11-27 22:31:15 +01:00
// input has to be [-1,1]. result will be [0,255]
2020-02-23 11:32:32 +01:00
static u16 ConvertAxis ( float value ) ;
2017-11-27 22:31:15 +01:00
// 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
2017-12-23 22:25:51 +01:00
// This function assumes inX and inY is already in 0-255
2020-02-23 11:32:32 +01:00
static std : : tuple < u16 , u16 > ConvertToSquirclePoint ( u16 inX , u16 inY , int squircle_factor ) ;
2012-11-15 00:39:56 +01:00
public :
2020-05-04 16:31:08 +02:00
// s32 thumb_min = 0; // Unused. Make sure all handlers report 0+ values for sticks in get_button_values.
s32 thumb_max = 255 ; // NOTE: Better keep this positive
2017-11-27 22:31:15 +01:00
s32 trigger_min = 0 ;
s32 trigger_max = 255 ;
s32 vibration_min = 0 ;
s32 vibration_max = 255 ;
2019-09-20 16:28:55 +02:00
u32 connected_devices = 0 ;
2017-11-27 22:31:15 +01:00
2020-02-15 23:36:20 +01:00
pad_handler m_type ;
2017-12-23 22:25:51 +01:00
2020-02-23 11:32:32 +01:00
std : : string name_string ( ) const ;
2020-12-18 08:39:54 +01:00
usz max_devices ( ) const ;
2020-02-23 11:32:32 +01:00
bool has_config ( ) const ;
bool has_rumble ( ) const ;
bool has_deadzones ( ) const ;
bool has_led ( ) const ;
2021-02-28 04:50:23 +01:00
bool has_rgb ( ) const ;
2020-03-05 19:02:28 +01:00
bool has_battery ( ) const ;
2017-12-23 22:25:51 +01:00
2021-02-09 02:24:33 +01:00
void set_player ( u32 player_id ) { m_player_id = player_id ; }
2018-11-20 16:35:06 +01:00
static std : : string get_config_dir ( pad_handler type , const std : : string & title_id = " " ) ;
static std : : string get_config_filename ( int i , const std : : string & title_id = " " ) ;
2017-12-23 22:25:51 +01:00
2020-07-12 19:30:45 +02:00
u16 NormalizeStickInput ( u16 raw_value , int threshold , int multiplier , bool ignore_threshold = false ) const ;
void convert_stick_values ( u16 & x_out , u16 & y_out , const s32 & x_in , const s32 & y_in , const s32 & deadzone , const s32 & padsquircling ) const ;
2019-05-11 10:14:56 +02:00
virtual bool Init ( ) { return true ; }
2017-12-23 22:25:51 +01:00
PadHandlerBase ( pad_handler type = pad_handler : : null ) ;
2014-04-15 16:12:15 +02:00
virtual ~ PadHandlerBase ( ) = default ;
2019-09-20 16:28:55 +02:00
// Sets window to config the controller(optional)
2020-03-05 19:02:28 +01:00
virtual void SetPadData ( const std : : string & /*padId*/ , u32 /*largeMotor*/ , u32 /*smallMotor*/ , s32 /*r*/ , s32 /*g*/ , s32 /*b*/ , bool /*battery_led*/ , u32 /*battery_led_brightness*/ ) { }
virtual u32 get_battery_level ( const std : : string & /*padId*/ ) { return 0 ; }
2019-09-20 16:28:55 +02:00
// Return list of devices for that handler
2017-08-15 14:03:07 +02:00
virtual std : : vector < std : : string > ListDevices ( ) = 0 ;
2019-09-20 16:28:55 +02:00
// Callback called during pad_thread::ThreadFunc
virtual void ThreadProc ( ) ;
// Binds a Pad to a device
virtual bool bindPadToDevice ( std : : shared_ptr < Pad > pad , const std : : string & device ) ;
2017-12-23 22:25:51 +01:00
virtual void init_config ( pad_config * /*cfg*/ , const std : : string & /*name*/ ) = 0 ;
2020-03-05 21:20:57 +01:00
virtual void get_next_button_press ( const std : : string & padId , const pad_callback & callback , const pad_fail_callback & fail_callback , bool get_blacklist , const std : : vector < std : : string > & buttons = { } ) ;
2017-11-27 22:31:15 +01:00
private :
2019-09-20 16:28:55 +02:00
virtual std : : shared_ptr < PadDevice > get_device ( const std : : string & /*device*/ ) { return nullptr ; } ;
virtual bool get_is_left_trigger ( u64 /*keyCode*/ ) { return false ; } ;
virtual bool get_is_right_trigger ( u64 /*keyCode*/ ) { return false ; } ;
virtual bool get_is_left_stick ( u64 /*keyCode*/ ) { return false ; } ;
virtual bool get_is_right_stick ( u64 /*keyCode*/ ) { return false ; } ;
virtual PadHandlerBase : : connection update_connection ( const std : : shared_ptr < PadDevice > & /*device*/ ) { return connection : : disconnected ; } ;
virtual void get_extended_info ( const std : : shared_ptr < PadDevice > & /*device*/ , const std : : shared_ptr < Pad > & /*pad*/ ) { } ;
virtual void apply_pad_data ( const std : : shared_ptr < PadDevice > & /*device*/ , const std : : shared_ptr < Pad > & /*pad*/ ) { } ;
virtual std : : unordered_map < u64 , u16 > get_button_values ( const std : : shared_ptr < PadDevice > & /*device*/ ) { return { } ; } ;
2020-12-14 14:33:43 +01:00
virtual pad_preview_values get_preview_values ( const std : : unordered_map < u64 , u16 > & /*data*/ ) { return { } ; } ;
2017-12-23 22:25:51 +01:00
protected :
2019-09-20 16:28:55 +02:00
virtual std : : array < u32 , PadHandlerBase : : button : : button_count > get_mapped_key_codes ( const std : : shared_ptr < PadDevice > & /*device*/ , const pad_config * profile ) ;
virtual void get_mapping ( const std : : shared_ptr < PadDevice > & device , const std : : shared_ptr < Pad > & pad ) ;
void TranslateButtonPress ( const std : : shared_ptr < PadDevice > & device , u64 keyCode , bool & pressed , u16 & val , bool ignore_stick_threshold = false , bool ignore_trigger_threshold = false ) ;
2017-12-23 22:25:51 +01:00
void init_configs ( ) ;
2015-09-26 22:46:04 +02:00
} ;