Wii: Add wiimote lightgun support

This commit is contained in:
benoa 2019-09-15 00:46:02 +02:00
parent e1a7b82b2e
commit 744fac6777
17 changed files with 372 additions and 2 deletions

View File

@ -93,6 +93,10 @@
#define DEFAULT_MAX_PADS 16
#endif
#if defined(GEKKO)
#define DEFAULT_MOUSE_SCALE 1
#endif
#if defined(RARCH_MOBILE) || defined(HAVE_LIBNX)
#define DEFAULT_POINTER_ENABLE true
#else

View File

@ -1726,6 +1726,9 @@ static struct config_uint_setting *populate_settings_uint(settings_t *settings,
SETTING_UINT("input_max_users", input_driver_get_uint(INPUT_ACTION_MAX_USERS), true, input_max_users, false);
SETTING_UINT("fps_update_interval", &settings->uints.fps_update_interval, true, DEFAULT_FPS_UPDATE_INTERVAL, false);
SETTING_UINT("input_menu_toggle_gamepad_combo", &settings->uints.input_menu_toggle_gamepad_combo, true, menu_toggle_gamepad_combo, false);
#ifdef GEKKO
SETTING_UINT("input_mouse_scale", &settings->uints.input_mouse_scale, true, DEFAULT_MOUSE_SCALE, false);
#endif
SETTING_UINT("audio_latency", &settings->uints.audio_latency, false, 0 /* TODO */, false);
SETTING_UINT("audio_resampler_quality", &settings->uints.audio_resampler_quality, true, audio_resampler_quality_level, false);
SETTING_UINT("audio_block_frames", &settings->uints.audio_block_frames, true, 0, false);

View File

@ -454,7 +454,9 @@ typedef struct settings
unsigned input_bind_timeout;
unsigned input_bind_hold;
#ifdef GEKKO
unsigned input_mouse_scale;
#endif
unsigned input_menu_toggle_gamepad_combo;
unsigned input_keyboard_gamepad_mapping_type;
unsigned input_poll_type_behavior;

View File

@ -32,11 +32,103 @@
/* TODO/FIXME -
* fix game focus toggle */
/* gx joypad functions */
bool gxpad_mousevalid(unsigned port);
void gx_joypad_read_mouse(unsigned port, int *irx, int *iry, uint32_t *button);
typedef struct
{
int x_abs, y_abs;
int x_last, y_last;
uint32_t button;
} gx_input_mouse_t;
typedef struct gx_input
{
const input_device_driver_t *joypad;
int mouse_max;
gx_input_mouse_t *mouse;
} gx_input_t;
static int16_t gx_lightgun_state(gx_input_t *gx, unsigned id, uint16_t joy_idx)
{
struct video_viewport vp = {0};
video_driver_get_viewport_info(&vp);
int16_t res_x = 0;
int16_t res_y = 0;
int16_t res_screen_x = 0;
int16_t res_screen_y = 0;
int16_t x = 0;
int16_t y = 0;
vp.x = 0;
vp.y = 0;
vp.width = 0;
vp.height = 0;
vp.full_width = 0;
vp.full_height = 0;
x = gx->mouse[joy_idx].x_abs;
y = gx->mouse[joy_idx].y_abs;
if (!(video_driver_translate_coord_viewport_wrap(&vp, x, y,
&res_x, &res_y, &res_screen_x, &res_screen_y)))
return 0;
switch (id)
{
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_X:
return res_screen_x;
case RETRO_DEVICE_ID_LIGHTGUN_SCREEN_Y:
return res_screen_y;
case RETRO_DEVICE_ID_LIGHTGUN_TRIGGER:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_TRIGGER);
case RETRO_DEVICE_ID_LIGHTGUN_AUX_A:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_AUX_A);
case RETRO_DEVICE_ID_LIGHTGUN_AUX_B:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_AUX_B);
case RETRO_DEVICE_ID_LIGHTGUN_AUX_C:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_AUX_C);
case RETRO_DEVICE_ID_LIGHTGUN_START:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_START);
case RETRO_DEVICE_ID_LIGHTGUN_SELECT:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_LIGHTGUN_SELECT);
case RETRO_DEVICE_ID_LIGHTGUN_IS_OFFSCREEN:
return !gxpad_mousevalid(joy_idx);
default:
return 0;
}
return 0;
}
static int16_t gx_mouse_state(gx_input_t *gx, unsigned id, uint16_t joy_idx)
{
int x = 0;
int y = 0;
settings_t *settings = config_get_ptr();
int x_scale = settings->uints.input_mouse_scale;
int y_scale = settings->uints.input_mouse_scale;
x = (gx->mouse[joy_idx].x_abs - gx->mouse[joy_idx].x_last) * x_scale;
y = (gx->mouse[joy_idx].y_abs - gx->mouse[joy_idx].y_last) * y_scale;
switch (id)
{
case RETRO_DEVICE_ID_MOUSE_X:
return x;
case RETRO_DEVICE_ID_MOUSE_Y:
return y;
case RETRO_DEVICE_ID_MOUSE_LEFT:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_MOUSE_LEFT);
case RETRO_DEVICE_ID_MOUSE_RIGHT:
return gx->mouse[joy_idx].button & (1 << RETRO_DEVICE_ID_MOUSE_RIGHT);
default:
return 0;
}
}
static int16_t gx_input_state(void *data,
rarch_joypad_info_t joypad_info,
const struct retro_keybind **binds,
@ -96,6 +188,12 @@ static int16_t gx_input_state(void *data,
return input_joypad_analog(gx->joypad,
joypad_info, port, idx, id, binds[port]);
break;
case RETRO_DEVICE_MOUSE:
return gx_mouse_state(gx, id, joypad_info.joy_idx);
case RETRO_DEVICE_LIGHTGUN:
return gx_lightgun_state(gx, id, joypad_info.joy_idx);
}
return 0;
@ -111,9 +209,33 @@ static void gx_input_free_input(void *data)
if (gx->joypad)
gx->joypad->destroy();
if(gx->mouse)
free(gx->mouse);
free(gx);
}
static inline int gx_count_mouse(gx_input_t *gx)
{
int count = 0;
if(gx)
{
for(int i=0; i<DEFAULT_MAX_PADS; i++)
{
if(gx->joypad->name(i))
{
if(!strcmp(gx->joypad->name(i), "Wiimote Controller"))
{
count++;
}
}
}
}
return count;
}
static void *gx_input_init(const char *joypad_driver)
{
gx_input_t *gx = (gx_input_t*)calloc(1, sizeof(*gx));
@ -122,22 +244,72 @@ static void *gx_input_init(const char *joypad_driver)
gx->joypad = input_joypad_init_driver(joypad_driver, gx);
/* Allocate at least 1 mouse at startup */
gx->mouse_max = 1;
gx->mouse = (gx_input_mouse_t*) calloc(gx->mouse_max, sizeof(gx_input_mouse_t));
return gx;
}
static void gx_input_poll_mouse(gx_input_t *gx)
{
int count = 0;
count = gx_count_mouse(gx);
if(gx && count > 0)
{
if(count != gx->mouse_max)
{
gx_input_mouse_t* tmp = NULL;
tmp = (gx_input_mouse_t*)realloc(gx->mouse, count * sizeof(gx_input_mouse_t));
if(!tmp)
{
free(gx->mouse);
}
else
{
gx->mouse = tmp;
gx->mouse_max = count;
for(int i=0; i<gx->mouse_max; i++)
{
gx->mouse[i].x_last = 0;
gx->mouse[i].y_last = 0;
}
}
}
for(unsigned i=0; i<gx->mouse_max; i++)
{
gx->mouse[i].x_last = gx->mouse[i].x_abs;
gx->mouse[i].y_last = gx->mouse[i].y_abs;
gx_joypad_read_mouse(i, &gx->mouse[i].x_abs, &gx->mouse[i].y_abs, &gx->mouse[i].button);
}
}
}
static void gx_input_poll(void *data)
{
gx_input_t *gx = (gx_input_t*)data;
if (gx && gx->joypad)
{
gx->joypad->poll();
if(gx->mouse)
gx_input_poll_mouse(gx);
}
}
static uint64_t gx_input_get_capabilities(void *data)
{
(void)data;
return (1 << RETRO_DEVICE_JOYPAD) | (1 << RETRO_DEVICE_ANALOG);
return (1 << RETRO_DEVICE_JOYPAD) |
(1 << RETRO_DEVICE_ANALOG) |
(1 << RETRO_DEVICE_MOUSE) |
(1 << RETRO_DEVICE_LIGHTGUN);
}
static const input_device_driver_t *gx_input_get_joypad_driver(void *data)

