2014-09-30 17:48:31 +02:00
/* RetroArch - A frontend for libretro.
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2017-01-22 13:40:32 +01:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2019-02-22 16:31:54 -05:00
* Copyright ( C ) 2016 - 2019 - Brad Parker
2019-06-16 13:32:27 -05:00
* Copyright ( C ) 2016 - 2019 - Andrés Suárez
2014-09-30 17:48:31 +02:00
*
* RetroArch is free software : you can redistribute it and / or modify it under the terms
* of the GNU General Public License as published by the Free Software Found -
* ation , either version 3 of the License , or ( at your option ) any later version .
*
* RetroArch is distributed in the hope that it will be useful , but WITHOUT ANY WARRANTY ;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE . See the GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along with RetroArch .
* If not , see < http : //www.gnu.org/licenses/>.
*/
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
2015-07-10 09:15:55 +02:00
2016-12-01 22:16:06 +01:00
# include <compat/strl.h>
2016-03-20 14:53:54 +01:00
# include <lists/dir_list.h>
2015-07-09 23:12:35 -05:00
# include <file/file_path.h>
2017-04-29 13:20:50 +02:00
# include <file/config_file.h>
2015-12-26 07:54:17 +01:00
# include <string/stdstring.h>
2014-09-30 17:48:31 +02:00
2017-11-28 22:32:41 -05:00
# ifdef HAVE_LIBUSB
2017-11-28 18:25:12 -05:00
# ifdef __FreeBSD__
# include <libusb.h>
# else
# include <libusb-1.0/libusb.h>
# endif
2017-11-28 22:32:41 -05:00
# endif
2017-11-28 18:25:12 -05:00
2017-12-01 14:07:40 -05:00
# if defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _WIN32_WINNT >= 0x0500
/* MinGW Win32 HID API */
2017-12-02 15:59:33 -05:00
# include <minwindef.h>
# include <wtypes.h>
2017-12-01 14:07:40 -05:00
# include <tchar.h>
2017-12-02 15:59:33 -05:00
# ifdef __NO_INLINE__
/* Workaround MinGW issue where compiling without -O2 (which sets __NO_INLINE__) causes the strsafe functions
* to never be defined ( only declared ) .
*/
# define __CRT_STRSAFE_IMPL
# endif
2017-12-01 14:07:40 -05:00
# include <strsafe.h>
2017-12-01 14:38:13 -05:00
# include <guiddef.h>
# include <ks.h>
2017-12-01 14:07:40 -05:00
# include <setupapi.h>
2018-02-04 20:57:30 +01:00
# include <winapifamily.h>
# ifdef __cplusplus
extern " C " {
# endif
2017-12-01 14:07:40 -05:00
# include <hidsdi.h>
2018-02-04 20:57:30 +01:00
# ifdef __cplusplus
}
# endif
2018-01-25 16:33:28 +01:00
2017-12-01 14:07:40 -05:00
/* Why doesn't including cguid.h work to get a GUID_NULL instead? */
2018-02-04 20:03:27 +01:00
# ifdef __cplusplus
EXTERN_C __attribute__ ( ( weak ) )
const GUID GUID_NULL = { 0 , 0 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } } ;
# else
2018-01-20 20:05:32 +01:00
__attribute__ ( ( weak ) )
2017-12-01 14:07:40 -05:00
const GUID GUID_NULL = { 0 , 0 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } } ;
# endif
2018-01-25 16:33:28 +01:00
# endif
2017-12-01 14:07:40 -05:00
2017-08-31 02:25:04 +02:00
# include "../input/input_driver.h"
2017-11-28 18:25:12 -05:00
# include "../input/include/blissbox.h"
2015-07-10 09:15:55 +02:00
2016-02-07 13:25:55 +01:00
# include "../configuration.h"
2016-06-11 21:51:28 +02:00
# include "../file_path_special.h"
2016-05-21 13:31:41 +02:00
# include "../list_special.h"
2015-11-23 12:03:38 +01:00
# include "../verbosity.h"
2017-12-07 17:47:16 -05:00
# include "../retroarch.h"
2014-09-30 17:48:31 +02:00
2016-12-01 20:38:20 +01:00
# include "tasks_internal.h"
2017-11-28 18:25:12 -05:00
/* HID Class-Specific Requests values. See section 7.2 of the HID specifications */
# define USB_HID_GET_REPORT 0x01
# define USB_CTRL_IN LIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE
2018-01-28 20:26:47 -05:00
# define USB_PACKET_CTRL_LEN 5
2017-11-28 18:25:12 -05:00
# define USB_TIMEOUT 5000 /* timeout in ms */
/* only one blissbox per machine is currently supported */
static const blissbox_pad_type_t * blissbox_pads [ BLISSBOX_MAX_PADS ] = { NULL } ;
2017-11-28 22:32:41 -05:00
# ifdef HAVE_LIBUSB
2017-11-28 18:25:12 -05:00
static struct libusb_device_handle * autoconfig_libusb_handle = NULL ;
2017-11-28 22:32:41 -05:00
# endif
2017-11-28 18:25:12 -05:00
2017-05-13 22:30:45 +02:00
typedef struct autoconfig_disconnect autoconfig_disconnect_t ;
typedef struct autoconfig_params autoconfig_params_t ;
struct autoconfig_disconnect
2016-12-01 22:36:38 +01:00
{
2016-12-16 12:20:31 +01:00
unsigned idx ;
2017-09-29 06:16:35 +02:00
char * msg ;
2017-05-13 22:30:45 +02:00
} ;
2016-12-01 22:36:38 +01:00
2017-05-13 22:30:45 +02:00
struct autoconfig_params
2016-12-31 07:43:34 +01:00
{
int32_t vid ;
int32_t pid ;
2017-05-13 22:30:45 +02:00
unsigned idx ;
2016-12-31 07:54:38 +01:00
uint32_t max_users ;
2017-09-29 06:16:35 +02:00
char * name ;
char * autoconfig_directory ;
2017-05-13 22:30:45 +02:00
} ;
2016-12-31 07:43:34 +01:00
2017-04-25 15:49:27 +02:00
static bool input_autoconfigured [ MAX_USERS ] ;
2017-12-05 22:03:56 +00:00
static unsigned input_device_name_index [ MAX_INPUT_DEVICES ] ;
2017-05-06 06:01:15 +02:00
static bool input_autoconfigure_swap_override ;
2019-02-03 15:49:35 -08:00
/* TODO/FIXME - Not thread safe to access this
2018-11-28 11:02:36 +01:00
* on main thread as well in its current state -
* menu_input . c - menu_event calls this function
* right now , while the underlying variable can
* be modified by a task thread . */
2017-05-06 06:01:15 +02:00
bool input_autoconfigure_get_swap_override ( void )
{
return input_autoconfigure_swap_override ;
}
2017-04-25 15:49:27 +02:00
2015-12-04 02:57:47 +01:00
/* Adds an index for devices with the same name,
* so they can be identified in the GUI . */
2019-04-30 13:43:01 +02:00
void input_autoconfigure_joypad_reindex_devices ( void )
2015-11-24 22:30:51 -05:00
{
2017-12-05 22:03:56 +00:00
unsigned i , j , k ;
2015-11-25 19:27:33 +01:00
2017-12-05 22:03:56 +00:00
for ( i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
2017-04-25 16:57:44 +02:00
input_device_name_index [ i ] = 0 ;
2015-11-25 19:27:33 +01:00
2017-12-05 22:03:56 +00:00
for ( i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
2015-11-24 22:30:51 -05:00
{
2017-04-25 15:53:30 +02:00
const char * tmp = input_config_get_device_name ( i ) ;
2017-12-05 22:03:56 +00:00
if ( ! tmp | | input_device_name_index [ i ] )
continue ;
2015-11-24 22:30:51 -05:00
2017-12-05 22:03:56 +00:00
k = 2 ; /*Additional devices start at two*/
for ( j = i + 1 ; j < MAX_INPUT_DEVICES ; j + + )
2015-11-24 22:30:51 -05:00
{
2017-12-05 22:03:56 +00:00
const char * other = input_config_get_device_name ( j ) ;
if ( ! other )
continue ;
/*another device with the same name found, for the first time*/
2019-04-22 01:23:50 +02:00
if ( string_is_equal ( tmp , other ) & &
2017-12-05 22:03:56 +00:00
input_device_name_index [ j ] = = 0 )
{
/*Mark the first device of the set*/
input_device_name_index [ i ] = 1 ;
/*count this additional device, from two up*/
2017-04-25 16:57:44 +02:00
input_device_name_index [ j ] = k + + ;
2017-12-05 22:03:56 +00:00
}
2015-11-24 22:30:51 -05:00
}
}
}
2016-12-01 18:52:34 +01:00
static int input_autoconfigure_joypad_try_from_conf ( config_file_t * conf ,
2015-07-09 22:46:28 -05:00
autoconfig_params_t * params )
2014-09-30 17:48:31 +02:00
{
2016-10-09 08:54:33 +02:00
char ident [ 256 ] ;
char input_driver [ 32 ] ;
2016-12-01 20:38:20 +01:00
int tmp_int = 0 ;
int input_vid = 0 ;
int input_pid = 0 ;
int score = 0 ;
2014-09-30 17:48:31 +02:00
2016-12-01 20:38:20 +01:00
ident [ 0 ] = input_driver [ 0 ] = ' \0 ' ;
2016-10-09 08:54:33 +02:00
2014-09-30 17:48:31 +02:00
config_get_array ( conf , " input_device " , ident , sizeof ( ident ) ) ;
config_get_array ( conf , " input_driver " , input_driver , sizeof ( input_driver ) ) ;
2016-05-24 23:53:35 +02:00
if ( config_get_int ( conf , " input_vendor_id " , & tmp_int ) )
input_vid = tmp_int ;
if ( config_get_int ( conf , " input_product_id " , & tmp_int ) )
input_pid = tmp_int ;
2014-09-30 17:48:31 +02:00
2017-11-28 21:25:54 -05:00
if ( params - > vid = = BLISSBOX_VID )
input_pid = BLISSBOX_PID ;
2015-07-09 22:46:28 -05:00
/* Check for VID/PID */
2015-03-27 17:27:21 +01:00
if ( ( params - > vid = = input_vid )
& & ( params - > pid = = input_pid )
2016-12-01 18:38:11 +01:00
& & ( params - > vid ! = 0 )
& & ( params - > pid ! = 0 )
2017-11-28 21:25:54 -05:00
& & ( params - > vid ! = BLISSBOX_VID )
& & ( params - > pid ! = BLISSBOX_PID ) )
2015-07-09 22:46:28 -05:00
score + = 3 ;
2015-07-02 21:48:06 -05:00
2015-04-30 16:28:07 -05:00
/* Check for name match */
2017-09-30 06:08:09 +02:00
if ( ! string_is_empty ( params - > name )
2017-09-30 01:18:33 -04:00
& & ! string_is_empty ( ident )
2017-09-29 06:16:35 +02:00
& & string_is_equal ( ident , params - > name ) )
2015-07-09 22:46:28 -05:00
score + = 2 ;
2017-12-31 04:24:42 +01:00
#if 0
else
{
2019-04-22 01:23:50 +02:00
if ( string_is_empty ( params - > name ) )
2019-04-30 13:43:01 +02:00
RARCH_LOG ( " [Autoconf]: failed match because params->name was empty \n " ) ;
2019-04-22 01:23:50 +02:00
else if ( string_is_empty ( ident ) )
2019-04-30 13:43:01 +02:00
RARCH_LOG ( " [Autoconf]: failed match because ident was empty \n " ) ;
2017-12-31 04:24:42 +01:00
else
2019-04-30 13:43:01 +02:00
RARCH_LOG ( " [Autoconf]: failed match because ident '%s' != param->name '%s' \n " ,
2017-12-31 04:24:42 +01:00
ident , params - > name ) ;
2017-12-28 15:06:39 -08:00
}
2017-12-31 04:24:42 +01:00
# endif
2016-09-12 18:39:46 +02:00
2015-07-09 22:46:28 -05:00
return score ;
2015-03-27 17:27:21 +01:00
}
2016-02-05 14:06:43 +01:00
static void input_autoconfigure_joypad_add ( config_file_t * conf ,
2016-12-01 22:16:06 +01:00
autoconfig_params_t * params , retro_task_t * task )
2015-03-27 17:27:21 +01:00
{
2017-04-26 18:48:28 +02:00
char msg [ 128 ] , display_name [ 128 ] , device_type [ 128 ] ;
/* This will be the case if input driver is reinitialized.
* No reason to spam autoconfigure messages every time . */
2017-12-05 22:03:56 +00:00
bool block_osd_spam =
2018-11-22 15:45:52 +01:00
# if defined(HAVE_LIBNX) && defined(HAVE_MENU_WIDGETS)
true ;
# else
2017-04-26 18:48:28 +02:00
input_autoconfigured [ params - > idx ]
2017-09-30 06:08:09 +02:00
& & ! string_is_empty ( params - > name ) ;
2018-11-22 15:45:52 +01:00
# endif
2015-03-27 17:34:09 +01:00
2016-10-09 08:54:33 +02:00
msg [ 0 ] = display_name [ 0 ] = device_type [ 0 ] = ' \0 ' ;
2016-02-05 14:06:43 +01:00
config_get_array ( conf , " input_device_display_name " ,
display_name , sizeof ( display_name ) ) ;
config_get_array ( conf , " input_device_type " , device_type ,
sizeof ( device_type ) ) ;
2015-07-12 13:45:17 -05:00
2017-04-25 15:49:27 +02:00
input_autoconfigured [ params - > idx ] = true ;
2017-04-25 15:31:32 +02:00
2015-03-27 17:27:21 +01:00
input_autoconfigure_joypad_conf ( conf ,
2017-04-25 16:33:30 +02:00
input_autoconf_binds [ params - > idx ] ) ;
2014-09-30 17:48:31 +02:00
2018-01-16 22:53:38 +01:00
if ( string_is_equal ( device_type , " remote " ) )
2015-07-31 23:09:25 -05:00
{
2017-04-26 18:48:28 +02:00
static bool remote_is_bound = false ;
2016-10-22 04:57:46 +02:00
snprintf ( msg , sizeof ( msg ) , " %s configured. " ,
2017-09-29 06:16:35 +02:00
( string_is_empty ( display_name ) & &
2019-05-28 09:26:09 -05:00
! string_is_empty ( params - > name ) ) ? params - > name : ( ! string_is_empty ( display_name ) ? display_name : " N/A " ) ) ;
2015-08-31 15:26:37 +02:00
2019-04-22 01:23:50 +02:00
if ( ! remote_is_bound )
2017-05-16 04:50:20 +02:00
{
task_free_title ( task ) ;
2016-12-29 00:50:18 -05:00
task_set_title ( task , strdup ( msg ) ) ;
2017-05-16 04:50:20 +02:00
}
2015-07-31 23:09:25 -05:00
remote_is_bound = true ;
2017-04-16 13:03:34 -05:00
if ( params - > idx = = 0 )
2017-05-06 06:01:15 +02:00
input_autoconfigure_swap_override = true ;
2015-07-31 23:09:25 -05:00
}
2015-07-12 13:45:17 -05:00
else
2015-07-31 23:09:25 -05:00
{
2017-04-20 21:52:29 +02:00
bool tmp = false ;
2016-10-22 04:57:46 +02:00
snprintf ( msg , sizeof ( msg ) , " %s %s #%u. " ,
2017-09-29 06:16:35 +02:00
( string_is_empty ( display_name ) & &
2019-05-28 09:26:09 -05:00
! string_is_empty ( params - > name ) )
2017-09-30 01:18:33 -04:00
? params - > name : ( ! string_is_empty ( display_name ) ? display_name : " N/A " ) ,
2016-10-22 04:57:46 +02:00
msg_hash_to_str ( MSG_DEVICE_CONFIGURED_IN_PORT ) ,
2016-01-20 04:07:24 +01:00
params - > idx ) ;
2019-02-03 15:49:35 -08:00
2017-04-16 16:59:05 -05:00
/* allow overriding the swap menu controls for player 1*/
2017-04-16 13:03:34 -05:00
if ( params - > idx = = 0 )
2017-04-25 15:31:32 +02:00
{
2017-04-20 21:52:29 +02:00
if ( config_get_bool ( conf , " input_swap_override " , & tmp ) )
2017-05-06 06:01:15 +02:00
input_autoconfigure_swap_override = tmp ;
2017-08-04 01:37:16 -05:00
else
input_autoconfigure_swap_override = false ;
2017-04-25 15:31:32 +02:00
}
2017-04-16 16:59:05 -05:00
2015-08-01 00:07:28 -05:00
if ( ! block_osd_spam )
2017-05-16 04:50:20 +02:00
{
task_free_title ( task ) ;
2016-12-29 00:50:18 -05:00
task_set_title ( task , strdup ( msg ) ) ;
2017-05-16 04:50:20 +02:00
}
2015-07-31 23:09:25 -05:00
}
2018-01-12 10:29:35 -05:00
if ( ! string_is_empty ( display_name ) )
input_config_set_device_display_name ( params - > idx , display_name ) ;
else
2018-01-16 22:18:28 -05:00
input_config_set_device_display_name ( params - > idx , params - > name ) ;
2018-01-12 10:29:35 -05:00
if ( ! string_is_empty ( conf - > path ) )
2019-03-07 19:17:54 -05:00
{
2018-01-12 10:29:35 -05:00
input_config_set_device_config_name ( params - > idx , path_basename ( conf - > path ) ) ;
2019-03-07 19:17:54 -05:00
input_config_set_device_config_path ( params - > idx , conf - > path ) ;
}
2018-01-12 10:29:35 -05:00
else
2019-03-07 19:17:54 -05:00
{
2018-01-12 10:29:35 -05:00
input_config_set_device_config_name ( params - > idx , " N/A " ) ;
2019-03-07 19:17:54 -05:00
input_config_set_device_config_path ( params - > idx , " N/A " ) ;
}
2016-12-16 12:33:56 +01:00
2017-12-05 22:03:56 +00:00
input_autoconfigure_joypad_reindex_devices ( ) ;
2014-09-30 17:48:31 +02:00
}
2015-05-08 17:25:55 +02:00
static int input_autoconfigure_joypad_from_conf (
2016-12-01 22:16:06 +01:00
config_file_t * conf , autoconfig_params_t * params , retro_task_t * task )
2015-05-08 17:25:55 +02:00
{
2016-12-01 18:52:34 +01:00
int ret = input_autoconfigure_joypad_try_from_conf ( conf ,
2015-07-09 22:46:28 -05:00
params ) ;
2015-05-08 17:25:55 +02:00
2017-12-31 04:24:42 +01:00
if ( ret )
2016-12-01 22:16:06 +01:00
input_autoconfigure_joypad_add ( conf , params , task ) ;
2015-05-08 17:25:55 +02:00
config_file_free ( conf ) ;
return ret ;
}
2015-03-27 18:05:43 +01:00
static bool input_autoconfigure_joypad_from_conf_dir (
2016-12-01 22:16:06 +01:00
autoconfig_params_t * params , retro_task_t * task )
2014-09-30 17:48:31 +02:00
{
size_t i ;
2016-10-09 08:54:33 +02:00
char path [ PATH_MAX_LENGTH ] ;
2015-09-29 17:35:28 +02:00
int ret = 0 ;
int index = - 1 ;
int current_best = 0 ;
2015-07-10 09:06:00 +02:00
struct string_list * list = NULL ;
2015-07-09 23:12:35 -05:00
2016-10-09 08:54:33 +02:00
path [ 0 ] = ' \0 ' ;
2016-06-11 21:51:28 +02:00
fill_pathname_application_special ( path , sizeof ( path ) ,
APPLICATION_SPECIAL_DIRECTORY_AUTOCONFIG ) ;
2015-09-29 17:35:28 +02:00
2016-05-21 13:31:41 +02:00
list = dir_list_new_special ( path , DIR_LIST_AUTOCONFIG , " cfg " ) ;
2014-09-30 17:48:31 +02:00
2015-07-09 23:51:39 -05:00
if ( ! list | | ! list - > size )
2016-05-23 21:28:43 +02:00
{
if ( list )
2017-09-30 19:03:39 -04:00
{
2016-05-23 21:28:43 +02:00
string_list_free ( list ) ;
2017-09-30 19:03:39 -04:00
list = NULL ;
}
2017-09-30 08:24:01 +02:00
if ( ! string_is_empty ( params - > autoconfig_directory ) )
2017-09-29 06:16:35 +02:00
list = dir_list_new_special ( params - > autoconfig_directory ,
DIR_LIST_AUTOCONFIG , " cfg " ) ;
2016-05-23 21:28:43 +02:00
}
2015-07-09 23:51:39 -05:00
2019-04-22 01:23:50 +02:00
if ( ! list )
2017-12-31 04:24:42 +01:00
{
2019-04-30 13:43:01 +02:00
RARCH_LOG ( " [Autoconf]: No profiles found. \n " ) ;
2015-03-27 18:05:43 +01:00
return false ;
2017-12-28 15:06:39 -08:00
}
2014-09-30 17:48:31 +02:00
2019-04-30 13:37:10 +02:00
RARCH_LOG ( " [Autoconf]: %d profiles found. \n " , ( int ) list - > size ) ;
2015-03-27 18:02:21 +01:00
2015-07-09 22:46:28 -05:00
for ( i = 0 ; i < list - > size ; i + + )
{
2019-05-23 13:05:15 +02:00
config_file_t * conf = config_file_new ( list - > elems [ i ] . data ) ;
2016-10-04 10:40:37 +02:00
if ( conf )
2016-12-01 18:52:34 +01:00
ret = input_autoconfigure_joypad_try_from_conf ( conf , params ) ;
2016-09-12 18:39:46 +02:00
2019-04-22 01:23:50 +02:00
if ( ret > = current_best )
2015-07-09 22:46:28 -05:00
{
2017-02-26 10:33:03 +01:00
index = ( int ) i ;
2015-07-10 09:06:00 +02:00
current_best = ret ;
2015-07-09 22:46:28 -05:00
}
config_file_free ( conf ) ;
2014-09-30 17:48:31 +02:00
}
2019-04-22 01:23:50 +02:00
if ( index > = 0 & & current_best > 0 )
2015-08-31 15:26:37 +02:00
{
2019-05-23 13:05:15 +02:00
config_file_t * conf = config_file_new ( list - > elems [ index ] . data ) ;
2015-11-15 22:28:57 +01:00
if ( conf )
{
char conf_path [ PATH_MAX_LENGTH ] ;
2016-10-09 08:54:33 +02:00
conf_path [ 0 ] = ' \0 ' ;
2015-11-15 22:28:57 +01:00
config_get_config_path ( conf , conf_path , sizeof ( conf_path ) ) ;
2019-04-30 13:43:01 +02:00
RARCH_LOG ( " [Autoconf]: selected configuration: %s \n " , conf_path ) ;
2016-12-01 22:16:06 +01:00
input_autoconfigure_joypad_add ( conf , params , task ) ;
2015-11-15 22:28:57 +01:00
config_file_free ( conf ) ;
ret = 1 ;
}
2015-07-09 22:52:52 -05:00
}
else
2015-07-10 09:06:00 +02:00
ret = 0 ;
2015-11-14 23:49:26 -05:00
2015-03-27 18:02:21 +01:00
string_list_free ( list ) ;
2015-03-27 18:05:43 +01:00
2015-07-10 09:06:00 +02:00
if ( ret = = 0 )
return false ;
return true ;
2015-03-27 18:02:21 +01:00
}
2014-09-30 17:48:31 +02:00
2015-03-27 18:02:21 +01:00
static bool input_autoconfigure_joypad_from_conf_internal (
2016-12-01 22:16:06 +01:00
autoconfig_params_t * params , retro_task_t * task )
2015-03-27 18:02:21 +01:00
{
size_t i ;
2015-03-27 17:55:00 +01:00
/* Load internal autoconfig files */
2014-09-30 17:48:31 +02:00
for ( i = 0 ; input_builtin_autoconfs [ i ] ; i + + )
{
2015-03-27 17:47:15 +01:00
config_file_t * conf = config_file_new_from_string (
input_builtin_autoconfs [ i ] ) ;
2016-12-01 22:16:06 +01:00
if ( conf & & input_autoconfigure_joypad_from_conf ( conf , params , task ) )
2017-12-28 15:06:39 -08:00
return true ;
2014-09-30 17:48:31 +02:00
}
2017-09-30 07:28:58 +02:00
if ( string_is_empty ( params - > autoconfig_directory ) )
2015-03-27 18:02:21 +01:00
return true ;
return false ;
}
2015-01-10 00:06:49 +01:00
2017-09-29 06:16:35 +02:00
static void input_autoconfigure_params_free ( autoconfig_params_t * params )
{
if ( ! params )
return ;
2017-09-30 06:08:09 +02:00
if ( ! string_is_empty ( params - > name ) )
2017-09-29 06:16:35 +02:00
free ( params - > name ) ;
2017-09-30 06:08:09 +02:00
if ( ! string_is_empty ( params - > autoconfig_directory ) )
2017-09-29 06:16:35 +02:00
free ( params - > autoconfig_directory ) ;
params - > name = NULL ;
params - > autoconfig_directory = NULL ;
}
2017-12-01 14:07:40 -05:00
# ifdef _WIN32
static const blissbox_pad_type_t * input_autoconfigure_get_blissbox_pad_type_win32 ( int vid , int pid )
{
/* TODO: Remove the check for !defined(_MSC_VER) after making sure this builds on MSVC */
/* HID API is available since Windows 2000 */
# if defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _WIN32_WINNT >= 0x0500
HDEVINFO hDeviceInfo ;
SP_DEVINFO_DATA DeviceInfoData ;
SP_DEVICE_INTERFACE_DATA deviceInterfaceData ;
2017-12-02 11:36:22 +01:00
HANDLE hDeviceHandle = INVALID_HANDLE_VALUE ;
BOOL bResult = TRUE ;
BOOL success = FALSE ;
GUID guidDeviceInterface = { 0 } ;
2017-12-05 22:03:56 +00:00
PSP_DEVICE_INTERFACE_DETAIL_DATA
2017-12-02 11:36:22 +01:00
pInterfaceDetailData = NULL ;
ULONG requiredLength = 0 ;
LPTSTR lpDevicePath = NULL ;
char * devicePath = NULL ;
DWORD index = 0 ;
DWORD intIndex = 0 ;
size_t nLength = 0 ;
unsigned len = 0 ;
unsigned i = 0 ;
char vidPidString [ 32 ] = { 0 } ;
char vidString [ 5 ] = { 0 } ;
char pidString [ 5 ] = { 0 } ;
2017-12-01 14:07:40 -05:00
char report [ USB_PACKET_CTRL_LEN + 1 ] = { 0 } ;
snprintf ( vidString , sizeof ( vidString ) , " %04x " , vid ) ;
snprintf ( pidString , sizeof ( pidString ) , " %04x " , pid ) ;
strlcat ( vidPidString , " vid_ " , sizeof ( vidPidString ) ) ;
strlcat ( vidPidString , vidString , sizeof ( vidPidString ) ) ;
strlcat ( vidPidString , " &pid_ " , sizeof ( vidPidString ) ) ;
strlcat ( vidPidString , pidString , sizeof ( vidPidString ) ) ;
HidD_GetHidGuid ( & guidDeviceInterface ) ;
if ( ! memcmp ( & guidDeviceInterface , & GUID_NULL , sizeof ( GUID_NULL ) ) )
{
RARCH_ERR ( " [Autoconf]: null guid \n " ) ;
return NULL ;
}
/* Get information about all the installed devices for the specified
* device interface class .
*/
hDeviceInfo = SetupDiGetClassDevs (
& guidDeviceInterface ,
NULL ,
NULL ,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE ) ;
if ( hDeviceInfo = = INVALID_HANDLE_VALUE )
{
2019-04-30 13:43:01 +02:00
RARCH_ERR ( " [Autoconf]: Error in SetupDiGetClassDevs: %d. \n " ,
GetLastError ( ) ) ;
2017-12-01 14:07:40 -05:00
goto done ;
}
/* Enumerate all the device interfaces in the device information set. */
DeviceInfoData . cbSize = sizeof ( SP_DEVINFO_DATA ) ;
while ( ! success )
{
success = SetupDiEnumDeviceInfo ( hDeviceInfo , index , & DeviceInfoData ) ;
/* Reset for this iteration */
if ( lpDevicePath )
{
LocalFree ( lpDevicePath ) ;
lpDevicePath = NULL ;
}
if ( pInterfaceDetailData )
{
LocalFree ( pInterfaceDetailData ) ;
pInterfaceDetailData = NULL ;
}
/* Check if this is the last item */
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
break ;
deviceInterfaceData . cbSize = sizeof ( SP_INTERFACE_DEVICE_DATA ) ;
/* Get information about the device interface. */
for ( intIndex = 0 ; ( bResult = SetupDiEnumDeviceInterfaces (
hDeviceInfo ,
& DeviceInfoData ,
& guidDeviceInterface ,
intIndex ,
& deviceInterfaceData ) ) ; intIndex + + )
{
/* Check if this is the last item */
if ( GetLastError ( ) = = ERROR_NO_MORE_ITEMS )
break ;
/* Check for some other error */
if ( ! bResult )
{
RARCH_ERR ( " [Autoconf]: Error in SetupDiEnumDeviceInterfaces: %d. \n " , GetLastError ( ) ) ;
goto done ;
}
/* Interface data is returned in SP_DEVICE_INTERFACE_DETAIL_DATA
* which we need to allocate , so we have to call this function twice .
* First to get the size so that we know how much to allocate , and
* second to do the actual call with the allocated buffer .
*/
bResult = SetupDiGetDeviceInterfaceDetail (
hDeviceInfo ,
& deviceInterfaceData ,
NULL , 0 ,
& requiredLength ,
NULL ) ;
/* Check for some other error */
if ( ! bResult )
{
if ( ( ERROR_INSUFFICIENT_BUFFER = = GetLastError ( ) ) & & ( requiredLength > 0 ) )
{
/* we got the size, now allocate buffer */
pInterfaceDetailData = ( PSP_DEVICE_INTERFACE_DETAIL_DATA ) LocalAlloc ( LPTR , requiredLength ) ;
if ( ! pInterfaceDetailData )
{
RARCH_ERR ( " [Autoconf]: Error allocating memory for the device detail buffer. \n " ) ;
goto done ;
}
}
else
{
RARCH_ERR ( " [Autoconf]: Other error: %d. \n " , GetLastError ( ) ) ;
goto done ;
}
}
/* get the interface detailed data */
pInterfaceDetailData - > cbSize = sizeof ( SP_DEVICE_INTERFACE_DETAIL_DATA ) ;
/* Now call it with the correct size and allocated buffer */
bResult = SetupDiGetDeviceInterfaceDetail (
hDeviceInfo ,
& deviceInterfaceData ,
pInterfaceDetailData ,
requiredLength ,
NULL ,
& DeviceInfoData ) ;
/* Check for some other error */
if ( ! bResult )
{
RARCH_LOG ( " [Autoconf]: Error in SetupDiGetDeviceInterfaceDetail: %d. \n " , GetLastError ( ) ) ;
goto done ;
}
/* copy device path */
2017-12-02 11:36:22 +01:00
nLength = _tcslen ( pInterfaceDetailData - > DevicePath ) + 1 ;
2017-12-01 14:07:40 -05:00
lpDevicePath = ( TCHAR * ) LocalAlloc ( LPTR , nLength * sizeof ( TCHAR ) ) ;
StringCchCopy ( lpDevicePath , nLength , pInterfaceDetailData - > DevicePath ) ;
2017-12-02 11:36:22 +01:00
devicePath = ( char * ) malloc ( nLength ) ;
2017-12-01 14:07:40 -05:00
for ( len = 0 ; len < nLength ; len + + )
devicePath [ len ] = lpDevicePath [ len ] ;
lpDevicePath [ nLength - 1 ] = 0 ;
if ( strstr ( devicePath , vidPidString ) )
goto found ;
}
success = FALSE ;
index + + ;
}
if ( ! lpDevicePath )
{
RARCH_ERR ( " [Autoconf]: No devicepath. Error %d. " , GetLastError ( ) ) ;
goto done ;
}
found :
/* Open the device */
hDeviceHandle = CreateFileA (
devicePath ,
GENERIC_READ , /* | GENERIC_WRITE,*/
FILE_SHARE_READ , /* | FILE_SHARE_WRITE,*/
NULL ,
OPEN_EXISTING ,
0 , /*FILE_FLAG_OVERLAPPED,*/
NULL ) ;
if ( hDeviceHandle = = INVALID_HANDLE_VALUE )
{
2017-12-07 17:47:16 -05:00
/* Windows sometimes erroneously fails to open with a sharing violation:
* https : //github.com/signal11/hidapi/issues/231
* If this happens , trying again with read + write usually works for some reason .
*/
/* Open the device */
hDeviceHandle = CreateFileA (
devicePath ,
GENERIC_READ | GENERIC_WRITE ,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
NULL ,
OPEN_EXISTING ,
0 , /*FILE_FLAG_OVERLAPPED,*/
NULL ) ;
if ( hDeviceHandle = = INVALID_HANDLE_VALUE )
{
RARCH_ERR ( " [Autoconf]: Can't open device for reading and writing: %d. " , GetLastError ( ) ) ;
2018-11-22 15:45:52 +01:00
runloop_msg_queue_push ( " Bliss-Box already in use. Please make sure other programs are not using it. " , 2 , 300 , false , NULL , MESSAGE_QUEUE_ICON_DEFAULT , MESSAGE_QUEUE_CATEGORY_INFO ) ;
2017-12-07 17:47:16 -05:00
goto done ;
}
2017-12-01 14:07:40 -05:00
}
done :
free ( devicePath ) ;
LocalFree ( lpDevicePath ) ;
LocalFree ( pInterfaceDetailData ) ;
2017-12-02 11:36:22 +01:00
bResult = SetupDiDestroyDeviceInfoList ( hDeviceInfo ) ;
2017-12-01 14:07:40 -05:00
2017-12-02 11:36:22 +01:00
devicePath = NULL ;
lpDevicePath = NULL ;
2017-12-01 14:07:40 -05:00
pInterfaceDetailData = NULL ;
if ( ! bResult )
RARCH_ERR ( " [Autoconf]: Could not destroy device info list. \n " ) ;
if ( ! hDeviceHandle | | hDeviceHandle = = INVALID_HANDLE_VALUE )
{
/* device is not connected */
return NULL ;
}
report [ 0 ] = BLISSBOX_USB_FEATURE_REPORT_ID ;
HidD_GetFeature ( hDeviceHandle , report , sizeof ( report ) ) ;
CloseHandle ( hDeviceHandle ) ;
for ( i = 0 ; i < sizeof ( blissbox_pad_types ) / sizeof ( blissbox_pad_types [ 0 ] ) ; i + + )
{
const blissbox_pad_type_t * pad = & blissbox_pad_types [ i ] ;
if ( ! pad | | string_is_empty ( pad - > name ) )
continue ;
if ( pad - > index = = report [ 0 ] )
return pad ;
}
RARCH_LOG ( " [Autoconf]: Could not find connected pad in Bliss-Box port#%d. \n " , pid - BLISSBOX_PID ) ;
2017-12-02 11:36:22 +01:00
# endif
2017-12-01 14:07:40 -05:00
return NULL ;
}
# endif
# ifndef _WIN32
static const blissbox_pad_type_t * input_autoconfigure_get_blissbox_pad_type_libusb ( int vid , int pid )
2017-11-28 18:25:12 -05:00
{
# ifdef HAVE_LIBUSB
unsigned i ;
2017-12-02 11:36:22 +01:00
unsigned char answer [ USB_PACKET_CTRL_LEN ] = { 0 } ;
int ret = libusb_init ( NULL ) ;
2017-11-28 18:25:12 -05:00
if ( ret < 0 )
{
2017-11-28 21:25:54 -05:00
RARCH_ERR ( " [Autoconf]: Could not initialize libusb. \n " ) ;
2017-11-28 18:25:12 -05:00
return NULL ;
}
autoconfig_libusb_handle = libusb_open_device_with_vid_pid ( NULL , vid , pid ) ;
if ( ! autoconfig_libusb_handle )
{
2017-11-28 21:25:54 -05:00
RARCH_ERR ( " [Autoconf]: Could not find or open libusb device %d:%d. \n " , vid , pid ) ;
2017-11-28 18:25:12 -05:00
goto error ;
}
# ifdef __linux__
libusb_detach_kernel_driver ( autoconfig_libusb_handle , 0 ) ;
# endif
ret = libusb_set_configuration ( autoconfig_libusb_handle , 1 ) ;
if ( ret < 0 )
{
2017-11-28 21:25:54 -05:00
RARCH_ERR ( " [Autoconf]: Error during libusb_set_configuration. \n " ) ;
2017-11-28 18:25:12 -05:00
goto error ;
}
ret = libusb_claim_interface ( autoconfig_libusb_handle , 0 ) ;
if ( ret < 0 )
{
2017-11-28 21:25:54 -05:00
RARCH_ERR ( " [Autoconf]: Error during libusb_claim_interface. \n " ) ;
2017-11-28 18:25:12 -05:00
goto error ;
}
ret = libusb_control_transfer ( autoconfig_libusb_handle , USB_CTRL_IN , USB_HID_GET_REPORT , BLISSBOX_USB_FEATURE_REPORT_ID , 0 , answer , USB_PACKET_CTRL_LEN , USB_TIMEOUT ) ;
if ( ret < 0 )
2017-11-28 21:25:54 -05:00
RARCH_ERR ( " [Autoconf]: Error during libusb_control_transfer. \n " ) ;
2017-11-28 18:25:12 -05:00
libusb_release_interface ( autoconfig_libusb_handle , 0 ) ;
# ifdef __linux__
libusb_attach_kernel_driver ( autoconfig_libusb_handle , 0 ) ;
# endif
libusb_close ( autoconfig_libusb_handle ) ;
libusb_exit ( NULL ) ;
for ( i = 0 ; i < sizeof ( blissbox_pad_types ) / sizeof ( blissbox_pad_types [ 0 ] ) ; i + + )
{
const blissbox_pad_type_t * pad = & blissbox_pad_types [ i ] ;
if ( ! pad | | string_is_empty ( pad - > name ) )
continue ;
if ( pad - > index = = answer [ 0 ] )
return pad ;
}
2017-11-28 21:25:54 -05:00
RARCH_LOG ( " [Autoconf]: Could not find connected pad in Bliss-Box port#%d. \n " , pid - BLISSBOX_PID ) ;
2017-11-28 18:25:12 -05:00
return NULL ;
2017-11-28 22:32:41 -05:00
2017-11-28 18:25:12 -05:00
error :
libusb_close ( autoconfig_libusb_handle ) ;
libusb_exit ( NULL ) ;
2017-11-28 22:32:41 -05:00
# endif
2017-12-02 11:36:22 +01:00
return NULL ;
2017-11-28 18:25:12 -05:00
}
2017-12-01 14:07:40 -05:00
# endif
static const blissbox_pad_type_t * input_autoconfigure_get_blissbox_pad_type ( int vid , int pid )
{
# if defined(_WIN32)
# if defined(_MSC_VER) || defined(_XBOX)
/* no MSVC/XBOX support */
return NULL ;
# else
/* MinGW */
return input_autoconfigure_get_blissbox_pad_type_win32 ( vid , pid ) ;
# endif
# else
return input_autoconfigure_get_blissbox_pad_type_libusb ( vid , pid ) ;
# endif
}
2017-11-28 18:25:12 -05:00
static void input_autoconfigure_override_handler ( autoconfig_params_t * params )
{
if ( params - > vid = = BLISSBOX_VID )
{
2017-11-28 21:25:54 -05:00
if ( params - > pid = = BLISSBOX_UPDATE_MODE_PID )
RARCH_LOG ( " [Autoconf]: Bliss-Box in update mode detected. Ignoring. \n " ) ;
else if ( params - > pid = = BLISSBOX_OLD_PID )
RARCH_LOG ( " [Autoconf]: Bliss-Box 1.0 firmware detected. Please update to 2.0 or later. \n " ) ;
else if ( params - > pid > = BLISSBOX_PID & & params - > pid < = BLISSBOX_PID + BLISSBOX_MAX_PAD_INDEX )
2017-11-28 18:25:12 -05:00
{
const blissbox_pad_type_t * pad ;
char name [ 255 ] = { 0 } ;
2019-04-30 13:43:01 +02:00
int index = params - > pid - BLISSBOX_PID ;
2017-11-28 18:25:12 -05:00
2017-11-28 21:25:54 -05:00
RARCH_LOG ( " [Autoconf]: Bliss-Box detected. Getting pad type... \n " ) ;
2017-11-28 18:25:12 -05:00
if ( blissbox_pads [ index ] )
pad = blissbox_pads [ index ] ;
else
pad = input_autoconfigure_get_blissbox_pad_type ( params - > vid , params - > pid ) ;
if ( pad & & ! string_is_empty ( pad - > name ) )
{
RARCH_LOG ( " [Autoconf]: Found Bliss-Box pad type: %s (%d) in port#%d \n " , pad - > name , pad - > index , index ) ;
if ( params - > name )
free ( params - > name ) ;
/* override name given to autoconfig so it knows what kind of pad this is */
2017-12-01 22:40:17 -05:00
strlcat ( name , " Bliss-Box 4-Play " , sizeof ( name ) ) ;
2017-11-28 18:25:12 -05:00
strlcat ( name , pad - > name , sizeof ( name ) ) ;
params - > name = strdup ( name ) ;
blissbox_pads [ index ] = pad ;
}
2019-05-23 13:05:15 +02:00
/* use NULL entry to mark as an unconnected port */
2017-11-28 18:25:12 -05:00
else
2019-05-23 13:05:15 +02:00
blissbox_pads [ index ] = & blissbox_pad_types [ ARRAY_SIZE ( blissbox_pad_types ) - 1 ] ;
2017-11-28 18:25:12 -05:00
}
}
}
2016-12-01 22:16:06 +01:00
static void input_autoconfigure_connect_handler ( retro_task_t * task )
2015-03-27 18:05:43 +01:00
{
2016-12-03 06:09:55 +01:00
autoconfig_params_t * params = ( autoconfig_params_t * ) task - > state ;
2016-12-01 22:16:06 +01:00
2016-12-29 05:49:24 +01:00
if ( ! params | | string_is_empty ( params - > name ) )
2017-01-03 03:52:08 +01:00
goto end ;
2015-07-02 21:48:06 -05:00
2016-12-01 22:16:06 +01:00
if ( ! input_autoconfigure_joypad_from_conf_dir ( params , task )
& & ! input_autoconfigure_joypad_from_conf_internal ( params , task ) )
2016-12-01 20:41:41 +01:00
{
char msg [ 255 ] ;
2015-11-14 23:27:05 -05:00
2016-12-01 20:41:41 +01:00
msg [ 0 ] = ' \0 ' ;
2017-05-13 23:41:13 +02:00
# ifdef ANDROID
2017-09-30 06:38:53 +02:00
if ( ! string_is_empty ( params - > name ) )
free ( params - > name ) ;
2017-09-29 06:16:35 +02:00
params - > name = strdup ( " Android Gamepad " ) ;
2019-03-07 19:17:54 -05:00
if ( input_autoconfigure_joypad_from_conf_internal ( params , task ) )
2017-02-05 14:24:34 -05:00
{
2017-06-17 18:32:55 -05:00
RARCH_LOG ( " [Autoconf]: no profiles found for %s (%d/%d). Using fallback \n " ,
2017-09-30 06:29:07 +02:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
params - > vid , params - > pid ) ;
2016-12-29 00:50:18 -05:00
2017-02-05 14:24:34 -05:00
snprintf ( msg , sizeof ( msg ) , " %s (%ld/%ld) %s. " ,
2017-09-30 06:29:07 +02:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
( long ) params - > vid , ( long ) params - > pid ,
2017-02-05 14:24:34 -05:00
msg_hash_to_str ( MSG_DEVICE_NOT_CONFIGURED_FALLBACK ) ) ;
}
2017-05-13 23:41:13 +02:00
# else
2017-06-17 18:32:55 -05:00
RARCH_LOG ( " [Autoconf]: no profiles found for %s (%d/%d). \n " ,
2017-09-30 06:29:07 +02:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
params - > vid , params - > pid ) ;
2017-05-13 23:41:13 +02:00
snprintf ( msg , sizeof ( msg ) , " %s (%ld/%ld) %s. " ,
2017-09-30 06:29:07 +02:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
( long ) params - > vid , ( long ) params - > pid ,
2017-05-13 23:41:13 +02:00
msg_hash_to_str ( MSG_DEVICE_NOT_CONFIGURED ) ) ;
2017-02-05 14:24:34 -05:00
# endif
2017-05-16 04:50:20 +02:00
task_free_title ( task ) ;
2016-12-29 00:50:18 -05:00
task_set_title ( task , strdup ( msg ) ) ;
2016-12-01 20:41:41 +01:00
}
2017-01-03 03:52:08 +01:00
end :
2017-09-29 06:16:35 +02:00
if ( params )
{
input_autoconfigure_params_free ( params ) ;
free ( params ) ;
}
2016-12-29 00:50:18 -05:00
task_set_finished ( task , true ) ;
2016-12-01 22:36:38 +01:00
}
2016-12-01 22:16:06 +01:00
2016-12-01 22:36:38 +01:00
static void input_autoconfigure_disconnect_handler ( retro_task_t * task )
{
2016-12-03 06:09:55 +01:00
autoconfig_disconnect_t * params = ( autoconfig_disconnect_t * ) task - > state ;
2016-12-01 22:36:38 +01:00
2016-12-29 00:50:18 -05:00
task_set_title ( task , strdup ( params - > msg ) ) ;
task_set_finished ( task , true ) ;
2016-12-01 22:36:38 +01:00
RARCH_LOG ( " %s: %s \n " , msg_hash_to_str ( MSG_AUTODETECT ) , params - > msg ) ;
2016-12-04 05:50:50 +01:00
2017-09-30 06:08:09 +02:00
if ( ! string_is_empty ( params - > msg ) )
2017-09-29 06:16:35 +02:00
free ( params - > msg ) ;
2016-12-04 05:50:50 +01:00
free ( params ) ;
2014-09-30 17:48:31 +02:00
}
2016-12-01 22:36:38 +01:00
bool input_autoconfigure_disconnect ( unsigned i , const char * ident )
2015-06-03 18:55:04 +02:00
{
2016-10-27 09:32:07 +02:00
char msg [ 255 ] ;
2018-11-22 15:45:52 +01:00
retro_task_t * task = task_init ( ) ;
2017-09-30 17:11:51 +02:00
autoconfig_disconnect_t * state = ( autoconfig_disconnect_t * ) calloc ( 1 , sizeof ( * state ) ) ;
2015-07-10 09:06:00 +02:00
2016-12-21 01:45:19 +01:00
if ( ! state | | ! task )
goto error ;
2016-12-16 12:20:31 +01:00
msg [ 0 ] = ' \0 ' ;
state - > idx = i ;
2016-10-09 08:54:33 +02:00
2017-12-05 22:03:56 +00:00
snprintf ( msg , sizeof ( msg ) , " %s #%u (%s). " ,
2016-10-22 04:57:46 +02:00
msg_hash_to_str ( MSG_DEVICE_DISCONNECTED_FROM_PORT ) ,
i , ident ) ;
2016-12-01 22:36:38 +01:00
2017-09-29 06:16:35 +02:00
state - > msg = strdup ( msg ) ;
2016-12-01 22:36:38 +01:00
2017-04-25 15:53:30 +02:00
input_config_clear_device_name ( state - > idx ) ;
2018-01-11 17:06:02 -05:00
input_config_clear_device_display_name ( state - > idx ) ;
input_config_clear_device_config_name ( state - > idx ) ;
2019-03-07 19:17:54 -05:00
input_config_clear_device_config_path ( state - > idx ) ;
2016-12-29 05:49:24 +01:00
2016-12-01 22:36:38 +01:00
task - > state = state ;
task - > handler = input_autoconfigure_disconnect_handler ;
2017-05-14 20:43:39 +02:00
task_queue_push ( task ) ;
2016-12-01 22:36:38 +01:00
return true ;
error :
if ( state )
2017-09-29 06:16:35 +02:00
{
2017-09-30 06:08:09 +02:00
if ( ! string_is_empty ( state - > msg ) )
2017-09-29 06:16:35 +02:00
free ( state - > msg ) ;
2016-12-01 22:36:38 +01:00
free ( state ) ;
2017-09-29 06:16:35 +02:00
}
2016-12-01 22:36:38 +01:00
if ( task )
free ( task ) ;
return false ;
2015-06-03 18:55:04 +02:00
}
2016-12-01 22:16:06 +01:00
2017-04-25 15:49:27 +02:00
void input_autoconfigure_reset ( void )
{
2017-04-25 16:33:30 +02:00
unsigned i , j ;
2017-04-25 15:49:27 +02:00
for ( i = 0 ; i < MAX_USERS ; i + + )
2017-04-25 16:33:30 +02:00
{
for ( j = 0 ; j < RARCH_BIND_LIST_END ; j + + )
{
input_autoconf_binds [ i ] [ j ] . joykey = NO_BTN ;
input_autoconf_binds [ i ] [ j ] . joyaxis = AXIS_NONE ;
}
2017-04-25 16:57:44 +02:00
input_device_name_index [ i ] = 0 ;
input_autoconfigured [ i ] = 0 ;
2017-04-25 16:33:30 +02:00
}
2017-05-06 06:01:15 +02:00
input_autoconfigure_swap_override = false ;
2017-04-25 15:49:27 +02:00
}
bool input_is_autoconfigured ( unsigned i )
{
return input_autoconfigured [ i ] ;
}
2017-04-25 16:57:44 +02:00
unsigned input_autoconfigure_get_device_name_index ( unsigned i )
{
return input_device_name_index [ i ] ;
}
2016-12-31 07:43:34 +01:00
bool input_autoconfigure_connect (
const char * name ,
const char * display_name ,
const char * driver ,
unsigned idx ,
unsigned vid ,
unsigned pid )
2016-12-01 22:16:06 +01:00
{
2016-12-29 05:49:24 +01:00
unsigned i ;
2018-11-22 15:45:52 +01:00
retro_task_t * task = task_init ( ) ;
2017-09-30 17:08:42 +02:00
autoconfig_params_t * state = ( autoconfig_params_t * ) calloc ( 1 , sizeof ( * state ) ) ;
2016-12-16 15:18:04 +01:00
settings_t * settings = config_get_ptr ( ) ;
2017-09-30 16:52:41 +02:00
const char * dir_autoconf = settings ? settings - > paths . directory_autoconfig : NULL ;
bool autodetect_enable = settings ? settings - > bools . input_autodetect_enable : false ;
2016-12-01 22:16:06 +01:00
2017-09-30 16:52:41 +02:00
if ( ! task | | ! state | | ! autodetect_enable )
2016-12-01 22:16:06 +01:00
goto error ;
2016-12-31 07:43:34 +01:00
if ( ! string_is_empty ( name ) )
2017-09-29 17:06:38 +02:00
state - > name = strdup ( name ) ;
2016-12-31 07:43:34 +01:00
2017-04-25 16:57:44 +02:00
if ( ! string_is_empty ( dir_autoconf ) )
2017-09-29 06:16:35 +02:00
state - > autoconfig_directory = strdup ( dir_autoconf ) ;
2017-01-02 05:33:29 +01:00
2017-09-29 17:06:38 +02:00
state - > idx = idx ;
state - > vid = vid ;
state - > pid = pid ;
state - > max_users = * (
input_driver_get_uint ( INPUT_ACTION_MAX_USERS ) ) ;
2016-12-01 22:16:06 +01:00
2017-11-28 18:25:12 -05:00
input_autoconfigure_override_handler ( state ) ;
2017-09-30 06:38:53 +02:00
if ( ! string_is_empty ( state - > name ) )
input_config_set_device_name ( state - > idx , state - > name ) ;
2017-04-25 16:49:54 +02:00
input_config_set_pid ( state - > idx , state - > pid ) ;
input_config_set_vid ( state - > idx , state - > vid ) ;
2017-01-02 05:33:29 +01:00
2016-12-29 05:49:24 +01:00
for ( i = 0 ; i < RARCH_BIND_LIST_END ; i + + )
{
2017-04-25 16:33:30 +02:00
input_autoconf_binds [ state - > idx ] [ i ] . joykey = NO_BTN ;
input_autoconf_binds [ state - > idx ] [ i ] . joyaxis = AXIS_NONE ;
2017-12-05 22:03:56 +00:00
if (
2017-09-30 06:08:09 +02:00
! string_is_empty ( input_autoconf_binds [ state - > idx ] [ i ] . joykey_label ) )
2017-09-27 20:08:37 +02:00
free ( input_autoconf_binds [ state - > idx ] [ i ] . joykey_label ) ;
2017-12-05 22:03:56 +00:00
if (
2017-09-30 06:08:09 +02:00
! string_is_empty ( input_autoconf_binds [ state - > idx ] [ i ] . joyaxis_label ) )
2017-09-27 20:11:44 +02:00
free ( input_autoconf_binds [ state - > idx ] [ i ] . joyaxis_label ) ;
input_autoconf_binds [ state - > idx ] [ i ] . joykey_label = NULL ;
input_autoconf_binds [ state - > idx ] [ i ] . joyaxis_label = NULL ;
2016-12-29 05:49:24 +01:00
}
2017-04-25 15:31:32 +02:00
2017-04-25 15:49:27 +02:00
input_autoconfigured [ state - > idx ] = false ;
2016-12-01 22:17:36 +01:00
2017-09-30 16:52:41 +02:00
task - > state = state ;
task - > handler = input_autoconfigure_connect_handler ;
2016-12-01 22:16:06 +01:00
2017-05-14 20:43:39 +02:00
task_queue_push ( task ) ;
2016-12-01 22:16:06 +01:00
return true ;
error :
if ( state )
2017-09-29 06:16:35 +02:00
{
input_autoconfigure_params_free ( state ) ;
2016-12-01 22:16:06 +01:00
free ( state ) ;
2017-09-29 06:16:35 +02:00
}
2016-12-01 22:16:06 +01:00
if ( task )
free ( task ) ;
return false ;
}