2020-12-05 13:08:24 +01:00
# include "stdafx.h"
2020-02-15 23:36:20 +01:00
# include "pad_thread.h"
2020-05-08 21:41:05 +02:00
# include "product_info.h"
2019-02-02 15:15:09 +01:00
# include "ds3_pad_handler.h"
2018-09-18 12:07:33 +02:00
# include "ds4_pad_handler.h"
2020-12-13 00:00:45 +01:00
# include "dualsense_pad_handler.h"
2023-08-26 15:47:52 +02:00
# include "skateboard_pad_handler.h"
2024-07-08 20:17:21 +02:00
# include "ps_move_handler.h"
2017-08-15 14:03:07 +02:00
# ifdef _WIN32
2018-09-18 12:07:33 +02:00
# include "xinput_pad_handler.h"
# include "mm_joystick_handler.h"
2017-08-15 14:03:07 +02:00
# elif HAVE_LIBEVDEV
2018-09-18 12:07:33 +02:00
# include "evdev_joystick_handler.h"
2017-08-15 14:03:07 +02:00
# endif
2022-10-15 21:01:38 +02:00
# ifdef HAVE_SDL2
# include "sdl_pad_handler.h"
# endif
2018-09-18 12:07:33 +02:00
# include "keyboard_pad_handler.h"
# include "Emu/Io/Null/NullPadHandler.h"
2024-08-12 20:31:06 +02:00
# include "Emu/Io/interception.h"
2020-02-22 20:42:49 +01:00
# include "Emu/Io/PadHandler.h"
# include "Emu/Io/pad_config.h"
2021-09-07 21:56:49 +02:00
# include "Emu/System.h"
2022-01-28 00:09:11 +01:00
# include "Emu/system_config.h"
2023-01-21 00:53:49 +01:00
# include "Emu/RSX/Overlays/HomeMenu/overlay_home_menu.h"
2022-10-29 19:53:00 +02:00
# include "Emu/RSX/Overlays/overlay_message.h"
2024-05-12 13:14:44 +02:00
# include "Emu/Cell/lv2/sys_usbd.h"
2024-03-26 14:14:54 +01:00
# include "Emu/Cell/Modules/cellGem.h"
2021-09-07 21:56:49 +02:00
# include "Utilities/Thread.h"
2022-01-28 00:09:11 +01:00
# include "util/atomic.hpp"
2017-08-15 14:03:07 +02:00
2022-10-29 19:53:00 +02:00
LOG_CHANNEL ( sys_log , " SYS " ) ;
2020-02-01 05:15:50 +01:00
2024-06-11 22:30:16 +02:00
extern void pad_state_notify_state_change ( usz index , u32 state ) ;
2022-07-05 21:47:05 +02:00
extern bool is_input_allowed ( ) ;
2023-08-29 21:05:04 +02:00
extern std : : string g_input_config_override ;
2022-07-05 21:47:05 +02:00
2018-12-13 06:24:17 +01:00
namespace pad
2017-08-15 14:03:07 +02:00
{
2025-01-20 22:55:21 +01:00
atomic_t < pad_thread * > g_pad_thread = nullptr ;
2021-05-28 11:35:03 +02:00
shared_mutex g_pad_mutex ;
2018-11-20 16:35:06 +01:00
std : : string g_title_id ;
2022-08-05 14:49:32 +02:00
atomic_t < bool > g_started { false } ;
2020-06-24 17:01:48 +02:00
atomic_t < bool > g_reset { false } ;
2020-06-26 08:40:05 +02:00
atomic_t < bool > g_enabled { true } ;
2024-09-30 21:22:05 +02:00
atomic_t < bool > g_home_menu_requested { false } ;
2017-08-15 14:03:07 +02:00
}
2022-10-29 19:53:00 +02:00
namespace rsx
{
void set_native_ui_flip ( ) ;
}
2018-12-17 19:13:35 +01:00
struct pad_setting
{
2020-05-08 21:41:05 +02:00
u32 port_status = 0 ;
u32 device_capability = 0 ;
u32 device_type = 0 ;
2025-01-22 09:38:36 +01:00
u32 class_type = 0 ;
u16 vendor_id = 0 ;
u16 product_id = 0 ;
2022-10-12 21:25:26 +02:00
bool is_ldd_pad = false ;
2018-12-17 19:13:35 +01:00
} ;
2022-08-05 14:49:32 +02:00
pad_thread : : pad_thread ( void * curthread , void * curwindow , std : : string_view title_id ) : m_curthread ( curthread ) , m_curwindow ( curwindow )
2017-08-15 14:03:07 +02:00
{
2018-11-20 16:35:06 +01:00
pad : : g_title_id = title_id ;
2025-01-20 22:55:21 +01:00
pad : : g_pad_thread = this ;
2022-08-05 14:49:32 +02:00
pad : : g_started = false ;
2018-12-17 19:13:35 +01:00
}
pad_thread : : ~ pad_thread ( )
{
2025-01-20 22:55:21 +01:00
pad : : g_pad_thread = nullptr ;
2018-12-17 19:13:35 +01:00
}
void pad_thread : : Init ( )
{
std : : lock_guard lock ( pad : : g_pad_mutex ) ;
// Cache old settings if possible
2020-05-08 21:41:05 +02:00
std : : array < pad_setting , CELL_PAD_MAX_PORT_NUM > pad_settings ;
2018-12-17 19:13:35 +01:00
for ( u32 i = 0 ; i < CELL_PAD_MAX_PORT_NUM ; i + + ) // max 7 pads
{
2020-05-08 21:41:05 +02:00
if ( m_pads [ i ] )
2018-12-17 19:13:35 +01:00
{
2020-05-08 21:41:05 +02:00
pad_settings [ i ] =
{
m_pads [ i ] - > m_port_status ,
m_pads [ i ] - > m_device_capability ,
m_pads [ i ] - > m_device_type ,
2025-01-22 09:38:36 +01:00
m_pads [ i ] - > m_class_type ,
m_pads [ i ] - > m_vendor_id ,
m_pads [ i ] - > m_product_id ,
2022-10-12 21:25:26 +02:00
m_pads [ i ] - > ldd
2020-05-08 21:41:05 +02:00
} ;
2018-12-17 19:13:35 +01:00
}
else
{
2020-05-08 21:41:05 +02:00
pad_settings [ i ] =
{
CELL_PAD_STATUS_DISCONNECTED ,
CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR ,
CELL_PAD_DEV_TYPE_STANDARD ,
2025-01-22 09:38:36 +01:00
CELL_PAD_PCLASS_TYPE_STANDARD ,
0 ,
0 ,
2022-10-12 21:25:26 +02:00
false
2020-05-08 21:41:05 +02:00
} ;
2018-12-17 19:13:35 +01:00
}
}
2020-05-08 21:41:05 +02:00
num_ldd_pad = 0 ;
2017-11-27 22:31:15 +01:00
m_info . now_connect = 0 ;
2017-08-15 14:03:07 +02:00
2024-06-11 22:30:16 +02:00
m_handlers . clear ( ) ;
2018-12-17 19:13:35 +01:00
2023-08-29 21:05:04 +02:00
g_cfg_input_configs . load ( ) ;
2021-08-15 19:41:06 +02:00
2023-08-29 21:05:04 +02:00
std : : string active_config = g_cfg_input_configs . active_configs . get_value ( pad : : g_title_id ) ;
2023-02-07 21:51:32 +01:00
2023-08-29 21:05:04 +02:00
if ( active_config . empty ( ) )
2021-09-05 03:12:23 +02:00
{
2023-08-29 21:05:04 +02:00
active_config = g_cfg_input_configs . active_configs . get_value ( g_cfg_input_configs . global_key ) ;
2021-09-05 03:12:23 +02:00
}
2023-08-29 21:05:04 +02:00
input_log . notice ( " Using input configuration: '%s' (override='%s') " , active_config , g_input_config_override ) ;
2022-10-12 20:35:32 +02:00
2021-08-15 19:41:06 +02:00
// Load in order to get the pad handlers
2023-08-29 21:05:04 +02:00
if ( ! g_cfg_input . load ( pad : : g_title_id , active_config ) )
2021-08-15 19:41:06 +02:00
{
input_log . notice ( " Loaded empty pad config " ) ;
}
// Adjust to the different pad handlers
for ( usz i = 0 ; i < g_cfg_input . player . size ( ) ; i + + )
{
std : : shared_ptr < PadHandlerBase > handler ;
pad_thread : : InitPadConfig ( g_cfg_input . player [ i ] - > config , g_cfg_input . player [ i ] - > handler , handler ) ;
}
// Reload with proper defaults
2023-08-29 21:05:04 +02:00
if ( ! g_cfg_input . load ( pad : : g_title_id , active_config ) )
2021-08-15 19:41:06 +02:00
{
input_log . notice ( " Reloaded empty pad config " ) ;
}
2017-08-15 14:03:07 +02:00
2023-06-12 03:45:37 +02:00
input_log . trace ( " Using pad config: \n %s " , g_cfg_input ) ;
2022-10-12 20:35:32 +02:00
2017-08-15 14:03:07 +02:00
std : : shared_ptr < keyboard_pad_handler > keyptr ;
2018-12-17 19:13:35 +01:00
// Always have a Null Pad Handler
2024-06-11 22:30:16 +02:00
std : : shared_ptr < NullPadHandler > nullpad = std : : make_shared < NullPadHandler > ( ) ;
m_handlers . emplace ( pad_handler : : null , nullpad ) ;
2017-08-15 14:03:07 +02:00
2018-12-17 19:13:35 +01:00
for ( u32 i = 0 ; i < CELL_PAD_MAX_PORT_NUM ; i + + ) // max 7 pads
2017-08-15 14:03:07 +02:00
{
2022-10-12 20:35:32 +02:00
cfg_player * cfg = g_cfg_input . player [ i ] ;
2017-08-15 14:03:07 +02:00
std : : shared_ptr < PadHandlerBase > cur_pad_handler ;
2022-10-12 21:25:26 +02:00
const pad_handler handler_type = pad_settings [ i ] . is_ldd_pad ? pad_handler : : null : cfg - > handler . get ( ) ;
2018-12-17 19:13:35 +01:00
2024-06-11 22:30:16 +02:00
if ( m_handlers . contains ( handler_type ) )
2017-08-15 14:03:07 +02:00
{
2024-06-11 22:30:16 +02:00
cur_pad_handler = m_handlers [ handler_type ] ;
2017-08-15 14:03:07 +02:00
}
else
{
2024-02-11 16:39:31 +01:00
if ( handler_type = = pad_handler : : keyboard )
2017-08-15 14:03:07 +02:00
{
2024-06-11 22:30:16 +02:00
keyptr = std : : make_shared < keyboard_pad_handler > ( ) ;
2022-08-05 14:49:32 +02:00
keyptr - > moveToThread ( static_cast < QThread * > ( m_curthread ) ) ;
keyptr - > SetTargetWindow ( static_cast < QWindow * > ( m_curwindow ) ) ;
2017-08-15 14:03:07 +02:00
cur_pad_handler = keyptr ;
}
2024-02-11 16:39:31 +01:00
else
{
cur_pad_handler = GetHandler ( handler_type ) ;
}
2024-06-11 22:30:16 +02:00
m_handlers . emplace ( handler_type , cur_pad_handler ) ;
2017-08-15 14:03:07 +02:00
}
cur_pad_handler - > Init ( ) ;
2024-07-22 20:37:57 +02:00
std : : shared_ptr < Pad > pad = std : : make_shared < Pad > ( handler_type , i , CELL_PAD_STATUS_DISCONNECTED , pad_settings [ i ] . device_capability , pad_settings [ i ] . device_type ) ;
m_pads [ i ] = pad ;
2017-08-15 14:03:07 +02:00
2022-10-12 21:25:26 +02:00
if ( pad_settings [ i ] . is_ldd_pad )
2020-05-08 21:41:05 +02:00
{
2022-10-12 21:48:13 +02:00
InitLddPad ( i , & pad_settings [ i ] . port_status ) ;
2020-05-08 21:41:05 +02:00
}
2022-10-12 20:35:32 +02:00
else
2017-08-15 14:03:07 +02:00
{
2024-07-22 20:37:57 +02:00
if ( ! cur_pad_handler - > bindPadToDevice ( pad ) )
2022-10-12 20:35:32 +02:00
{
// Failed to bind the device to cur_pad_handler so binds to NullPadHandler
input_log . error ( " Failed to bind device '%s' to handler %s. Falling back to NullPadHandler. " , cfg - > device . to_string ( ) , handler_type ) ;
2024-07-22 20:37:57 +02:00
nullpad - > bindPadToDevice ( pad ) ;
2022-10-12 20:35:32 +02:00
}
2021-08-08 18:50:37 +02:00
2022-10-12 20:35:32 +02:00
input_log . notice ( " Pad %d: device='%s', handler=%s, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x " ,
2024-07-22 20:37:57 +02:00
i , cfg - > device . to_string ( ) , pad - > m_pad_handler , pad - > m_vendor_id , pad - > m_product_id , pad - > m_class_type , pad - > m_class_profile ) ;
if ( pad - > m_pad_handler ! = pad_handler : : null )
{
input_log . notice ( " Pad %d: config= \n %s " , i , cfg - > to_string ( ) ) ;
}
2025-01-22 09:38:36 +01:00
// If the user changes the emulated controller, then simulate unplugging and plugging in a new controller
if ( m_pads_connected [ i ] & & ( pad_settings [ i ] . class_type ! = pad - > m_class_type | | pad_settings [ i ] . vendor_id ! = pad - > m_vendor_id | | pad_settings [ i ] . product_id ! = pad - > m_product_id ) )
{
pad - > m_disconnection_timer = get_system_time ( ) + 30'000ull ;
}
2022-10-12 20:35:32 +02:00
}
2024-05-12 10:40:42 +02:00
2024-07-08 20:17:21 +02:00
pad - > is_fake_pad = ( ( g_cfg . io . move = = move_handler : : real | | g_cfg . io . move = = move_handler : : fake ) & & i > = ( static_cast < u32 > ( CELL_PAD_MAX_PORT_NUM ) - static_cast < u32 > ( CELL_GEM_MAX_NUM ) ) )
2024-07-22 20:37:57 +02:00
| | ( pad - > m_class_type > = CELL_PAD_FAKE_TYPE_FIRST & & pad - > m_class_type < CELL_PAD_FAKE_TYPE_LAST ) ;
connect_usb_controller ( i , input : : get_product_by_vid_pid ( pad - > m_vendor_id , pad - > m_product_id ) ) ;
2017-08-15 14:03:07 +02:00
}
2024-08-12 20:31:06 +02:00
// Initialize active mouse and keyboard. Activate pad handler if one exists.
input : : set_mouse_and_keyboard ( m_handlers . contains ( pad_handler : : keyboard ) ? input : : active_mouse_and_keyboard : : pad : input : : active_mouse_and_keyboard : : emulated ) ;
2017-08-15 14:03:07 +02:00
}
2022-10-21 22:35:31 +02:00
void pad_thread : : SetRumble ( const u32 pad , u8 large_motor , bool small_motor )
2017-09-12 23:42:00 +02:00
{
2021-11-15 18:26:31 +01:00
if ( pad > = m_pads . size ( ) )
2017-08-15 14:03:07 +02:00
return ;
2024-10-15 00:53:07 +02:00
m_pads [ pad ] - > m_vibrateMotors [ 0 ] . m_value = large_motor ;
m_pads [ pad ] - > m_vibrateMotors [ 1 ] . m_value = small_motor ? 255 : 0 ;
2017-08-15 14:03:07 +02:00
}
2018-12-30 02:34:15 +01:00
void pad_thread : : SetIntercepted ( bool intercepted )
{
if ( intercepted )
{
m_info . system_info | = CELL_PAD_INFO_INTERCEPTED ;
2019-09-20 10:12:01 +02:00
m_info . ignore_input = true ;
2018-12-30 02:34:15 +01:00
}
else
{
2019-09-20 10:12:01 +02:00
m_info . system_info & = ~ CELL_PAD_INFO_INTERCEPTED ;
2018-12-30 02:34:15 +01:00
}
}
2024-06-11 22:30:16 +02:00
void pad_thread : : update_pad_states ( )
{
for ( usz i = 0 ; i < m_pads . size ( ) ; i + + )
{
const auto & pad = m_pads [ i ] ;
2025-01-22 09:38:36 +01:00
// Simulate unplugging and plugging in a new controller
if ( pad & & pad - > m_disconnection_timer > 0 )
{
const bool is_connected = pad - > m_port_status & CELL_PAD_STATUS_CONNECTED ;
const u64 now = get_system_time ( ) ;
if ( is_connected & & now < pad - > m_disconnection_timer )
{
pad - > m_port_status & = ~ CELL_PAD_STATUS_CONNECTED ;
pad - > m_port_status | = CELL_PAD_STATUS_ASSIGN_CHANGES ;
}
else if ( ! is_connected & & now > = pad - > m_disconnection_timer )
{
pad - > m_port_status | = CELL_PAD_STATUS_CONNECTED + CELL_PAD_STATUS_ASSIGN_CHANGES ;
pad - > m_disconnection_timer = 0 ;
}
}
2024-06-11 22:30:16 +02:00
const bool connected = pad & & ! pad - > is_fake_pad & & ! ! ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED ) ;
if ( m_pads_connected [ i ] = = connected )
continue ;
pad_state_notify_state_change ( i , connected ? CELL_PAD_STATUS_CONNECTED : CELL_PAD_STATUS_DISCONNECTED ) ;
m_pads_connected [ i ] = connected ;
}
}
2021-09-07 21:56:49 +02:00
void pad_thread : : operator ( ) ( )
2017-08-15 14:03:07 +02:00
{
2022-07-04 15:02:17 +02:00
Init ( ) ;
2022-08-05 14:49:32 +02:00
2023-01-19 19:11:46 +01:00
const bool is_vsh = Emu . IsVsh ( ) ;
2022-07-04 15:02:17 +02:00
pad : : g_reset = false ;
2022-08-05 14:49:32 +02:00
pad : : g_started = true ;
bool mode_changed = true ;
2021-09-07 21:56:49 +02:00
2022-01-28 00:09:11 +01:00
atomic_t < pad_handler_mode > pad_mode { g_cfg . io . pad_mode . get ( ) } ;
std : : vector < std : : unique_ptr < named_thread < std : : function < void ( ) > > > > threads ;
const auto stop_threads = [ & threads ] ( )
{
2022-08-05 14:49:32 +02:00
input_log . notice ( " Stopping pad threads... " ) ;
2022-01-28 00:09:11 +01:00
for ( auto & thread : threads )
{
if ( thread )
{
auto & enumeration_thread = * thread ;
enumeration_thread = thread_state : : aborting ;
enumeration_thread ( ) ;
}
}
threads . clear ( ) ;
2022-08-05 14:49:32 +02:00
input_log . notice ( " Pad threads stopped " ) ;
2022-01-28 00:09:11 +01:00
} ;
const auto start_threads = [ this , & threads , & pad_mode ] ( )
{
if ( pad_mode = = pad_handler_mode : : single_threaded )
{
return ;
}
2022-08-05 14:49:32 +02:00
input_log . notice ( " Starting pad threads... " ) ;
2024-06-11 22:30:16 +02:00
for ( const auto & handler : m_handlers )
2022-01-28 00:09:11 +01:00
{
if ( handler . first = = pad_handler : : null )
{
continue ;
}
2022-08-05 14:49:32 +02:00
2022-01-28 00:09:11 +01:00
threads . push_back ( std : : make_unique < named_thread < std : : function < void ( ) > > > ( fmt : : format ( " %s Thread " , handler . second - > m_type ) , [ & handler = handler . second , & pad_mode ] ( )
{
while ( thread_ctrl : : state ( ) ! = thread_state : : aborting )
{
2022-10-29 19:53:00 +02:00
if ( ! pad : : g_enabled | | ! is_input_allowed ( ) )
2022-01-28 00:09:11 +01:00
{
2022-10-29 19:53:00 +02:00
thread_ctrl : : wait_for ( 30'000 ) ;
2022-01-28 00:09:11 +01:00
continue ;
}
2022-10-21 22:48:38 +02:00
handler - > process ( ) ;
2022-01-28 00:09:11 +01:00
2022-10-29 19:53:00 +02:00
u64 pad_sleep = g_cfg . io . pad_sleep ;
if ( Emu . IsPaused ( ) )
{
pad_sleep = std : : max < u64 > ( pad_sleep , 30'000 ) ;
}
thread_ctrl : : wait_for ( pad_sleep ) ;
2022-01-28 00:09:11 +01:00
}
} ) ) ;
}
2022-08-05 14:49:32 +02:00
input_log . notice ( " Pad threads started " ) ;
2022-01-28 00:09:11 +01:00
} ;
2021-09-07 21:56:49 +02:00
while ( thread_ctrl : : state ( ) ! = thread_state : : aborting )
2017-08-15 14:03:07 +02:00
{
2022-10-29 19:53:00 +02:00
if ( ! pad : : g_enabled | | ! is_input_allowed ( ) )
2018-12-23 01:35:10 +01:00
{
2022-10-29 19:53:00 +02:00
m_resume_emulation_flag = false ;
2023-01-14 00:07:07 +01:00
m_mask_start_press_to_resume = 0 ;
2022-10-29 19:53:00 +02:00
thread_ctrl : : wait_for ( 30'000 ) ;
2018-12-23 01:35:10 +01:00
continue ;
}
2019-07-16 22:51:39 +02:00
2022-01-28 00:09:11 +01:00
// Update variables
const bool needs_reset = pad : : g_reset & & pad : : g_reset . exchange ( false ) ;
2023-01-26 23:43:49 +01:00
const pad_handler_mode new_pad_mode = g_cfg . io . pad_mode . get ( ) ;
mode_changed | = new_pad_mode ! = pad_mode . exchange ( new_pad_mode ) ;
2022-01-28 00:09:11 +01:00
// Reset pad handlers if necessary
if ( needs_reset | | mode_changed )
2018-12-17 19:13:35 +01:00
{
2022-08-05 14:49:32 +02:00
mode_changed = false ;
2022-01-28 00:09:11 +01:00
stop_threads ( ) ;
if ( needs_reset )
{
Init ( ) ;
}
else
{
input_log . success ( " The pad mode was changed to %s " , pad_mode . load ( ) ) ;
}
start_threads ( ) ;
2018-12-17 19:13:35 +01:00
}
2019-07-16 22:51:39 +02:00
2019-09-20 16:28:55 +02:00
u32 connected_devices = 0 ;
2019-07-16 22:51:39 +02:00
2022-01-28 00:09:11 +01:00
if ( pad_mode = = pad_handler_mode : : single_threaded )
2021-08-08 18:50:37 +02:00
{
2024-06-11 22:30:16 +02:00
for ( auto & handler : m_handlers )
2022-01-28 00:09:11 +01:00
{
2022-10-21 22:48:38 +02:00
handler . second - > process ( ) ;
2022-01-28 00:09:11 +01:00
connected_devices + = handler . second - > connected_devices ;
}
}
else
{
2024-06-11 22:30:16 +02:00
for ( auto & handler : m_handlers )
2022-01-28 00:09:11 +01:00
{
connected_devices + = handler . second - > connected_devices ;
}
2021-08-29 08:40:39 +02:00
}
2021-08-08 18:50:37 +02:00
2024-07-06 17:44:47 +02:00
if ( Emu . IsRunning ( ) )
{
update_pad_states ( ) ;
}
2024-06-11 22:30:16 +02:00
2021-08-29 08:40:39 +02:00
m_info . now_connect = connected_devices + num_ldd_pad ;
2021-08-08 18:50:37 +02:00
2021-09-07 20:42:18 +02:00
// The ignore_input section is only reached when a dialog was closed and the pads are still intercepted.
2021-08-29 08:40:39 +02:00
// As long as any of the listed buttons is pressed, cellPadGetData will ignore all input (needed for Hotline Miami).
// ignore_input was added because if we keep the pads intercepted, then some games will enter the menu due to unexpected system interception (tested with Ninja Gaiden Sigma).
2021-09-07 20:42:18 +02:00
if ( m_info . ignore_input & & ! ( m_info . system_info & CELL_PAD_INFO_INTERCEPTED ) )
2021-08-29 08:40:39 +02:00
{
2021-09-07 20:42:18 +02:00
bool any_button_pressed = false ;
2019-07-16 22:51:39 +02:00
2021-09-07 20:42:18 +02:00
for ( usz i = 0 ; i < m_pads . size ( ) & & ! any_button_pressed ; i + + )
2019-07-16 22:51:39 +02:00
{
2021-09-07 20:42:18 +02:00
const auto & pad = m_pads [ i ] ;
if ( ! ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED ) )
continue ;
2022-10-29 19:53:00 +02:00
for ( const auto & button : pad - > m_buttons )
2019-07-16 22:51:39 +02:00
{
2021-09-07 20:42:18 +02:00
if ( button . m_pressed & & (
button . m_outKeyCode = = CELL_PAD_CTRL_CROSS | |
button . m_outKeyCode = = CELL_PAD_CTRL_CIRCLE | |
button . m_outKeyCode = = CELL_PAD_CTRL_TRIANGLE | |
button . m_outKeyCode = = CELL_PAD_CTRL_SQUARE | |
button . m_outKeyCode = = CELL_PAD_CTRL_START | |
button . m_outKeyCode = = CELL_PAD_CTRL_SELECT ) )
2019-07-16 22:51:39 +02:00
{
2021-09-07 20:42:18 +02:00
any_button_pressed = true ;
break ;
2019-07-16 22:51:39 +02:00
}
}
}
2021-09-07 20:42:18 +02:00
if ( ! any_button_pressed )
{
m_info . ignore_input = false ;
}
2021-08-06 02:08:18 +02:00
}
2023-01-14 00:07:07 +01:00
// Handle home menu if requested
2023-01-19 19:11:46 +01:00
if ( ! is_vsh & & ! m_home_menu_open & & Emu . IsRunning ( ) )
2023-01-14 00:07:07 +01:00
{
2023-01-21 19:01:20 +01:00
bool ps_button_pressed = false ;
for ( usz i = 0 ; i < m_pads . size ( ) & & ! ps_button_pressed ; i + + )
2023-01-14 00:07:07 +01:00
{
2023-06-26 21:42:37 +02:00
if ( i > 0 & & g_cfg . io . lock_overlay_input_to_player_one )
break ;
2023-01-14 00:07:07 +01:00
const auto & pad = m_pads [ i ] ;
if ( ! ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED ) )
continue ;
2023-02-10 03:35:47 +01:00
// Check if an LDD pad pressed the PS button (bit 0 of the first button)
2024-05-25 17:38:26 +02:00
// NOTE: Rock Band 3 doesn't seem to care about the len. It's always 0.
if ( pad - > ldd /*&& pad->ldd_data.len >= 1 */ & & ! ! ( pad - > ldd_data . button [ 0 ] & CELL_PAD_CTRL_LDD_PS ) )
2023-02-10 03:35:47 +01:00
{
ps_button_pressed = true ;
break ;
}
2023-01-14 00:07:07 +01:00
for ( const auto & button : pad - > m_buttons )
{
2023-02-10 03:53:10 +01:00
if ( button . m_offset = = CELL_PAD_BTN_OFFSET_DIGITAL1 & & button . m_outKeyCode = = CELL_PAD_CTRL_PS & & button . m_pressed )
2023-01-14 00:07:07 +01:00
{
2023-01-21 19:01:20 +01:00
ps_button_pressed = true ;
2023-01-14 00:07:07 +01:00
break ;
}
}
}
2023-01-21 19:01:20 +01:00
2023-02-10 03:35:47 +01:00
// Make sure we call this function only once per button press
2024-09-30 21:22:05 +02:00
if ( ( ps_button_pressed & & ! m_ps_button_pressed ) | | pad : : g_home_menu_requested . exchange ( false ) )
2023-02-10 03:35:47 +01:00
{
open_home_menu ( ) ;
}
2023-01-21 19:01:20 +01:00
m_ps_button_pressed = ps_button_pressed ;
2023-01-14 00:07:07 +01:00
}
// Handle paused emulation (if triggered by home menu).
if ( m_home_menu_open & & g_cfg . misc . pause_during_home_menu )
{
// Reset resume control if the home menu is open
m_resume_emulation_flag = false ;
m_mask_start_press_to_resume = 0 ;
m_track_start_press_begin_timestamp = 0 ;
// Update UI
rsx : : set_native_ui_flip ( ) ;
thread_ctrl : : wait_for ( 33'000 ) ;
continue ;
}
2022-10-29 19:53:00 +02:00
if ( m_resume_emulation_flag )
{
m_resume_emulation_flag = false ;
Emu . BlockingCallFromMainThread ( [ ] ( )
{
Emu . Resume ( ) ;
} ) ;
}
u64 pad_sleep = g_cfg . io . pad_sleep ;
2022-11-01 08:10:40 +01:00
if ( Emu . GetStatus ( false ) = = system_state : : paused )
2022-10-29 19:53:00 +02:00
{
pad_sleep = std : : max < u64 > ( pad_sleep , 30'000 ) ;
u64 timestamp = get_system_time ( ) ;
u32 pressed_mask = 0 ;
for ( usz i = 0 ; i < m_pads . size ( ) ; i + + )
{
const auto & pad = m_pads [ i ] ;
if ( ! ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED ) )
continue ;
for ( const auto & button : pad - > m_buttons )
{
if ( button . m_offset = = CELL_PAD_BTN_OFFSET_DIGITAL1 & & button . m_outKeyCode = = CELL_PAD_CTRL_START & & button . m_pressed )
{
pressed_mask | = 1u < < i ;
break ;
}
}
}
2023-01-14 00:07:07 +01:00
m_mask_start_press_to_resume & = pressed_mask ;
2022-10-29 19:53:00 +02:00
2022-11-04 18:15:53 +01:00
if ( ! pressed_mask | | timestamp - m_track_start_press_begin_timestamp > = 700'000 )
2022-10-29 19:53:00 +02:00
{
m_track_start_press_begin_timestamp = timestamp ;
2023-01-14 00:07:07 +01:00
if ( std : : exchange ( m_mask_start_press_to_resume , u32 { umax } ) )
2022-10-29 19:53:00 +02:00
{
2023-01-14 00:07:07 +01:00
m_mask_start_press_to_resume = 0 ;
2022-10-29 19:53:00 +02:00
m_track_start_press_begin_timestamp = 0 ;
2022-11-01 08:10:40 +01:00
sys_log . success ( " Resuming emulation using the START button in a few seconds... " ) ;
auto msg_ref = std : : make_shared < atomic_t < u32 > > ( 1 ) ;
rsx : : overlays : : queue_message ( localized_string_id : : EMULATION_RESUMING , 2'000'000 , msg_ref ) ;
2022-10-29 19:53:00 +02:00
m_resume_emulation_flag = true ;
for ( u32 i = 0 ; i < 40 ; i + + )
{
2022-11-01 08:10:40 +01:00
if ( Emu . GetStatus ( false ) ! = system_state : : paused )
2022-10-29 19:53:00 +02:00
{
// Abort if emulation has been resumed by other means
m_resume_emulation_flag = false ;
2022-11-01 08:10:40 +01:00
msg_ref - > release ( 0 ) ;
2022-10-29 19:53:00 +02:00
break ;
}
thread_ctrl : : wait_for ( 50'000 ) ;
rsx : : set_native_ui_flip ( ) ;
}
}
}
}
else
{
2023-01-14 00:07:07 +01:00
// Reset resume control if caught a state of unpaused emulation
m_mask_start_press_to_resume = 0 ;
2022-10-29 19:53:00 +02:00
m_track_start_press_begin_timestamp = 0 ;
}
thread_ctrl : : wait_for ( pad_sleep ) ;
2017-08-15 14:03:07 +02:00
}
2022-01-28 00:09:11 +01:00
stop_threads ( ) ;
2017-08-15 14:03:07 +02:00
}
2019-04-28 23:35:11 +02:00
2022-10-12 21:48:13 +02:00
void pad_thread : : InitLddPad ( u32 handle , const u32 * port_status )
2020-05-08 21:41:05 +02:00
{
if ( handle > = m_pads . size ( ) )
{
return ;
}
2022-10-12 21:48:13 +02:00
static const input : : product_info product = input : : get_product_info ( input : : product_type : : playstation_3_controller ) ;
2020-05-08 21:41:05 +02:00
m_pads [ handle ] - > ldd = true ;
m_pads [ handle ] - > Init
(
2022-10-12 21:48:13 +02:00
port_status ? * port_status : CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES | CELL_PAD_STATUS_CUSTOM_CONTROLLER ,
2020-05-08 21:41:05 +02:00
CELL_PAD_CAPABILITY_PS3_CONFORMITY ,
CELL_PAD_DEV_TYPE_LDD ,
2023-08-26 15:47:52 +02:00
CELL_PAD_PCLASS_TYPE_STANDARD ,
2020-05-08 21:41:05 +02:00
product . pclass_profile ,
product . vendor_id ,
2021-08-06 02:08:18 +02:00
product . product_id ,
50
2020-05-08 21:41:05 +02:00
) ;
2022-10-12 20:35:32 +02:00
input_log . notice ( " Pad %d: LDD, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x " ,
handle , m_pads [ handle ] - > m_vendor_id , m_pads [ handle ] - > m_product_id , m_pads [ handle ] - > m_class_type , m_pads [ handle ] - > m_class_profile ) ;
2020-05-08 21:41:05 +02:00
num_ldd_pad + + ;
}
2019-04-28 23:35:11 +02:00
s32 pad_thread : : AddLddPad ( )
{
// Look for first null pad
for ( u32 i = 0 ; i < CELL_PAD_MAX_PORT_NUM ; i + + )
{
2020-04-06 22:06:35 +02:00
if ( g_cfg_input . player [ i ] - > handler = = pad_handler : : null & & ! m_pads [ i ] - > ldd )
2019-04-28 23:35:11 +02:00
{
2022-10-12 21:48:13 +02:00
InitLddPad ( i , nullptr ) ;
2019-04-28 23:35:11 +02:00
return i ;
}
}
return - 1 ;
}
void pad_thread : : UnregisterLddPad ( u32 handle )
{
2021-08-08 18:50:37 +02:00
ensure ( handle < m_pads . size ( ) ) ;
2019-04-28 23:35:11 +02:00
m_pads [ handle ] - > ldd = false ;
2025-01-23 23:49:24 +01:00
m_pads [ handle ] - > m_port_status & = ~ CELL_PAD_STATUS_CONNECTED ;
m_pads [ handle ] - > m_port_status | = CELL_PAD_STATUS_ASSIGN_CHANGES ;
2021-08-08 18:50:37 +02:00
2019-04-28 23:35:11 +02:00
num_ldd_pad - - ;
}
2021-08-15 19:41:06 +02:00
std : : shared_ptr < PadHandlerBase > pad_thread : : GetHandler ( pad_handler type )
{
switch ( type )
{
case pad_handler : : null :
2024-06-11 22:30:16 +02:00
return std : : make_shared < NullPadHandler > ( ) ;
2021-08-15 19:41:06 +02:00
case pad_handler : : keyboard :
2024-06-11 22:30:16 +02:00
return std : : make_shared < keyboard_pad_handler > ( ) ;
2021-08-15 19:41:06 +02:00
case pad_handler : : ds3 :
2024-06-11 22:30:16 +02:00
return std : : make_shared < ds3_pad_handler > ( ) ;
2021-08-15 19:41:06 +02:00
case pad_handler : : ds4 :
2024-06-11 22:30:16 +02:00
return std : : make_shared < ds4_pad_handler > ( ) ;
2021-08-15 19:41:06 +02:00
case pad_handler : : dualsense :
2024-06-11 22:30:16 +02:00
return std : : make_shared < dualsense_pad_handler > ( ) ;
2023-08-26 15:47:52 +02:00
case pad_handler : : skateboard :
2024-06-11 22:30:16 +02:00
return std : : make_shared < skateboard_pad_handler > ( ) ;
2024-07-08 20:17:21 +02:00
case pad_handler : : move :
return std : : make_shared < ps_move_handler > ( ) ;
2021-08-15 19:41:06 +02:00
# ifdef _WIN32
case pad_handler : : xinput :
2024-06-11 22:30:16 +02:00
return std : : make_shared < xinput_pad_handler > ( ) ;
2021-08-15 19:41:06 +02:00
case pad_handler : : mm :
2024-06-11 22:30:16 +02:00
return std : : make_shared < mm_joystick_handler > ( ) ;
2021-08-15 19:41:06 +02:00
# endif
2022-10-15 21:01:38 +02:00
# ifdef HAVE_SDL2
case pad_handler : : sdl :
2024-06-11 22:30:16 +02:00
return std : : make_shared < sdl_pad_handler > ( ) ;
2022-10-15 21:01:38 +02:00
# endif
2021-08-15 19:41:06 +02:00
# ifdef HAVE_LIBEVDEV
case pad_handler : : evdev :
2024-06-11 22:30:16 +02:00
return std : : make_shared < evdev_joystick_handler > ( ) ;
2021-08-15 19:41:06 +02:00
# endif
}
return nullptr ;
}
void pad_thread : : InitPadConfig ( cfg_pad & cfg , pad_handler type , std : : shared_ptr < PadHandlerBase > & handler )
{
if ( ! handler )
{
handler = GetHandler ( type ) ;
}
2022-10-15 12:10:40 +02:00
ensure ( ! ! handler ) ;
handler - > init_config ( & cfg ) ;
2021-08-15 19:41:06 +02:00
}
2023-01-14 00:07:07 +01:00
extern bool send_open_home_menu_cmds ( ) ;
extern void send_close_home_menu_cmds ( ) ;
2023-01-21 19:01:20 +01:00
extern bool close_osk_from_ps_button ( ) ;
2023-01-14 00:07:07 +01:00
void pad_thread : : open_home_menu ( )
{
2023-01-21 19:01:20 +01:00
// Check if the OSK is open and can be closed
if ( ! close_osk_from_ps_button ( ) )
{
rsx : : overlays : : queue_message ( get_localized_string ( localized_string_id : : CELL_OSK_DIALOG_BUSY ) ) ;
return ;
}
2023-01-14 00:07:07 +01:00
if ( auto manager = g_fxo - > try_get < rsx : : overlays : : display_manager > ( ) )
{
if ( m_home_menu_open . exchange ( true ) )
{
return ;
}
if ( ! send_open_home_menu_cmds ( ) )
{
m_home_menu_open = false ;
return ;
}
2023-02-07 00:03:21 +01:00
input_log . notice ( " opening home menu... " ) ;
2023-01-14 00:07:07 +01:00
const error_code result = manager - > create < rsx : : overlays : : home_menu_dialog > ( ) - > show ( [ this ] ( s32 status )
{
input_log . notice ( " closing home menu with status %d " , status ) ;
m_home_menu_open = false ;
send_close_home_menu_cmds ( ) ;
} ) ;
2023-02-07 00:03:21 +01:00
( result ? input_log . error : input_log . notice ) ( " opened home menu with result %d " , s32 { result } ) ;
2023-01-14 00:07:07 +01:00
}
}