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"
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
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 } ;
atomic_t < bool > g_active { false } ;
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
Init ( ) ;
thread = std : : make_shared < std : : thread > ( & pad_thread : : ThreadFunc , this ) ;
pad : : g_current = this ;
}
pad_thread : : ~ pad_thread ( )
{
pad : : g_current = nullptr ;
2020-06-24 17:01:48 +02:00
pad : : g_active = false ;
2018-12-17 19:13:35 +01:00
thread - > join ( ) ;
handlers . clear ( ) ;
}
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 ( ) ;
g_cfg_input . load ( pad : : g_title_id , g_cfg_profile . active_profiles . get_value ( pad : : g_title_id ) ) ;
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 ( ) ;
2019-03-11 08:30:00 +01:00
m_pads [ i ] = std : : make_shared < Pad > ( 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
m_pads_interface [ i ] = std : : make_shared < Pad > ( CELL_PAD_STATUS_DISCONNECTED , pad_settings [ i ] . device_capability , pad_settings [ i ] . device_type ) ;
* m_pads_interface [ i ] = * m_pads [ i ] ;
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-08-08 18:50:37 +02:00
if ( pad > m_pads_interface . size ( ) )
2017-08-15 14:03:07 +02:00
return ;
2021-08-08 18:50:37 +02:00
if ( m_pads_interface [ pad ] - > m_vibrateMotors . size ( ) > = 2 )
2017-08-15 14:03:07 +02:00
{
2021-08-08 18:50:37 +02:00
m_pads_interface [ pad ] - > m_vibrateMotors [ 0 ] . m_value = largeMotor ;
m_pads_interface [ 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
}
}
2017-08-15 14:03:07 +02:00
void pad_thread : : ThreadFunc ( )
{
2020-06-24 17:01:48 +02:00
pad : : g_active = true ;
while ( pad : : g_active )
2017-08-15 14:03:07 +02:00
{
2020-06-24 17:01:48 +02:00
if ( ! pad : : g_enabled )
2018-12-23 01:35:10 +01:00
{
std : : this_thread : : sleep_for ( 1 ms ) ;
continue ;
}
2019-07-16 22:51:39 +02:00
2020-06-24 17:01:48 +02:00
if ( pad : : g_reset & & pad : : g_reset . exchange ( false ) )
2018-12-17 19:13:35 +01:00
{
Init ( ) ;
}
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
2021-08-08 18:50:37 +02:00
// Copy public pad data - which might have been changed - to internal pads
{
std : : lock_guard lock ( pad : : g_pad_mutex ) ;
for ( usz i = 0 ; i < m_pads . size ( ) ; i + + )
{
* m_pads [ i ] = * m_pads_interface [ i ] ;
}
}
2017-08-15 14:03:07 +02:00
for ( auto & cur_pad_handler : handlers )
{
cur_pad_handler . second - > ThreadProc ( ) ;
2019-09-20 16:28:55 +02:00
connected_devices + = cur_pad_handler . second - > connected_devices ;
2017-08-15 14:03:07 +02:00
}
2019-07-16 22:51:39 +02:00
2021-08-08 18:50:37 +02:00
// Copy new internal pad data back to public pads
2019-07-16 22:51:39 +02:00
{
2021-08-08 18:50:37 +02:00
std : : lock_guard lock ( pad : : g_pad_mutex ) ;
m_info . now_connect = connected_devices + num_ldd_pad ;
// The input_ignored section is only reached when a dialog was closed and the pads are still intercepted.
// 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).
const bool input_ignored = m_info . ignore_input & & ! ( m_info . system_info & CELL_PAD_INFO_INTERCEPTED ) ;
2019-07-16 22:51:39 +02:00
bool any_button_pressed = false ;
2021-08-08 18:50:37 +02:00
for ( usz i = 0 ; i < m_pads . size ( ) ; i + + )
2019-07-16 22:51:39 +02:00
{
2021-08-08 18:50:37 +02:00
const auto & pad = m_pads [ i ] ;
// I guess this is the best place to add pressure sensitivity without too much code duplication.
2019-07-16 22:51:39 +02:00
if ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED )
{
2021-08-08 18:50:37 +02:00
const bool adjust_pressure = pad - > m_pressure_intensity_button_index > = 0 & & pad - > m_buttons [ pad - > m_pressure_intensity_button_index ] . m_pressed ;
for ( auto & button : pad - > m_buttons )
2019-07-16 22:51:39 +02:00
{
2021-08-08 18:50:37 +02:00
if ( button . m_pressed )
2019-07-16 22:51:39 +02:00
{
2021-08-08 18:50:37 +02:00
if ( 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 )
{
any_button_pressed = true ;
}
if ( adjust_pressure )
{
button . m_value = pad - > m_pressure_intensity ;
}
2019-07-16 22:51:39 +02:00
}
}
}
2021-08-08 18:50:37 +02:00
* m_pads_interface [ i ] = * pad ;
2019-07-16 22:51:39 +02:00
}
2021-08-08 18:50:37 +02:00
if ( input_ignored & & ! any_button_pressed )
2021-08-06 02:08:18 +02:00
{
2021-08-08 18:50:37 +02:00
m_info . ignore_input = false ;
2021-08-06 02:08:18 +02:00
}
}
2017-08-15 14:03:07 +02:00
std : : this_thread : : sleep_for ( 1 ms ) ;
}
}
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
) ;
2021-08-08 18:50:37 +02:00
* m_pads_interface [ handle ] = * m_pads [ handle ] ;
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
m_pads_interface [ handle ] - > ldd = false ;
2019-04-28 23:35:11 +02:00
num_ldd_pad - - ;
}