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"
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
2018-09-18 12:07:33 +02:00
# include "keyboard_pad_handler.h"
# include "Emu/Io/Null/NullPadHandler.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"
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
2020-02-01 08:43:43 +01:00
LOG_CHANNEL ( input_log , " Input " ) ;
2020-02-01 05:15:50 +01:00
2022-07-05 21:47:05 +02:00
extern bool is_input_allowed ( ) ;
2018-12-13 06:24:17 +01:00
namespace pad
2017-08-15 14:03:07 +02:00
{
2018-12-13 06:24:17 +01:00
atomic_t < pad_thread * > g_current = 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 ;
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 } ;
2017-08-15 14:03:07 +02:00
}
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 ;
s32 ldd_handle = - 1 ;
2018-12-17 19:13:35 +01:00
} ;
2019-09-18 01:44:06 +02:00
pad_thread : : pad_thread ( void * _curthread , void * _curwindow , std : : string_view title_id ) : curthread ( _curthread ) , curwindow ( _curwindow )
2017-08-15 14:03:07 +02:00
{
2018-11-20 16:35:06 +01:00
pad : : g_title_id = title_id ;
2018-12-17 19:13:35 +01:00
pad : : g_current = this ;
2022-07-04 15:02:17 +02:00
pad : : g_reset = true ;
2018-12-17 19:13:35 +01:00
}
pad_thread : : ~ pad_thread ( )
{
pad : : g_current = nullptr ;
}
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 ,
m_pads [ i ] - > ldd ? static_cast < s32 > ( i ) : - 1
} ;
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 ,
- 1
} ;
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
2018-12-17 19:13:35 +01:00
handlers . clear ( ) ;
2021-08-10 21:45:26 +02:00
g_cfg_profile . load ( ) ;
2021-08-15 19:41:06 +02:00
2021-09-05 03:12:23 +02:00
std : : string active_profile = g_cfg_profile . active_profiles . get_value ( pad : : g_title_id ) ;
if ( active_profile . empty ( ) )
{
active_profile = g_cfg_profile . active_profiles . get_value ( g_cfg_profile . global_key ) ;
}
2021-08-15 19:41:06 +02:00
// Load in order to get the pad handlers
2021-09-05 03:12:23 +02:00
if ( ! g_cfg_input . load ( pad : : g_title_id , active_profile ) )
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
2021-09-05 03:12:23 +02:00
if ( ! g_cfg_input . load ( pad : : g_title_id , active_profile ) )
2021-08-15 19:41:06 +02:00
{
input_log . notice ( " Reloaded empty pad config " ) ;
}
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
2017-08-15 14:03:07 +02:00
std : : shared_ptr < NullPadHandler > nullpad = std : : make_shared < NullPadHandler > ( ) ;
handlers . emplace ( pad_handler : : null , nullpad ) ;
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
{
std : : shared_ptr < PadHandlerBase > cur_pad_handler ;
2020-05-08 21:41:05 +02:00
const bool is_ldd_pad = pad_settings [ i ] . ldd_handle = = static_cast < s32 > ( i ) ;
const auto handler_type = is_ldd_pad ? pad_handler : : null : g_cfg_input . player [ i ] - > handler . get ( ) ;
2018-12-17 19:13:35 +01:00
2020-11-01 01:11:16 +01:00
if ( handlers . contains ( handler_type ) )
2017-08-15 14:03:07 +02:00
{
2017-11-27 22:31:15 +01:00
cur_pad_handler = handlers [ handler_type ] ;
2017-08-15 14:03:07 +02:00
}
else
{
2017-11-27 22:31:15 +01:00
switch ( handler_type )
2017-08-15 14:03:07 +02:00
{
case pad_handler : : keyboard :
keyptr = std : : make_shared < keyboard_pad_handler > ( ) ;
2019-12-04 21:56:19 +01:00
keyptr - > moveToThread ( static_cast < QThread * > ( curthread ) ) ;
keyptr - > SetTargetWindow ( static_cast < QWindow * > ( curwindow ) ) ;
2017-08-15 14:03:07 +02:00
cur_pad_handler = keyptr ;
break ;
2019-02-02 15:15:09 +01:00
case pad_handler : : ds3 :
cur_pad_handler = std : : make_shared < ds3_pad_handler > ( ) ;
break ;
2017-08-15 14:03:07 +02:00
case pad_handler : : ds4 :
cur_pad_handler = std : : make_shared < ds4_pad_handler > ( ) ;
break ;
2020-12-13 00:00:45 +01:00
case pad_handler : : dualsense :
cur_pad_handler = std : : make_shared < dualsense_pad_handler > ( ) ;
break ;
2018-08-29 13:27:10 +02:00
# ifdef _WIN32
2017-08-15 14:03:07 +02:00
case pad_handler : : xinput :
cur_pad_handler = std : : make_shared < xinput_pad_handler > ( ) ;
break ;
case pad_handler : : mm :
cur_pad_handler = std : : make_shared < mm_joystick_handler > ( ) ;
break ;
# endif
# ifdef HAVE_LIBEVDEV
case pad_handler : : evdev :
cur_pad_handler = std : : make_shared < evdev_joystick_handler > ( ) ;
break ;
# endif
2021-04-07 23:05:18 +02:00
case pad_handler : : null :
2018-01-17 02:23:50 +01:00
break ;
2017-08-15 14:03:07 +02:00
}
2017-11-27 22:31:15 +01:00
handlers . emplace ( handler_type , cur_pad_handler ) ;
2017-08-15 14:03:07 +02:00
}
cur_pad_handler - > Init ( ) ;
2022-04-25 18:44:28 +02:00
m_pads [ i ] = std : : make_shared < Pad > ( handler_type , CELL_PAD_STATUS_DISCONNECTED , pad_settings [ i ] . device_capability , pad_settings [ i ] . device_type ) ;
2017-08-15 14:03:07 +02:00
2020-05-08 21:41:05 +02:00
if ( is_ldd_pad )
{
InitLddPad ( pad_settings [ i ] . ldd_handle ) ;
}
2021-08-09 23:41:49 +02:00
else if ( ! cur_pad_handler - > bindPadToDevice ( m_pads [ i ] , g_cfg_input . player [ i ] - > device . to_string ( ) , i ) )
2017-08-15 14:03:07 +02:00
{
2018-12-17 19:13:35 +01:00
// Failed to bind the device to cur_pad_handler so binds to NullPadHandler
2020-05-08 21:41:05 +02:00
input_log . error ( " Failed to bind device %s to handler %s " , g_cfg_input . player [ i ] - > device . to_string ( ) , handler_type ) ;
2021-08-09 23:41:49 +02:00
nullpad - > bindPadToDevice ( m_pads [ i ] , g_cfg_input . player [ i ] - > device . to_string ( ) , i ) ;
2017-08-15 14:03:07 +02:00
}
2021-08-08 18:50:37 +02:00
2021-08-10 21:45:26 +02:00
input_log . notice ( " Pad %d: %s " , i , g_cfg_input . player [ i ] - > device . to_string ( ) ) ;
2017-08-15 14:03:07 +02:00
}
}
2017-09-12 23:42:00 +02:00
void pad_thread : : SetRumble ( const u32 pad , u8 largeMotor , bool smallMotor )
{
2021-11-15 18:26:31 +01:00
if ( pad > = m_pads . size ( ) )
2017-08-15 14:03:07 +02:00
return ;
2021-08-26 04:55:24 +02:00
if ( m_pads [ pad ] - > m_vibrateMotors . size ( ) > = 2 )
2017-08-15 14:03:07 +02:00
{
2021-08-26 04:55:24 +02:00
m_pads [ pad ] - > m_vibrateMotors [ 0 ] . m_value = largeMotor ;
m_pads [ pad ] - > m_vibrateMotors [ 1 ] . m_value = smallMotor ? 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
}
}
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 ( ) ;
pad : : g_reset = false ;
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 ] ( )
{
for ( auto & thread : threads )
{
if ( thread )
{
auto & enumeration_thread = * thread ;
enumeration_thread = thread_state : : aborting ;
enumeration_thread ( ) ;
}
}
threads . clear ( ) ;
} ;
const auto start_threads = [ this , & threads , & pad_mode ] ( )
{
if ( pad_mode = = pad_handler_mode : : single_threaded )
{
return ;
}
for ( const auto & handler : handlers )
{
if ( handler . first = = pad_handler : : null )
{
continue ;
}
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-07-05 21:47:05 +02:00
if ( ! pad : : g_enabled | | Emu . IsPaused ( ) | | ! is_input_allowed ( ) )
2022-01-28 00:09:11 +01:00
{
thread_ctrl : : wait_for ( 10'000 ) ;
continue ;
}
handler - > ThreadProc ( ) ;
thread_ctrl : : wait_for ( g_cfg . io . pad_sleep ) ;
}
} ) ) ;
}
} ;
2021-09-07 21:56:49 +02:00
while ( thread_ctrl : : state ( ) ! = thread_state : : aborting )
2017-08-15 14:03:07 +02:00
{
2022-07-05 21:47:05 +02:00
if ( ! pad : : g_enabled | | Emu . IsPaused ( ) | | ! is_input_allowed ( ) )
2018-12-23 01:35:10 +01:00
{
2021-09-07 21:56:49 +02:00
thread_ctrl : : wait_for ( 10000 ) ;
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 ) ;
const bool mode_changed = pad_mode ! = pad_mode . exchange ( g_cfg . io . pad_mode . get ( ) ) ;
// Reset pad handlers if necessary
if ( needs_reset | | mode_changed )
2018-12-17 19:13:35 +01:00
{
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
{
2022-01-28 00:09:11 +01:00
for ( auto & handler : handlers )
{
handler . second - > ThreadProc ( ) ;
connected_devices + = handler . second - > connected_devices ;
}
}
else
{
for ( auto & handler : handlers )
{
connected_devices + = handler . second - > connected_devices ;
}
2021-08-29 08:40:39 +02:00
}
2021-08-08 18:50:37 +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 ;
2021-08-29 08:40:39 +02:00
for ( 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
}
2022-01-28 00:09:11 +01:00
thread_ctrl : : wait_for ( g_cfg . io . 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
2020-05-08 21:41:05 +02:00
void pad_thread : : InitLddPad ( u32 handle )
{
if ( handle > = m_pads . size ( ) )
{
return ;
}
2021-08-10 21:45:26 +02:00
input_log . notice ( " Pad %d: LDD " , handle ) ;
2020-05-08 21:41:05 +02:00
static const auto product = input : : get_product_info ( input : : product_type : : playstation_3_controller ) ;
m_pads [ handle ] - > ldd = true ;
m_pads [ handle ] - > Init
(
CELL_PAD_STATUS_CONNECTED | CELL_PAD_STATUS_ASSIGN_CHANGES | CELL_PAD_STATUS_CUSTOM_CONTROLLER ,
CELL_PAD_CAPABILITY_PS3_CONFORMITY ,
CELL_PAD_DEV_TYPE_LDD ,
0 , // CELL_PAD_PCLASS_TYPE_STANDARD
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
) ;
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
{
2020-05-08 21:41:05 +02:00
InitLddPad ( i ) ;
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 ;
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 :
return std : : make_unique < NullPadHandler > ( ) ;
case pad_handler : : keyboard :
return std : : make_unique < keyboard_pad_handler > ( ) ;
case pad_handler : : ds3 :
return std : : make_unique < ds3_pad_handler > ( ) ;
case pad_handler : : ds4 :
return std : : make_unique < ds4_pad_handler > ( ) ;
case pad_handler : : dualsense :
return std : : make_unique < dualsense_pad_handler > ( ) ;
# ifdef _WIN32
case pad_handler : : xinput :
return std : : make_unique < xinput_pad_handler > ( ) ;
case pad_handler : : mm :
return std : : make_unique < mm_joystick_handler > ( ) ;
# endif
# ifdef HAVE_LIBEVDEV
case pad_handler : : evdev :
return std : : make_unique < evdev_joystick_handler > ( ) ;
# endif
}
return nullptr ;
}
void pad_thread : : InitPadConfig ( cfg_pad & cfg , pad_handler type , std : : shared_ptr < PadHandlerBase > & handler )
{
if ( ! handler )
{
handler = GetHandler ( type ) ;
}
switch ( handler - > m_type )
{
case pad_handler : : null :
static_cast < NullPadHandler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
case pad_handler : : keyboard :
static_cast < keyboard_pad_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
case pad_handler : : ds3 :
static_cast < ds3_pad_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
case pad_handler : : ds4 :
static_cast < ds4_pad_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
case pad_handler : : dualsense :
static_cast < dualsense_pad_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
# ifdef _WIN32
case pad_handler : : xinput :
static_cast < xinput_pad_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
case pad_handler : : mm :
static_cast < mm_joystick_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
# endif
# ifdef HAVE_LIBEVDEV
case pad_handler : : evdev :
static_cast < evdev_joystick_handler * > ( handler . get ( ) ) - > init_config ( & cfg ) ;
break ;
# endif
}
}