Enable pads to register in any order

== DETAILS

Whereas the last commit had a hack (that disabled the wiimote
driver in the process), this has.. well, a *different* hack that
allows pads to register in any order.

Note that due to the initialization routines, the gamepad will still
likely always get slot 0. Not sure if this can be overridden via config
or not.

== TESTING

Tested locally with GC adapter
This commit is contained in:
gblues 2018-04-01 18:52:26 -07:00
parent 2cf89feb86
commit 9bc5a15c2d
10 changed files with 193 additions and 94 deletions

View File

@ -57,6 +57,24 @@ joypad_connection_t *hid_pad_register(void *pad_handle, pad_connection_interface
return result;
}
static bool init_pad_list(hid_driver_instance_t *instance, unsigned slots)
{
if(!instance || slots > MAX_USERS)
return false;
if(instance->pad_list)
return true;
RARCH_LOG("[hid]: initializing pad list...\n");
instance->pad_list = pad_connection_init(slots);
if(!instance->pad_list)
return false;
instance->max_slot = slots;
return true;
}
/**
* Fill in instance with data from initialized hid subsystem.
*
@ -80,16 +98,13 @@ bool hid_init(hid_driver_instance_t *instance,
if(!instance->os_driver_data)
return false;
RARCH_LOG("[hid]: initializing pad list...\n");
instance->pad_list = pad_connection_init(slots);
if(!instance->pad_list)
if(!init_pad_list(instance, slots))
{
hid_driver->free(instance->os_driver_data);
instance->os_driver_data = NULL;
return false;
}
instance->max_slot = slots;
instance->os_driver = hid_driver;
instance->pad_driver = pad_driver;

View File

@ -19,6 +19,8 @@
#include "wiiu_dbg.h"
static input_device_driver_t *pad_drivers[MAX_USERS];
extern pad_connection_listener_t wiiu_pad_connection_listener;
static bool ready = false;
@ -31,52 +33,18 @@ static int16_t wiiu_joypad_axis(unsigned pad, uint32_t axis);
static void wiiu_joypad_poll(void);
static const char *wiiu_joypad_name(unsigned pad);
/**
* Translates a pad to its appropriate driver.
* Note that this is a helper for build_pad_map and shouldn't be
* used directly.
*/
static input_device_driver_t *get_driver_for_pad(unsigned pad)
{
if(wpad_driver.query_pad(pad))
return &wpad_driver;
if(kpad_driver.query_pad(pad))
return &kpad_driver;
#ifdef WIIU_HID
return &hidpad_driver;
#else
return NULL;
#endif
}
/**
* Populates the pad_driver array. We do this once at init time so
* that lookups at runtime are constant time.
*/
static void build_pad_map(void)
{
unsigned i;
for(i = 0; i < MAX_USERS; i++)
{
pad_drivers[i] = get_driver_for_pad(i);
}
}
static bool wiiu_joypad_init(void* data)
{
/* the sub-drivers have to init first, otherwise
* build_pad_map will fail (because all lookups will return false). */
set_connection_listener(&wiiu_pad_connection_listener);
hid_instance.pad_list = pad_connection_init(MAX_USERS);
hid_instance.max_slot = MAX_USERS;
wpad_driver.init(data);
kpad_driver.init(data);
#ifdef WIIU_HID
hidpad_driver.init(data);
#endif
build_pad_map();
ready = true;
(void)data;
@ -85,7 +53,10 @@ static bool wiiu_joypad_init(void* data)
static bool wiiu_joypad_query_pad(unsigned pad)
{
return ready && pad < MAX_USERS;
return ready &&
pad < MAX_USERS &&
pad_drivers[pad] != NULL &&
pad_drivers[pad]->query_pad(pad);
}
static void wiiu_joypad_destroy(void)
@ -140,6 +111,13 @@ static const char* wiiu_joypad_name(unsigned pad)
return pad_drivers[pad]->name(pad);
}
static void wiiu_joypad_connection_listener(unsigned pad,
input_device_driver_t *driver)
{
if(pad < MAX_USERS)
pad_drivers[pad] = driver;
}
input_device_driver_t wiiu_joypad =
{
wiiu_joypad_init,
@ -153,3 +131,8 @@ input_device_driver_t wiiu_joypad =
wiiu_joypad_name,
"wiiu",
};
pad_connection_listener_t wiiu_pad_connection_listener =
{
wiiu_joypad_connection_listener
};

27
input/include/gamepad.h Normal file
View File

@ -0,0 +1,27 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
* Copyright (C) 2016-2017 - Andrés Suárez
*
* 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/>.
*/
#ifndef GAMEPAD_H__
#define GAMEPAD_H__
#include "../input_driver.h"
typedef struct pad_connection_listener_interface {
void (*connected)(unsigned port, input_device_driver_t *driver);
} pad_connection_listener_t;
#endif /* GAMEPAD_H__ */

View File

