Skip to content

wiimote: flesh out Wii U Pro Controller support #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions gc/wiiuse/wiiuse.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,17 @@
#define CLASSIC_CTRL_BUTTON_RIGHT 0x8000
#define CLASSIC_CTRL_BUTTON_ALL 0xFEFF

/* wii u pro controller extra button codes */
#define WII_U_PRO_CTRL_BUTTON_RSTICK 0x00010000
#define WII_U_PRO_CTRL_BUTTON_LSTICK 0x00020000
#define WII_U_PRO_CTRL_BUTTON_EXTRA 0x00030000
#define WII_U_PRO_CTRL_BUTTON_ALL (WII_U_PRO_CTRL_BUTTON_EXTRA | CLASSIC_CTRL_BUTTON_ALL)

/* wii u pro controller extra data */
#define WII_U_PRO_CTRL_CHARGING 0x04
#define WII_U_PRO_CTRL_WIRED 0x08
#define WII_U_PRO_CTRL_BATTERY 0x70

/* guitar hero 3 button codes */
#define GUITAR_HERO_3_BUTTON_STRUM_UP 0x0001
#define GUITAR_HERO_3_BUTTON_YELLOW 0x0008
Expand Down Expand Up @@ -105,6 +116,11 @@
#define EXP_WII_BOARD 4
#define EXP_MOTION_PLUS 5

/* classic controller types */
#define CLASSIC_TYPE_ORIG 0 /* original classic controller (analog triggers) */
#define CLASSIC_TYPE_PRO 1 /* classic controller pro (no analog triggers) */
#define CLASSIC_TYPE_WIIU 2