View File

@ -29,6 +29,7 @@
#define WPADInit WPAD_Init
#define WPADDisconnect WPAD_Disconnect
#define WPADProbe WPAD_Probe
#define WPADSetDataFormat WPAD_SetDataFormat
#endif
#define WPAD_EXP_SICKSAXIS 252
@ -41,6 +42,12 @@
#define NUM_DEVICES 1
#endif
#ifdef HW_RVL
#define MAX_MOUSEBUTTONS 6
static const uint32_t gx_mousemask[MAX_MOUSEBUTTONS] = {WPAD_BUTTON_B, WPAD_BUTTON_A, WPAD_BUTTON_1, WPAD_BUTTON_2,
WPAD_BUTTON_PLUS, WPAD_BUTTON_MINUS};
#endif
enum
{
GX_GC_A = 0,
@ -102,6 +109,17 @@ static uint32_t pad_type[DEFAULT_MAX_PADS] = { WPAD_EXP_NOCONTROLLER, WPAD_EXP_N
static int16_t analog_state[DEFAULT_MAX_PADS][2][2];
static bool g_menu = false;
struct gx_mousedata
{
int32_t x, y;
uint32_t mouse_button;
bool valid;
};
static struct gx_mousedata gx_mouse[2];
static bool gx_joypad_query_pad(unsigned pad);
#ifdef HW_RVL
static bool g_quit = false;
@ -116,6 +134,45 @@ static void reset_cb(void)
g_menu = true;
}
static inline void gx_mouse_info(uint32_t joybutton, unsigned port) {
uint8_t i;
ir_t ir;
/* Get the IR data from the wiimote */
WPAD_IR(port, &ir);
if (ir.valid)
{
gx_mouse[port].valid = true;
gx_mouse[port].x = ir.x;
gx_mouse[port].y = ir.y;
}
else
{
gx_mouse[port].valid = false;
}
/* reset button state */
gx_mouse[port].mouse_button = 0;
for (i = 0; i < MAX_MOUSEBUTTONS; i++) {
gx_mouse[port].mouse_button |= (joybutton & gx_mousemask[i]) ? (1 << i) : 0;
}
/* Small adjustment to match the RA buttons */
gx_mouse[port].mouse_button = gx_mouse[port].mouse_button << 2;
}
bool gxpad_mousevalid(unsigned port)
{
return gx_mouse[port].valid;
}
void gx_joypad_read_mouse(unsigned port, int *irx, int *iry, uint32_t *button)
{
*irx = gx_mouse[port].x;
*iry = gx_mouse[port].y;
*button = gx_mouse[port].mouse_button;
}
static const char *gx_joypad_name(unsigned pad)
{
switch (pad_type[pad])
@ -150,6 +207,33 @@ static void handle_hotplug(unsigned port, uint32_t ptype)
);
}
static void check_port0_active(uint8_t pad_count)
{
settings_t *settings = config_get_ptr();
int idx = settings->uints.input_joypad_map[0];
if(pad_count < 2 && idx != 0)
{
#ifdef HW_RVL
pad_type[0] = WPAD_EXP_NONE;
#else
pad_type[0] = WPAD_EXP_GAMECUBE;
#endif
settings->uints.input_joypad_map[0] = 0;
input_autoconfigure_connect(
gx_joypad_name(0),
NULL,
gx_joypad.ident,
0, // port
0,
0
);
input_config_set_device_name(0, gx_joypad_name(0));
}
}
static bool gx_joypad_button(unsigned port, uint16_t key)
{
if (port >= DEFAULT_MAX_PADS)
@ -309,6 +393,7 @@ static int16_t WPAD_StickY(WPADData *data, u8 right)
static void gx_joypad_poll(void)
{
unsigned i, j, port;
uint8_t pad_count = 0;
uint8_t gcpad = 0;
uint64_t state_p1;
uint64_t check_menu_toggle;
@ -381,6 +466,13 @@ static void gx_joypad_poll(void)
down = wpaddata->btns_h;
/* Mouse & Lightgun: Retrieve IR data */
if (ptype == WPAD_EXP_NONE)
{
if (port == WPAD_CHAN_0 || port == WPAD_CHAN_1)
gx_mouse_info(wpaddata->btns_h, port);
}
*state_cur |= (down & WPAD_BUTTON_A) ? (UINT64_C(1) << GX_WIIMOTE_A) : 0;
*state_cur |= (down & WPAD_BUTTON_B) ? (UINT64_C(1) << GX_WIIMOTE_B) : 0;
*state_cur |= (down & WPAD_BUTTON_1) ? (UINT64_C(1) << GX_WIIMOTE_1) : 0;
@ -389,6 +481,8 @@ static void gx_joypad_poll(void)
*state_cur |= (down & WPAD_BUTTON_MINUS) ? (UINT64_C(1) << GX_WIIMOTE_MINUS) : 0;
*state_cur |= (down & WPAD_BUTTON_HOME) ? (UINT64_C(1) << GX_WIIMOTE_HOME) : 0;
if (ptype != WPAD_EXP_NUNCHUK)
{
/* Rotated d-pad on Wiimote. */
@ -439,6 +533,14 @@ static void gx_joypad_poll(void)
}
#endif
/* Count active controllers */
if(gx_joypad_query_pad(port))
pad_count++;
/* Always enable 1 pad in port 0 if there's only 1 controller connected.
* This avoids being stuck in rgui input settings. */
check_port0_active(pad_count);
if (ptype != pad_type[port])
handle_hotplug(port, ptype);
@ -482,6 +584,9 @@ static bool gx_joypad_init(void *data)
PAD_Init();
#ifdef HW_RVL
WPADInit();
/* Set IR for all wiimotes */
WPAD_SetVRes(WPAD_CHAN_ALL,640,480);
WPAD_SetDataFormat(WPAD_CHAN_ALL,WPAD_FMT_BTNS_ACC_IR);
#endif
gx_joypad_poll();

View File

@ -567,6 +567,10 @@ MSG_HASH(MENU_ENUM_LABEL_INPUT_ANALOG_DEADZONE,
"input_analog_deadzone")
MSG_HASH(MENU_ENUM_LABEL_INPUT_ANALOG_SENSITIVITY,
"input_analog_sensitivity")
#ifdef GEKKO
MSG_HASH(MENU_ENUM_LABEL_INPUT_MOUSE_SCALE,
"input_mouse_scale")
#endif
MSG_HASH(MENU_ENUM_LABEL_INPUT_BIND_MODE,
"input_bind_mode")
MSG_HASH(MENU_ENUM_LABEL_INPUT_BIND_TIMEOUT,

View File

@ -1085,6 +1085,16 @@ MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_ANALOG_SENSITIVITY,
"Analog Sensitivity"
)
#ifdef GEKKO
MSG_HASH(
MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_SCALE,
"Mouse Scale"
)
MSG_HASH(
MENU_ENUM_SUBLABEL_INPUT_MOUSE_SCALE,
"Adjust x/y scale for Wiimote lightgun speed."
)
#endif
MSG_HASH(
MENU_ENUM_LABEL_VALUE_MENU_INPUT_SWAP_OK_CANCEL,
"Menu Swap OK & Cancel Buttons"

View File

@ -230,6 +230,9 @@ default_sublabel_macro(action_bind_sublabel_audio_volume, MENU_
default_sublabel_macro(action_bind_sublabel_audio_mixer_volume, MENU_ENUM_SUBLABEL_AUDIO_MIXER_VOLUME)
#endif
default_sublabel_macro(action_bind_sublabel_audio_sync, MENU_ENUM_SUBLABEL_AUDIO_SYNC)
#if defined(GEKKO)
default_sublabel_macro(action_bind_sublabel_input_mouse_scale, MENU_ENUM_SUBLABEL_INPUT_MOUSE_SCALE)
#endif
default_sublabel_macro(action_bind_sublabel_axis_threshold, MENU_ENUM_SUBLABEL_INPUT_BUTTON_AXIS_THRESHOLD)
default_sublabel_macro(action_bind_sublabel_input_turbo_period, MENU_ENUM_SUBLABEL_INPUT_TURBO_PERIOD)
default_sublabel_macro(action_bind_sublabel_input_duty_cycle, MENU_ENUM_SUBLABEL_INPUT_DUTY_CYCLE)
@ -2402,6 +2405,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs,
case MENU_ENUM_LABEL_INPUT_BUTTON_AXIS_THRESHOLD:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_axis_threshold);
break;
#if defined(GEKKO)
case MENU_ENUM_LABEL_INPUT_MOUSE_SCALE:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_input_mouse_scale);
break;
#endif
case MENU_ENUM_LABEL_AUDIO_SYNC:
BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_audio_sync);
break;

View File

@ -3768,6 +3768,12 @@ unsigned menu_displaylist_build_list(file_list_t *list, enum menu_displaylist_ct
MENU_ENUM_LABEL_INPUT_BUTTON_AXIS_THRESHOLD,
PARSE_ONLY_FLOAT, false) == 0)
count++;
#if defined(GEKKO)
if (menu_displaylist_parse_settings_enum(list,
MENU_ENUM_LABEL_INPUT_MOUSE_SCALE,
PARSE_ONLY_UINT, false) == 0)
count++;
#endif
if (menu_displaylist_parse_settings_enum(list,
MENU_ENUM_LABEL_INPUT_ANALOG_DEADZONE,
PARSE_ONLY_FLOAT, false) == 0)

