2019-02-02 15:15:09 +01:00
# include " pad_thread.h "
# include "ds3_pad_handler.h"
2018-09-18 12:07:33 +02:00
# include "ds4_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"
2017-08-15 14:03:07 +02: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 ;
2018-12-17 19:13:35 +01:00
std : : recursive_mutex g_pad_mutex ;
2018-11-20 16:35:06 +01:00
std : : string g_title_id ;
2017-08-15 14:03:07 +02:00
}
2018-12-17 19:13:35 +01:00
struct pad_setting
{
u32 port_status ;
u32 device_capability ;
u32 device_type ;
} ;
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 ;
active = false ;
thread - > join ( ) ;
handlers . clear ( ) ;
}
void pad_thread : : Init ( )
{
std : : lock_guard lock ( pad : : g_pad_mutex ) ;
// Cache old settings if possible
std : : vector < pad_setting > pad_settings ;
for ( u32 i = 0 ; i < CELL_PAD_MAX_PORT_NUM ; i + + ) // max 7 pads
{
2019-03-11 08:30:00 +01:00
if ( ! m_pads [ i ] )
2018-12-17 19:13:35 +01:00
{
pad_settings . push_back ( { CELL_PAD_STATUS_DISCONNECTED , CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR , CELL_PAD_DEV_TYPE_STANDARD } ) ;
}
else
{
pad_settings . push_back ( { m_pads [ i ] - > m_port_status , m_pads [ i ] - > m_device_capability , m_pads [ i ] - > m_device_type } ) ;
}
}
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 ( ) ;
2018-11-20 16:35:06 +01:00
g_cfg_input . load ( 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 ;
2017-12-23 22:25:51 +01:00
const auto & handler_type = g_cfg_input . player [ i ] - > handler ;
2018-12-17 19:13:35 +01:00
2017-11-27 22:31:15 +01:00
if ( handlers . count ( handler_type ) ! = 0 )
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 ;
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
2018-01-17 02:23:50 +01:00
default :
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
2019-03-11 08:30:00 +01:00
if ( cur_pad_handler - > bindPadToDevice ( m_pads [ i ] , g_cfg_input . player [ i ] - > device . to_string ( ) ) = = false )
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
2017-12-23 22:25:51 +01:00
LOG_ERROR ( GENERAL , " Failed to bind device %s to handler %s " , g_cfg_input . player [ i ] - > device . to_string ( ) , handler_type . to_string ( ) ) ;
2019-03-11 08:30:00 +01:00
nullpad - > bindPadToDevice ( m_pads [ 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 )
{
2017-08-15 14:03:07 +02:00
if ( pad > m_pads . size ( ) )
return ;
if ( m_pads [ pad ] - > m_vibrateMotors . size ( ) > = 2 )
{
m_pads [ pad ] - > m_vibrateMotors [ 0 ] . m_value = largeMotor ;
m_pads [ pad ] - > m_vibrateMotors [ 1 ] . m_value = smallMotor ? 255 : 0 ;
}
}
2019-09-18 01:44:06 +02:00
void pad_thread : : Reset ( std : : string_view title_id )
2018-12-17 19:13:35 +01:00
{
2018-11-20 16:35:06 +01:00
pad : : g_title_id = title_id ;
2018-12-17 19:13:35 +01:00
reset = active . load ( ) ;
}
2018-12-23 01:35:10 +01:00
void pad_thread : : SetEnabled ( bool enabled )
{
is_enabled = enabled ;
}
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 ( )
{
active = true ;
while ( active )
{
2018-12-23 01:35:10 +01:00
if ( ! is_enabled )
{
std : : this_thread : : sleep_for ( 1 ms ) ;
continue ;
}
2019-07-16 22:51:39 +02:00
2018-12-17 19:13:35 +01:00
if ( reset & & reset . exchange ( false ) )
{
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
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
2019-09-20 16:28:55 +02:00
m_info . now_connect = connected_devices + num_ldd_pad ;
2019-07-16 22:51:39 +02:00
// The following section is only reached when a dialog was closed and the pads are still intercepted.
2019-09-20 10:12:01 +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).
if ( ! ( m_info . system_info & CELL_PAD_INFO_INTERCEPTED ) & & m_info . ignore_input )
2019-07-16 22:51:39 +02:00
{
bool any_button_pressed = false ;
for ( const auto & pad : m_pads )
{
if ( pad - > m_port_status & CELL_PAD_STATUS_CONNECTED )
{
for ( const auto & button : pad - > m_buttons )
{
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 ) )
{
any_button_pressed = true ;
break ;
}
}
if ( any_button_pressed )
{
break ;
}
}
}
if ( ! any_button_pressed )
{
2019-09-20 10:12:01 +02:00
m_info . ignore_input = false ;
2019-07-16 22:51:39 +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
s32 pad_thread : : AddLddPad ( )
{
// Look for first null pad
for ( u32 i = 0 ; i < CELL_PAD_MAX_PORT_NUM ; i + + )
{
if ( g_cfg_input . player [ i ] - > handler = = pad_handler : : null )
{
m_pads [ i ] - > ldd = true ;
num_ldd_pad + + ;
return i ;
}
}
return - 1 ;
}
void pad_thread : : UnregisterLddPad ( u32 handle )
{
m_pads [ handle ] - > ldd = false ;
num_ldd_pad - - ;
}