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>
2023-06-13 01:19:32 +02:00
# include <set>
2020-12-22 16:04:08 +01:00
# include <vector>
# include <memory>
# include <unordered_map>
2023-06-13 01:19:32 +02:00
LOG_CHANNEL ( input_log , " Input " ) ;
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 :
2021-12-15 08:17:11 +01:00
virtual ~ PadDevice ( ) = default ;
2021-08-10 21:45:26 +02:00
cfg_pad * config { nullptr } ;
2021-08-09 23:41:49 +02:00
u8 player_id { 0 } ;
2022-10-21 22:35:31 +02:00
u8 large_motor { 0 } ;
u8 small_motor { 0 } ;
2023-06-13 01:19:32 +02:00
std : : set < u64 > trigger_code_left { } ;
std : : set < u64 > trigger_code_right { } ;
std : : array < std : : set < u64 > , 4 > axis_code_left { } ;
std : : array < std : : set < u64 > , 4 > axis_code_right { } ;
2019-09-20 16:28:55 +02:00
} ;
2022-08-13 09:56:04 +02:00
struct pad_ensemble
{
std : : shared_ptr < Pad > pad ;
std : : shared_ptr < PadDevice > device ;
std : : shared_ptr < PadDevice > buddy_device ;
explicit pad_ensemble ( std : : shared_ptr < Pad > _pad , std : : shared_ptr < PadDevice > _device , std : : shared_ptr < PadDevice > _buddy_device )
: pad ( _pad ) , device ( _device ) , buddy_device ( _buddy_device )
{ }
} ;
struct pad_list_entry
{
std : : string name ;
bool is_buddy_only = false ;
explicit pad_list_entry ( std : : string _name , bool _is_buddy_only )
2023-06-11 13:08:07 +02:00
: name ( std : : move ( _name ) ) , is_buddy_only ( _is_buddy_only )
2022-08-13 09:56:04 +02:00
{ }
} ;
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*/ ) > ;
2022-08-13 09:56:04 +02:00
using motion_preview_values = std : : array < u16 , 4 > ;
using motion_callback = std : : function < void ( std : : string /*pad_name*/ , motion_preview_values /*preview_values*/ ) > ;
using motion_fail_callback = std : : function < void ( std : : string /*pad_name*/ , motion_preview_values /*preview_values*/ ) > ;
2012-11-15 00:39:56 +01:00
class PadHandlerBase
{
2022-10-21 22:55:31 +02:00
public :
2023-05-18 17:56:16 +02:00
enum class connection
2022-10-21 22:55:31 +02:00
{
no_data ,
connected ,
disconnected
} ;
2012-11-15 00:39:56 +01:00
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 ,
2021-08-06 02:08:18 +02:00
pressure_intensity_button ,
2019-09-20 16:28:55 +02:00
button_count
} ;
2022-08-13 09:56:04 +02:00
static constexpr u32 MAX_GAMEPADS = 7 ;
2017-11-27 22:31:15 +01:00
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 ;
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 ;
2022-10-19 21:47:18 +02:00
bool b_has_player_led = 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 ;
2022-08-13 09:56:04 +02:00
bool b_has_motion = false ;
2017-08-15 14:03:07 +02:00
bool b_has_config = false ;
2021-08-06 02:08:18 +02:00
bool b_has_pressure_intensity_button = true ;
2021-08-10 21:45:26 +02:00
std : : array < cfg_pad , MAX_GAMEPADS > m_pad_configs ;
2022-08-13 09:56:04 +02:00
std : : vector < pad_ensemble > m_bindings ;
2019-09-20 16:28:55 +02:00
std : : unordered_map < u32 , std : : string > button_list ;
2023-06-14 20:57:30 +02:00
std : : set < u32 > blacklist ;
2017-11-27 22:31:15 +01:00
2023-06-13 01:19:32 +02:00
static std : : set < u32 > narrow_set ( const std : : set < u64 > & src ) ;
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
2023-06-13 01:19:32 +02:00
template < typename S , typename T >
static std : : set < T > FindKeyCodes ( const std : : unordered_map < S , std : : string > & map , const cfg : : string & cfg_string , bool fallback = true )
{
std : : set < T > key_codes ;
const std : : string & def = cfg_string . def ;
const std : : vector < std : : string > names = cfg_pad : : get_buttons ( cfg_string ) ;
T def_code = umax ;
for ( const std : : string & nam : names )
{
for ( const auto & [ code , name ] : map )
{
if ( name = = nam )
{
key_codes . insert ( static_cast < T > ( code ) ) ;
}
if ( fallback & & name = = def )
def_code = static_cast < T > ( code ) ;
}
}
if ( ! key_codes . empty ( ) )
{
return key_codes ;
}
if ( fallback )
{
if ( ! names . empty ( ) )
input_log . error ( " FindKeyCode for [name = %s] returned with [def_code = %d] for [def = %s] " , cfg_string . to_string ( ) , def_code , def ) ;
if ( def_code ! = umax )
{
return { def_code } ;
}
}
return { } ;
}
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
2023-06-13 01:19:32 +02:00
template < typename S , typename T >
static std : : set < T > FindKeyCodes ( const std : : unordered_map < S , std : : string > & map , const std : : vector < std : : string > & names )
{
std : : set < T > key_codes ;
for ( const std : : string & name : names )
{
for ( const auto & [ code , nam ] : map )
{
if ( nam = = name )
{
key_codes . insert ( static_cast < T > ( code ) ) ;
break ;
}
}
}
if ( ! key_codes . empty ( ) )
{
return key_codes ;
}
return { } ;
}
2017-11-27 22:31:15 +01:00
2021-12-16 23:19:09 +01:00
// Get new multiplied value based on the multiplier
static s32 MultipliedInput ( s32 raw_value , s32 multiplier ) ;
2017-11-27 22:31:15 +01:00
// Get new scaled value between 0 and 255 based on its minimum and maximum
2022-08-13 09:56:04 +02:00
static f32 ScaledInput ( s32 raw_value , int minimum , int maximum , f32 range = 255.0f ) ;
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
2022-08-13 09:56:04 +02:00
static f32 ScaledInput2 ( s32 raw_value , int minimum , int maximum , f32 range = 255.0f ) ;
2017-12-23 22:25:51 +01:00
// Get normalized trigger value based on the range defined by a threshold
2021-04-09 21:12:47 +02:00
u16 NormalizeTriggerInput ( u16 value , int threshold ) const ;
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]
2022-08-13 09:56:04 +02:00
static u16 ConvertAxis ( f32 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 ;
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 ;
2022-10-21 22:47:25 +02:00
bool m_is_init = false ;
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 ;
2022-08-13 09:56:04 +02:00
bool has_motion ( ) const ;
2020-02-23 11:32:32 +01:00
bool has_deadzones ( ) const ;
bool has_led ( ) const ;
2021-02-28 04:50:23 +01:00
bool has_rgb ( ) const ;
2022-10-19 21:47:18 +02:00
bool has_player_led ( ) const ;
2020-03-05 19:02:28 +01:00
bool has_battery ( ) const ;
2021-08-06 02:08:18 +02:00
bool has_pressure_intensity_button ( ) const ;
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)
2022-10-21 22:35:31 +02:00
virtual void SetPadData ( const std : : string & /*padId*/ , u8 /*player_id*/ , u8 /*large_motor*/ , u8 /*small_motor*/ , s32 /*r*/ , s32 /*g*/ , s32 /*b*/ , bool /*player_led*/ , bool /*battery_led*/ , u32 /*battery_led_brightness*/ ) { }
2020-03-05 19:02:28 +01:00
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
2022-08-13 09:56:04 +02:00
virtual std : : vector < pad_list_entry > list_devices ( ) = 0 ;
2019-09-20 16:28:55 +02:00
// Callback called during pad_thread::ThreadFunc
2022-10-21 22:48:38 +02:00
virtual void process ( ) ;
2019-09-20 16:28:55 +02:00
// Binds a Pad to a device
2022-08-13 09:56:04 +02:00
virtual bool bindPadToDevice ( std : : shared_ptr < Pad > pad , u8 player_id ) ;
virtual void init_config ( cfg_pad * cfg ) = 0 ;
2022-10-21 22:55:31 +02:00
virtual connection 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 = { } ) ;
2022-08-13 09:56:04 +02:00
virtual void get_motion_sensors ( const std : : string & pad_id , const motion_callback & callback , const motion_fail_callback & fail_callback , motion_preview_values preview_values , const std : : array < AnalogSensor , 4 > & sensors ) ;
virtual std : : unordered_map < u32 , std : : string > get_motion_axis_list ( ) const { return { } ; }
2017-11-27 22:31:15 +01:00
private :
2021-04-09 21:12:47 +02:00
virtual std : : shared_ptr < PadDevice > get_device ( const std : : string & /*device*/ ) { return nullptr ; }
2022-10-15 12:41:21 +02:00
virtual bool get_is_left_trigger ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 /*keyCode*/ ) { return false ; }
virtual bool get_is_right_trigger ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 /*keyCode*/ ) { return false ; }
virtual bool get_is_left_stick ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 /*keyCode*/ ) { return false ; }
virtual bool get_is_right_stick ( const std : : shared_ptr < PadDevice > & /*device*/ , u64 /*keyCode*/ ) { return false ; }
2021-04-09 21:12:47 +02:00
virtual PadHandlerBase : : connection update_connection ( const std : : shared_ptr < PadDevice > & /*device*/ ) { return connection : : disconnected ; }
2022-08-13 09:56:04 +02:00
virtual void get_extended_info ( const pad_ensemble & /*binding*/ ) { }
virtual void apply_pad_data ( const pad_ensemble & /*binding*/ ) { }
2021-04-09 21:12:47 +02:00
virtual std : : unordered_map < u64 , u16 > get_button_values ( const std : : shared_ptr < PadDevice > & /*device*/ ) { return { } ; }
virtual pad_preview_values get_preview_values ( const std : : unordered_map < u64 , u16 > & /*data*/ ) { return { } ; }
2017-12-23 22:25:51 +01:00
protected :
2023-06-13 01:19:32 +02:00
virtual std : : array < std : : set < u32 > , PadHandlerBase : : button : : button_count > get_mapped_key_codes ( const std : : shared_ptr < PadDevice > & device , const cfg_pad * cfg ) ;
2022-08-13 09:56:04 +02:00
virtual void get_mapping ( const pad_ensemble & binding ) ;
2019-09-20 16:28:55 +02:00
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 ( ) ;
2023-01-17 01:28:54 +01:00
cfg_pad * get_config ( const std : : string & pad_id ) ;
2015-09-26 22:46:04 +02:00
} ;