@ -58,8 +58,8 @@ struct hid_driver
hid_instance.os_driver_data, pad, key)
#define HID_AXIS(pad, axis) hid_instance.os_driver->axis( \
hid_instance.os_driver_data, pad, axis)
#define HID_PAD_NAME(pad) hid_instance.os_driver->name( \
hid_instance.os_driver_data, pad)
#define HID_PAD_NAME(pad) \
hid_instance.os_driver->name(hid_instance.os_driver_data, pad)
#define HID_POLL() hid_instance.os_driver->poll( \
hid_instance.os_driver_data)
#define HID_MAX_SLOT() hid_instance.max_slot

View File

@ -60,6 +60,22 @@
#include "../verbosity.h"
#include "../tasks/tasks_internal.h"
#include "../command.h"
#include "include/gamepad.h"
static pad_connection_listener_t *pad_connection_listener = NULL;
void set_connection_listener(pad_connection_listener_t *listener)
{
pad_connection_listener = listener;
}
void fire_connection_listener(unsigned port, input_device_driver_t *driver)
{
if(!pad_connection_listener)
return;
pad_connection_listener->connected(port, driver);
}
static const input_driver_t *input_drivers[] = {
#ifdef __CELLOS_LV2__
@ -1790,6 +1806,8 @@ void input_pad_connect(unsigned port, input_device_driver_t *driver)
return;
}
fire_connection_listener(port, driver);
if(!input_autoconfigure_connect(driver->name(port), NULL, driver->ident,
port, 0, 0))
input_config_set_device_name(port, driver->name(port));

View File

@ -22,6 +22,8 @@
#include <stddef.h>
#include <sys/types.h>
#include "input_types.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@ -36,14 +38,10 @@
#include "../msg_hash.h"
#include "include/hid_types.h"
#include "include/gamepad.h"
RETRO_BEGIN_DECLS
typedef struct rarch_joypad_driver input_device_driver_t;
/* Keyboard line reader. Handles textual input in a direct fashion. */
typedef struct input_keyboard_line input_keyboard_line_t;
enum input_device_type
{
INPUT_DEVICE_TYPE_NONE = 0,
@ -120,14 +118,14 @@ struct retro_keybind
char *joyaxis_label;
};
typedef struct rarch_joypad_info
struct rarch_joypad_info
{
uint16_t joy_idx;
const struct retro_keybind *auto_binds;
float axis_threshold;
} rarch_joypad_info_t;
};
typedef struct input_driver
struct input_driver
{
/* Inits input driver.
*/
@ -163,7 +161,7 @@ typedef struct input_driver
const input_device_driver_t *(*get_sec_joypad_driver)(void *data);
bool (*keyboard_mapping_is_blocked)(void *data);
void (*keyboard_mapping_set_block)(void *data, bool value);
} input_driver_t;
};
struct rarch_joypad_driver
{
@ -657,11 +655,11 @@ typedef void (*input_keyboard_line_complete_t)(void *userdata,
typedef bool (*input_keyboard_press_t)(void *userdata, unsigned code);
typedef struct input_keyboard_ctx_wait
struct input_keyboard_ctx_wait
{
void *userdata;
input_keyboard_press_t cb;
} input_keyboard_ctx_wait_t;
};
/**
* input_keyboard_event:
@ -789,6 +787,9 @@ uint16_t input_config_get_vid(unsigned port);
void input_config_reset(void);
void set_connection_listener(pad_connection_listener_t *listener);
void fire_connection_listener(unsigned port, input_device_driver_t *driver);
extern input_device_driver_t dinput_joypad;
extern input_device_driver_t linuxraw_joypad;
extern input_device_driver_t parport_joypad;

26
input/input_types.h Normal file
View File

@ -0,0 +1,26 @@
/* RetroArch - A frontend for libretro.
* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
* Copyright (C) 2011-2017 - Daniel De Matteis
*
* 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/>.
*/
#ifndef __INPUT_TYPES__H
#define __INPUT_TYPES__H
typedef struct rarch_joypad_driver input_device_driver_t;
typedef struct input_keyboard_line input_keyboard_line_t;
typedef struct rarch_joypad_info rarch_joypad_info_t;
typedef struct input_driver input_driver_t;
typedef struct input_keyboard_ctx_wait input_keyboard_ctx_wait_t;
#endif /* __INPUT_TYPES__H */

View File

@ -30,8 +30,6 @@ static bool ready = false;
static bool init_hid_driver(void)
{
memset(&hid_instance, 0, sizeof(hid_instance));
return hid_init(&hid_instance, &wiiu_hid, &hidpad_driver, MAX_USERS);
}
@ -46,14 +44,6 @@ static bool hidpad_init(void *data)
return false;
}
hid_instance.pad_list[0].connected = true;
/*
for(i = 0; i < (WIIU_WIIMOTE_CHANNELS+1); i++)
{
hid_instance.pad_list[i].connected = true;
}
*/
hidpad_poll();
ready = true;

