2020-12-05 13:08:24 +01:00
// This makes debugging on windows less painful
2017-11-27 22:31:15 +01:00
//#define HAVE_LIBEVDEV
2017-07-26 13:03:06 -05:00
#ifdef HAVE_LIBEVDEV
2020-04-25 02:12:19 +02:00
#include "Input/product_info.h"
2020-02-22 20:42:49 +01:00
#include "Emu/Io/pad_config.h"
2017-07-26 13:03:06 -05:00
#include "evdev_joystick_handler.h"
2020-03-07 12:29:23 +03:00
#include "util/logs.hpp"
2017-07-26 13:03:06 -05:00
#include <algorithm>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <cstring>
#include <cstdio>
2017-08-16 09:57:38 -07:00
#include <cmath>
2017-07-26 13:03:06 -05:00
2020-02-01 10:43:43 +03:00
LOG_CHANNEL ( evdev_log , "evdev" );
2020-02-01 07:15:50 +03:00
2025-04-13 11:01:58 +02:00
bool positive_axis :: load ()
{
if ( fs :: file cfg_file { cfg_name , fs :: read })
{
return from_string ( cfg_file . to_string ());
}
from_default ();
return false ;
}
void positive_axis :: save () const
{
fs :: pending_file file ( cfg_name );
if ( file . file )
{
file . file . write ( to_string ());
file . commit ();
}
}
bool positive_axis :: exist () const
{
return fs :: is_file ( cfg_name );
}
2024-06-11 22:30:16 +02:00
evdev_joystick_handler :: evdev_joystick_handler ()
: PadHandlerBase ( pad_handler :: evdev )
2017-11-27 22:31:15 +01:00
{
2017-12-23 22:25:51 +01:00
init_configs ();
2017-11-27 22:31:15 +01:00
// Define border values
2020-03-12 10:32:22 +01:00
thumb_max = 255 ;
trigger_min = 0 ;
trigger_max = 255 ;
2017-07-26 13:03:06 -05:00
2017-11-27 22:31:15 +01:00
// set capabilities
2020-03-12 10:32:22 +01:00
b_has_config = true ;
b_has_rumble = true ;
2022-08-13 09:56:04 +02:00
b_has_motion = true ;
2017-11-27 22:31:15 +01:00
b_has_deadzones = true ;
2025-01-08 01:22:50 +01:00
b_has_orientation = true ;
2017-11-27 22:31:15 +01:00
m_trigger_threshold = trigger_max / 2 ;
2020-03-12 10:32:22 +01:00
m_thumb_threshold = thumb_max / 2 ;
2019-09-20 16:28:55 +02:00
m_dev = std :: make_shared < EvdevDevice > ();
2017-11-27 22:31:15 +01:00
}
evdev_joystick_handler ::~ evdev_joystick_handler ()
{
2022-08-13 09:56:04 +02:00
close_devices ();
2017-11-27 22:31:15 +01:00
}
2017-07-26 13:03:06 -05:00
2021-08-10 21:45:26 +02:00
void evdev_joystick_handler :: init_config ( cfg_pad * cfg )
2017-12-23 22:25:51 +01:00
{
2020-11-26 00:06:03 +01:00
if ( ! cfg ) return ;
2017-12-23 22:25:51 +01:00
// Set default button mapping
2022-09-19 15:57:51 +03:00
cfg -> ls_left . def = :: at32 ( rev_axis_list , ABS_X );
cfg -> ls_down . def = :: at32 ( axis_list , ABS_Y );
cfg -> ls_right . def = :: at32 ( axis_list , ABS_X );
cfg -> ls_up . def = :: at32 ( rev_axis_list , ABS_Y );
cfg -> rs_left . def = :: at32 ( rev_axis_list , ABS_RX );
cfg -> rs_down . def = :: at32 ( axis_list , ABS_RY );
cfg -> rs_right . def = :: at32 ( axis_list , ABS_RX );
cfg -> rs_up . def = :: at32 ( rev_axis_list , ABS_RY );
cfg -> start . def = :: at32 ( button_list , BTN_START );
cfg -> select . def = :: at32 ( button_list , BTN_SELECT );
2026-03-18 09:09:18 +01:00
cfg -> ps . def = cfg_pad :: make_button_string ( button_list , {{ BTN_MODE }, { BTN_START , BTN_SELECT }});
2022-09-19 15:57:51 +03:00
cfg -> square . def = :: at32 ( button_list , BTN_X );
cfg -> cross . def = :: at32 ( button_list , BTN_A );
cfg -> circle . def = :: at32 ( button_list , BTN_B );
cfg -> triangle . def = :: at32 ( button_list , BTN_Y );
cfg -> left . def = :: at32 ( rev_axis_list , ABS_HAT0X );
cfg -> down . def = :: at32 ( axis_list , ABS_HAT0Y );
cfg -> right . def = :: at32 ( axis_list , ABS_HAT0X );
cfg -> up . def = :: at32 ( rev_axis_list , ABS_HAT0Y );
cfg -> r1 . def = :: at32 ( button_list , BTN_TR );
cfg -> r2 . def = :: at32 ( axis_list , ABS_RZ );
cfg -> r3 . def = :: at32 ( button_list , BTN_THUMBR );
cfg -> l1 . def = :: at32 ( button_list , BTN_TL );
cfg -> l2 . def = :: at32 ( axis_list , ABS_Z );
cfg -> l3 . def = :: at32 ( button_list , BTN_THUMBL );
2017-12-23 22:25:51 +01:00
2022-09-19 15:57:51 +03:00
cfg -> motion_sensor_x . axis . def = :: at32 ( motion_axis_list , ABS_X );
cfg -> motion_sensor_y . axis . def = :: at32 ( motion_axis_list , ABS_Y );
cfg -> motion_sensor_z . axis . def = :: at32 ( motion_axis_list , ABS_Z );
2022-10-17 23:48:00 +02:00
cfg -> motion_sensor_g . axis . def = :: at32 ( motion_axis_list , ABS_RY ); // DS3 uses the yaw axis for gyros
2022-08-13 09:56:04 +02:00
2022-09-19 15:57:51 +03:00
cfg -> pressure_intensity_button . def = :: at32 ( button_list , NO_BUTTON );
2024-08-09 23:44:45 +02:00
cfg -> analog_limiter_button . def = :: at32 ( button_list , NO_BUTTON );
2025-01-08 01:22:50 +01:00
cfg -> orientation_reset_button . def = :: at32 ( button_list , NO_BUTTON );
2021-08-06 02:08:18 +02:00
2017-12-23 22:25:51 +01:00
// Set default misc variables
2024-05-27 21:50:09 +02:00
cfg -> lstick_anti_deadzone . def = static_cast < u32 > ( 0.13 * thumb_max ); // 13%
cfg -> rstick_anti_deadzone . def = static_cast < u32 > ( 0.13 * thumb_max ); // 13%
2020-03-12 10:32:22 +01:00
cfg -> lstickdeadzone . def = 30 ; // between 0 and 255
cfg -> rstickdeadzone . def = 30 ; // between 0 and 255
cfg -> ltriggerthreshold . def = 0 ; // between 0 and 255
cfg -> rtriggerthreshold . def = 0 ; // between 0 and 255
2017-12-23 22:25:51 +01:00
// apply defaults
cfg -> from_default ();
}
2022-08-13 09:56:04 +02:00
std :: unordered_map < u32 , std :: string > evdev_joystick_handler :: get_motion_axis_list () const
{
return motion_axis_list ;
}
2017-08-15 14:03:07 +02:00
bool evdev_joystick_handler :: Init ()
2017-07-26 13:03:06 -05:00
{
2017-12-23 12:28:10 +01:00
if ( m_is_init )
return true ;
2025-04-13 11:01:58 +02:00
if ( ! m_pos_axis_config . load ())
{
evdev_log . notice ( "positive_axis config missing. Using defaults" );
}
evdev_log . notice ( "positive_axis config= \n %s" , m_pos_axis_config . to_string ());
2017-12-23 12:28:10 +01:00
if ( ! m_pos_axis_config . exist ())
m_pos_axis_config . save ();
for ( const auto & node : m_pos_axis_config . get_nodes ())
{
2023-06-13 01:19:32 +02:00
if ( node && * static_cast < cfg :: _bool *> ( node ))
2017-12-23 12:28:10 +01:00
{
2023-06-13 01:19:32 +02:00
const std :: string & name = node -> get_name ();
const int code = libevdev_event_code_from_name ( EV_ABS , name . c_str ());
2017-12-23 12:28:10 +01:00
if ( code < 0 )
2020-02-01 11:23:50 +03:00
evdev_log . error ( "Failed to read axis name from %s. [code = %d] [name = %s]" , m_pos_axis_config . cfg_name , code , name );
2017-12-23 12:28:10 +01:00
else
2023-06-14 20:57:30 +02:00
m_positive_axis . insert ( code );
2017-12-23 12:28:10 +01:00
}
}
m_is_init = true ;
2017-11-27 22:31:15 +01:00
return true ;
2017-07-26 13:03:06 -05:00
}
2018-01-27 15:13:39 +01:00
std :: string evdev_joystick_handler :: get_device_name ( const libevdev * dev )
{
2023-06-13 01:19:32 +02:00
std :: string name ;
if ( const char * raw_name = libevdev_get_name ( dev ))
name = raw_name ;
2018-01-27 15:13:39 +01:00
2022-08-13 09:56:04 +02:00
if ( name . empty ())
{
2023-06-13 01:19:32 +02:00
if ( const char * unique = libevdev_get_uniq ( dev ))
2022-08-13 09:56:04 +02:00
name = unique ;
2018-01-27 15:13:39 +01:00
2022-08-13 09:56:04 +02:00
if ( name . empty ())
name = "Unknown Device" ;
}
2018-01-27 15:13:39 +01:00
return name ;
}
2019-09-20 16:28:55 +02:00
bool evdev_joystick_handler :: update_device ( const std :: shared_ptr < PadDevice >& device )
2017-07-26 13:03:06 -05:00
{
2021-02-12 01:55:32 +01:00
EvdevDevice * evdev_device = static_cast < EvdevDevice *> ( device . get ());
2019-09-20 16:28:55 +02:00
if ( ! evdev_device )
return false ;
2023-06-13 01:19:32 +02:00
const std :: string & path = evdev_device -> path ;
libevdev *& dev = evdev_device -> device ;
2017-11-27 22:31:15 +01:00
2020-03-12 10:32:22 +01:00
const bool was_connected = dev != nullptr ;
2017-11-27 22:31:15 +01:00
if ( access ( path . c_str (), R_OK ) == - 1 )
{
if ( was_connected )
{
2020-03-12 10:32:22 +01:00
const int fd = libevdev_get_fd ( dev );
2017-11-27 22:31:15 +01:00
libevdev_free ( dev );
close ( fd );
dev = nullptr ;
}
2020-02-01 07:15:50 +03:00
evdev_log . error ( "Joystick %s is not present or accessible [previous status: %d]" , path . c_str (), was_connected ? 1 : 0 );
2017-11-27 22:31:15 +01:00
return false ;
}
2017-12-02 11:45:58 +01:00
if ( was_connected )
2020-03-12 10:32:22 +01:00
return true ; // It's already been connected, and the js is still present.
2017-11-27 22:31:15 +01:00
2020-03-12 10:32:22 +01:00
const int fd = open ( path . c_str (), O_RDWR | O_NONBLOCK );
2017-11-27 22:31:15 +01:00
if ( fd == - 1 )
{
2020-03-12 10:32:22 +01:00
const int err = errno ;
2020-02-01 07:15:50 +03:00
evdev_log . error ( "Failed to open joystick: %s [errno %d]" , strerror ( err ), err );
2017-11-27 22:31:15 +01:00
return false ;
}
2020-03-12 10:32:22 +01:00
const int ret = libevdev_new_from_fd ( fd , & dev );
2017-11-27 22:31:15 +01:00
if ( ret < 0 )
{
2020-02-01 07:15:50 +03:00
evdev_log . error ( "Failed to initialize libevdev for joystick: %s [errno %d]" , strerror ( - ret ), - ret );
2017-11-27 22:31:15 +01:00
return false ;
}
2020-02-01 07:15:50 +03:00
evdev_log . notice ( "Opened joystick: '%s' at %s (fd %d)" , get_device_name ( dev ), path , fd );
2017-11-27 22:31:15 +01:00
return true ;
2017-07-26 13:03:06 -05:00
}
2022-08-13 09:56:04 +02:00
void evdev_joystick_handler :: close_devices ()
2017-08-16 09:57:38 -07:00
{
2022-08-13 09:56:04 +02:00
const auto free_device = []( EvdevDevice * evdev_device )
2017-11-27 22:31:15 +01:00
{
2022-08-13 09:56:04 +02:00
if ( evdev_device && evdev_device -> device )
2017-11-27 22:31:15 +01:00
{
2022-08-13 09:56:04 +02:00
const int fd = libevdev_get_fd ( evdev_device -> device );
if ( evdev_device -> effect_id != - 1 )
ioctl ( fd , EVIOCRMFF , evdev_device -> effect_id );
libevdev_free ( evdev_device -> device );
close ( fd );
2017-11-27 22:31:15 +01:00
}
2022-08-13 09:56:04 +02:00
};
2023-06-13 01:19:32 +02:00
for ( pad_ensemble & binding : m_bindings )
2022-08-13 09:56:04 +02:00
{
free_device ( static_cast < EvdevDevice *> ( binding . device . get ()));
free_device ( static_cast < EvdevDevice *> ( binding . buddy_device . get ()));
}
2023-06-13 01:19:32 +02:00
for ( auto & [ name , device ] : m_settings_added )
2022-08-13 09:56:04 +02:00
{
free_device ( static_cast < EvdevDevice *> ( device . get ()));
}
2023-06-13 01:19:32 +02:00
for ( auto & [ name , device ] : m_motion_settings_added )
2022-08-13 09:56:04 +02:00
{
free_device ( static_cast < EvdevDevice *> ( device . get ()));
2017-11-27 22:31:15 +01:00
}
2017-07-26 13:03:06 -05:00
}
2026-03-15 11:17:23 +01:00
std :: unordered_map < u32 , std :: pair < u16 , bool >> evdev_joystick_handler :: GetButtonValues ( const std :: shared_ptr < EvdevDevice >& device )
2017-10-05 03:59:35 +02:00
{
2026-03-15 11:17:23 +01:00
std :: unordered_map < u32 , std :: pair < u16 , bool >> button_values ;
2019-09-20 16:28:55 +02:00
if ( ! device )
return button_values ;
2023-06-13 01:19:32 +02:00
libevdev * dev = device -> device ;
2017-11-27 22:31:15 +01:00
2017-12-23 12:28:10 +01:00
if ( ! Init ())
return button_values ;
2024-08-09 20:39:56 +02:00
for ( const auto & [ code , name ] : button_list )
2017-11-27 22:31:15 +01:00
{
2021-08-08 16:45:45 +02:00
if ( code == NO_BUTTON )
continue ;
int val = 0 ;
2020-03-12 10:32:22 +01:00
2017-11-27 22:31:15 +01:00
if ( libevdev_fetch_event_value ( dev , EV_KEY , code , & val ) == 0 )
continue ;
button_values . emplace ( code , std :: make_pair < u16 , bool > ( static_cast < u16 > ( val > 0 ? 255 : 0 ), false ));
}
2024-08-09 20:39:56 +02:00
for ( const auto & [ code , name ] : axis_list )
2017-11-27 22:31:15 +01:00
{
2023-06-13 01:19:32 +02:00
int val = 0 ;
2020-03-12 10:32:22 +01:00
2017-11-27 22:31:15 +01:00
if ( libevdev_fetch_event_value ( dev , EV_ABS , code , & val ) == 0 )
continue ;
2020-03-12 10:32:22 +01:00
const int min = libevdev_get_abs_minimum ( dev , code );
const int max = libevdev_get_abs_maximum ( dev , code );
2023-12-11 22:03:40 +01:00
const int flat = libevdev_get_abs_flat ( dev , code );
2017-12-02 11:45:58 +01:00
// Triggers do not need handling of negative values
2023-06-14 20:57:30 +02:00
if ( min >= 0 && ! m_positive_axis . contains ( code ))
2017-11-27 22:31:15 +01:00
{
2023-12-11 22:03:40 +01:00
const float fvalue = ScaledInput ( val , min , max , flat );
2017-11-27 22:31:15 +01:00
button_values . emplace ( code , std :: make_pair < u16 , bool > ( static_cast < u16 > ( fvalue ), false ));
continue ;
}
2023-12-11 22:03:40 +01:00
const float fvalue = ScaledAxisInput ( val , min , max , flat );
2017-12-01 10:16:48 +01:00
if ( fvalue < 0 )
button_values . emplace ( code , std :: make_pair < u16 , bool > ( static_cast < u16 > ( std :: abs ( fvalue )), true ));
2017-11-27 22:31:15 +01:00
else
2017-12-01 10:16:48 +01:00
button_values . emplace ( code , std :: make_pair < u16 , bool > ( static_cast < u16 > ( fvalue ), false ));
2017-11-27 22:31:15 +01:00
}
return button_values ;
2017-10-05 03:59:35 +02:00
}
2019-09-20 16:28:55 +02:00
std :: shared_ptr < evdev_joystick_handler :: EvdevDevice > evdev_joystick_handler :: get_evdev_device ( const std :: string & device )
2017-12-02 11:45:58 +01:00
{
// Add device if not yet present
2022-08-13 09:56:04 +02:00
std :: shared_ptr < EvdevDevice > evdev_device = add_device ( device , true );
if ( ! evdev_device )
2017-12-02 11:45:58 +01:00
return nullptr ;
// Check if our device is connected
2022-08-13 09:56:04 +02:00
if ( ! update_device ( evdev_device ))
2017-12-02 11:45:58 +01:00
return nullptr ;
2022-08-13 09:56:04 +02:00
return evdev_device ;
2017-12-02 11:45:58 +01:00
}
2024-08-09 20:39:56 +02:00
PadHandlerBase :: connection evdev_joystick_handler :: get_next_button_press ( const std :: string & padId , const pad_callback & callback , const pad_fail_callback & fail_callback , gui_call_type call_type , const std :: vector < std :: string >& buttons )
2017-08-15 14:14:13 -05:00
{
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: blacklist )
2020-12-14 14:33:43 +01:00
m_blacklist . clear ();
2017-11-30 00:43:52 +01:00
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: reset_input || call_type == gui_call_type :: blacklist )
2024-08-08 03:04:21 +02:00
m_min_button_values . clear ();
2017-12-02 11:45:58 +01:00
// Get our evdev device
2023-06-13 01:19:32 +02:00
std :: shared_ptr < EvdevDevice > device = get_evdev_device ( padId );
2022-08-13 09:56:04 +02:00
if ( ! device || ! device -> device )
2020-07-04 13:18:45 +02:00
{
if ( fail_callback )
fail_callback ( padId );
2022-10-21 22:55:31 +02:00
return connection :: disconnected ;
2020-07-04 13:18:45 +02:00
}
2024-08-08 03:04:21 +02:00
2018-06-12 08:12:37 -07:00
libevdev * dev = device -> device ;
2017-11-27 22:31:15 +01:00
2022-03-20 00:19:44 +01:00
// Try to fetch all new events from the joystick.
2017-11-27 22:31:15 +01:00
input_event evt ;
2022-03-20 00:19:44 +01:00
bool has_new_event = false ;
int ret = LIBEVDEV_READ_STATUS_SUCCESS ;
while ( ret >= 0 )
{
if ( ret == LIBEVDEV_READ_STATUS_SYNC )
{
// Grab any pending sync event.
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_SYNC , & evt );
}
else
{
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL , & evt );
}
2017-11-27 22:31:15 +01:00
2022-03-20 00:19:44 +01:00
has_new_event |= ret == LIBEVDEV_READ_STATUS_SUCCESS ;
}
2017-12-01 00:06:31 +01:00
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: get_connection )
{
return has_new_event ? connection :: connected : connection :: no_data ;
}
const auto data = GetButtonValues ( device );
2019-06-17 20:52:00 +02:00
2026-06-14 06:21:03 +02:00
const auto find_value = [ & , this ]( std :: string_view str )
2019-06-17 20:52:00 +02:00
{
2026-03-17 21:30:18 +01:00
const std :: vector < pad :: combo > combos = cfg_pad :: get_combos ( str );
2023-06-13 01:19:32 +02:00
u16 value {};
const auto set_value = [ & value , & data ]( u32 code , bool dir )
{
2026-03-15 11:17:23 +01:00
if ( const auto it = data . find ( code ); it != data . cend () && dir == it -> second . second )
2023-06-13 01:19:32 +02:00
{
value = std :: max ( value , it -> second . first );
}
};
2026-03-17 21:30:18 +01:00
for ( const pad :: combo & combo : combos )
2023-06-13 01:19:32 +02:00
{
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( rev_axis_list , combo ))
2026-03-15 11:01:58 +01:00
{
set_value ( code , true );
}
2023-06-13 01:19:32 +02:00
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( axis_list , combo ))
2026-03-15 11:01:58 +01:00
{
set_value ( code , false );
}
2023-06-13 01:19:32 +02:00
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( button_list , combo ))
2026-03-15 11:01:58 +01:00
{
set_value ( code , false );
}
2023-06-13 01:19:32 +02:00
}
return value ;
2019-06-17 20:52:00 +02:00
};
2022-10-15 12:10:40 +02:00
pad_preview_values preview_values {};
2019-06-17 20:52:00 +02:00
if ( buttons . size () == 10 )
{
preview_values [ 0 ] = find_value ( buttons [ 0 ]); // Left Trigger
preview_values [ 1 ] = find_value ( buttons [ 1 ]); // Right Trigger
preview_values [ 2 ] = find_value ( buttons [ 3 ]) - find_value ( buttons [ 2 ]); // Left Stick X
preview_values [ 3 ] = find_value ( buttons [ 5 ]) - find_value ( buttons [ 4 ]); // Left Stick Y
preview_values [ 4 ] = find_value ( buttons [ 7 ]) - find_value ( buttons [ 6 ]); // Right Stick X
preview_values [ 5 ] = find_value ( buttons [ 9 ]) - find_value ( buttons [ 8 ]); // Right Stick Y
}
2024-08-09 20:39:56 +02:00
// return if nothing new has happened. ignore this to get the current state for blacklist or reset_input
if ( call_type != gui_call_type :: blacklist && call_type != gui_call_type :: reset_input && ! has_new_event )
2020-07-04 13:18:45 +02:00
{
if ( callback )
2026-03-17 13:37:08 +01:00
callback ({}, {}, padId , 0 , std :: move ( preview_values ), get_capabilities ( padId ));
2022-10-21 22:55:31 +02:00
return connection :: no_data ;
2020-07-04 13:18:45 +02:00
}
2017-11-27 22:31:15 +01:00
2026-03-17 13:37:08 +01:00
// Check for each button in our list if its corresponding (maybe remapped) button or axis was pressed.
// Return the new value if the button was pressed (aka. its value was bigger than 0 or the defined threshold)
// Get all the legally pressed buttons. We only accept one value for axis though, otherwise it will get messy.
std :: map < std :: string , u16 > pressed_buttons ;
std :: array < std :: pair < std :: string , u16 > , 2 > pressed_sticks {};
2017-12-10 10:41:55 +01:00
2024-08-09 20:39:56 +02:00
const auto set_button_press = [ & ]( const u32 code , const std :: string & name , std :: string_view type , u16 threshold , int ev_type , bool is_rev_axis )
2024-08-08 03:04:21 +02:00
{
2024-08-09 20:39:56 +02:00
if ( call_type != gui_call_type :: blacklist && m_blacklist . contains ( name ))
return ;
// Ignore codes that aren't part of the latest events. Otherwise we will get value 0 which will reset our min_value.
2026-03-15 11:17:23 +01:00
const auto it = data . find ( code );
2024-08-09 20:39:56 +02:00
if ( it == data . cend ())
{
if ( call_type == gui_call_type :: reset_input )
{
// Set to max. We won't have all the events for all the buttons or axis at this point.
m_min_button_values [ name ] = 65535 ;
if ( ev_type == EV_ABS )
{
// Also set the other direction to max if it wasn't already found.
const auto it_other_axis = is_rev_axis ? axis_list . find ( code ) : rev_axis_list . find ( code );
ensure ( it_other_axis != ( is_rev_axis ? axis_list . cend () : rev_axis_list . cend ()));
if ( const std :: string & other_name = it_other_axis -> second ; ! m_min_button_values . contains ( other_name ))
{
m_min_button_values [ other_name ] = 65535 ;
}
}
}
return ;
}
const auto & [ value , is_rev_ax ] = it -> second ;
// If we want the value for an axis, its direction has to match the direction of the data.
if ( ev_type == EV_ABS && is_rev_axis != is_rev_ax )
2024-08-08 04:35:40 +02:00
return ;
u16 & min_value = m_min_button_values [ name ];
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: reset_input || value < min_value )
2024-08-08 04:35:40 +02:00
{
min_value = value ;
return ;
}
if ( value <= threshold )
return ;
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: blacklist )
2024-08-08 04:35:40 +02:00
{
m_blacklist . insert ( name );
if ( ev_type == EV_ABS )
{
const int min = libevdev_get_abs_minimum ( dev , code );
const int max = libevdev_get_abs_maximum ( dev , code );
evdev_log . error ( "Evdev Calibration: Added %s [ %d = %s = %s ] to blacklist. [ Value = %d ] [ Min = %d ] [ Max = %d ]" , type , code , libevdev_event_code_get_name ( ev_type , code ), name , value , min , max );
}
else
{
evdev_log . error ( "Evdev Calibration: Added %s [ %d = %s = %s ] to blacklist. Value = %d" , type , code , libevdev_event_code_get_name ( ev_type , code ), name , value );
}
return ;
}
2024-08-09 20:39:56 +02:00
const u16 diff = value > min_value ? value - min_value : 0 ;
2024-08-08 03:04:21 +02:00
2026-03-17 13:37:08 +01:00
if ( diff > button_press_threshold )
2024-08-08 03:04:21 +02:00
{
2026-03-17 13:37:08 +01:00
if ( ev_type == EV_ABS )
{
if ( pressed_sticks [ 0 ]. second < value )
{
pressed_sticks [ 0 ] = { name , value };
}
}
else
{
u16 & pressed_value = pressed_buttons [ name ];
pressed_value = std :: max ( pressed_value , value );
}
2024-08-08 03:04:21 +02:00
}
};
2023-02-09 00:01:26 +01:00
const bool is_xbox_360_controller = padId . find ( "Xbox 360" ) != umax ;
const bool is_sony_controller = ! is_xbox_360_controller && padId . find ( "Sony" ) != umax ;
2023-02-09 00:01:56 +01:00
const bool is_sony_guitar = is_sony_controller && padId . find ( "Guitar" ) != umax ;
2023-02-09 00:01:26 +01:00
2020-03-12 10:32:22 +01:00
for ( const auto & [ code , name ] : button_list )
2017-11-27 22:31:15 +01:00
{
2017-12-10 10:41:55 +01:00
// Handle annoying useless buttons
2021-08-08 16:45:45 +02:00
if ( code == NO_BUTTON )
continue ;
2023-02-09 00:01:26 +01:00
if ( is_xbox_360_controller && code >= BTN_TRIGGER_HAPPY )
2017-11-27 22:31:15 +01:00
continue ;
2023-02-09 00:01:56 +01:00
if ( is_sony_controller && ! is_sony_guitar && ( code == BTN_TL2 || code == BTN_TR2 ))
2017-11-27 22:31:15 +01:00
continue ;
2024-08-09 20:39:56 +02:00
set_button_press ( code , name , "button" sv , 0 , EV_KEY , false );
2017-11-27 22:31:15 +01:00
}
2020-03-12 10:32:22 +01:00
for ( const auto & [ code , name ] : axis_list )
2017-11-27 22:31:15 +01:00
{
2024-08-09 20:39:56 +02:00
set_button_press ( code , name , "axis" sv , m_thumb_threshold , EV_ABS , false );
2017-11-27 22:31:15 +01:00
}
2020-03-12 10:32:22 +01:00
for ( const auto & [ code , name ] : rev_axis_list )
2017-11-27 22:31:15 +01:00
{
2024-08-09 20:39:56 +02:00
set_button_press ( code , name , "rev axis" sv , m_thumb_threshold , EV_ABS , true );
2024-08-08 03:04:21 +02:00
}
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: reset_input )
2024-08-08 03:04:21 +02:00
{
return connection :: no_data ;
2017-11-30 00:43:52 +01:00
}
2024-08-09 20:39:56 +02:00
if ( call_type == gui_call_type :: blacklist )
2017-11-30 00:43:52 +01:00
{
2020-12-14 14:33:43 +01:00
if ( m_blacklist . empty ())
2020-02-01 11:23:50 +03:00
evdev_log . success ( "Evdev Calibration: Blacklist is clear. No input spam detected" );
2022-10-21 22:55:31 +02:00
return connection :: connected ;
2017-11-27 22:31:15 +01:00
}
2020-07-04 13:18:45 +02:00
if ( callback )
{
2025-09-30 20:10:55 +02:00
pad_capabilities capabilities = get_capabilities ( padId );
2026-03-17 13:37:08 +01:00
callback ( std :: move ( pressed_buttons ), std :: move ( pressed_sticks ), padId , 0 , std :: move ( preview_values ), std :: move ( capabilities ));
2020-07-04 13:18:45 +02:00
}
2022-10-21 22:55:31 +02:00
return connection :: connected ;
2017-11-27 22:31:15 +01:00
}
2022-08-13 09:56:04 +02:00
void evdev_joystick_handler :: get_motion_sensors ( const std :: string & padId , const motion_callback & callback , const motion_fail_callback & fail_callback , motion_preview_values preview_values , const std :: array < AnalogSensor , 4 >& sensors )
{
// Add device if not yet present
2023-06-13 01:19:32 +02:00
std :: shared_ptr < EvdevDevice > device = add_motion_device ( padId , true );
2022-08-13 09:56:04 +02:00
if ( ! device || ! update_device ( device ) || ! device -> device )
{
if ( fail_callback )
fail_callback ( padId , std :: move ( preview_values ));
return ;
}
2023-06-13 01:19:32 +02:00
libevdev * dev = device -> device ;
2022-08-13 09:56:04 +02:00
// Try to fetch all new events from the joystick.
bool is_dirty = false ;
int ret = LIBEVDEV_READ_STATUS_SUCCESS ;
while ( ret >= 0 )
{
input_event evt ;
if ( ret == LIBEVDEV_READ_STATUS_SYNC )
{
// Grab any pending sync event.
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC , & evt );
}
else
{
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL , & evt );
}
if ( ret == LIBEVDEV_READ_STATUS_SUCCESS && evt . type == EV_ABS )
{
for ( usz i = 0 ; i < sensors . size (); i ++ )
{
const AnalogSensor & sensor = sensors [ i ];
if ( sensor . m_keyCode != evt . code )
continue ;
preview_values [ i ] = get_sensor_value ( dev , sensor , evt );;
is_dirty = true ;
}
}
}
if ( ret < 0 )
{
// -EAGAIN signifies no available events, not an actual *error*.
if ( ret != - EAGAIN )
evdev_log . error ( "Failed to read latest event from motion device: %s [errno %d]" , strerror ( - ret ), - ret );
}
if ( callback && is_dirty )
callback ( padId , std :: move ( preview_values ));
}
2017-12-02 11:45:58 +01:00
// https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/InputCommon/ControllerInterface/evdev/evdev.cpp
// https://github.com/reicast/reicast-emulator/blob/master/core/linux-dist/evdev.cpp
// http://www.infradead.org/~mchehab/kernel_docs_pdf/linux-input.pdf
2022-10-21 22:35:31 +02:00
void evdev_joystick_handler :: SetRumble ( EvdevDevice * device , u8 large , u8 small )
2017-12-02 11:45:58 +01:00
{
2019-09-20 16:28:55 +02:00
if ( ! device || ! device -> has_rumble || device -> effect_id == - 2 )
2017-12-02 11:45:58 +01:00
return ;
2020-03-12 10:32:22 +01:00
const int fd = libevdev_get_fd ( device -> device );
2017-12-02 11:45:58 +01:00
if ( fd < 0 )
return ;
2024-08-17 11:21:11 +02:00
device -> new_output_data = large != device -> large_motor || small != device -> small_motor ;
const auto now = steady_clock :: now ();
const auto elapsed = now - device -> last_output ;
2017-12-02 11:45:58 +01:00
2017-12-03 19:16:41 +01:00
// XBox One Controller can't handle faster vibration updates than ~10ms. Elite is even worse.
// So I'll use 20ms to be on the safe side. No lag was noticable.
2024-08-17 11:21:11 +02:00
if (( ! device -> new_output_data || elapsed <= 20 ms ) && elapsed <= min_output_interval )
2017-12-03 19:16:41 +01:00
return ;
2024-08-17 11:21:11 +02:00
device -> new_output_data = false ;
device -> last_output = now ;
2017-12-03 19:16:41 +01:00
2017-12-02 11:45:58 +01:00
// delete the previous effect (which also stops it)
if ( device -> effect_id != - 1 )
{
ioctl ( fd , EVIOCRMFF , device -> effect_id );
device -> effect_id = - 1 ;
}
if ( large == 0 && small == 0 )
{
2022-10-21 22:35:31 +02:00
device -> large_motor = large ;
device -> small_motor = small ;
2017-12-02 11:45:58 +01:00
return ;
}
ff_effect effect ;
if ( libevdev_has_event_code ( device -> device , EV_FF , FF_RUMBLE ))
{
2020-03-12 10:32:22 +01:00
effect . type = FF_RUMBLE ;
effect . id = device -> effect_id ;
effect . direction = 0 ;
2022-10-21 22:35:31 +02:00
effect . u . rumble . strong_magnitude = large * 257 ;
effect . u . rumble . weak_magnitude = small * 257 ;
2020-03-12 10:32:22 +01:00
effect . replay . length = 0 ;
effect . replay . delay = 0 ;
effect . trigger . button = 0 ;
effect . trigger . interval = 0 ;
2017-12-02 11:45:58 +01:00
}
else
{
// TODO: handle other Rumble effects
device -> effect_id = - 2 ;
return ;
}
if ( ioctl ( fd , EVIOCSFF , & effect ) == - 1 )
{
2020-02-01 11:23:50 +03:00
evdev_log . error ( "evdev SetRumble ioctl failed! [large = %d] [small = %d] [fd = %d]" , large , small , fd );
2017-12-02 11:45:58 +01:00
device -> effect_id = - 2 ;
}
device -> effect_id = effect . id ;
input_event play ;
2020-03-12 10:32:22 +01:00
play . type = EV_FF ;
play . code = device -> effect_id ;
2017-12-02 11:45:58 +01:00
play . value = 1 ;
if ( write ( fd , & play , sizeof ( play )) == - 1 )
{
2020-02-01 11:23:50 +03:00
evdev_log . error ( "evdev SetRumble write failed! [large = %d] [small = %d] [fd = %d] [effect_id = %d]" , large , small , fd , device -> effect_id );
2017-12-02 11:45:58 +01:00
device -> effect_id = - 2 ;
}
2022-10-21 22:35:31 +02:00
device -> large_motor = large ;
device -> small_motor = small ;
2017-12-02 11:45:58 +01:00
}
2022-10-21 22:35:31 +02:00
void evdev_joystick_handler :: 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*/ )
2017-11-27 22:31:15 +01:00
{
2017-12-02 11:45:58 +01:00
// Get our evdev device
2023-06-13 01:19:32 +02:00
std :: shared_ptr < EvdevDevice > dev = get_evdev_device ( padId );
2019-09-20 16:28:55 +02:00
if ( ! dev )
2017-12-02 11:45:58 +01:00
{
2022-10-21 22:35:31 +02:00
evdev_log . error ( "evdev TestVibration: Device [%s] not found! [large_motor = %d] [small_motor = %d]" , padId , large_motor , small_motor );
2017-12-02 11:45:58 +01:00
return ;
}
if ( ! dev -> has_rumble )
{
2022-10-21 22:35:31 +02:00
evdev_log . error ( "evdev TestVibration: Device [%s] does not support rumble features! [large_motor = %d] [small_motor = %d]" , padId , large_motor , small_motor );
2017-12-02 11:45:58 +01:00
return ;
}
2022-10-21 22:35:31 +02:00
SetRumble ( static_cast < EvdevDevice *> ( dev . get ()), large_motor , small_motor );
2017-11-27 22:31:15 +01:00
}
2022-08-13 09:56:04 +02:00
std :: vector < pad_list_entry > evdev_joystick_handler :: list_devices ()
2017-07-26 13:03:06 -05:00
{
2017-11-27 22:31:15 +01:00
Init ();
2018-01-27 15:13:39 +01:00
std :: unordered_map < std :: string , u32 > unique_names ;
2022-08-13 09:56:04 +02:00
std :: vector < pad_list_entry > evdev_joystick_list ;
2017-08-15 14:03:07 +02:00
2022-08-13 09:56:04 +02:00
for ( auto && et : fs :: dir { "/dev/input/" })
2017-11-27 22:31:15 +01:00
{
// Check if the entry starts with event (a 5-letter word)
2022-08-13 09:56:04 +02:00
if ( et . name . size () > 5 && et . name . starts_with ( "event" ))
2017-11-27 22:31:15 +01:00
{
2022-08-13 09:56:04 +02:00
const int fd = open (( "/dev/input/" + et . name ). c_str (), O_RDONLY | O_NONBLOCK );
2020-03-12 10:32:22 +01:00
struct libevdev * dev = NULL ;
const int rc = libevdev_new_from_fd ( fd , & dev );
2017-11-27 22:31:15 +01:00
if ( rc < 0 )
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if ( rc != - 9 )
2020-02-01 07:15:50 +03:00
evdev_log . warning ( "Failed to connect to device at %s, the error was: %s" , "/dev/input/" + et . name , strerror ( - rc ));
2017-11-27 22:31:15 +01:00
libevdev_free ( dev );
close ( fd );
continue ;
}
2022-08-13 09:56:04 +02:00
if ( libevdev_has_event_type ( dev , EV_ABS ))
2017-11-27 22:31:15 +01:00
{
2022-08-13 09:56:04 +02:00
bool is_motion_device = false ;
bool is_pad_device = libevdev_has_event_type ( dev , EV_KEY );
2018-01-27 15:13:39 +01:00
2022-08-13 09:56:04 +02:00
if ( ! is_pad_device )
{
// Check if it's a motion device.
is_motion_device = libevdev_has_property ( dev , INPUT_PROP_ACCELEROMETER );
}
2018-01-27 15:13:39 +01:00
2022-08-13 09:56:04 +02:00
if ( is_pad_device || is_motion_device )
{
// It's a joystick or motion device.
std :: string name = get_device_name ( dev );
if ( unique_names . find ( name ) == unique_names . end ())
unique_names . emplace ( name , 1 );
else
name = fmt :: format ( "%d. %s" , ++ unique_names [ name ], name );
evdev_joystick_list . emplace_back ( name , is_motion_device );
}
2017-11-27 22:31:15 +01:00
}
2022-08-13 09:56:04 +02:00
2017-11-27 22:31:15 +01:00
libevdev_free ( dev );
close ( fd );
}
}
return evdev_joystick_list ;
2017-08-15 14:03:07 +02:00
}
2017-07-26 13:03:06 -05:00
2022-08-13 09:56:04 +02:00
std :: shared_ptr < evdev_joystick_handler :: EvdevDevice > evdev_joystick_handler :: add_device ( const std :: string & device , bool in_settings )
2017-08-15 14:03:07 +02:00
{
2020-12-14 14:33:43 +01:00
if ( in_settings && m_settings_added . count ( device ))
2022-09-19 15:57:51 +03:00
return :: at32 ( m_settings_added , device );
2017-07-26 13:03:06 -05:00
2017-11-27 22:31:15 +01:00
// Now we need to find the device with the same name, and make sure not to grab any duplicates.
2018-01-27 15:13:39 +01:00
std :: unordered_map < std :: string , u32 > unique_names ;
2022-08-13 09:56:04 +02:00
for ( auto && et : fs :: dir { "/dev/input/" })
2017-11-27 22:31:15 +01:00
{
// Check if the entry starts with event (a 5-letter word)
2022-08-13 09:56:04 +02:00
if ( et . name . size () > 5 && et . name . starts_with ( "event" ))
2017-11-27 22:31:15 +01:00
{
2020-03-12 10:32:22 +01:00
const std :: string path = "/dev/input/" + et . name ;
const int fd = open ( path . c_str (), O_RDWR | O_NONBLOCK );
struct libevdev * dev = NULL ;
const int rc = libevdev_new_from_fd ( fd , & dev );
2017-11-27 22:31:15 +01:00
if ( rc < 0 )
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if ( rc != - 9 )
2020-02-01 07:15:50 +03:00
evdev_log . warning ( "Failed to connect to device at %s, the error was: %s" , path , strerror ( - rc ));
2017-11-27 22:31:15 +01:00
libevdev_free ( dev );
close ( fd );
continue ;
}
2018-01-27 15:13:39 +01:00
std :: string name = get_device_name ( dev );
if ( unique_names . find ( name ) == unique_names . end ())
unique_names . emplace ( name , 1 );
else
name = fmt :: format ( "%d. %s" , ++ unique_names [ name ], name );
2022-08-13 09:56:04 +02:00
if ( name == device &&
libevdev_has_event_type ( dev , EV_KEY ) &&
libevdev_has_event_type ( dev , EV_ABS ))
2017-11-27 22:31:15 +01:00
{
2022-08-13 09:56:04 +02:00
// It's a joystick.
2017-08-15 14:03:07 +02:00
2019-11-05 17:34:04 +01:00
if ( in_settings )
{
2022-08-13 09:56:04 +02:00
m_dev = std :: make_shared < EvdevDevice > ();
m_settings_added [ device ] = m_dev ;
2020-08-18 10:59:33 +02:00
// Let's log axis information while we are in the settings in order to identify problems more easily.
for ( const auto & [ code , axis_name ] : axis_list )
{
2025-04-13 11:01:58 +02:00
if ( const input_absinfo * info = libevdev_get_abs_info ( dev , code ))
2020-08-18 10:59:33 +02:00
{
2023-06-13 01:19:32 +02:00
const char * code_name = libevdev_event_code_get_name ( EV_ABS , code );
2022-08-13 09:56:04 +02:00
evdev_log . notice ( "Axis info for %s: %s (%s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d" ,
name , code_name , axis_name , info -> minimum , info -> maximum , info -> fuzz , info -> flat , info -> resolution );
2020-08-18 10:59:33 +02:00
}
}
2019-11-05 17:34:04 +01:00
}
2017-11-27 22:31:15 +01:00
// Alright, now that we've confirmed we haven't added this joystick yet, les do dis.
2020-03-12 10:32:22 +01:00
m_dev -> device = dev ;
m_dev -> path = path ;
2019-09-20 16:28:55 +02:00
m_dev -> has_rumble = libevdev_has_event_type ( dev , EV_FF );
2022-08-13 09:56:04 +02:00
m_dev -> has_motion = libevdev_has_property ( dev , INPUT_PROP_ACCELEROMETER );
evdev_log . notice ( "Capability info for %s: rumble=%d, motion=%d" , name , m_dev -> has_rumble , m_dev -> has_motion );
return m_dev ;
2017-11-27 22:31:15 +01:00
}
libevdev_free ( dev );
close ( fd );
}
}
2022-08-13 09:56:04 +02:00
return nullptr ;
}
std :: shared_ptr < evdev_joystick_handler :: EvdevDevice > evdev_joystick_handler :: add_motion_device ( const std :: string & device , bool in_settings )
{
if ( device . empty ())
return nullptr ;
if ( in_settings && m_motion_settings_added . count ( device ))
2022-09-19 15:57:51 +03:00
return :: at32 ( m_motion_settings_added , device );
2022-08-13 09:56:04 +02:00
// Now we need to find the device with the same name, and make sure not to grab any duplicates.
std :: unordered_map < std :: string , u32 > unique_names ;
for ( auto && et : fs :: dir { "/dev/input/" })
{
// Check if the entry starts with event (a 5-letter word)
if ( et . name . size () > 5 && et . name . starts_with ( "event" ))
{
const std :: string path = "/dev/input/" + et . name ;
const int fd = open ( path . c_str (), O_RDWR | O_NONBLOCK );
struct libevdev * dev = NULL ;
const int rc = libevdev_new_from_fd ( fd , & dev );
if ( rc < 0 )
{
// If it's just a bad file descriptor, don't bother logging, but otherwise, log it.
if ( rc != - 9 )
evdev_log . warning ( "Failed to connect to device at %s, the error was: %s" , path , strerror ( - rc ));
libevdev_free ( dev );
close ( fd );
continue ;
}
std :: string name = get_device_name ( dev );
if ( unique_names . find ( name ) == unique_names . end ())
unique_names . emplace ( name , 1 );
else
name = fmt :: format ( "%d. %s" , ++ unique_names [ name ], name );
if ( name == device &&
libevdev_has_property ( dev , INPUT_PROP_ACCELEROMETER ) &&
libevdev_has_event_type ( dev , EV_ABS ))
{
// Let's log axis information while we are in the settings in order to identify problems more easily.
// Directional axes on this device (absolute and/or relative x, y, z) represent accelerometer data.
// Some devices also report gyroscope data, which devices can report through the rotational axes (absolute and/or relative rx, ry, rz).
// All other axes retain their meaning.
// A device must not mix regular directional axes and accelerometer axes on the same event node.
for ( const auto & [ code , axis_name ] : axis_list )
{
2025-04-13 11:01:58 +02:00
if ( const input_absinfo * info = libevdev_get_abs_info ( dev , code ))
2022-08-13 09:56:04 +02:00
{
const bool is_accel = code == ABS_X || code == ABS_Y || code == ABS_Z ;
2023-06-13 01:19:32 +02:00
const char * code_name = libevdev_event_code_get_name ( EV_ABS , code );
2022-08-13 09:56:04 +02:00
evdev_log . notice ( "Axis info for %s: %s (%s, %s) => minimum=%d, maximum=%d, fuzz=%d, flat=%d, resolution=%d" ,
name , code_name , axis_name , is_accel ? "accelerometer" : "gyro" , info -> minimum , info -> maximum , info -> fuzz , info -> flat , info -> resolution );
}
}
std :: shared_ptr < EvdevDevice > motion_device = std :: make_shared < EvdevDevice > ();
motion_device -> device = dev ;
motion_device -> path = path ;
motion_device -> has_motion = true ;
if ( in_settings )
{
m_motion_settings_added [ device ] = motion_device ;
}
return motion_device ;
}
libevdev_free ( dev );
close ( fd );
}
}
return nullptr ;
2017-08-15 14:03:07 +02:00
}
2019-09-20 16:28:55 +02:00
PadHandlerBase :: connection evdev_joystick_handler :: update_connection ( const std :: shared_ptr < PadDevice >& device )
2017-08-15 14:03:07 +02:00
{
2019-09-20 16:28:55 +02:00
if ( ! update_device ( device ))
return connection :: disconnected ;
2017-08-15 14:03:07 +02:00
2021-02-12 01:55:32 +01:00
EvdevDevice * evdev_device = static_cast < EvdevDevice *> ( device . get ());
2019-09-20 16:28:55 +02:00
if ( ! evdev_device || ! evdev_device -> device )
return connection :: disconnected ;
return connection :: connected ;
}
2022-08-13 09:56:04 +02:00
void evdev_joystick_handler :: get_mapping ( const pad_ensemble & binding )
2019-09-20 16:28:55 +02:00
{
2022-08-13 09:56:04 +02:00
m_dev = std :: static_pointer_cast < EvdevDevice > ( binding . device );
const auto & pad = binding . pad ;
2019-09-20 16:28:55 +02:00
if ( ! m_dev || ! pad )
return ;
2023-06-13 01:19:32 +02:00
libevdev * dev = m_dev -> device ;
2022-08-13 09:56:04 +02:00
if ( ! dev )
2019-09-20 16:28:55 +02:00
return ;
2022-03-20 00:19:44 +01:00
// Try to fetch all new events from the joystick.
2023-06-14 20:57:30 +02:00
bool got_changes = false ;
2019-09-20 16:28:55 +02:00
input_event evt ;
2022-03-20 00:19:44 +01:00
int ret = LIBEVDEV_READ_STATUS_SUCCESS ;
while ( ret >= 0 )
2017-11-27 22:31:15 +01:00
{
2022-03-20 00:19:44 +01:00
if ( ret == LIBEVDEV_READ_STATUS_SYNC )
{
// Grab any pending sync event.
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC , & evt );
}
else
{
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL , & evt );
}
if ( ret == LIBEVDEV_READ_STATUS_SUCCESS )
{
2023-06-14 20:57:30 +02:00
switch ( evt . type )
{
case EV_KEY :
{
auto & wrapper = m_dev -> events_by_code [ evt . code ];
if ( ! wrapper )
{
wrapper . reset ( new key_event_wrapper ());
}
key_event_wrapper * key_wrapper = static_cast < key_event_wrapper *> ( wrapper . get ());
if ( ! key_wrapper -> is_initialized )
{
if ( ! button_list . contains ( evt . code ))
{
evdev_log . error ( "Evdev button %s (%d) is unknown. Please add it to the button list." , libevdev_event_code_get_name ( EV_KEY , evt . code ), evt . code );
}
key_wrapper -> is_initialized = true ;
}
const u16 new_value = evt . value > 0 ? 255 : 0 ;
if ( key_wrapper -> value != new_value )
{
key_wrapper -> value = new_value ;
got_changes = true ;
}
break ;
}
case EV_ABS :
{
auto & wrapper = m_dev -> events_by_code [ evt . code ];
if ( ! wrapper )
{
wrapper . reset ( new axis_event_wrapper ());
}
axis_event_wrapper * axis_wrapper = static_cast < axis_event_wrapper *> ( wrapper . get ());
if ( ! axis_wrapper -> is_initialized )
{
axis_wrapper -> min = libevdev_get_abs_minimum ( dev , evt . code );
axis_wrapper -> max = libevdev_get_abs_maximum ( dev , evt . code );
2023-12-11 22:03:40 +01:00
axis_wrapper -> flat = libevdev_get_abs_flat ( dev , evt . code );
2023-06-14 20:57:30 +02:00
axis_wrapper -> is_initialized = true ;
// Triggers do not need handling of negative values
if ( axis_wrapper -> min >= 0 && ! m_positive_axis . contains ( evt . code ))
{
axis_wrapper -> is_trigger = true ;
}
}
// Triggers do not need handling of negative values
if ( axis_wrapper -> is_trigger )
{
2023-12-11 22:03:40 +01:00
const u16 new_value = static_cast < u16 > ( ScaledInput ( evt . value , axis_wrapper -> min , axis_wrapper -> max , axis_wrapper -> flat ));
2023-06-14 20:57:30 +02:00
u16 & key_value = axis_wrapper -> values [ false ];
if ( key_value != new_value )
{
key_value = new_value ;
got_changes = true ;
}
}
else
{
2023-12-11 22:03:40 +01:00
const float fvalue = ScaledAxisInput ( evt . value , axis_wrapper -> min , axis_wrapper -> max , axis_wrapper -> flat );
2023-06-14 20:57:30 +02:00
const bool is_negative = fvalue < 0 ;
const u16 new_value_0 = static_cast < u16 > ( std :: abs ( fvalue ));
const u16 new_value_1 = 0 ; // We need to reset the other direction of this axis
u16 & key_value_0 = axis_wrapper -> values [ is_negative ];
u16 & key_value_1 = axis_wrapper -> values [ ! is_negative ];
if ( key_value_0 != new_value_0 || key_value_1 != new_value_1 )
{
key_value_0 = new_value_0 ;
key_value_1 = new_value_1 ;
got_changes = true ;
}
}
break ;
}
default :
break ;
}
2022-03-20 00:19:44 +01:00
}
2017-11-27 22:31:15 +01:00
}
2019-09-20 16:28:55 +02:00
if ( ret < 0 )
{
// -EAGAIN signifies no available events, not an actual *error*.
if ( ret != - EAGAIN )
2020-02-01 07:15:50 +03:00
evdev_log . error ( "Failed to read latest event from joystick: %s [errno %d]" , strerror ( - ret ), - ret );
2019-09-20 16:28:55 +02:00
}
2023-06-14 20:57:30 +02:00
// Apply all events
if ( got_changes )
{
apply_input_events ( pad );
}
2022-03-20 00:19:44 +01:00
}
2022-08-13 09:56:04 +02:00
void evdev_joystick_handler :: get_extended_info ( const pad_ensemble & binding )
{
// We use this to get motion controls from our buddy device
const auto & device = std :: static_pointer_cast < EvdevDevice > ( binding . buddy_device );
const auto & pad = binding . pad ;
if ( ! pad || ! device || ! update_device ( device ))
return ;
2023-06-13 01:19:32 +02:00
libevdev * dev = device -> device ;
2022-08-13 09:56:04 +02:00
if ( ! dev )
return ;
// Try to fetch all new events from the joystick.
input_event evt ;
int ret = LIBEVDEV_READ_STATUS_SUCCESS ;
while ( ret >= 0 )
{
if ( ret == LIBEVDEV_READ_STATUS_SYNC )
{
// Grab any pending sync event.
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL | LIBEVDEV_READ_FLAG_SYNC , & evt );
}
else
{
ret = libevdev_next_event ( dev , LIBEVDEV_READ_FLAG_NORMAL , & evt );
}
if ( ret == LIBEVDEV_READ_STATUS_SUCCESS && evt . type == EV_ABS )
{
for ( AnalogSensor & sensor : pad -> m_sensors )
{
if ( sensor . m_keyCode != evt . code )
continue ;
sensor . m_value = get_sensor_value ( dev , sensor , evt );
}
}
}
2025-01-08 01:22:50 +01:00
set_raw_orientation ( * pad );
2022-08-13 09:56:04 +02:00
if ( ret < 0 )
{
// -EAGAIN signifies no available events, not an actual *error*.
if ( ret != - EAGAIN )
evdev_log . error ( "Failed to read latest event from buddy device: %s [errno %d]" , strerror ( - ret ), - ret );
}
}
u16 evdev_joystick_handler :: get_sensor_value ( const libevdev * dev , const AnalogSensor & sensor , const input_event & evt ) const
{
if ( dev )
{
const int min = libevdev_get_abs_minimum ( dev , evt . code );
const int max = libevdev_get_abs_maximum ( dev , evt . code );
2023-12-11 22:03:40 +01:00
const int flat = libevdev_get_abs_flat ( dev , evt . code );
2022-08-13 09:56:04 +02:00
2023-12-11 22:03:40 +01:00
s16 value = ScaledInput ( evt . value , min , max , flat , 1023.0f );
2022-08-13 09:56:04 +02:00
if ( sensor . m_mirrored )
{
value = 1023 - value ;
}
return Clamp0To1023 ( value + sensor . m_shift );
}
return 0 ;
}
2023-06-14 20:57:30 +02:00
void evdev_joystick_handler :: apply_input_events ( const std :: shared_ptr < Pad >& pad )
2022-03-20 00:19:44 +01:00
{
if ( ! pad )
return ;
2019-09-20 16:28:55 +02:00
2023-06-13 01:19:32 +02:00
const cfg_pad * cfg = m_dev -> config ;
2023-06-05 21:56:01 +02:00
if ( ! cfg )
return ;
2021-08-29 09:08:31 +02:00
// Find out if special buttons are pressed (introduced by RPCS3).
// These buttons will have a delay of one cycle, but whatever.
2024-08-09 23:44:45 +02:00
const bool analog_limiter_enabled = pad -> get_analog_limiter_button_active ( cfg -> analog_limiter_toggle_mode . get (), pad -> m_player_id );
2024-07-06 18:52:47 +02:00
const bool adjust_pressure = pad -> get_pressure_intensity_button_active ( cfg -> pressure_intensity_toggle_mode . get (), pad -> m_player_id );
2023-08-26 10:07:28 +02:00
const u32 pressure_intensity_deadzone = cfg -> pressure_intensity_deadzone . get ();
2021-08-29 09:08:31 +02:00
2023-06-14 20:57:30 +02:00
const auto update_values = [ & ]( bool & pressed , u16 & final_value , bool is_stick_value , u32 code , u16 val )
2023-06-13 01:19:32 +02:00
{
2023-06-14 20:57:30 +02:00
bool press {};
2024-08-09 23:44:45 +02:00
TranslateButtonPress ( m_dev , code , press , val , analog_limiter_enabled , is_stick_value );
2023-06-14 20:57:30 +02:00
if ( press )
2023-06-13 01:19:32 +02:00
{
2023-06-14 20:57:30 +02:00
if ( ! is_stick_value )
2023-06-13 01:19:32 +02:00
{
2023-06-14 20:57:30 +02:00
// Modify pressure if necessary if the button was pressed
if ( adjust_pressure )
{
val = pad -> m_pressure_intensity ;
}
2023-08-26 10:07:28 +02:00
else if ( pressure_intensity_deadzone > 0 )
{
// Ignore triggers, since they have their own deadzones
if ( ! get_is_left_trigger ( m_dev , code ) && ! get_is_right_trigger ( m_dev , code ))
{
val = NormalizeDirectedInput ( val , pressure_intensity_deadzone , 255 );
}
}
2023-06-13 01:19:32 +02:00
}
2023-06-14 20:57:30 +02:00
final_value = std :: max ( final_value , val );
2023-08-26 10:07:28 +02:00
pressed = final_value > 0 ;
2023-06-14 20:57:30 +02:00
}
};
const auto process_mapped_button = [ & ]( u32 index , bool & pressed , u16 & final_value , bool is_stick_value )
{
const EvdevButton & evdev_button = :: at32 ( m_dev -> all_buttons , index );
auto & wrapper = m_dev -> events_by_code [ evdev_button . code ];
if ( ! wrapper || ! wrapper -> is_initialized )
{
return ;
}
// We need to set the current direction and type for TranslateButtonPress
m_dev -> cur_type = wrapper -> type ;
m_dev -> cur_dir = evdev_button . dir ;
switch ( wrapper -> type )
{
case EV_KEY :
{
key_event_wrapper * key_wrapper = static_cast < key_event_wrapper *> ( wrapper . get ());
update_values ( pressed , final_value , is_stick_value , evdev_button . code , key_wrapper -> value );
break ;
}
case EV_ABS : // Be careful to handle mapped axis specially
{
if ( evdev_button . dir < 0 )
{
evdev_log . error ( "Invalid axis direction = %d, Button Nr.%d" , evdev_button . dir , index );
break ;
}
axis_event_wrapper * axis_wrapper = static_cast < axis_event_wrapper *> ( wrapper . get ());
if ( is_stick_value && axis_wrapper -> is_trigger )
{
update_values ( pressed , final_value , is_stick_value , evdev_button . code , axis_wrapper -> values [ false ]);
break ;
}
for ( const auto & [ is_negative , value ] : axis_wrapper -> values )
{
// Only set value if the stick / hat is actually pointing to the correct direction.
if ( is_negative == ( evdev_button . dir == 1 ))
{
update_values ( pressed , final_value , is_stick_value , evdev_button . code , value );
}
}
break ;
}
default :
fmt :: throw_exception ( "Unknown evdev input_event_wrapper type: %d" , wrapper -> type );
2023-06-13 01:19:32 +02:00
}
};
2026-03-15 11:01:58 +01:00
const auto process_mapped_combo = [ & ]( const std :: vector < std :: set < u32 >>& combos , bool is_stick_value )
{
bool pressed {};
u16 value = 0 ;
for ( const std :: set < u32 >& combo : combos )
{
bool combo_pressed = ! combo . empty ();
u16 combo_val = 0 ;
// The button combination is only considered pressed if all the buttons are pressed
for ( u32 index : combo )
{
bool btn_pressed {};
u16 btn_val = 0 ;
process_mapped_button ( index , btn_pressed , btn_val , is_stick_value );
if ( btn_pressed == false )
{
combo_pressed = false ;
break ;
}
// Take minimum combo value. Otherwise we will always end up with the max value in case an actual button is part of the combo.
combo_val = ( combo_val == 0 ) ? btn_val : std :: min ( combo_val , btn_val );
}
if ( combo_pressed )
{
value = std :: max ( value , combo_val );
pressed = value > 0 ;
}
}
return std :: make_pair ( pressed , value );
};
2019-09-20 16:28:55 +02:00
// Translate any corresponding keycodes to our normal DS3 buttons and triggers
2023-06-14 20:57:30 +02:00
for ( Button & button : pad -> m_buttons )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
const std :: pair < bool , u16 > val = process_mapped_combo ( button . m_key_combos , false );
2021-08-29 09:08:31 +02:00
2026-03-15 11:01:58 +01:00
button . m_pressed = val . first ;
button . m_value = val . second ;
2019-09-20 16:28:55 +02:00
}
2023-06-14 20:57:30 +02:00
// used to get the absolute value of an axis
s32 stick_val [ 4 ]{};
2019-09-20 16:28:55 +02:00
// Translate any corresponding keycodes to our two sticks. (ignoring thresholds for now)
2024-10-15 00:53:07 +02:00
for ( usz i = 0 ; i < pad -> m_sticks . size (); i ++ )
2019-09-20 16:28:55 +02:00
{
2023-06-13 01:19:32 +02:00
// m_key_codes_min are the mapped keys for left or down
2026-03-15 11:01:58 +01:00
const std :: pair < bool , u16 > val_min = process_mapped_combo ( pad -> m_sticks [ i ]. m_key_combos_min , true );
2019-09-20 16:28:55 +02:00
2023-06-13 01:19:32 +02:00
// m_key_codes_max are the mapped keys for right or up
2026-03-15 11:01:58 +01:00
const std :: pair < bool , u16 > val_max = process_mapped_combo ( pad -> m_sticks [ i ]. m_key_combos_max , true );
2019-09-20 16:28:55 +02:00
// cancel out opposing values and get the resulting difference. if there was no change, use the old value.
2026-03-15 11:01:58 +01:00
stick_val [ i ] = val_max . second - val_min . second ;
2019-09-20 16:28:55 +02:00
}
u16 lx , ly , rx , ry ;
2020-07-12 19:30:45 +02:00
// Normalize and apply pad squircling
2024-05-27 21:50:09 +02:00
convert_stick_values ( lx , ly , stick_val [ 0 ], stick_val [ 1 ], cfg -> lstickdeadzone , cfg -> lstick_anti_deadzone , cfg -> lpadsquircling );
convert_stick_values ( rx , ry , stick_val [ 2 ], stick_val [ 3 ], cfg -> rstickdeadzone , cfg -> rstick_anti_deadzone , cfg -> rpadsquircling );
2019-09-20 16:28:55 +02:00
pad -> m_sticks [ 0 ]. m_value = lx ;
pad -> m_sticks [ 1 ]. m_value = 255 - ly ;
pad -> m_sticks [ 2 ]. m_value = rx ;
pad -> m_sticks [ 3 ]. m_value = 255 - ry ;
}
2022-08-13 09:56:04 +02:00
void evdev_joystick_handler :: apply_pad_data ( const pad_ensemble & binding )
2019-09-20 16:28:55 +02:00
{
2022-08-13 09:56:04 +02:00
const auto & device = binding . device ;
const auto & pad = binding . pad ;
2021-02-12 01:55:32 +01:00
EvdevDevice * evdev_device = static_cast < EvdevDevice *> ( device . get ());
2019-09-20 16:28:55 +02:00
if ( ! evdev_device )
return ;
2023-06-13 01:19:32 +02:00
cfg_pad * cfg = device -> config ;
2022-08-13 09:56:04 +02:00
if ( ! cfg )
return ;
2019-09-20 16:28:55 +02:00
// Handle vibration
2025-09-10 17:49:09 +02:00
const u8 force_large = cfg -> get_large_motor_speed ( pad -> m_vibrate_motors );
const u8 force_small = cfg -> get_small_motor_speed ( pad -> m_vibrate_motors );
2019-09-20 16:28:55 +02:00
SetRumble ( evdev_device , force_large , force_small );
2017-11-27 22:31:15 +01:00
}
2024-07-06 18:41:41 +02:00
bool evdev_joystick_handler :: bindPadToDevice ( std :: shared_ptr < Pad > pad )
2017-11-27 22:31:15 +01:00
{
2024-07-06 18:41:41 +02:00
if ( ! pad || pad -> m_player_id >= g_cfg_input . player . size ())
2022-08-13 09:56:04 +02:00
return false ;
2024-07-06 18:41:41 +02:00
const cfg_player * player_config = g_cfg_input . player [ pad -> m_player_id ];
2019-09-20 16:28:55 +02:00
if ( ! pad )
return false ;
2017-11-27 22:31:15 +01:00
Init ();
2019-11-05 17:34:04 +01:00
m_dev = std :: make_shared < EvdevDevice > ();
2024-07-06 18:41:41 +02:00
m_pad_configs [ pad -> m_player_id ]. from_string ( player_config -> config . to_string ());
m_dev -> config = & m_pad_configs [ pad -> m_player_id ];
m_dev -> player_id = pad -> m_player_id ;
2021-08-10 21:45:26 +02:00
cfg_pad * cfg = m_dev -> config ;
2022-08-13 09:56:04 +02:00
if ( ! cfg )
2017-12-23 22:25:51 +01:00
return false ;
2023-06-13 01:19:32 +02:00
// We need to register EvdevButtons due to their axis directions.
const auto register_evdevbutton = [ this ]( u32 code , bool is_axis , bool is_reverse ) -> u32
2017-11-27 22:31:15 +01:00
{
2023-06-13 01:19:32 +02:00
const u32 index = :: narrow < u32 > ( m_dev -> all_buttons . size ());
2020-05-01 11:01:29 +02:00
2023-06-13 01:19:32 +02:00
if ( is_axis )
2017-11-27 22:31:15 +01:00
{
2023-06-13 01:19:32 +02:00
m_dev -> all_buttons . push_back ( EvdevButton { code , is_reverse ? 1 : 0 , EV_ABS });
2020-05-01 11:01:29 +02:00
}
else
{
2023-06-13 01:19:32 +02:00
m_dev -> all_buttons . push_back ( EvdevButton { code , - 1 , EV_KEY });
2017-12-01 16:03:17 +01:00
}
2017-11-27 22:31:15 +01:00
2023-06-13 01:19:32 +02:00
return index ;
};
2017-12-01 16:03:17 +01:00
2026-03-15 11:01:58 +01:00
const auto find_buttons = [ & ]( const cfg :: string & name ) -> std :: vector < std :: set < u32 >>
2023-06-13 01:19:32 +02:00
{
2026-03-17 21:30:18 +01:00
const std :: vector < pad :: combo > combos = cfg_pad :: get_combos ( name . to_string ());
2023-06-13 01:19:32 +02:00
// In evdev we store indices to an EvdevButton vector in our pad objects instead of the usual key codes.
2026-03-17 21:30:18 +01:00
std :: vector < std :: set < u32 >> index_combos ;
2023-06-13 01:19:32 +02:00
2026-03-17 21:30:18 +01:00
for ( const pad :: combo & combo : combos )
2023-06-13 01:19:32 +02:00
{
2026-03-15 11:01:58 +01:00
std :: set < u32 > indices ;
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( axis_list , combo ))
2026-03-15 11:01:58 +01:00
{
indices . insert ( register_evdevbutton ( code , true , false ));
}
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( rev_axis_list , combo ))
2026-03-15 11:01:58 +01:00
{
indices . insert ( register_evdevbutton ( code , true , true ));
}
2026-03-17 21:30:18 +01:00
for ( const u32 code : find_key_codes ( button_list , combo ))
2026-03-15 11:01:58 +01:00
{
indices . insert ( register_evdevbutton ( code , false , false ));
}
if ( ! indices . empty ())
{
2026-03-17 21:30:18 +01:00
index_combos . push_back ( std :: move ( indices ));
2026-03-15 11:01:58 +01:00
}
2023-06-13 01:19:32 +02:00
}
2026-03-17 21:30:18 +01:00
return index_combos ;
2017-11-27 22:31:15 +01:00
};
2022-08-13 09:56:04 +02:00
const auto find_motion_button = [ & ]( const cfg_sensor & sensor ) -> evdev_sensor
{
evdev_sensor e_sensor {};
e_sensor . type = EV_ABS ;
e_sensor . mirrored = sensor . mirrored . get ();
e_sensor . shift = sensor . shift . get ();
2023-06-13 01:19:32 +02:00
2026-06-14 06:21:03 +02:00
const std :: vector < std :: set < u32 >> combos = find_key_combos ( motion_axis_list , sensor . axis . to_string ());
2026-03-15 11:01:58 +01:00
if ( ! combos . empty () && ! combos . front (). empty ()) e_sensor . code = * combos . front (). begin (); // We should only have one key for each of our sensors
2022-08-13 09:56:04 +02:00
return e_sensor ;
};
2020-04-25 02:12:19 +02:00
u32 pclass_profile = 0x0 ;
2023-06-13 01:19:32 +02:00
for ( const input :: product_info & product : input :: get_products_by_class ( cfg -> device_class_type ))
2020-04-25 02:12:19 +02:00
{
2021-08-10 21:45:26 +02:00
if ( product . vendor_id == cfg -> vendor_id && product . product_id == cfg -> product_id )
2020-04-25 02:12:19 +02:00
{
pclass_profile = product . pclass_profile ;
}
}
2017-11-27 22:31:15 +01:00
pad -> Init
(
2018-01-13 00:55:51 +01:00
CELL_PAD_STATUS_DISCONNECTED ,
2017-11-27 22:31:15 +01:00
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_HP_ANALOG_STICK | CELL_PAD_CAPABILITY_ACTUATOR | CELL_PAD_CAPABILITY_SENSOR_MODE ,
2019-02-25 18:47:16 +01:00
CELL_PAD_DEV_TYPE_STANDARD ,
2021-08-10 21:45:26 +02:00
cfg -> device_class_type ,
2020-04-25 02:12:19 +02:00
pclass_profile ,
2021-08-10 21:45:26 +02:00
cfg -> vendor_id ,
cfg -> product_id ,
cfg -> pressure_intensity
2017-11-27 22:31:15 +01:00
);
2024-08-09 23:44:45 +02:00
if ( b_has_pressure_intensity_button )
{
pad -> m_buttons . emplace_back ( special_button_offset , find_buttons ( cfg -> pressure_intensity_button ), special_button_value :: pressure_intensity );
pad -> m_pressure_intensity_button_index = static_cast < s32 > ( pad -> m_buttons . size ()) - 1 ;
}
if ( b_has_analog_limiter_button )
{
pad -> m_buttons . emplace_back ( special_button_offset , find_buttons ( cfg -> analog_limiter_button ), special_button_value :: analog_limiter );
pad -> m_analog_limiter_button_index = static_cast < s32 > ( pad -> m_buttons . size ()) - 1 ;
}
2021-08-06 02:08:18 +02:00
2025-01-08 01:22:50 +01:00
if ( b_has_orientation )
{
pad -> m_buttons . emplace_back ( special_button_offset , find_buttons ( cfg -> orientation_reset_button ), special_button_value :: orientation_reset );
pad -> m_orientation_reset_button_index = static_cast < s32 > ( pad -> m_buttons . size ()) - 1 ;
}
2026-03-15 11:01:58 +01:00
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> triangle ), CELL_PAD_CTRL_TRIANGLE );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> circle ), CELL_PAD_CTRL_CIRCLE );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> cross ), CELL_PAD_CTRL_CROSS );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> square ), CELL_PAD_CTRL_SQUARE );
2017-12-01 16:03:17 +01:00
2023-06-13 01:19:32 +02:00
m_dev -> trigger_left = find_buttons ( cfg -> l2 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , m_dev -> trigger_left , CELL_PAD_CTRL_L2 );
2017-12-01 16:03:17 +01:00
2023-06-13 01:19:32 +02:00
m_dev -> trigger_right = find_buttons ( cfg -> r2 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , m_dev -> trigger_right , CELL_PAD_CTRL_R2 );
2017-12-01 16:03:17 +01:00
2023-06-13 01:19:32 +02:00
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> l1 ), CELL_PAD_CTRL_L1 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL2 , find_buttons ( cfg -> r1 ), CELL_PAD_CTRL_R1 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> start ), CELL_PAD_CTRL_START );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> select ), CELL_PAD_CTRL_SELECT );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> l3 ), CELL_PAD_CTRL_L3 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> r3 ), CELL_PAD_CTRL_R3 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> ps ), CELL_PAD_CTRL_PS );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> up ), CELL_PAD_CTRL_UP );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> down ), CELL_PAD_CTRL_DOWN );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> left ), CELL_PAD_CTRL_LEFT );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_DIGITAL1 , find_buttons ( cfg -> right ), CELL_PAD_CTRL_RIGHT );
2017-11-27 22:31:15 +01:00
2023-08-26 15:47:52 +02:00
if ( pad -> m_class_type == CELL_PAD_PCLASS_TYPE_SKATEBOARD )
{
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> ir_nose ), CELL_PAD_CTRL_PRESS_TRIANGLE );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> ir_tail ), CELL_PAD_CTRL_PRESS_CIRCLE );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> ir_left ), CELL_PAD_CTRL_PRESS_CROSS );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> ir_right ), CELL_PAD_CTRL_PRESS_SQUARE );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> tilt_left ), CELL_PAD_CTRL_PRESS_L1 );
pad -> m_buttons . emplace_back ( CELL_PAD_BTN_OFFSET_PRESS_PIGGYBACK , find_buttons ( cfg -> tilt_right ), CELL_PAD_CTRL_PRESS_R1 );
}
2023-06-13 01:19:32 +02:00
m_dev -> axis_left [ 0 ] = find_buttons ( cfg -> ls_right );
m_dev -> axis_left [ 1 ] = find_buttons ( cfg -> ls_left );
m_dev -> axis_left [ 2 ] = find_buttons ( cfg -> ls_up );
m_dev -> axis_left [ 3 ] = find_buttons ( cfg -> ls_down );
m_dev -> axis_right [ 0 ] = find_buttons ( cfg -> rs_right );
m_dev -> axis_right [ 1 ] = find_buttons ( cfg -> rs_left );
m_dev -> axis_right [ 2 ] = find_buttons ( cfg -> rs_up );
m_dev -> axis_right [ 3 ] = find_buttons ( cfg -> rs_down );
2017-12-01 16:03:17 +01:00
2024-10-15 00:53:07 +02:00
pad -> m_sticks [ 0 ] = AnalogStick ( CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X , m_dev -> axis_left [ 1 ], m_dev -> axis_left [ 0 ]);
pad -> m_sticks [ 1 ] = AnalogStick ( CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y , m_dev -> axis_left [ 3 ], m_dev -> axis_left [ 2 ]);
pad -> m_sticks [ 2 ] = AnalogStick ( CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X , m_dev -> axis_right [ 1 ], m_dev -> axis_right [ 0 ]);
pad -> m_sticks [ 3 ] = AnalogStick ( CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y , m_dev -> axis_right [ 3 ], m_dev -> axis_right [ 2 ]);
2017-11-27 22:31:15 +01:00
2022-08-13 09:56:04 +02:00
m_dev -> axis_motion [ 0 ] = find_motion_button ( cfg -> motion_sensor_x );
m_dev -> axis_motion [ 1 ] = find_motion_button ( cfg -> motion_sensor_y );
m_dev -> axis_motion [ 2 ] = find_motion_button ( cfg -> motion_sensor_z );
m_dev -> axis_motion [ 3 ] = find_motion_button ( cfg -> motion_sensor_g );
2024-10-15 00:53:07 +02:00
pad -> m_sensors [ 0 ] = AnalogSensor ( CELL_PAD_BTN_OFFSET_SENSOR_X , m_dev -> axis_motion [ 0 ]. code , m_dev -> axis_motion [ 0 ]. mirrored , m_dev -> axis_motion [ 0 ]. shift , DEFAULT_MOTION_X );
pad -> m_sensors [ 1 ] = AnalogSensor ( CELL_PAD_BTN_OFFSET_SENSOR_Y , m_dev -> axis_motion [ 1 ]. code , m_dev -> axis_motion [ 1 ]. mirrored , m_dev -> axis_motion [ 1 ]. shift , DEFAULT_MOTION_Y );
pad -> m_sensors [ 2 ] = AnalogSensor ( CELL_PAD_BTN_OFFSET_SENSOR_Z , m_dev -> axis_motion [ 2 ]. code , m_dev -> axis_motion [ 2 ]. mirrored , m_dev -> axis_motion [ 2 ]. shift , DEFAULT_MOTION_Z );
pad -> m_sensors [ 3 ] = AnalogSensor ( CELL_PAD_BTN_OFFSET_SENSOR_G , m_dev -> axis_motion [ 3 ]. code , m_dev -> axis_motion [ 3 ]. mirrored , m_dev -> axis_motion [ 3 ]. shift , DEFAULT_MOTION_G );
2017-11-27 22:31:15 +01:00
2025-09-10 17:49:09 +02:00
pad -> m_vibrate_motors [ 0 ] = VibrateMotor ( true );
pad -> m_vibrate_motors [ 1 ] = VibrateMotor ( false );
2017-11-27 22:31:15 +01:00
2023-06-13 01:19:32 +02:00
if ( std :: shared_ptr < EvdevDevice > evdev_device = add_device ( player_config -> device , false ))
2022-08-13 09:56:04 +02:00
{
2023-06-13 01:19:32 +02:00
if ( std :: shared_ptr < EvdevDevice > motion_device = add_motion_device ( player_config -> buddy_device , false ))
2022-08-13 09:56:04 +02:00
{
m_bindings . emplace_back ( pad , evdev_device , motion_device );
}
else
{
m_bindings . emplace_back ( pad , evdev_device , nullptr );
2024-08-15 06:37:33 +02:00
if ( const std :: string buddy_device_name = player_config -> buddy_device . to_string (); buddy_device_name != "Null" )
{
evdev_log . warning ( "evdev add_motion_device in bindPadToDevice failed for device %s" , buddy_device_name );
}
2022-08-13 09:56:04 +02:00
}
}
else
{
evdev_log . warning ( "evdev add_device in bindPadToDevice failed for device %s" , player_config -> device . to_string ());
}
2023-06-13 01:19:32 +02:00
for ( pad_ensemble & binding : m_bindings )
2022-08-13 09:56:04 +02:00
{
update_device ( binding . device );
update_device ( binding . buddy_device );
}
2017-12-01 16:03:17 +01:00
2017-11-27 22:31:15 +01:00
return true ;
2017-07-26 13:03:06 -05:00
}
2023-06-13 01:19:32 +02:00
bool evdev_joystick_handler :: check_button_set ( const std :: set < u32 >& indices , const u32 code )
2019-09-20 16:28:55 +02:00
{
2023-06-13 01:19:32 +02:00
if ( ! m_dev )
return false ;
for ( u32 index : indices )
{
const EvdevButton & button = :: at32 ( m_dev -> all_buttons , index );
if ( button . code == code && button . type == m_dev -> cur_type && button . dir == m_dev -> cur_dir )
{
return true ;
}
}
return false ;
2019-09-20 16:28:55 +02:00
}
2026-03-15 11:01:58 +01:00
bool evdev_joystick_handler :: check_button_combos ( const std :: vector < std :: set < u32 >>& combos , const u32 code )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
return std :: any_of ( combos . begin (), combos . end (), [ this , code ]( const std :: set < u32 >& indices ) { return check_button_set ( indices , code ); });
}
bool evdev_joystick_handler :: check_button_combos ( const std :: array < std :: vector < std :: set < u32 >> , 4 >& combo_array , const u32 code )
{
return std :: any_of ( combo_array . begin (), combo_array . end (), [ this , code ]( const std :: vector < std :: set < u32 >>& combos ) { return check_button_combos ( combos , code ); });
}
2019-09-20 16:28:55 +02:00
2026-03-15 11:17:23 +01:00
bool evdev_joystick_handler :: get_is_left_trigger ( const std :: shared_ptr < PadDevice >& /*device*/ , u32 keyCode )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
return check_button_combos ( m_dev -> trigger_left , keyCode );
2019-09-20 16:28:55 +02:00
}
2026-03-15 11:17:23 +01:00
bool evdev_joystick_handler :: get_is_right_trigger ( const std :: shared_ptr < PadDevice >& /*device*/ , u32 keyCode )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
return check_button_combos ( m_dev -> trigger_right , keyCode );
2019-09-20 16:28:55 +02:00
}
2026-03-15 11:17:23 +01:00
bool evdev_joystick_handler :: get_is_left_stick ( const std :: shared_ptr < PadDevice >& /*device*/ , u32 keyCode )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
return check_button_combos ( m_dev -> axis_left , keyCode );
2019-09-20 16:28:55 +02:00
}
2026-03-15 11:17:23 +01:00
bool evdev_joystick_handler :: get_is_right_stick ( const std :: shared_ptr < PadDevice >& /*device*/ , u32 keyCode )
2019-09-20 16:28:55 +02:00
{
2026-03-15 11:01:58 +01:00
return check_button_combos ( m_dev -> axis_right , keyCode );
2019-09-20 16:28:55 +02:00
}
2017-07-26 13:03:06 -05:00
#endif