not64/gc_input/controller-Classic.c
Extrems 2fe266379e Added option to invert analog X axis.
Improved support for horizontal Wii Remote.
2025-02-02 12:31:45 -05:00

423 lines
12 KiB
C

/**
* Wii64 - controller-Classic.c
* Copyright (C) 2007, 2008, 2009, 2010 Mike Slegeir
* Copyright (C) 2007, 2008, 2009, 2010 sepp256
*
* Classic controller input module
*
* Wii64 homepage: http://www.emulatemii.com
* email address: tehpola@gmail.com
* sepp256@gmail.com
*
*
* This program is free software; you can redistribute it and/
* or modify it under the terms of the GNU General Public Li-
* cence as published by the Free Software Foundation; either
* version 2 of the Licence, or any later version.
*
* This program is distributed in the hope that it will be use-
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public Licence for more details.
*
**/
#include <string.h>
#include <math.h>
#include <wiiuse/wpad.h>
#include "controller.h"
enum { STICK_X, STICK_Y };
static float getStickValue(joystick_t* j, int axis, float maxAbsValue){
float angle = M_PI * j->ang / 180.0f;
float magnitude = j->mag * maxAbsValue;
float value;
if(axis == STICK_X)
value = magnitude * sinf( angle );
else
value = magnitude * cosf( angle );
return value;
}
enum {
LSTICK_AS_ANALOG = 1, RSTICK_AS_ANALOG = 2, BUTTON_AS_ANALOG = 3,
};
enum {
LSTICK_L = 0x01 << 24,
LSTICK_R = 0x02 << 24,
LSTICK_U = 0x04 << 24,
LSTICK_D = 0x08 << 24,
RSTICK_L = 0x10 << 24,
RSTICK_R = 0x20 << 24,
RSTICK_U = 0x40 << 24,
RSTICK_D = 0x80 << 24,
};
#define NUM_CLASSIC_BUTTONS 24
static button_t buttons[] = {
{ 0, ~0, "None" },
{ 1, CLASSIC_CTRL_BUTTON_UP, "D-Up" },
{ 2, CLASSIC_CTRL_BUTTON_LEFT, "D-Left" },
{ 3, CLASSIC_CTRL_BUTTON_RIGHT, "D-Right" },
{ 4, CLASSIC_CTRL_BUTTON_DOWN, "D-Down" },
{ 5, CLASSIC_CTRL_BUTTON_FULL_L, "L" },
{ 6, CLASSIC_CTRL_BUTTON_FULL_R, "R" },
{ 7, CLASSIC_CTRL_BUTTON_ZL, "ZL" },
{ 8, CLASSIC_CTRL_BUTTON_ZR, "ZR" },
{ 9, CLASSIC_CTRL_BUTTON_A, "A" },
{ 10, CLASSIC_CTRL_BUTTON_B, "B" },
{ 11, CLASSIC_CTRL_BUTTON_X, "X" },
{ 12, CLASSIC_CTRL_BUTTON_Y, "Y" },
{ 13, CLASSIC_CTRL_BUTTON_PLUS, "+" },
{ 14, CLASSIC_CTRL_BUTTON_MINUS, "-" },
{ 15, CLASSIC_CTRL_BUTTON_HOME, "Home" },
{ 16, RSTICK_U, "RS-Up" },
{ 17, RSTICK_L, "RS-Left" },
{ 18, RSTICK_R, "RS-Right" },
{ 19, RSTICK_D, "RS-Down" },
{ 20, LSTICK_U, "LS-Up" },
{ 21, LSTICK_L, "LS-Left" },
{ 22, LSTICK_R, "LS-Right" },
{ 23, LSTICK_D, "LS-Down" },
{ 24, WIIU_PRO_CTRL_BUTTON_LS, "LS" },
{ 25, WIIU_PRO_CTRL_BUTTON_RS, "RS" },
};
static button_t analog_sources[] = {
{ 0, LSTICK_AS_ANALOG, "Left Stick" },
{ 1, RSTICK_AS_ANALOG, "Right Stick" },
{ 2, BUTTON_AS_ANALOG, "D-Pad" },
};
static button_t menu_combos[] = {
{ 0, CLASSIC_CTRL_BUTTON_X|CLASSIC_CTRL_BUTTON_Y, "X+Y" },
{ 1, CLASSIC_CTRL_BUTTON_PLUS|CLASSIC_CTRL_BUTTON_MINUS, "+&-" },
{ 2, CLASSIC_CTRL_BUTTON_HOME, "Home" },
};
static int checkType(int Control, int type){
int err;
u32 expType;
err = WPAD_Probe(Control, &expType);
if(err != WPAD_ERR_NONE)
return -1;
switch(expType){
case WPAD_EXP_NONE:
controller_Wiimote.available[Control] = 1;
break;
case WPAD_EXP_NUNCHUK:
controller_WiimoteNunchuk.available[Control] = 1;
break;
case WPAD_EXP_CLASSIC:
controller_Classic.available[Control] = 1;
break;
case WPAD_EXP_WIIUPRO:
controller_WiiUPro.available[Control] = 1;
break;
case WPAD_EXP_NES:
controller_ExtenmoteNES.available[Control] = 1;
break;
case WPAD_EXP_SNES:
controller_ExtenmoteSNES.available[Control] = 1;
break;
case WPAD_EXP_N64:
controller_ExtenmoteN64.available[Control] = 1;
break;
case WPAD_EXP_GC:
controller_ExtenmoteGC.available[Control] = 1;
break;
}
return expType;
}
static unsigned int getButtonsCC(classic_ctrl_t* controller)
{
unsigned int b = controller->btns;
float stickX = getStickValue(&controller->ljs, STICK_X, 1);
float stickY = getStickValue(&controller->ljs, STICK_Y, 1);
float substickX = getStickValue(&controller->rjs, STICK_X, 1);
float substickY = getStickValue(&controller->rjs, STICK_Y, 1);
if(stickX < -.5) b |= LSTICK_L;
if(stickX > .5) b |= LSTICK_R;
if(stickY > .5) b |= LSTICK_U;
if(stickY < -.5) b |= LSTICK_D;
if(substickX < -.5) b |= RSTICK_L;
if(substickX > .5) b |= RSTICK_R;
if(substickY > .5) b |= RSTICK_U;
if(substickY < -.5) b |= RSTICK_D;
return b;
}
static int availableCC(int Control){
if(checkType(Control, WPAD_EXP_CLASSIC) != WPAD_EXP_CLASSIC){
controller_Classic.available[Control] = 0;
return 0;
} else {
return 1;
}
}
static int GetKeysCC(int Control, BUTTONS * Keys, controller_config_t* config)
{
WPADData* wpad = WPAD_Data(Control);
BUTTONS* c = Keys;
memset(c, 0, sizeof(BUTTONS));
// Only use a connected classic controller
if(!availableCC(Control))
return 0;
WPAD_ReadPending(Control, NULL);
unsigned int b = getButtonsCC(&wpad->exp.classic);
inline int isHeld(button_tp button){
return (b & button->mask) == button->mask;
}
c->R_DPAD = isHeld(config->DR);
c->L_DPAD = isHeld(config->DL);
c->D_DPAD = isHeld(config->DD);
c->U_DPAD = isHeld(config->DU);
c->START_BUTTON = isHeld(config->START);
c->B_BUTTON = isHeld(config->B);
c->A_BUTTON = isHeld(config->A);
c->Z_TRIG = isHeld(config->Z);
c->R_TRIG = isHeld(config->R);
c->L_TRIG = isHeld(config->L);
c->R_CBUTTON = isHeld(config->CR);
c->L_CBUTTON = isHeld(config->CL);
c->D_CBUTTON = isHeld(config->CD);
c->U_CBUTTON = isHeld(config->CU);
if(config->analog->mask == LSTICK_AS_ANALOG){
c->X_AXIS = getStickValue(&wpad->exp.classic.ljs, STICK_X, 80);
c->Y_AXIS = getStickValue(&wpad->exp.classic.ljs, STICK_Y, 80);
} else if(config->analog->mask == RSTICK_AS_ANALOG){
c->X_AXIS = getStickValue(&wpad->exp.classic.rjs, STICK_X, 80);
c->Y_AXIS = getStickValue(&wpad->exp.classic.rjs, STICK_Y, 80);
} else if(config->analog->mask == BUTTON_AS_ANALOG){
if(b & CLASSIC_CTRL_BUTTON_RIGHT)
c->X_AXIS = +80;
else if(b & CLASSIC_CTRL_BUTTON_LEFT)
c->X_AXIS = -80;
if(b & CLASSIC_CTRL_BUTTON_UP)
c->Y_AXIS = +80;
else if(b & CLASSIC_CTRL_BUTTON_DOWN)
c->Y_AXIS = -80;
}
if(config->inverted & 2) c->X_AXIS = -c->X_AXIS;
if(config->inverted & 1) c->Y_AXIS = -c->Y_AXIS;
// Return whether the exit button(s) are pressed
return isHeld(config->exit);
}
static unsigned int getButtonsWUP(wiiu_pro_ctrl_t* controller)
{
unsigned int b = controller->btns;
float stickX = getStickValue(&controller->ljs, STICK_X, 1);
float stickY = getStickValue(&controller->ljs, STICK_Y, 1);
float substickX = getStickValue(&controller->rjs, STICK_X, 1);
float substickY = getStickValue(&controller->rjs, STICK_Y, 1);
if(stickX < -.5) b |= LSTICK_L;
if(stickX > .5) b |= LSTICK_R;
if(stickY > .5) b |= LSTICK_U;
if(stickY < -.5) b |= LSTICK_D;
if(substickX < -.5) b |= RSTICK_L;
if(substickX > .5) b |= RSTICK_R;
if(substickY > .5) b |= RSTICK_U;
if(substickY < -.5) b |= RSTICK_D;
return b;
}
static int availableWUP(int Control){
if(checkType(Control, WPAD_EXP_WIIUPRO) != WPAD_EXP_WIIUPRO){
controller_WiiUPro.available[Control] = 0;
return 0;
} else {
return 1;
}
}
static int GetKeysWUP(int Control, BUTTONS * Keys, controller_config_t* config)
{
WPADData* wpad = WPAD_Data(Control);
BUTTONS* c = Keys;
memset(c, 0, sizeof(BUTTONS));
// Only use a connected wiiu pro controller
if(!availableWUP(Control))
return 0;
WPAD_ReadPending(Control, NULL);
unsigned int b = getButtonsWUP(&wpad->exp.wup);
inline int isHeld(button_tp button){
return (b & button->mask) == button->mask;
}
c->R_DPAD = isHeld(config->DR);
c->L_DPAD = isHeld(config->DL);
c->D_DPAD = isHeld(config->DD);
c->U_DPAD = isHeld(config->DU);
c->START_BUTTON = isHeld(config->START);
c->B_BUTTON = isHeld(config->B);
c->A_BUTTON = isHeld(config->A);
c->Z_TRIG = isHeld(config->Z);
c->R_TRIG = isHeld(config->R);
c->L_TRIG = isHeld(config->L);
c->R_CBUTTON = isHeld(config->CR);
c->L_CBUTTON = isHeld(config->CL);
c->D_CBUTTON = isHeld(config->CD);
c->U_CBUTTON = isHeld(config->CU);
if(config->analog->mask == LSTICK_AS_ANALOG){
c->X_AXIS = getStickValue(&wpad->exp.wup.ljs, STICK_X, 80);
c->Y_AXIS = getStickValue(&wpad->exp.wup.ljs, STICK_Y, 80);
} else if(config->analog->mask == RSTICK_AS_ANALOG){
c->X_AXIS = getStickValue(&wpad->exp.wup.rjs, STICK_X, 80);
c->Y_AXIS = getStickValue(&wpad->exp.wup.rjs, STICK_Y, 80);
} else if(config->analog->mask == BUTTON_AS_ANALOG){
if(b & WIIU_PRO_CTRL_BUTTON_RIGHT)
c->X_AXIS = +80;
else if(b & WIIU_PRO_CTRL_BUTTON_LEFT)
c->X_AXIS = -80;
if(b & WIIU_PRO_CTRL_BUTTON_UP)
c->Y_AXIS = +80;
else if(b & WIIU_PRO_CTRL_BUTTON_DOWN)
c->Y_AXIS = -80;
}
if(config->inverted & 2) c->X_AXIS = -c->X_AXIS;
if(config->inverted & 1) c->Y_AXIS = -c->Y_AXIS;
// Return whether the exit button(s) are pressed
return isHeld(config->exit);
}
static void pause(int Control){
WPAD_Rumble(Control, 0);
}
static void resume(int Control){
WPAD_SetDataFormat(Control, WPAD_FMT_BTNS_IR);
}
static void rumble(int Control, int rumble){
WPAD_Rumble(Control, rumble ? 1 : 0);
}
static void configure(int Control, controller_config_t* config){
// Don't know how this should be integrated
}
static void assign(int p, int v){
WPAD_ControlLed(p, WPAD_LED_1 << v);
}
static void refreshAvailableCC(void);
static void refreshAvailableWUP(void);
controller_t controller_Classic =
{ 'C',
GetKeysCC,
configure,
assign,
pause,
resume,
rumble,
refreshAvailableCC,
{0, 0, 0, 0},
NUM_CLASSIC_BUTTONS,
buttons,
sizeof(analog_sources)/sizeof(analog_sources[0]),
analog_sources,
sizeof(menu_combos)/sizeof(menu_combos[0]),
menu_combos,
{ .DU = &buttons[1], // D-Pad Up
.DL = &buttons[2], // D-Pad Left
.DR = &buttons[3], // D-Pad Right
.DD = &buttons[4], // D-Pad Down
.Z = &buttons[5], // Left Trigger
.L = &buttons[8], // Right Z
.R = &buttons[6], // Right Trigger
.A = &buttons[9], // A
.B = &buttons[10], // B
.START = &buttons[13], // +
.CU = &buttons[16], // Right Stick Up
.CL = &buttons[17], // Right Stick Left
.CR = &buttons[18], // Right Stick Right
.CD = &buttons[19], // Right Stick Down
.analog = &analog_sources[0],
.exit = &menu_combos[2],
.inverted = 0,
}
};
controller_t controller_WiiUPro =
{ 'P',
GetKeysWUP,
configure,
assign,
pause,
resume,
rumble,
refreshAvailableWUP,
{0, 0, 0, 0},
sizeof(buttons)/sizeof(buttons[0]),
buttons,
sizeof(analog_sources)/sizeof(analog_sources[0]),
analog_sources,
sizeof(menu_combos)/sizeof(menu_combos[0]),
menu_combos,
{ .DU = &buttons[1], // D-Pad Up
.DL = &buttons[2], // D-Pad Left
.DR = &buttons[3], // D-Pad Right
.DD = &buttons[4], // D-Pad Down
.Z = &buttons[7], // Left Z
.L = &buttons[6], // Right Trigger
.R = &buttons[8], // Right Z
.A = &buttons[9], // A
.B = &buttons[10], // B
.START = &buttons[13], // +
.CU = &buttons[16], // Right Stick Up
.CL = &buttons[17], // Right Stick Left
.CR = &buttons[18], // Right Stick Right
.CD = &buttons[19], // Right Stick Down
.analog = &analog_sources[0],
.exit = &menu_combos[2],
.inverted = 0,
}
};
static void refreshAvailableCC(void){
int i;
for(i=0; i<4; ++i){
availableCC(i);
}
}
static void refreshAvailableWUP(void){
int i;
for(i=0; i<4; ++i){
availableWUP(i);
}
}