/* IR correction types */
typedef enum ir_position_t {
WIIUSE_IR_ABOVE,
Expand Down Expand Up @@ -458,10 +474,10 @@ typedef struct nunchuk_t {
* @brief Classic controller expansion device.
*/
typedef struct classic_ctrl_t {
short btns; /**< what buttons have just been pressed */
short btns_last; /**< what buttons have just been pressed */
short btns_held; /**< what buttons are being held down */
short btns_released; /**< what buttons were just released this */
u32 btns; /**< what buttons have just been pressed */
u32 btns_last; /**< what buttons have just been pressed */
u32 btns_held; /**< what buttons are being held down */
u32 btns_released; /**< what buttons were just released this */

ubyte rs_raw;
ubyte ls_raw;
Expand All @@ -471,7 +487,12 @@ typedef struct classic_ctrl_t {

struct joystick_t ljs; /**< left joystick calibration */
struct joystick_t rjs; /**< right joystick calibration */
ubyte type; /**< original, pro, wiiu pro */
ubyte type; /**< original, pro, wiiu pro */

ubyte charging;
ubyte wired;
ubyte battery;

} classic_ctrl_t;


Expand Down
3 changes: 3 additions & 0 deletions gc/wiiuse/wpad.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ enum {
#define WPAD_CLASSIC_BUTTON_DOWN (0x4000u<<16)
#define WPAD_CLASSIC_BUTTON_RIGHT (0x8000u<<16)

#define WPAD_WII_U_PRO_BUTTON_RSTICK 0x0001
#define WPAD_WII_U_PRO_BUTTON_LSTICK 0x0002

#define WPAD_GUITAR_HERO_3_BUTTON_STRUM_UP (0x0001<<16)
#define WPAD_GUITAR_HERO_3_BUTTON_YELLOW (0x0008<<16)
#define WPAD_GUITAR_HERO_3_BUTTON_GREEN (0x0010<<16)
Expand Down
49 changes: 35 additions & 14 deletions wiiuse/classic.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
#include "io.h"

static void fix_bad_calibration_values(struct joystick_t* js, short right_stick);
static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now);
static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, ubyte *now);

/**
* @brief Handle the handshake data from the classic controller.
Expand Down Expand Up @@ -81,7 +81,7 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyt

cc->rjs = cc->ljs;

cc->type = 2;
cc->type = CLASSIC_TYPE_WIIU;
}
else {
if (data[offset] == 0xFF) {
Expand All @@ -102,9 +102,9 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyt
}

if (len > 218 && data[218])
cc->type = 1; /* classic controller pro (no analog triggers) */
cc->type = CLASSIC_TYPE_PRO;
else
cc->type = 0; /* original classic controller (analog triggers) */
cc->type = CLASSIC_TYPE_ORIG;

/* joystick stuff */
cc->ljs.max.x = data[0 + offset] / 4 == 0 ? 64 : data[0 + offset] / 4;
Expand All @@ -124,6 +124,7 @@ int classic_ctrl_handshake(struct wiimote_t* wm, struct classic_ctrl_t* cc, ubyt
fix_bad_calibration_values(&cc->ljs, 0);
fix_bad_calibration_values(&cc->rjs, 1);
}

/* handshake done */
wm->event = WIIUSE_CLASSIC_CTRL_INSERTED;
wm->exp.type = EXP_CLASSIC;
Expand Down Expand Up @@ -162,8 +163,8 @@ void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg) {
for (i = 0; i < 6; ++i)
msg[i] = (msg[i] ^ 0x17) + 0x17;
*/
if (cc->type==2) {
classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 8)));
if (cc->type==CLASSIC_TYPE_WIIU) {
classic_ctrl_pressed_buttons(cc, msg + 8);

/* 12-bit little endian values adjusted to 8-bit */
cc->ljs.pos.x = (msg[0] >> 4) | (msg[1] << 4);
Expand All @@ -173,11 +174,16 @@ void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg) {

cc->ls_raw = cc->btns & CLASSIC_CTRL_BUTTON_FULL_L ? 0x1F : 0;
cc->rs_raw = cc->btns & CLASSIC_CTRL_BUTTON_FULL_R ? 0x1F : 0;

/* Wii U pro controller specific data */
cc->charging = !(((msg[10] & WII_U_PRO_CTRL_CHARGING) >> 2) & 1);
cc->wired = !(((msg[10] & WII_U_PRO_CTRL_WIRED) >> 3) & 1);
cc->battery = ((msg[10] & WII_U_PRO_CTRL_BATTERY) >> 4) & 7;
}
else {
classic_ctrl_pressed_buttons(cc, BIG_ENDIAN_SHORT(*(short*)(msg + 4)));
classic_ctrl_pressed_buttons(cc, msg + 4);

/* left/right buttons */
/* left/right triggers */
cc->ls_raw = (((msg[2] & 0x60) >> 2) | ((msg[3] & 0xE0) >> 5));
cc->rs_raw = (msg[3] & 0x1F);

Expand All @@ -194,6 +200,11 @@ void classic_ctrl_event(struct classic_ctrl_t* cc, ubyte* msg) {
cc->ljs.pos.y = (msg[1] & 0x3F);
cc->rjs.pos.x = ((msg[0] & 0xC0) >> 3) | ((msg[1] & 0xC0) >> 5) | ((msg[2] & 0x80) >> 7);
cc->rjs.pos.y = (msg[2] & 0x1F);

/* wipe Wii U pro controller specific data */
cc->charging = 0;
cc->wired = 0;
cc->battery = 0;
}

#ifndef GEKKO
Expand Down Expand Up @@ -221,19 +232,29 @@ static void fix_bad_calibration_values(struct joystick_t* js, short right_stick)
* @param cc A pointer to a classic_ctrl_t structure.
* @param msg The message byte specified in the event packet.
*/
static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, short now) {
/* message is inverted (0 is active, 1 is inactive) */
now = ~now & CLASSIC_CTRL_BUTTON_ALL;
static void classic_ctrl_pressed_buttons(struct classic_ctrl_t* cc, ubyte *now) {
u32 buttons = (now[0] << 0x8) | now[1];

if (cc->type==CLASSIC_TYPE_WIIU) {
/* append Wii U Pro Controller stick buttons to top 16 bits */
buttons |= (now[2] << 0x10);

/* message is inverted (0 is active, 1 is inactive) */
buttons = ~buttons & WII_U_PRO_CTRL_BUTTON_ALL;
} else {
/* message is inverted (0 is active, 1 is inactive) */
buttons = ~buttons & CLASSIC_CTRL_BUTTON_ALL;
}

/* preserve old btns pressed */
cc->btns_last = cc->btns;

/* pressed now & were pressed, then held */
cc->btns_held = (now & cc->btns);
cc->btns_held = (buttons & cc->btns);

/* were pressed or were held & not pressed now, then released */
cc->btns_released = ((cc->btns | cc->btns_held) & ~now);
cc->btns_released = ((cc->btns | cc->btns_held) & ~buttons);

/* buttons pressed now */
cc->btns = now;
cc->btns = buttons;
}
1 change: 0 additions & 1 deletion wiiuse/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ void wiiuse_handshake_expansion(struct wiimote_t *wm,ubyte *data,uword len)
case 3:
if(!data || !len) return;
id = BIG_ENDIAN_LONG(*(int*)(&data[220]));
//printf("New exp type: %d\n", id);

switch(id) {
case EXP_ID_CODE_NUNCHUK:
Expand Down
11 changes: 8 additions & 3 deletions wiiuse/wpad.c
Original file line number Diff line number Diff line change
Expand Up @@ -492,7 +492,12 @@ static void __wpad_calc_data(WPADData *data,WPADData *lstate,struct accel_t *acc
cc->l_shoulder = ((f32)cc->ls_raw/0x1F);
calc_joystick_state(&cc->ljs, cc->ljs.pos.x, cc->ljs.pos.y);
calc_joystick_state(&cc->rjs, cc->rjs.pos.x, cc->rjs.pos.y);
data->btns_h |= (data->exp.classic.btns<<16);

// overwrite Wiimote buttons (unused) with extra Wii U Pro Controller stick buttons
if (data->exp.classic.type == CLASSIC_TYPE_WIIU)
data->btns_h = (data->exp.classic.btns & WII_U_PRO_CTRL_BUTTON_EXTRA) >> 16;

data->btns_h |= ((data->exp.classic.btns & CLASSIC_CTRL_BUTTON_ALL)<<16);
}
break;

Expand Down Expand Up @@ -765,9 +770,9 @@ static void __wpad_eventCB(struct wiimote_t *wm,s32 event)
case WIIUSE_ACK:
break;
default:
WIIUSE_DEBUG("__wpad_eventCB(%02x)", event);
WIIUSE_DEBUG("__wpad_eventCB(%02x)\n", event);
break;
}
}
}

void __wpad_disconnectCB(struct bd_addr *pad_addr, u8 reason)
Expand Down