View File

@ -52,17 +52,30 @@ wiimote_state wiimotes[WIIU_WIIMOTE_CHANNELS] = {
{ 0, {{0,0},{0,0},{0,0}}, WIIMOTE_TYPE_NONE },
};
static unsigned to_wiimote_channel(unsigned pad)
{
if (pad == PAD_GAMEPAD || pad > WIIU_WIIMOTE_CHANNELS)
return 0xffffffff;
static int channel_slot_map[] = { -1, -1, -1, -1 };
return pad-1;
static int to_wiimote_channel(unsigned pad)
{
int i;
for(i = 0; i < WIIU_WIIMOTE_CHANNELS; i++)
if(channel_slot_map[i] == pad)
return i;
return -1;
}
static unsigned to_retro_pad(unsigned channel)
static int get_slot_for_channel(unsigned channel)
{
return channel+1;
int slot = pad_connection_find_vacant_pad(hid_instance.pad_list);
if(slot >= 0)
{
RARCH_LOG("[kpad]: got slot %d\n", slot);
channel_slot_map[channel] = slot;
hid_instance.pad_list[slot].connected = true;
}
return slot;
}
static bool kpad_init(void *data)
@ -75,7 +88,7 @@ static bool kpad_init(void *data)
static bool kpad_query_pad(unsigned pad)
{
return ready && pad <= WIIU_WIIMOTE_CHANNELS && pad > PAD_GAMEPAD;
return ready && pad < MAX_USERS;
}
static void kpad_destroy(void)
@ -88,27 +101,34 @@ static bool kpad_button(unsigned pad, uint16_t button_bit)
if (!kpad_query_pad(pad))
return false;
return wiimotes[to_wiimote_channel(pad)].button_state
int channel = to_wiimote_channel(pad);
if(channel < 0)
return false;
return wiimotes[channel].button_state
& (UINT64_C(1) << button_bit);
}
static void kpad_get_buttons(unsigned pad, retro_bits_t *state)
{
if (!kpad_query_pad(pad))
int channel = to_wiimote_channel(pad);
if (!kpad_query_pad(pad) || channel < 0)
BIT256_CLEAR_ALL_PTR(state);
else
BITS_COPY16_PTR(state, wiimotes[to_wiimote_channel(pad)].button_state);
BITS_COPY16_PTR(state, wiimotes[channel].button_state);
}
static int16_t kpad_axis(unsigned pad, uint32_t axis)
{
int channel = to_wiimote_channel(pad);
axis_data data;
if (!kpad_query_pad(pad) || axis == AXIS_NONE)
if (!kpad_query_pad(pad) || channel < 0 || axis == AXIS_NONE)
return 0;
pad_functions.read_axis_data(axis, &data);
return pad_functions.get_axis_value(data.axis,
wiimotes[to_wiimote_channel(pad)].analog_state,
wiimotes[channel].analog_state,
data.is_negative);
}
@ -116,8 +136,15 @@ static void kpad_register(unsigned channel, uint8_t device_type)
{
if (wiimotes[channel].type != device_type)
{
int slot = get_slot_for_channel(channel);
if(slot < 0)
{
RARCH_ERR("Couldn't get a slot for this remote.\n");
return;
}
wiimotes[channel].type = device_type;
input_pad_connect(to_retro_pad(channel), &kpad_driver);
input_pad_connect(slot, &kpad_driver);
}
}
@ -173,6 +200,13 @@ static void kpad_poll(void)
result = KPADRead(channel, &kpad, 1);
if (result == 0) {
int slot = channel_slot_map[channel];
if(slot > 0)
{
hid_instance.pad_list[slot].connected = false;
channel_slot_map[channel] = -1;
}
continue;
}
@ -182,11 +216,11 @@ static void kpad_poll(void)
static const char *kpad_name(unsigned pad)
{
pad = to_wiimote_channel(pad);
if (pad >= WIIU_WIIMOTE_CHANNELS)
int channel = to_wiimote_channel(pad);
if (channel < 0)
return "unknown";
switch(wiimotes[pad].type)
switch(wiimotes[channel].type)
{
case WIIMOTE_TYPE_PRO:
return PAD_NAME_WIIU_PRO;

View File

@ -186,7 +186,12 @@ static void wpad_poll(void)
static bool wpad_init(void *data)
{
input_pad_connect(PAD_GAMEPAD, &wpad_driver);
int slot = pad_connection_find_vacant_pad(hid_instance.pad_list);
if(slot < 0)
return false;
hid_instance.pad_list[slot].connected = true;
input_pad_connect(slot, &wpad_driver);
wpad_poll();
ready = true;
@ -195,7 +200,7 @@ static bool wpad_init(void *data)
static bool wpad_query_pad(unsigned pad)
{
return ready && pad == PAD_GAMEPAD;
return ready && pad < MAX_USERS;
}
static void wpad_destroy(void)