mirror of
https://github.com/CTCaer/RetroArch.git
synced 2025-02-04 02:26:13 +00:00
Split wiiu_gamepad into three sub-drivers
== DETAILS Well, after a lot of code analysis, this seems like the best way to handle things on the Wii U without also completely re-architecting the I/O handling in RetroArch. How it works: - the top-level wiiu_joypad driver is now nothing more than a delegator. - the wiiu-specific drivers live in `wiiu/input/` - wpad_driver.c handles the WiiU gamepad - kpad_driver.c handles the wiimotes - hidpad_driver.c will handle HID devices like the GC adapter, DS3/DS4, etc. (I say "will" because this isn't implemented yet) == TESTING Haven't actually tried the build to see if it works, but it does compile.
This commit is contained in:
parent
8f900de65e
commit
52c754cfa8
@ -15,6 +15,10 @@ PC_DEVELOPMENT_TCP_PORT ?=4405
|
||||
|
||||
OBJ :=
|
||||
OBJ += input/drivers_hid/wiiu_hid.o
|
||||
OBJ += wiiu/input/wpad_driver.o
|
||||
OBJ += wiiu/input/kpad_driver.o
|
||||
OBJ += wiiu/input/hidpad_driver.o
|
||||
OBJ += wiiu/input/pad_functions.o
|
||||
OBJ += wiiu/system/memory.o
|
||||
OBJ += wiiu/system/exception_handler.o
|
||||
OBJ += wiiu/system/missing_libc_functions.o
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <retro_endianness.h>
|
||||
#include "../input_driver.h"
|
||||
|
||||
#define VID_NONE 0x0000
|
||||
#define VID_NINTENDO swap_if_big16(0x057e)
|
||||
#define VID_SONY swap_if_big16(0x054c)
|
||||
#define VID_MICRONTEK swap_if_big16(0x0079)
|
||||
@ -32,6 +33,7 @@
|
||||
#define VID_PS3_CLONE swap_if_big16(0x0313)
|
||||
#define VID_SNES_CLONE swap_if_big16(0x081f)
|
||||
|
||||
#define PID_NONE 0x0000
|
||||
#define PID_NINTENDO_PRO swap_if_big16(0x0330)
|
||||
#define PID_SONY_DS3 swap_if_big16(0x0268)
|
||||
#define PID_SONY_DS4 swap_if_big16(0x05c4)
|
||||
|
@ -398,7 +398,7 @@ static void log_buffer(uint8_t *data, uint32_t len) {
|
||||
|
||||
static void wiiu_hid_do_read(wiiu_adapter_t *adapter, uint8_t *data, uint32_t length)
|
||||
{
|
||||
log_buffer(data, length);
|
||||
// log_buffer(data, length);
|
||||
// do_sampling()
|
||||
// do other stuff?
|
||||
}
|
||||
|
@ -14,320 +14,131 @@
|
||||
* If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../../config.h"
|
||||
#endif
|
||||
|
||||
#include <wiiu/vpad.h>
|
||||
#include <wiiu/kpad.h>
|
||||
|
||||
#include "../input_driver.h"
|
||||
|
||||
#include "../../tasks/tasks_internal.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../../command.h"
|
||||
#include "../../gfx/video_driver.h"
|
||||
#include "string.h"
|
||||
#include <wiiu/pad_driver.h>
|
||||
|
||||
#include "wiiu_dbg.h"
|
||||
|
||||
#ifndef MAX_PADS
|
||||
#define MAX_PADS 5
|
||||
#endif
|
||||
static input_device_driver_t *pad_drivers[MAX_USERS];
|
||||
static bool ready = false;
|
||||
|
||||
#define WIIUINPUT_TYPE_WIIMOTE 0x00
|
||||
#define WIIUINPUT_TYPE_NUNCHUK 0x01
|
||||
#define WIIUINPUT_TYPE_CLASSIC_CONTROLLER 0x02
|
||||
#define WIIUINPUT_TYPE_PRO_CONTROLLER 0x1F
|
||||
#define WIIUINPUT_TYPE_NONE 0xFD
|
||||
static bool wiiu_joypad_init(void *data);
|
||||
static bool wiiu_joypad_query_pad(unsigned pad);
|
||||
static void wiiu_joypad_destroy(void);
|
||||
static bool wiiu_joypad_button(unsigned pad, uint16_t button);
|
||||
static void wiiu_joypad_get_buttons(unsigned pad, retro_bits_t *state);
|
||||
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);
|
||||
|
||||
#define GAMEPAD_OFFSET 0
|
||||
|
||||
static uint64_t pad_state[MAX_PADS];
|
||||
static uint8_t pad_type[MAX_PADS-1] = {WIIUINPUT_TYPE_NONE, WIIUINPUT_TYPE_NONE, WIIUINPUT_TYPE_NONE, WIIUINPUT_TYPE_NONE};
|
||||
|
||||
/* 3 axis - one for touch/future IR support? */
|
||||
static int16_t analog_state[MAX_PADS][3][2];
|
||||
static bool wiiu_pad_inited = false;
|
||||
|
||||
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 (pad > MAX_PADS) return "N/A";
|
||||
if(wpad_driver.query_pad(pad))
|
||||
return &wpad_driver;
|
||||
if(kpad_driver.query_pad(pad))
|
||||
return &kpad_driver;
|
||||
|
||||
if (pad == GAMEPAD_OFFSET)
|
||||
return "WIIU Gamepad";
|
||||
|
||||
if (pad < MAX_PADS)
|
||||
{
|
||||
switch (pad_type[pad-1])
|
||||
{
|
||||
case WIIUINPUT_TYPE_PRO_CONTROLLER:
|
||||
return "WIIU Pro Controller";
|
||||
|
||||
case WIIUINPUT_TYPE_WIIMOTE:
|
||||
return "Wiimote Controller";
|
||||
|
||||
case WIIUINPUT_TYPE_NUNCHUK:
|
||||
return "Nunchuk Controller";
|
||||
|
||||
case WIIUINPUT_TYPE_CLASSIC_CONTROLLER:
|
||||
return "Classic Controller";
|
||||
|
||||
case WIIUINPUT_TYPE_NONE:
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
return "unknown";
|
||||
return &hidpad_driver;
|
||||
}
|
||||
|
||||
static void wiiu_joypad_autodetect_add(unsigned autoconf_pad)
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
if (!input_autoconfigure_connect(
|
||||
wiiu_joypad_name(autoconf_pad),
|
||||
NULL,
|
||||
wiiu_joypad.ident,
|
||||
autoconf_pad,
|
||||
0,
|
||||
0
|
||||
))
|
||||
input_config_set_device_name(autoconf_pad, wiiu_joypad_name(autoconf_pad));
|
||||
}
|
||||
unsigned i;
|
||||
|
||||
static bool wiiu_joypad_button(unsigned port_num, uint16_t key)
|
||||
{
|
||||
if (port_num >= MAX_PADS)
|
||||
return false;
|
||||
|
||||
return (pad_state[port_num] & (UINT64_C(1) << key));
|
||||
}
|
||||
|
||||
static void wiiu_joypad_get_buttons(unsigned port_num, retro_bits_t *state)
|
||||
{
|
||||
if (port_num < MAX_PADS)
|
||||
{
|
||||
BITS_COPY16_PTR( state, pad_state[port_num] );
|
||||
}
|
||||
else
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
}
|
||||
|
||||
static int16_t wiiu_joypad_axis(unsigned port_num, uint32_t joyaxis)
|
||||
{
|
||||
int val = 0;
|
||||
int axis = -1;
|
||||
bool is_neg = false;
|
||||
bool is_pos = false;
|
||||
|
||||
if (joyaxis == AXIS_NONE || port_num >= MAX_PADS)
|
||||
return 0;
|
||||
|
||||
if (AXIS_NEG_GET(joyaxis) < 6)
|
||||
{
|
||||
axis = AXIS_NEG_GET(joyaxis);
|
||||
is_neg = true;
|
||||
}
|
||||
else if (AXIS_POS_GET(joyaxis) < 6)
|
||||
{
|
||||
axis = AXIS_POS_GET(joyaxis);
|
||||
is_pos = true;
|
||||
}
|
||||
|
||||
switch (axis)
|
||||
{
|
||||
case 0:
|
||||
val = analog_state[port_num][0][0];
|
||||
break;
|
||||
|
||||
case 1:
|
||||
val = analog_state[port_num][0][1];
|
||||
break;
|
||||
|
||||
case 2:
|
||||
val = analog_state[port_num][1][0];
|
||||
break;
|
||||
|
||||
case 3:
|
||||
val = analog_state[port_num][1][1];
|
||||
break;
|
||||
|
||||
//For position data; just return the unmodified value
|
||||
case 4:
|
||||
return analog_state[port_num][2][0];
|
||||
|
||||
case 5:
|
||||
return analog_state[port_num][2][1];
|
||||
}
|
||||
|
||||
if (is_neg && val > 0)
|
||||
val = 0;
|
||||
else if (is_pos && val < 0)
|
||||
val = 0;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
static int16_t scaleTP(int16_t oldMin, int16_t oldMax, int16_t newMin, int16_t newMax, int16_t val) {
|
||||
int32_t oldRange = oldMax - oldMin;
|
||||
int32_t newRange = newMax - newMin;
|
||||
return (((val - oldMin) * newRange) / oldRange) + newMin;
|
||||
}
|
||||
|
||||
static void wiiu_joypad_poll(void)
|
||||
{
|
||||
int i, c;
|
||||
VPADStatus vpad;
|
||||
VPADReadError vpadError;
|
||||
#if defined(ENABLE_CONTROLLER_PATCHER)
|
||||
int result;
|
||||
#endif
|
||||
|
||||
VPADRead(0, &vpad, 1, &vpadError);
|
||||
|
||||
if (!vpadError)
|
||||
{
|
||||
pad_state[0] = vpad.hold & VPAD_MASK_BUTTONS; /* buttons only */
|
||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = vpad.leftStick.x * 0x7FF0;
|
||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = vpad.leftStick.y * 0x7FF0;
|
||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = vpad.rightStick.x * 0x7FF0;
|
||||
analog_state[0][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = vpad.rightStick.y * 0x7FF0;
|
||||
|
||||
/* You can only call VPADData once every loop, else the second one
|
||||
won't get any data. Thus; I had to hack touch support into the existing
|
||||
joystick API. Woo-hoo? Misplaced requests for touch axis are filtered
|
||||
out in wiiu_input.
|
||||
*/
|
||||
if (vpad.tpNormal.touched && vpad.tpNormal.validity == VPAD_VALID) {
|
||||
struct video_viewport vp = {0};
|
||||
video_driver_get_viewport_info(&vp);
|
||||
VPADTouchData cal720p = {0};
|
||||
/* Calibrates data to a 720p screen, seems to clamp outer 12px */
|
||||
VPADGetTPCalibratedPoint(0, &cal720p, &(vpad.tpNormal));
|
||||
/* Recalibrate to match video driver's coordinate system */
|
||||
VPADTouchData calNative = {0};
|
||||
calNative.x = scaleTP(12, 1268, 0, vp.full_width, cal720p.x);
|
||||
calNative.y = scaleTP(12, 708, 0, vp.full_height, cal720p.y);
|
||||
/* Clamp to actual game image */
|
||||
VPADTouchData calClamped = calNative;
|
||||
bool touchClamped = false;
|
||||
if (calClamped.x < vp.x) {
|
||||
calClamped.x = vp.x;
|
||||
touchClamped = true;
|
||||
} else if (calClamped.x > vp.x + vp.width) {
|
||||
calClamped.x = vp.x + vp.width;
|
||||
touchClamped = true;
|
||||
}
|
||||
if (calClamped.y < vp.y) {
|
||||
calClamped.y = vp.y;
|
||||
touchClamped = true;
|
||||
} else if (calClamped.y > vp.y + vp.height) {
|
||||
calClamped.y = vp.y + vp.height;
|
||||
touchClamped = true;
|
||||
}
|
||||
/* Calibrate to libretro spec and save as axis 2 (idx 4,5) */
|
||||
analog_state[0][2][0] = scaleTP(vp.x, vp.x + vp.width, -0x7fff, 0x7fff, calClamped.x);
|
||||
analog_state[0][2][1] = scaleTP(vp.y, vp.y + vp.height, -0x7fff, 0x7fff, calClamped.y);
|
||||
|
||||
/* Emulating a button (#19) for touch; lets people assign it to menu
|
||||
for that traditional RetroArch Wii U feel */
|
||||
if (!touchClamped) {
|
||||
pad_state[0] |= VPAD_BUTTON_TOUCH;
|
||||
} else {
|
||||
pad_state[0] &= ~VPAD_BUTTON_TOUCH;
|
||||
}
|
||||
} else {
|
||||
/* This is probably 0 anyway */
|
||||
pad_state[0] &= ~VPAD_BUTTON_TOUCH;
|
||||
}
|
||||
|
||||
/* panic button */
|
||||
if ((vpad.hold & (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L))
|
||||
== (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L))
|
||||
command_event(CMD_EVENT_QUIT, NULL);
|
||||
}
|
||||
|
||||
for (c = 0; c < 4; c++)
|
||||
{
|
||||
KPADData kpad;
|
||||
|
||||
if (!KPADRead(c, &kpad, 1))
|
||||
continue;
|
||||
|
||||
if (pad_type[c] != kpad.device_type)
|
||||
{
|
||||
pad_type[c] = kpad.device_type;
|
||||
wiiu_joypad_autodetect_add(c + 1);
|
||||
}
|
||||
|
||||
switch (kpad.device_type)
|
||||
{
|
||||
case WIIUINPUT_TYPE_WIIMOTE:
|
||||
pad_state[c + 1] = kpad.btns_h;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = 0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = 0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = 0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = 0;
|
||||
break;
|
||||
|
||||
case WIIUINPUT_TYPE_NUNCHUK:
|
||||
pad_state[c + 1] = kpad.btns_h;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = kpad.nunchuck.stick_x * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = kpad.nunchuck.stick_y * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = 0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = 0;
|
||||
break;
|
||||
|
||||
case WIIUINPUT_TYPE_PRO_CONTROLLER:
|
||||
pad_state[c + 1] = kpad.classic.btns_h & ~0x3FC0000; /* clear out emulated analog sticks */
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = kpad.classic.lstick_x * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = kpad.classic.lstick_y * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = kpad.classic.rstick_x * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = kpad.classic.rstick_y * 0x7FF0;
|
||||
break;
|
||||
|
||||
case WIIUINPUT_TYPE_CLASSIC_CONTROLLER:
|
||||
pad_state[c + 1] = kpad.classic.btns_h & ~0xFF0000; /* clear out emulated analog sticks */
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = kpad.classic.lstick_x * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = kpad.classic.lstick_y * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_X] = kpad.classic.rstick_x * 0x7FF0;
|
||||
analog_state[c + 1][RETRO_DEVICE_INDEX_ANALOG_RIGHT] [RETRO_DEVICE_ID_ANALOG_Y] = kpad.classic.rstick_y * 0x7FF0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(i = 0; i < MAX_USERS; i++)
|
||||
{
|
||||
pad_drivers[i] = get_driver_for_pad(i);
|
||||
}
|
||||
}
|
||||
|
||||
static bool wiiu_joypad_init(void* data)
|
||||
{
|
||||
wiiu_joypad_autodetect_add(0);
|
||||
// the sub-drivers have to init first, otherwise
|
||||
// build_pad_map will fail (because all lookups will return false).
|
||||
wpad_driver.init(data);
|
||||
kpad_driver.init(data);
|
||||
hidpad_driver.init(data);
|
||||
|
||||
wiiu_joypad_poll();
|
||||
wiiu_pad_inited = true;
|
||||
(void)data;
|
||||
build_pad_map();
|
||||
|
||||
return true;
|
||||
ready = true;
|
||||
(void)data;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool wiiu_joypad_query_pad(unsigned pad)
|
||||
{
|
||||
return pad < MAX_PADS && wiiu_pad_inited;
|
||||
return ready && pad < MAX_USERS;
|
||||
}
|
||||
|
||||
static void wiiu_joypad_destroy(void)
|
||||
{
|
||||
wiiu_pad_inited = false;
|
||||
ready = false;
|
||||
|
||||
wpad_driver.destroy();
|
||||
kpad_driver.destroy();
|
||||
hidpad_driver.destroy();
|
||||
}
|
||||
|
||||
static bool wiiu_joypad_button(unsigned pad, uint16_t key)
|
||||
{
|
||||
if(!wiiu_joypad_query_pad(pad))
|
||||
return false;
|
||||
|
||||
return pad_drivers[pad]->button(pad, key);
|
||||
}
|
||||
|
||||
static void wiiu_joypad_get_buttons(unsigned pad, retro_bits_t *state)
|
||||
{
|
||||
if(!wiiu_joypad_query_pad(pad))
|
||||
return;
|
||||
|
||||
pad_drivers[pad]->get_buttons(pad, state);
|
||||
}
|
||||
|
||||
static int16_t wiiu_joypad_axis(unsigned pad, uint32_t joyaxis)
|
||||
{
|
||||
if(!wiiu_joypad_query_pad(pad))
|
||||
return 0;
|
||||
|
||||
return pad_drivers[pad]->axis(pad, joyaxis);
|
||||
}
|
||||
|
||||
static void wiiu_joypad_poll(void)
|
||||
{
|
||||
wpad_driver.poll();
|
||||
kpad_driver.poll();
|
||||
hidpad_driver.poll();
|
||||
}
|
||||
|
||||
static const char* wiiu_joypad_name(unsigned pad)
|
||||
{
|
||||
if(!wiiu_joypad_query_pad(pad))
|
||||
return "N/A";
|
||||
|
||||
return pad_drivers[pad]->name(pad);
|
||||
}
|
||||
|
||||
input_device_driver_t wiiu_joypad =
|
||||
{
|
||||
wiiu_joypad_init,
|
||||
wiiu_joypad_query_pad,
|
||||
wiiu_joypad_destroy,
|
||||
wiiu_joypad_button,
|
||||
wiiu_joypad_get_buttons,
|
||||
wiiu_joypad_axis,
|
||||
wiiu_joypad_poll,
|
||||
NULL,
|
||||
wiiu_joypad_name,
|
||||
"wiiu",
|
||||
wiiu_joypad_init,
|
||||
wiiu_joypad_query_pad,
|
||||
wiiu_joypad_destroy,
|
||||
wiiu_joypad_button,
|
||||
wiiu_joypad_get_buttons,
|
||||
wiiu_joypad_axis,
|
||||
wiiu_joypad_poll,
|
||||
NULL,
|
||||
wiiu_joypad_name,
|
||||
"wiiu",
|
||||
};
|
||||
|
||||
|
102
wiiu/include/wiiu/pad_driver.h
Normal file
102
wiiu/include/wiiu/pad_driver.h
Normal file
@ -0,0 +1,102 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2014-2017 - Ali Bouhlel
|
||||
* 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 __PAD_DRIVER__H
|
||||
#define __PAD_DRIVER__H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "../../config.h"
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <wiiu/vpad.h>
|
||||
#include <wiiu/kpad.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../../input/input_driver.h"
|
||||
#include "../../input/connect/joypad_connection.h"
|
||||
#include "../../tasks/tasks_internal.h"
|
||||
#include "../../retroarch.h"
|
||||
#include "../../verbosity.h"
|
||||
#include "../../command.h"
|
||||
#include "../../gfx/video_driver.h"
|
||||
|
||||
/**
|
||||
* Magic button sequence that triggers an exit. Useful for if the visuals are
|
||||
* corrupted, but won't work in the case of a hard lock.
|
||||
*/
|
||||
#define PANIC_BUTTON_MASK (VPAD_BUTTON_R | VPAD_BUTTON_L | VPAD_BUTTON_STICK_R | VPAD_BUTTON_STICK_L)
|
||||
|
||||
/**
|
||||
* Applies a standard transform to the Wii U gamepad's analog stick.
|
||||
* No idea where 0x7ff0 comes from.
|
||||
*/
|
||||
|
||||
#define WIIU_ANALOG_FACTOR 0x7ff0
|
||||
#define WIIU_READ_STICK(stick) ((stick) * WIIU_ANALOG_FACTOR)
|
||||
|
||||
/**
|
||||
* the wiimote driver uses these to delimit which pads correspond to the
|
||||
* wiimotes.
|
||||
*/
|
||||
#define PAD_GAMEPAD 0
|
||||
#define WIIU_WIIMOTE_CHANNELS 4
|
||||
|
||||
/**
|
||||
* These are used by the wiimote driver to identify the wiimote configuration
|
||||
* attached to the channel.
|
||||
*/
|
||||
// wiimote with Wii U Pro controller
|
||||
#define WIIMOTE_TYPE_PRO 0x1f
|
||||
// wiimote with Classic Controller
|
||||
#define WIIMOTE_TYPE_CLASSIC 0x02
|
||||
// wiimote with nunchuk
|
||||
#define WIIMOTE_TYPE_NUNCHUK 0x01
|
||||
// wiimote plus (no accessory attached)
|
||||
#define WIIMOTE_TYPE_WIIPLUS 0x00
|
||||
// wiimote not attached on this channel
|
||||
#define WIIMOTE_TYPE_NONE 0xFD
|
||||
|
||||
/**
|
||||
* The Wii U gamepad and wiimotes have 3 sets of x/y axes. The third
|
||||
* is used by the gamepad for the touchpad driver; the wiimotes is
|
||||
* currently unimplemented, but could be used for future IR pointer
|
||||
* support.
|
||||
*/
|
||||
#define WIIU_DEVICE_INDEX_TOUCHPAD 2
|
||||
|
||||
typedef struct _axis_data axis_data;
|
||||
|
||||
struct _axis_data {
|
||||
int32_t axis;
|
||||
bool is_negative;
|
||||
};
|
||||
|
||||
typedef struct _wiiu_pad_functions wiiu_pad_functions_t;
|
||||
|
||||
struct _wiiu_pad_functions {
|
||||
int16_t (*get_axis_value)(int32_t axis, int16_t state[3][2], bool is_negative);
|
||||
void (*set_axis_value)(int16_t state[3][2], int16_t left_x, int16_t left_y,
|
||||
int16_t right_x, int16_t right_y, int16_t touch_x, int16_t touch_y);
|
||||
void (*read_axis_data)(uint32_t axis, axis_data *data);
|
||||
void (*connect)(unsigned pad, input_device_driver_t *driver);
|
||||
};
|
||||
|
||||
extern wiiu_pad_functions_t pad_functions;
|
||||
extern input_device_driver_t wpad_driver;
|
||||
extern input_device_driver_t kpad_driver;
|
||||
extern input_device_driver_t hidpad_driver;
|
||||
|
||||
#endif // __PAD_DRIVER__H
|
99
wiiu/input/hidpad_driver.c
Normal file
99
wiiu/input/hidpad_driver.c
Normal file
@ -0,0 +1,99 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2014-2017 - Ali Bouhlel
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <wiiu/pad_driver.h>
|
||||
|
||||
static bool hidpad_init(void *data);
|
||||
static bool hidpad_query_pad(unsigned pad);
|
||||
static void hidpad_destroy(void);
|
||||
static bool hidpad_button(unsigned pad, uint16_t button);
|
||||
static void hidpad_get_buttons(unsigned pad, retro_bits_t *state);
|
||||
static int16_t hidpad_axis(unsigned pad, uint32_t axis);
|
||||
static void hidpad_poll(void);
|
||||
static const char *hidpad_name(unsigned pad);
|
||||
|
||||
static bool ready = false;
|
||||
|
||||
// if the GameCube adapter is attached, this will be the offset
|
||||
// of the first pad.
|
||||
static unsigned gca_pad = 0;
|
||||
static joypad_connection_t *hid_pads;
|
||||
|
||||
static bool hidpad_init(void *data)
|
||||
{
|
||||
(void *)data;
|
||||
hid_pads = pad_connection_init(MAX_USERS-(WIIU_WIIMOTE_CHANNELS+1));
|
||||
|
||||
hidpad_poll();
|
||||
ready = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool hidpad_query_pad(unsigned pad)
|
||||
{
|
||||
return (pad > WIIU_WIIMOTE_CHANNELS && pad < MAX_USERS);
|
||||
}
|
||||
|
||||
static void hidpad_destroy(void)
|
||||
{
|
||||
ready = false;
|
||||
if(hid_pads) {
|
||||
pad_connection_destroy(hid_pads);
|
||||
hid_pads = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool hidpad_button(unsigned pad, uint16_t button)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void hidpad_get_buttons(unsigned pad, retro_bits_t *state)
|
||||
{
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
}
|
||||
|
||||
static int16_t hidpad_axis(unsigned pad, uint32_t axis)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hidpad_poll(void)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *hidpad_name(unsigned pad)
|
||||
{
|
||||
if(!hidpad_query_pad(pad))
|
||||
return "n/a";
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
input_device_driver_t hidpad_driver =
|
||||
{
|
||||
hidpad_init,
|
||||
hidpad_query_pad,
|
||||
hidpad_destroy,
|
||||
hidpad_button,
|
||||
hidpad_get_buttons,
|
||||
hidpad_axis,
|
||||
hidpad_poll,
|
||||
NULL,
|
||||
hidpad_name,
|
||||
"hid"
|
||||
};
|
195
wiiu/input/kpad_driver.c
Normal file
195
wiiu/input/kpad_driver.c
Normal file
@ -0,0 +1,195 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2014-2017 - Ali Bouhlel
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This sub-driver handles the wiimotes. The Wii U has 4 channels available.
|
||||
* This also handles wiimote attachments such as the nunchuk and classic/pro
|
||||
* controllers.
|
||||
*/
|
||||
|
||||
#include <wiiu/pad_driver.h>
|
||||
|
||||
static bool kpad_init(void *data);
|
||||
static bool kpad_query_pad(unsigned pad);
|
||||
static void kpad_destroy(void);
|
||||
static bool kpad_button(unsigned pad, uint16_t button);
|
||||
static void kpad_get_buttons(unsigned pad, retro_bits_t *state);
|
||||
static int16_t kpad_axis(unsigned pad, uint32_t axis);
|
||||
static void kpad_poll(void);
|
||||
static const char *kpad_name(unsigned pad);
|
||||
|
||||
typedef struct _wiimote_state wiimote_state;
|
||||
|
||||
struct _wiimote_state {
|
||||
uint64_t button_state;
|
||||
int16_t analog_state[3][2];
|
||||
uint8_t type;
|
||||
};
|
||||
|
||||
static bool ready = false;
|
||||
|
||||
wiimote_state wiimotes[WIIU_WIIMOTE_CHANNELS];
|
||||
|
||||
static unsigned to_wiimote_channel(unsigned pad) {
|
||||
if(pad == PAD_GAMEPAD || pad > WIIU_WIIMOTE_CHANNELS)
|
||||
return 0xffffffff;
|
||||
|
||||
return pad-1;
|
||||
}
|
||||
|
||||
static unsigned to_retro_pad(unsigned channel) {
|
||||
return channel+1;
|
||||
}
|
||||
|
||||
static bool kpad_init(void *data)
|
||||
{
|
||||
(void *)data;
|
||||
|
||||
kpad_poll();
|
||||
ready = true;
|
||||
}
|
||||
|
||||
static bool kpad_query_pad(unsigned pad)
|
||||
{
|
||||
return ready && pad <= WIIU_WIIMOTE_CHANNELS && pad > PAD_GAMEPAD;
|
||||
}
|
||||
|
||||
static void kpad_destroy(void)
|
||||
{
|
||||
ready = false;
|
||||
}
|
||||
|
||||
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 & (UINT64_C(1) << button_bit);
|
||||
}
|
||||
|
||||
static void kpad_get_buttons(unsigned pad, retro_bits_t *state)
|
||||
{
|
||||
if(!kpad_query_pad(pad))
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
else
|
||||
BITS_COPY16_PTR(state, wiimotes[to_wiimote_channel(pad)].button_state);
|
||||
}
|
||||
|
||||
static int16_t kpad_axis(unsigned pad, uint32_t axis)
|
||||
{
|
||||
axis_data data;
|
||||
if(!kpad_query_pad(pad) || 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, data.is_negative);
|
||||
}
|
||||
|
||||
static void kpad_register(unsigned channel, uint8_t device_type)
|
||||
{
|
||||
if(wiimotes[channel].type != device_type) {
|
||||
wiimotes[channel].type = device_type;
|
||||
pad_functions.connect(to_retro_pad(channel), &kpad_driver);
|
||||
}
|
||||
}
|
||||
|
||||
#define WIIU_PRO_BUTTON_MASK 0x3FC0000;
|
||||
#define CLASSIC_BUTTON_MASK 0xFF0000;
|
||||
|
||||
static void kpad_poll_one_channel(unsigned channel, KPADData *kpad)
|
||||
{
|
||||
kpad_register(channel, kpad->device_type);
|
||||
switch(kpad->device_type)
|
||||
{
|
||||
case WIIMOTE_TYPE_PRO:
|
||||
wiimotes[channel].button_state = kpad->classic.btns_h & ~WIIU_PRO_BUTTON_MASK;
|
||||
pad_functions.set_axis_value(wiimotes[channel].analog_state,
|
||||
WIIU_READ_STICK(kpad->classic.lstick_x),
|
||||
WIIU_READ_STICK(kpad->classic.lstick_y),
|
||||
WIIU_READ_STICK(kpad->classic.rstick_x),
|
||||
WIIU_READ_STICK(kpad->classic.rstick_y), 0, 0);
|
||||
break;
|
||||
case WIIMOTE_TYPE_CLASSIC:
|
||||
wiimotes[channel].button_state = kpad->classic.btns_h & ~CLASSIC_BUTTON_MASK;
|
||||
pad_functions.set_axis_value(wiimotes[channel].analog_state,
|
||||
WIIU_READ_STICK(kpad->classic.lstick_x),
|
||||
WIIU_READ_STICK(kpad->classic.lstick_y),
|
||||
WIIU_READ_STICK(kpad->classic.rstick_x),
|
||||
WIIU_READ_STICK(kpad->classic.rstick_y), 0, 0);
|
||||
break;
|
||||
case WIIMOTE_TYPE_NUNCHUK:
|
||||
wiimotes[channel].button_state = kpad->btns_h;
|
||||
pad_functions.set_axis_value(wiimotes[channel].analog_state,
|
||||
WIIU_READ_STICK(kpad->nunchuck.stick_x),
|
||||
WIIU_READ_STICK(kpad->nunchuck.stick_y), 0, 0, 0, 0);
|
||||
break;
|
||||
case WIIMOTE_TYPE_WIIPLUS:
|
||||
wiimotes[channel].button_state = kpad->btns_h;
|
||||
pad_functions.set_axis_value(wiimotes[channel].analog_state, 0, 0, 0, 0, 0, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void kpad_poll(void)
|
||||
{
|
||||
unsigned channel;
|
||||
|
||||
for(channel = 0; channel < WIIU_WIIMOTE_CHANNELS; channel++)
|
||||
{
|
||||
KPADData kpad;
|
||||
|
||||
if(!KPADRead(channel, &kpad, 1))
|
||||
continue;
|
||||
|
||||
kpad_poll_one_channel(channel, &kpad);
|
||||
}
|
||||
}
|
||||
|
||||
static const char *kpad_name(unsigned pad)
|
||||
{
|
||||
pad = to_wiimote_channel(pad);
|
||||
if(pad >= WIIU_WIIMOTE_CHANNELS)
|
||||
return "unknown";
|
||||
|
||||
switch(wiimotes[pad].type)
|
||||
{
|
||||
case WIIMOTE_TYPE_PRO:
|
||||
return "WiiU Pro Controller";
|
||||
case WIIMOTE_TYPE_CLASSIC:
|
||||
return "Classic Controller";
|
||||
case WIIMOTE_TYPE_NUNCHUK:
|
||||
return "Wiimote+Nunchuk Controller";
|
||||
case WIIMOTE_TYPE_WIIPLUS:
|
||||
return "Wiimote Controller";
|
||||
case WIIMOTE_TYPE_NONE:
|
||||
default:
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
input_device_driver_t kpad_driver =
|
||||
{
|
||||
kpad_init,
|
||||
kpad_query_pad,
|
||||
kpad_destroy,
|
||||
kpad_button,
|
||||
kpad_get_buttons,
|
||||
kpad_axis,
|
||||
kpad_poll,
|
||||
NULL,
|
||||
kpad_name,
|
||||
"wiimote",
|
||||
};
|
98
wiiu/input/pad_functions.c
Normal file
98
wiiu/input/pad_functions.c
Normal file
@ -0,0 +1,98 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2014-2017 - Ali Bouhlel
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include <wiiu/pad_driver.h>
|
||||
|
||||
enum wiiu_pad_axes {
|
||||
AXIS_LEFT_ANALOG_X,
|
||||
AXIS_LEFT_ANALOG_Y,
|
||||
AXIS_RIGHT_ANALOG_X,
|
||||
AXIS_RIGHT_ANALOG_Y,
|
||||
AXIS_TOUCH_X,
|
||||
AXIS_TOUCH_Y,
|
||||
AXIS_INVALID
|
||||
};
|
||||
|
||||
static int16_t clamp_axis(int16_t value, bool is_negative) {
|
||||
if(is_negative && value > 0)
|
||||
return 0;
|
||||
if(!is_negative && value < 0)
|
||||
return 0;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int16_t wiiu_pad_get_axis_value(int32_t axis, int16_t state[3][2], bool is_negative) {
|
||||
int16_t value = 0;
|
||||
|
||||
switch(axis) {
|
||||
case AXIS_LEFT_ANALOG_X:
|
||||
value = state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X];
|
||||
break;
|
||||
case AXIS_LEFT_ANALOG_Y:
|
||||
value = state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y];
|
||||
break;
|
||||
case AXIS_RIGHT_ANALOG_X:
|
||||
value = state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X];
|
||||
break;
|
||||
case AXIS_RIGHT_ANALOG_Y:
|
||||
value = state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y];
|
||||
break;
|
||||
case AXIS_TOUCH_X:
|
||||
return state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_X];
|
||||
case AXIS_TOUCH_Y:
|
||||
return state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y];
|
||||
}
|
||||
|
||||
return clamp_axis(value, is_negative);
|
||||
}
|
||||
|
||||
void wiiu_pad_set_axis_value(int16_t state[3][2], int16_t left_x, int16_t left_y,
|
||||
int16_t right_x, int16_t right_y, int16_t touch_x, int16_t touch_y)
|
||||
{
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_X] = left_x;
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_LEFT][RETRO_DEVICE_ID_ANALOG_Y] = left_y;
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = right_x;
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = right_y;
|
||||
state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_X] = touch_x;
|
||||
state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y] = touch_y;
|
||||
}
|
||||
|
||||
|
||||
void wiiu_pad_read_axis_data(uint32_t axis, axis_data *data) {
|
||||
data->axis = AXIS_POS_GET(axis);
|
||||
data->is_negative = false;
|
||||
|
||||
if(data->axis >= AXIS_INVALID) {
|
||||
data->axis = AXIS_NEG_GET(axis);
|
||||
data->is_negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
void wiiu_pad_connect(unsigned pad, input_device_driver_t *driver) {
|
||||
if(!input_autoconfigure_connect(driver->name(pad), NULL, driver->ident,
|
||||
pad, VID_NONE, PID_NONE))
|
||||
{
|
||||
input_config_set_device_name(pad, driver->name(pad));
|
||||
}
|
||||
}
|
||||
|
||||
wiiu_pad_functions_t pad_functions = {
|
||||
wiiu_pad_get_axis_value,
|
||||
wiiu_pad_set_axis_value,
|
||||
wiiu_pad_read_axis_data,
|
||||
wiiu_pad_connect
|
||||
};
|
208
wiiu/input/wpad_driver.c
Normal file
208
wiiu/input/wpad_driver.c
Normal file
@ -0,0 +1,208 @@
|
||||
/* RetroArch - A frontend for libretro.
|
||||
* Copyright (C) 2014-2017 - Ali Bouhlel
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This driver handles the Wii U Gamepad.
|
||||
*
|
||||
* - For wiimote and wiimote attachments, see kpad_driver.c
|
||||
* - For HID controllers, see hid_driver.c
|
||||
*/
|
||||
|
||||
#include <wiiu/pad_driver.h>
|
||||
|
||||
static bool wpad_init(void *data);
|
||||
static bool wpad_query_pad(unsigned pad);
|
||||
static void wpad_destroy(void);
|
||||
static bool wpad_button(unsigned pad, uint16_t button);
|
||||
static void wpad_get_buttons(unsigned pad, retro_bits_t *state);
|
||||
static int16_t wpad_axis(unsigned pad, uint32_t axis);
|
||||
static void wpad_poll(void);
|
||||
static const char *wpad_name(unsigned pad);
|
||||
|
||||
static void update_button_state(uint64_t *state, uint32_t held_buttons);
|
||||
static void update_analog_state(int16_t state[3][2], VPADStatus *vpad);
|
||||
static void update_touch_state(int16_t state[3][2], uint64_t *buttons, VPADStatus *vpad);
|
||||
static void get_touch_coordinates(VPADTouchData *point, VPADStatus *vpad, bool *clamped);
|
||||
static void get_calibrated_point(VPADTouchData *point, struct video_viewport *viewport, VPADStatus *vpad);
|
||||
static void apply_clamping(VPADTouchData *point, struct video_viewport *viewport, bool *clamped);
|
||||
static void check_panic_button(uint32_t held_buttons);
|
||||
|
||||
static int16_t scale_touchpad(int16_t from_min, int16_t from_max,
|
||||
int16_t to_min, int16_t to_max, int16_t value );
|
||||
|
||||
static bool ready = false;
|
||||
static uint64_t button_state = 0;
|
||||
static int16_t analog_state[3][2];
|
||||
|
||||
static bool wpad_init(void *data) {
|
||||
pad_functions.connect(PAD_GAMEPAD, &wpad_driver);
|
||||
wpad_poll();
|
||||
ready = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool wpad_query_pad(unsigned pad) {
|
||||
return ready && pad == PAD_GAMEPAD;
|
||||
}
|
||||
|
||||
static void wpad_destroy(void) {
|
||||
ready = false;
|
||||
}
|
||||
|
||||
static bool wpad_button(unsigned pad, uint16_t button_bit) {
|
||||
if(!wpad_query_pad(pad))
|
||||
return false;
|
||||
|
||||
return button_state & (UINT64_C(1) << button_bit);
|
||||
}
|
||||
|
||||
static void wpad_get_buttons(unsigned pad, retro_bits_t *state) {
|
||||
if(!wpad_query_pad(pad))
|
||||
BIT256_CLEAR_ALL_PTR(state);
|
||||
else
|
||||
BITS_COPY16_PTR(state, button_state);
|
||||
}
|
||||
|
||||
static int16_t wpad_axis(unsigned pad, uint32_t axis) {
|
||||
axis_data data;
|
||||
|
||||
if(!wpad_query_pad(pad) || axis == AXIS_NONE)
|
||||
return 0;
|
||||
|
||||
pad_functions.read_axis_data(axis, &data);
|
||||
return pad_functions.get_axis_value(data.axis, analog_state, data.is_negative);
|
||||
}
|
||||
|
||||
static void wpad_poll(void) {
|
||||
VPADStatus vpad;
|
||||
VPADReadError error;
|
||||
|
||||
VPADRead(PAD_GAMEPAD, &vpad, 1, &error);
|
||||
|
||||
if(!error) {
|
||||
update_button_state(&button_state, vpad.hold);
|
||||
update_analog_state(analog_state, &vpad);
|
||||
update_touch_state(analog_state, &button_state, &vpad);
|
||||
check_panic_button(vpad.hold);
|
||||
}
|
||||
}
|
||||
|
||||
static void update_button_state(uint64_t *state, uint32_t held_buttons)
|
||||
{
|
||||
*state = held_buttons & VPAD_MASK_BUTTONS;
|
||||
}
|
||||
|
||||
static void update_analog_state(int16_t state[3][2], VPADStatus *vpad)
|
||||
{
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_X] = WIIU_READ_STICK(vpad->leftStick.x);
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_LEFT] [RETRO_DEVICE_ID_ANALOG_Y] = WIIU_READ_STICK(vpad->leftStick.y);
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_X] = WIIU_READ_STICK(vpad->rightStick.x);
|
||||
state[RETRO_DEVICE_INDEX_ANALOG_RIGHT][RETRO_DEVICE_ID_ANALOG_Y] = WIIU_READ_STICK(vpad->rightStick.y);
|
||||
}
|
||||
|
||||
static void update_touch_state(int16_t state[3][2], uint64_t *buttons, VPADStatus *vpad)
|
||||
{
|
||||
VPADTouchData point = {0};
|
||||
bool touch_clamped = false;
|
||||
|
||||
if(!vpad->tpNormal.touched || vpad->tpNormal.validity != VPAD_VALID)
|
||||
{
|
||||
*buttons &= ~VPAD_BUTTON_TOUCH;
|
||||
return;
|
||||
}
|
||||
|
||||
get_touch_coordinates(&point, vpad, &touch_clamped);
|
||||
|
||||
state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_X] = point.x;
|
||||
state[WIIU_DEVICE_INDEX_TOUCHPAD][RETRO_DEVICE_ID_ANALOG_Y] = point.y;
|
||||
|
||||
if(!touch_clamped) {
|
||||
*buttons |= VPAD_BUTTON_TOUCH;
|
||||
} else {
|
||||
*buttons &= ~VPAD_BUTTON_TOUCH;
|
||||
}
|
||||
}
|
||||
|
||||
static void get_touch_coordinates(VPADTouchData *point, VPADStatus *vpad, bool *clamped)
|
||||
{
|
||||
struct video_viewport viewport = {0};
|
||||
|
||||
video_driver_get_viewport_info(&viewport);
|
||||
get_calibrated_point(point, &viewport, vpad);
|
||||
apply_clamping(point, &viewport, clamped);
|
||||
}
|
||||
|
||||
static void get_calibrated_point(VPADTouchData *point, struct video_viewport *viewport, VPADStatus *vpad) {
|
||||
VPADTouchData calibrated720p = {0};
|
||||
|
||||
VPADGetTPCalibratedPoint(PAD_GAMEPAD, &calibrated720p, &(vpad->tpNormal));
|
||||
point->x = scale_touchpad(12, 1268, 0, viewport->full_width, calibrated720p.x);
|
||||
point->y = scale_touchpad(12, 708, 0, viewport->full_height, calibrated720p.y);
|
||||
}
|
||||
|
||||
static void apply_clamping(VPADTouchData *point, struct video_viewport *viewport, bool *clamped) {
|
||||
// clamp the x domain to the viewport
|
||||
if(point->x < viewport->x) {
|
||||
point->x = viewport->x;
|
||||
*clamped = true;
|
||||
} else if(point->x > (viewport->x + viewport->width)) {
|
||||
point->x = viewport->x + viewport->width;
|
||||
*clamped = true;
|
||||
}
|
||||
// clamp the y domain to the viewport
|
||||
if(point->y < viewport->y) {
|
||||
point->y = viewport->y;
|
||||
*clamped = true;
|
||||
} else if(point->y > (viewport->y + viewport->height)) {
|
||||
point->y = viewport->y + viewport->height;
|
||||
*clamped = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void check_panic_button(uint32_t held_buttons) {
|
||||
if( (held_buttons & PANIC_BUTTON_MASK) == PANIC_BUTTON_MASK)
|
||||
{
|
||||
command_event(CMD_EVENT_QUIT, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static int16_t scale_touchpad(int16_t from_min, int16_t from_max,
|
||||
int16_t to_min, int16_t to_max, int16_t value )
|
||||
{
|
||||
int32_t from_range = from_max - from_min;
|
||||
int32_t to_range = to_max - to_min;
|
||||
|
||||
return (((value - from_min) * to_range) / from_range) + to_min;
|
||||
}
|
||||
|
||||
static const char *wpad_name(unsigned pad) {
|
||||
return "WiiU Gamepad";
|
||||
}
|
||||
|
||||
input_device_driver_t wpad_driver =
|
||||
{
|
||||
wpad_init,
|
||||
wpad_query_pad,
|
||||
wpad_destroy,
|
||||
wpad_button,
|
||||
wpad_get_buttons,
|
||||
wpad_axis,
|
||||
wpad_poll,
|
||||
NULL,
|
||||
wpad_name,
|
||||
"gamepad",
|
||||
};
|
Loading…
x
Reference in New Issue
Block a user