2014-09-30 15:48:31 +00:00
/* RetroArch - A frontend for libretro.
* Copyright ( C ) 2010 - 2014 - Hans - Kristian Arntzen
2017-01-22 12:40:32 +00:00
* Copyright ( C ) 2011 - 2017 - Daniel De Matteis
2019-02-22 21:31:54 +00:00
* Copyright ( C ) 2016 - 2019 - Brad Parker
2014-09-30 15:48:31 +00: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 07:15:55 +00:00
2016-12-01 21:16:06 +00:00
# include <compat/strl.h>
2016-03-20 13:53:54 +00:00
# include <lists/dir_list.h>
2015-07-10 04:12:35 +00:00
# include <file/file_path.h>
2017-04-29 11:20:50 +00:00
# include <file/config_file.h>
2015-12-26 06:54:17 +00:00
# include <string/stdstring.h>
2014-09-30 15:48:31 +00:00
2017-11-29 03:32:41 +00:00
# ifdef HAVE_LIBUSB
2017-11-28 23:25:12 +00:00
# ifdef __FreeBSD__
# include <libusb.h>
# else
# include <libusb-1.0/libusb.h>
# endif
2017-11-29 03:32:41 +00:00
# endif
2017-11-28 23:25:12 +00:00
2017-12-01 19:07:40 +00:00
# if defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) && _WIN32_WINNT >= 0x0500
/* MinGW Win32 HID API */
2017-12-02 20:59:33 +00:00
# include <minwindef.h>
# include <wtypes.h>
2017-12-01 19:07:40 +00:00
# include <tchar.h>
2017-12-02 20:59:33 +00: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 19:07:40 +00:00
# include <strsafe.h>
2017-12-01 19:38:13 +00:00
# include <guiddef.h>
# include <ks.h>
2017-12-01 19:07:40 +00:00
# include <setupapi.h>
2018-02-04 19:57:30 +00:00
# include <winapifamily.h>
# ifdef __cplusplus
extern " C " {
# endif
2017-12-01 19:07:40 +00:00
# include <hidsdi.h>
2018-02-04 19:57:30 +00:00
# ifdef __cplusplus
}
# endif
2018-01-25 15:33:28 +00:00
2017-12-01 19:07:40 +00:00
/* Why doesn't including cguid.h work to get a GUID_NULL instead? */
2018-02-04 19:03:27 +00: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 19:05:32 +00:00
__attribute__ ( ( weak ) )
2017-12-01 19:07:40 +00:00
const GUID GUID_NULL = { 0 , 0 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } } ;
# endif
2018-01-25 15:33:28 +00:00
# endif
2017-12-01 19:07:40 +00:00
2017-08-31 00:25:04 +00:00
# include "../input/input_driver.h"
2017-11-28 23:25:12 +00:00
# include "../input/include/blissbox.h"
2015-07-10 07:15:55 +00:00
2016-02-07 12:25:55 +00:00
# include "../configuration.h"
2016-06-11 19:51:28 +00:00
# include "../file_path_special.h"
2016-05-21 11:31:41 +00:00
# include "../list_special.h"
2015-11-23 11:03:38 +00:00
# include "../verbosity.h"
2017-12-07 22:47:16 +00:00
# include "../retroarch.h"
2014-09-30 15:48:31 +00:00
2016-12-01 19:38:20 +00:00
# include "tasks_internal.h"
2017-11-28 23:25:12 +00: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-29 01:26:47 +00:00
# define USB_PACKET_CTRL_LEN 5
2017-11-28 23:25:12 +00: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-29 03:32:41 +00:00
# ifdef HAVE_LIBUSB
2017-11-28 23:25:12 +00:00
static struct libusb_device_handle * autoconfig_libusb_handle = NULL ;
2017-11-29 03:32:41 +00:00
# endif
2017-11-28 23:25:12 +00:00
2017-05-13 20:30:45 +00:00
typedef struct autoconfig_disconnect autoconfig_disconnect_t ;
typedef struct autoconfig_params autoconfig_params_t ;
struct autoconfig_disconnect
2016-12-01 21:36:38 +00:00
{
2016-12-16 11:20:31 +00:00
unsigned idx ;
2017-09-29 04:16:35 +00:00
char * msg ;
2017-05-13 20:30:45 +00:00
} ;
2016-12-01 21:36:38 +00:00
2017-05-13 20:30:45 +00:00
struct autoconfig_params
2016-12-31 06:43:34 +00:00
{
int32_t vid ;
int32_t pid ;
2017-05-13 20:30:45 +00:00
unsigned idx ;
2016-12-31 06:54:38 +00:00
uint32_t max_users ;
2017-09-29 04:16:35 +00:00
char * name ;
char * autoconfig_directory ;
2017-05-13 20:30:45 +00:00
} ;
2016-12-31 06:43:34 +00:00
2017-04-25 13:49:27 +00: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 04:01:15 +00:00
static bool input_autoconfigure_swap_override ;
2019-02-03 23:49:35 +00:00
/* TODO/FIXME - Not thread safe to access this
2018-11-28 10:02:36 +00: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 04:01:15 +00:00
bool input_autoconfigure_get_swap_override ( void )
{
return input_autoconfigure_swap_override ;
}
2017-04-25 13:49:27 +00:00
2015-12-04 01:57:47 +00:00
/* Adds an index for devices with the same name,
* so they can be identified in the GUI . */
2017-12-05 22:03:56 +00:00
void input_autoconfigure_joypad_reindex_devices ( )
2015-11-25 03:30:51 +00:00
{
2017-12-05 22:03:56 +00:00
unsigned i , j , k ;
2015-11-25 18:27:33 +00:00
2017-12-05 22:03:56 +00:00
for ( i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
2017-04-25 14:57:44 +00:00
input_device_name_index [ i ] = 0 ;
2015-11-25 18:27:33 +00:00
2017-12-05 22:03:56 +00:00
for ( i = 0 ; i < MAX_INPUT_DEVICES ; i + + )
2015-11-25 03:30:51 +00:00
{
2017-04-25 13:53:30 +00: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-25 03:30:51 +00: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-25 03:30:51 +00: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*/
if ( string_is_equal ( tmp , other ) & &
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 14:57:44 +00:00
input_device_name_index [ j ] = k + + ;
2017-12-05 22:03:56 +00:00
}
2015-11-25 03:30:51 +00:00
}
}
}
2014-09-30 15:48:31 +00:00
static void input_autoconfigure_joypad_conf ( config_file_t * conf ,
struct retro_keybind * binds )
{
unsigned i ;
2015-01-09 23:06:49 +00:00
2014-09-30 15:48:31 +00:00
for ( i = 0 ; i < RARCH_BIND_LIST_END ; i + + )
{
input_config_parse_joy_button ( conf , " input " ,
2015-11-28 01:13:27 +00:00
input_config_bind_map_get_base ( i ) , & binds [ i ] ) ;
2014-09-30 15:48:31 +00:00
input_config_parse_joy_axis ( conf , " input " ,
2015-11-28 01:13:27 +00:00
input_config_bind_map_get_base ( i ) , & binds [ i ] ) ;
2014-09-30 15:48:31 +00:00
}
}
2016-12-01 17:52:34 +00:00
static int input_autoconfigure_joypad_try_from_conf ( config_file_t * conf ,
2015-07-10 03:46:28 +00:00
autoconfig_params_t * params )
2014-09-30 15:48:31 +00:00
{
2016-10-09 06:54:33 +00:00
char ident [ 256 ] ;
char input_driver [ 32 ] ;
2016-12-01 19:38:20 +00:00
int tmp_int = 0 ;
int input_vid = 0 ;
int input_pid = 0 ;
int score = 0 ;
2014-09-30 15:48:31 +00:00
2016-12-01 19:38:20 +00:00
ident [ 0 ] = input_driver [ 0 ] = ' \0 ' ;
2016-10-09 06:54:33 +00:00
2014-09-30 15:48:31 +00:00
config_get_array ( conf , " input_device " , ident , sizeof ( ident ) ) ;
config_get_array ( conf , " input_driver " , input_driver , sizeof ( input_driver ) ) ;
2016-05-24 21:53:35 +00: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 15:48:31 +00:00
2017-11-29 02:25:54 +00:00
if ( params - > vid = = BLISSBOX_VID )
input_pid = BLISSBOX_PID ;
2015-07-10 03:46:28 +00:00
/* Check for VID/PID */
2015-03-27 16:27:21 +00:00
if ( ( params - > vid = = input_vid )
& & ( params - > pid = = input_pid )
2016-12-01 17:38:11 +00:00
& & ( params - > vid ! = 0 )
& & ( params - > pid ! = 0 )
2017-11-29 02:25:54 +00:00
& & ( params - > vid ! = BLISSBOX_VID )
& & ( params - > pid ! = BLISSBOX_PID ) )
2015-07-10 03:46:28 +00:00
score + = 3 ;
2015-07-03 02:48:06 +00:00
2015-04-30 21:28:07 +00:00
/* Check for name match */
2017-09-30 04:08:09 +00:00
if ( ! string_is_empty ( params - > name )
2017-09-30 05:18:33 +00:00
& & ! string_is_empty ( ident )
2017-09-29 04:16:35 +00:00
& & string_is_equal ( ident , params - > name ) )
2015-07-10 03:46:28 +00:00
score + = 2 ;
2017-12-31 03:24:42 +00:00
#if 0
else
{
if ( string_is_empty ( params - > name ) )
RARCH_LOG ( " [autoconf]: failed match because params->name was empty \n " ) ;
else if ( string_is_empty ( ident ) )
RARCH_LOG ( " [autoconf]: failed match because ident was empty \n " ) ;
else
RARCH_LOG ( " [autoconf]: failed match because ident '%s' != param->name '%s' \n " ,
ident , params - > name ) ;
2017-12-28 23:06:39 +00:00
}
2017-12-31 03:24:42 +00:00
# endif
2016-09-12 16:39:46 +00:00
2015-07-10 03:46:28 +00:00
return score ;
2015-03-27 16:27:21 +00:00
}
2016-02-05 13:06:43 +00:00
static void input_autoconfigure_joypad_add ( config_file_t * conf ,
2016-12-01 21:16:06 +00:00
autoconfig_params_t * params , retro_task_t * task )
2015-03-27 16:27:21 +00:00
{
2017-04-26 16:48:28 +00: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 14:45:52 +00:00
# if defined(HAVE_LIBNX) && defined(HAVE_MENU_WIDGETS)
true ;
# else
2017-04-26 16:48:28 +00:00
input_autoconfigured [ params - > idx ]
2017-09-30 04:08:09 +00:00
& & ! string_is_empty ( params - > name ) ;
2018-11-22 14:45:52 +00:00
# endif
2015-03-27 16:34:09 +00:00
2016-10-09 06:54:33 +00:00
msg [ 0 ] = display_name [ 0 ] = device_type [ 0 ] = ' \0 ' ;
2016-02-05 13:06:43 +00: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 18:45:17 +00:00
2017-04-25 13:49:27 +00:00
input_autoconfigured [ params - > idx ] = true ;
2017-04-25 13:31:32 +00:00
2015-03-27 16:27:21 +00:00
input_autoconfigure_joypad_conf ( conf ,
2017-04-25 14:33:30 +00:00
input_autoconf_binds [ params - > idx ] ) ;
2014-09-30 15:48:31 +00:00
2018-01-16 21:53:38 +00:00
if ( string_is_equal ( device_type , " remote " ) )
2015-08-01 04:09:25 +00:00
{
2017-04-26 16:48:28 +00:00
static bool remote_is_bound = false ;
2016-10-22 02:57:46 +00:00
snprintf ( msg , sizeof ( msg ) , " %s configured. " ,
2017-09-29 04:16:35 +00:00
( string_is_empty ( display_name ) & &
2017-09-30 05:18:33 +00:00
! string_is_empty ( params - > name ) ) ? params - > name : ( ! string_is_empty ( display_name ) ? display_name : " N/A " ) ) ;
2015-08-31 13:26:37 +00:00
2015-08-01 05:07:28 +00:00
if ( ! remote_is_bound )
2017-05-16 02:50:20 +00:00
{
task_free_title ( task ) ;
2016-12-29 05:50:18 +00:00
task_set_title ( task , strdup ( msg ) ) ;
2017-05-16 02:50:20 +00:00
}
2015-08-01 04:09:25 +00:00
remote_is_bound = true ;
2017-04-16 18:03:34 +00:00
if ( params - > idx = = 0 )
2017-05-06 04:01:15 +00:00
input_autoconfigure_swap_override = true ;
2015-08-01 04:09:25 +00:00
}
2015-07-12 18:45:17 +00:00
else
2015-08-01 04:09:25 +00:00
{
2017-04-20 19:52:29 +00:00
bool tmp = false ;
2016-10-22 02:57:46 +00:00
snprintf ( msg , sizeof ( msg ) , " %s %s #%u. " ,
2017-09-29 04:16:35 +00:00
( string_is_empty ( display_name ) & &
2017-12-05 22:03:56 +00:00
! string_is_empty ( params - > name ) )
2017-09-30 05:18:33 +00:00
? params - > name : ( ! string_is_empty ( display_name ) ? display_name : " N/A " ) ,
2016-10-22 02:57:46 +00:00
msg_hash_to_str ( MSG_DEVICE_CONFIGURED_IN_PORT ) ,
2016-01-20 03:07:24 +00:00
params - > idx ) ;
2019-02-03 23:49:35 +00:00
2017-04-16 21:59:05 +00:00
/* allow overriding the swap menu controls for player 1*/
2017-04-16 18:03:34 +00:00
if ( params - > idx = = 0 )
2017-04-25 13:31:32 +00:00
{
2017-04-20 19:52:29 +00:00
if ( config_get_bool ( conf , " input_swap_override " , & tmp ) )
2017-05-06 04:01:15 +00:00
input_autoconfigure_swap_override = tmp ;
2017-08-04 06:37:16 +00:00
else
input_autoconfigure_swap_override = false ;
2017-04-25 13:31:32 +00:00
}
2017-04-16 21:59:05 +00:00
2015-08-01 05:07:28 +00:00
if ( ! block_osd_spam )
2017-05-16 02:50:20 +00:00
{
task_free_title ( task ) ;
2016-12-29 05:50:18 +00:00
task_set_title ( task , strdup ( msg ) ) ;
2017-05-16 02:50:20 +00:00
}
2015-08-01 04:09:25 +00:00
}
2018-01-12 15:29:35 +00:00
if ( ! string_is_empty ( display_name ) )
input_config_set_device_display_name ( params - > idx , display_name ) ;
else
2018-01-17 03:18:28 +00:00
input_config_set_device_display_name ( params - > idx , params - > name ) ;
2018-01-12 15:29:35 +00:00
if ( ! string_is_empty ( conf - > path ) )
2019-03-08 00:17:54 +00:00
{
2018-01-12 15:29:35 +00:00
input_config_set_device_config_name ( params - > idx , path_basename ( conf - > path ) ) ;
2019-03-08 00:17:54 +00:00
input_config_set_device_config_path ( params - > idx , conf - > path ) ;
}
2018-01-12 15:29:35 +00:00
else
2019-03-08 00:17:54 +00:00
{
2018-01-12 15:29:35 +00:00
input_config_set_device_config_name ( params - > idx , " N/A " ) ;
2019-03-08 00:17:54 +00:00
input_config_set_device_config_path ( params - > idx , " N/A " ) ;
}
2016-12-16 11:33:56 +00:00
2017-12-05 22:03:56 +00:00
input_autoconfigure_joypad_reindex_devices ( ) ;
2014-09-30 15:48:31 +00:00
}
2015-05-08 15:25:55 +00:00
static int input_autoconfigure_joypad_from_conf (
2016-12-01 21:16:06 +00:00
config_file_t * conf , autoconfig_params_t * params , retro_task_t * task )
2015-05-08 15:25:55 +00:00
{
2016-12-01 17:52:34 +00:00
int ret = input_autoconfigure_joypad_try_from_conf ( conf ,
2015-07-10 03:46:28 +00:00
params ) ;
2015-05-08 15:25:55 +00:00
2017-12-31 03:24:42 +00:00
if ( ret )
2016-12-01 21:16:06 +00:00
input_autoconfigure_joypad_add ( conf , params , task ) ;
2015-05-08 15:25:55 +00:00
config_file_free ( conf ) ;
return ret ;
}
2015-03-27 17:05:43 +00:00
static bool input_autoconfigure_joypad_from_conf_dir (
2016-12-01 21:16:06 +00:00
autoconfig_params_t * params , retro_task_t * task )
2014-09-30 15:48:31 +00:00
{
size_t i ;
2016-10-09 06:54:33 +00:00
char path [ PATH_MAX_LENGTH ] ;
2015-09-29 15:35:28 +00:00
int ret = 0 ;
int index = - 1 ;
int current_best = 0 ;
2015-07-10 07:06:00 +00:00
config_file_t * conf = NULL ;
struct string_list * list = NULL ;
2015-07-10 04:12:35 +00:00
2016-10-09 06:54:33 +00:00
path [ 0 ] = ' \0 ' ;
2016-06-11 19:51:28 +00:00
fill_pathname_application_special ( path , sizeof ( path ) ,
APPLICATION_SPECIAL_DIRECTORY_AUTOCONFIG ) ;
2015-09-29 15:35:28 +00:00
2016-05-21 11:31:41 +00:00
list = dir_list_new_special ( path , DIR_LIST_AUTOCONFIG , " cfg " ) ;
2014-09-30 15:48:31 +00:00
2015-07-10 04:51:39 +00:00
if ( ! list | | ! list - > size )
2016-05-23 19:28:43 +00:00
{
if ( list )
2017-09-30 23:03:39 +00:00
{
2016-05-23 19:28:43 +00:00
string_list_free ( list ) ;
2017-09-30 23:03:39 +00:00
list = NULL ;
}
2017-09-30 06:24:01 +00:00
if ( ! string_is_empty ( params - > autoconfig_directory ) )
2017-09-29 04:16:35 +00:00
list = dir_list_new_special ( params - > autoconfig_directory ,
DIR_LIST_AUTOCONFIG , " cfg " ) ;
2016-05-23 19:28:43 +00:00
}
2015-07-10 04:51:39 +00:00
2017-12-31 03:24:42 +00:00
if ( ! list )
{
2017-12-28 23:06:39 +00:00
RARCH_LOG ( " [autoconf]: No profiles found. \n " ) ;
2015-03-27 17:05:43 +00:00
return false ;
2017-12-28 23:06:39 +00:00
}
2014-09-30 15:48:31 +00:00
2017-09-30 14:52:41 +00:00
if ( list )
{
RARCH_LOG ( " [Autoconf]: %d profiles found. \n " , list - > size ) ;
}
2015-03-27 17:02:21 +00:00
2015-07-10 03:46:28 +00:00
for ( i = 0 ; i < list - > size ; i + + )
{
conf = config_file_new ( list - > elems [ i ] . data ) ;
2016-10-04 08:40:37 +00:00
if ( conf )
2016-12-01 17:52:34 +00:00
ret = input_autoconfigure_joypad_try_from_conf ( conf , params ) ;
2016-09-12 16:39:46 +00:00
2015-07-11 03:36:28 +00:00
if ( ret > = current_best )
2015-07-10 03:46:28 +00:00
{
2017-02-26 09:33:03 +00:00
index = ( int ) i ;
2015-07-10 07:06:00 +00:00
current_best = ret ;
2015-07-10 03:46:28 +00:00
}
config_file_free ( conf ) ;
2014-09-30 15:48:31 +00:00
}
2015-07-23 04:38:31 +00:00
if ( index > = 0 & & current_best > 0 )
2015-08-31 13:26:37 +00:00
{
2015-07-10 03:52:52 +00:00
conf = config_file_new ( list - > elems [ index ] . data ) ;
2015-11-15 21:28:57 +00:00
if ( conf )
{
char conf_path [ PATH_MAX_LENGTH ] ;
2016-10-09 06:54:33 +00:00
conf_path [ 0 ] = ' \0 ' ;
2015-11-15 21:28:57 +00:00
config_get_config_path ( conf , conf_path , sizeof ( conf_path ) ) ;
2017-12-28 23:06:39 +00:00
RARCH_LOG ( " [autoconf]: selected configuration: %s \n " , conf_path ) ;
2016-12-01 21:16:06 +00:00
input_autoconfigure_joypad_add ( conf , params , task ) ;
2015-11-15 21:28:57 +00:00
config_file_free ( conf ) ;
ret = 1 ;
}
2015-07-10 03:52:52 +00:00
}
else
2015-07-10 07:06:00 +00:00
ret = 0 ;
2015-11-15 04:49:26 +00:00
2015-03-27 17:02:21 +00:00
string_list_free ( list ) ;
2015-03-27 17:05:43 +00:00
2015-07-10 07:06:00 +00:00
if ( ret = = 0 )
return false ;
return true ;
2015-03-27 17:02:21 +00:00
}
2014-09-30 15:48:31 +00:00
2015-03-27 17:02:21 +00:00
static bool input_autoconfigure_joypad_from_conf_internal (
2016-12-01 21:16:06 +00:00
autoconfig_params_t * params , retro_task_t * task )
2015-03-27 17:02:21 +00:00
{
size_t i ;
2015-03-27 16:55:00 +00:00
/* Load internal autoconfig files */
2014-09-30 15:48:31 +00:00
for ( i = 0 ; input_builtin_autoconfs [ i ] ; i + + )
{
2015-03-27 16:47:15 +00:00
config_file_t * conf = config_file_new_from_string (
input_builtin_autoconfs [ i ] ) ;
2016-12-01 21:16:06 +00:00
if ( conf & & input_autoconfigure_joypad_from_conf ( conf , params , task ) )
2017-12-28 23:06:39 +00:00
return true ;
2014-09-30 15:48:31 +00:00
}
2017-09-30 05:28:58 +00:00
if ( string_is_empty ( params - > autoconfig_directory ) )
2015-03-27 17:02:21 +00:00
return true ;
return false ;
}
2015-01-09 23:06:49 +00:00
2017-09-29 04:16:35 +00:00
static void input_autoconfigure_params_free ( autoconfig_params_t * params )
{
if ( ! params )
return ;
2017-09-30 04:08:09 +00:00
if ( ! string_is_empty ( params - > name ) )
2017-09-29 04:16:35 +00:00
free ( params - > name ) ;
2017-09-30 04:08:09 +00:00
if ( ! string_is_empty ( params - > autoconfig_directory ) )
2017-09-29 04:16:35 +00:00
free ( params - > autoconfig_directory ) ;
params - > name = NULL ;
params - > autoconfig_directory = NULL ;
}
2017-12-01 19:07:40 +00: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 10:36:22 +00: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 10:36:22 +00: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 19:07:40 +00: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 )
{
RARCH_ERR ( " [Autoconf]: Error in SetupDiGetClassDevs: %d. \n " , GetLastError ( ) ) ;
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 10:36:22 +00:00
nLength = _tcslen ( pInterfaceDetailData - > DevicePath ) + 1 ;
2017-12-01 19:07:40 +00:00
lpDevicePath = ( TCHAR * ) LocalAlloc ( LPTR , nLength * sizeof ( TCHAR ) ) ;
StringCchCopy ( lpDevicePath , nLength , pInterfaceDetailData - > DevicePath ) ;
2017-12-02 10:36:22 +00:00
devicePath = ( char * ) malloc ( nLength ) ;
2017-12-01 19:07:40 +00: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 22:47:16 +00: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 14:45:52 +00: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 22:47:16 +00:00
goto done ;
}
2017-12-01 19:07:40 +00:00
}
done :
free ( devicePath ) ;
LocalFree ( lpDevicePath ) ;
LocalFree ( pInterfaceDetailData ) ;
2017-12-02 10:36:22 +00:00
bResult = SetupDiDestroyDeviceInfoList ( hDeviceInfo ) ;
2017-12-01 19:07:40 +00:00
2017-12-02 10:36:22 +00:00
devicePath = NULL ;
lpDevicePath = NULL ;
2017-12-01 19:07:40 +00: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 10:36:22 +00:00
# endif
2017-12-01 19:07:40 +00: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 23:25:12 +00:00
{
# ifdef HAVE_LIBUSB
unsigned i ;
2017-12-02 10:36:22 +00:00
unsigned char answer [ USB_PACKET_CTRL_LEN ] = { 0 } ;
int ret = libusb_init ( NULL ) ;
2017-11-28 23:25:12 +00:00
if ( ret < 0 )
{
2017-11-29 02:25:54 +00:00
RARCH_ERR ( " [Autoconf]: Could not initialize libusb. \n " ) ;
2017-11-28 23:25:12 +00:00
return NULL ;
}
autoconfig_libusb_handle = libusb_open_device_with_vid_pid ( NULL , vid , pid ) ;
if ( ! autoconfig_libusb_handle )
{
2017-11-29 02:25:54 +00:00
RARCH_ERR ( " [Autoconf]: Could not find or open libusb device %d:%d. \n " , vid , pid ) ;
2017-11-28 23:25:12 +00: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-29 02:25:54 +00:00
RARCH_ERR ( " [Autoconf]: Error during libusb_set_configuration. \n " ) ;
2017-11-28 23:25:12 +00:00
goto error ;
}
ret = libusb_claim_interface ( autoconfig_libusb_handle , 0 ) ;
if ( ret < 0 )
{
2017-11-29 02:25:54 +00:00
RARCH_ERR ( " [Autoconf]: Error during libusb_claim_interface. \n " ) ;
2017-11-28 23:25:12 +00: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-29 02:25:54 +00:00
RARCH_ERR ( " [Autoconf]: Error during libusb_control_transfer. \n " ) ;
2017-11-28 23:25:12 +00: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-29 02:25:54 +00:00
RARCH_LOG ( " [Autoconf]: Could not find connected pad in Bliss-Box port#%d. \n " , pid - BLISSBOX_PID ) ;
2017-11-28 23:25:12 +00:00
return NULL ;
2017-11-29 03:32:41 +00:00
2017-11-28 23:25:12 +00:00
error :
libusb_close ( autoconfig_libusb_handle ) ;
libusb_exit ( NULL ) ;
2017-11-29 03:32:41 +00:00
# endif
2017-12-02 10:36:22 +00:00
return NULL ;
2017-11-28 23:25:12 +00:00
}
2017-12-01 19:07:40 +00: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 23:25:12 +00:00
static void input_autoconfigure_override_handler ( autoconfig_params_t * params )
{
if ( params - > vid = = BLISSBOX_VID )
{
2017-11-29 02:25:54 +00: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 23:25:12 +00:00
{
const blissbox_pad_type_t * pad ;
char name [ 255 ] = { 0 } ;
int index = params - > pid - BLISSBOX_PID ;
2017-11-29 02:25:54 +00:00
RARCH_LOG ( " [Autoconf]: Bliss-Box detected. Getting pad type... \n " ) ;
2017-11-28 23:25:12 +00: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-02 03:40:17 +00:00
strlcat ( name , " Bliss-Box 4-Play " , sizeof ( name ) ) ;
2017-11-28 23:25:12 +00:00
strlcat ( name , pad - > name , sizeof ( name ) ) ;
params - > name = strdup ( name ) ;
blissbox_pads [ index ] = pad ;
}
else
{
int count = sizeof ( blissbox_pad_types ) / sizeof ( blissbox_pad_types [ 0 ] ) ;
/* use NULL entry to mark as an unconnected port */
blissbox_pads [ index ] = & blissbox_pad_types [ count - 1 ] ;
}
}
}
}
2016-12-01 21:16:06 +00:00
static void input_autoconfigure_connect_handler ( retro_task_t * task )
2015-03-27 17:05:43 +00:00
{
2016-12-03 05:09:55 +00:00
autoconfig_params_t * params = ( autoconfig_params_t * ) task - > state ;
2016-12-01 21:16:06 +00:00
2016-12-29 04:49:24 +00:00
if ( ! params | | string_is_empty ( params - > name ) )
2017-01-03 02:52:08 +00:00
goto end ;
2015-07-03 02:48:06 +00:00
2016-12-01 21:16:06 +00:00
if ( ! input_autoconfigure_joypad_from_conf_dir ( params , task )
& & ! input_autoconfigure_joypad_from_conf_internal ( params , task ) )
2016-12-01 19:41:41 +00:00
{
char msg [ 255 ] ;
2015-11-15 04:27:05 +00:00
2016-12-01 19:41:41 +00:00
msg [ 0 ] = ' \0 ' ;
2017-05-13 21:41:13 +00:00
# ifdef ANDROID
2017-09-30 04:38:53 +00:00
if ( ! string_is_empty ( params - > name ) )
free ( params - > name ) ;
2017-09-29 04:16:35 +00:00
params - > name = strdup ( " Android Gamepad " ) ;
2019-03-08 00:17:54 +00:00
if ( input_autoconfigure_joypad_from_conf_internal ( params , task ) )
2017-02-05 19:24:34 +00:00
{
2017-06-17 23:32:55 +00:00
RARCH_LOG ( " [Autoconf]: no profiles found for %s (%d/%d). Using fallback \n " ,
2017-09-30 04:29:07 +00:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
params - > vid , params - > pid ) ;
2016-12-29 05:50:18 +00:00
2017-02-05 19:24:34 +00:00
snprintf ( msg , sizeof ( msg ) , " %s (%ld/%ld) %s. " ,
2017-09-30 04:29:07 +00:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
( long ) params - > vid , ( long ) params - > pid ,
2017-02-05 19:24:34 +00:00
msg_hash_to_str ( MSG_DEVICE_NOT_CONFIGURED_FALLBACK ) ) ;
}
2017-05-13 21:41:13 +00:00
# else
2017-06-17 23:32:55 +00:00
RARCH_LOG ( " [Autoconf]: no profiles found for %s (%d/%d). \n " ,
2017-09-30 04:29:07 +00:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
params - > vid , params - > pid ) ;
2017-05-13 21:41:13 +00:00
snprintf ( msg , sizeof ( msg ) , " %s (%ld/%ld) %s. " ,
2017-09-30 04:29:07 +00:00
! string_is_empty ( params - > name ) ? params - > name : " N/A " ,
( long ) params - > vid , ( long ) params - > pid ,
2017-05-13 21:41:13 +00:00
msg_hash_to_str ( MSG_DEVICE_NOT_CONFIGURED ) ) ;
2017-02-05 19:24:34 +00:00
# endif
2017-05-16 02:50:20 +00:00
task_free_title ( task ) ;
2016-12-29 05:50:18 +00:00
task_set_title ( task , strdup ( msg ) ) ;
2016-12-01 19:41:41 +00:00
}
2017-01-03 02:52:08 +00:00
end :
2017-09-29 04:16:35 +00:00
if ( params )
{
input_autoconfigure_params_free ( params ) ;
free ( params ) ;
}
2016-12-29 05:50:18 +00:00
task_set_finished ( task , true ) ;
2016-12-01 21:36:38 +00:00
}
2016-12-01 21:16:06 +00:00
2016-12-01 21:36:38 +00:00
static void input_autoconfigure_disconnect_handler ( retro_task_t * task )
{
2016-12-03 05:09:55 +00:00
autoconfig_disconnect_t * params = ( autoconfig_disconnect_t * ) task - > state ;
2016-12-01 21:36:38 +00:00
2016-12-29 05:50:18 +00:00
task_set_title ( task , strdup ( params - > msg ) ) ;
task_set_finished ( task , true ) ;
2016-12-01 21:36:38 +00:00
RARCH_LOG ( " %s: %s \n " , msg_hash_to_str ( MSG_AUTODETECT ) , params - > msg ) ;
2016-12-04 04:50:50 +00:00
2017-09-30 04:08:09 +00:00
if ( ! string_is_empty ( params - > msg ) )
2017-09-29 04:16:35 +00:00
free ( params - > msg ) ;
2016-12-04 04:50:50 +00:00
free ( params ) ;
2014-09-30 15:48:31 +00:00
}
2016-12-01 21:36:38 +00:00
bool input_autoconfigure_disconnect ( unsigned i , const char * ident )
2015-06-03 16:55:04 +00:00
{
2016-10-27 07:32:07 +00:00
char msg [ 255 ] ;
2018-11-22 14:45:52 +00:00
retro_task_t * task = task_init ( ) ;
2017-09-30 15:11:51 +00:00
autoconfig_disconnect_t * state = ( autoconfig_disconnect_t * ) calloc ( 1 , sizeof ( * state ) ) ;
2015-07-10 07:06:00 +00:00
2016-12-21 00:45:19 +00:00
if ( ! state | | ! task )
goto error ;
2016-12-16 11:20:31 +00:00
msg [ 0 ] = ' \0 ' ;
state - > idx = i ;
2016-10-09 06:54:33 +00:00
2017-12-05 22:03:56 +00:00
snprintf ( msg , sizeof ( msg ) , " %s #%u (%s). " ,
2016-10-22 02:57:46 +00:00
msg_hash_to_str ( MSG_DEVICE_DISCONNECTED_FROM_PORT ) ,
i , ident ) ;
2016-12-01 21:36:38 +00:00
2017-09-29 04:16:35 +00:00
state - > msg = strdup ( msg ) ;
2016-12-01 21:36:38 +00:00
2017-04-25 13:53:30 +00:00
input_config_clear_device_name ( state - > idx ) ;
2018-01-11 22:06:02 +00:00
input_config_clear_device_display_name ( state - > idx ) ;
input_config_clear_device_config_name ( state - > idx ) ;
2019-03-08 00:17:54 +00:00
input_config_clear_device_config_path ( state - > idx ) ;
2016-12-29 04:49:24 +00:00
2016-12-01 21:36:38 +00:00
task - > state = state ;
task - > handler = input_autoconfigure_disconnect_handler ;
2017-05-14 18:43:39 +00:00
task_queue_push ( task ) ;
2016-12-01 21:36:38 +00:00
return true ;
error :
if ( state )
2017-09-29 04:16:35 +00:00
{
2017-09-30 04:08:09 +00:00
if ( ! string_is_empty ( state - > msg ) )
2017-09-29 04:16:35 +00:00
free ( state - > msg ) ;
2016-12-01 21:36:38 +00:00
free ( state ) ;
2017-09-29 04:16:35 +00:00
}
2016-12-01 21:36:38 +00:00
if ( task )
free ( task ) ;
return false ;
2015-06-03 16:55:04 +00:00
}
2016-12-01 21:16:06 +00:00
2017-04-25 13:49:27 +00:00
void input_autoconfigure_reset ( void )
{
2017-04-25 14:33:30 +00:00
unsigned i , j ;
2017-04-25 13:49:27 +00:00
for ( i = 0 ; i < MAX_USERS ; i + + )
2017-04-25 14:33:30 +00: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 14:57:44 +00:00
input_device_name_index [ i ] = 0 ;
input_autoconfigured [ i ] = 0 ;
2017-04-25 14:33:30 +00:00
}
2017-05-06 04:01:15 +00:00
input_autoconfigure_swap_override = false ;
2017-04-25 13:49:27 +00:00
}
bool input_is_autoconfigured ( unsigned i )
{
return input_autoconfigured [ i ] ;
}
2017-04-25 14:57:44 +00:00
unsigned input_autoconfigure_get_device_name_index ( unsigned i )
{
return input_device_name_index [ i ] ;
}
2016-12-31 06:43:34 +00:00
bool input_autoconfigure_connect (
const char * name ,
const char * display_name ,
const char * driver ,
unsigned idx ,
unsigned vid ,
unsigned pid )
2016-12-01 21:16:06 +00:00
{
2016-12-29 04:49:24 +00:00
unsigned i ;
2018-11-22 14:45:52 +00:00
retro_task_t * task = task_init ( ) ;
2017-09-30 15:08:42 +00:00
autoconfig_params_t * state = ( autoconfig_params_t * ) calloc ( 1 , sizeof ( * state ) ) ;
2016-12-16 14:18:04 +00:00
settings_t * settings = config_get_ptr ( ) ;
2017-09-30 14:52:41 +00:00
const char * dir_autoconf = settings ? settings - > paths . directory_autoconfig : NULL ;
bool autodetect_enable = settings ? settings - > bools . input_autodetect_enable : false ;
2016-12-01 21:16:06 +00:00
2017-09-30 14:52:41 +00:00
if ( ! task | | ! state | | ! autodetect_enable )
2016-12-01 21:16:06 +00:00
goto error ;
2016-12-31 06:43:34 +00:00
if ( ! string_is_empty ( name ) )
2017-09-29 15:06:38 +00:00
state - > name = strdup ( name ) ;
2016-12-31 06:43:34 +00:00
2017-04-25 14:57:44 +00:00
if ( ! string_is_empty ( dir_autoconf ) )
2017-09-29 04:16:35 +00:00
state - > autoconfig_directory = strdup ( dir_autoconf ) ;
2017-01-02 04:33:29 +00:00
2017-09-29 15:06:38 +00:00
state - > idx = idx ;
state - > vid = vid ;
state - > pid = pid ;
state - > max_users = * (
input_driver_get_uint ( INPUT_ACTION_MAX_USERS ) ) ;
2016-12-01 21:16:06 +00:00
2017-11-28 23:25:12 +00:00
input_autoconfigure_override_handler ( state ) ;
2017-09-30 04:38:53 +00:00
if ( ! string_is_empty ( state - > name ) )
input_config_set_device_name ( state - > idx , state - > name ) ;
2017-04-25 14:49:54 +00:00
input_config_set_pid ( state - > idx , state - > pid ) ;
input_config_set_vid ( state - > idx , state - > vid ) ;
2017-01-02 04:33:29 +00:00
2016-12-29 04:49:24 +00:00
for ( i = 0 ; i < RARCH_BIND_LIST_END ; i + + )
{
2017-04-25 14:33:30 +00: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 04:08:09 +00:00
! string_is_empty ( input_autoconf_binds [ state - > idx ] [ i ] . joykey_label ) )
2017-09-27 18:08:37 +00:00
free ( input_autoconf_binds [ state - > idx ] [ i ] . joykey_label ) ;
2017-12-05 22:03:56 +00:00
if (
2017-09-30 04:08:09 +00:00
! string_is_empty ( input_autoconf_binds [ state - > idx ] [ i ] . joyaxis_label ) )
2017-09-27 18:11:44 +00: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 04:49:24 +00:00
}
2017-04-25 13:31:32 +00:00
2017-04-25 13:49:27 +00:00
input_autoconfigured [ state - > idx ] = false ;
2016-12-01 21:17:36 +00:00
2017-09-30 14:52:41 +00:00
task - > state = state ;
task - > handler = input_autoconfigure_connect_handler ;
2016-12-01 21:16:06 +00:00
2017-05-14 18:43:39 +00:00
task_queue_push ( task ) ;
2016-12-01 21:16:06 +00:00
return true ;
error :
if ( state )
2017-09-29 04:16:35 +00:00
{
input_autoconfigure_params_free ( state ) ;
2016-12-01 21:16:06 +00:00
free ( state ) ;
2017-09-29 04:16:35 +00:00
}
2016-12-01 21:16:06 +00:00
if ( task )
free ( task ) ;
return false ;
}