View File

@ -10349,6 +10349,21 @@ static bool setting_append_list(
menu_settings_list_current_add_range(list, list_info, 0, 2, 1, true, true);
SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED);
#ifdef GEKKO
CONFIG_UINT(
list, list_info,
&settings->uints.input_mouse_scale,
MENU_ENUM_LABEL_INPUT_MOUSE_SCALE,
MENU_ENUM_LABEL_VALUE_INPUT_MOUSE_SCALE,
DEFAULT_MOUSE_SCALE,
&group_info,
&subgroup_info,
parent_group,
general_write_handler,
general_read_handler);
menu_settings_list_current_add_range(list, list_info, 1, 4, 1, true, true);
#endif
#ifdef VITA
CONFIG_BOOL(
list, list_info,

View File

@ -772,6 +772,9 @@ enum msg_hash_enums
MENU_LABEL(INPUT_DESCRIPTOR_LABEL_SHOW),
MENU_LABEL(INPUT_DESCRIPTOR_HIDE_UNBOUND),
MENU_LABEL(INPUT_BUTTON_AXIS_THRESHOLD),
#if defined(GEKKO)
MENU_LABEL(INPUT_MOUSE_SCALE),
#endif
MENU_LABEL(INPUT_ANALOG_DEADZONE),
MENU_LABEL(INPUT_ANALOG_SENSITIVITY),
MENU_LABEL(INPUT_BIND_TIMEOUT),

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1104,3 +1104,41 @@ void WPAD_Accel(int chan, struct vec3w_t *accel)
//if(chan<0 || chan>=WPAD_MAX_WIIMOTES || accel==NULL ) return;
*accel = wpaddata[chan].accel;
}
s32 WPAD_SetDataFormat(s32 chan, s32 fmt)
{
u32 level;
s32 ret;
int i;
if(chan == WPAD_CHAN_ALL) {
for(i=WPAD_CHAN_0; i<WPAD_MAX_WIIMOTES; i++)
if((ret = WPAD_SetDataFormat(i, fmt)) < WPAD_ERR_NONE)
return ret;
return WPAD_ERR_NONE;
}
if(chan<WPAD_CHAN_0 || chan>=WPAD_MAX_WIIMOTES) return WPAD_ERR_BAD_CHANNEL;
_CPU_ISR_Disable(level);
if(__wpads_inited==WPAD_STATE_DISABLED) {
_CPU_ISR_Restore(level);
return WPAD_ERR_NOT_READY;
}
if(__wpads[chan]!=NULL) {
switch(fmt) {
case WPAD_FMT_BTNS:
case WPAD_FMT_BTNS_ACC:
case WPAD_FMT_BTNS_ACC_IR:
__wpdcb[chan].data_fmt = fmt;
__wpad_setfmt(chan);
break;
default:
_CPU_ISR_Restore(level);
return WPAD_ERR_BADVALUE;
}
}
_CPU_ISR_Restore(level);
return WPAD_ERR_NONE;
}