Ported tehpola's gc_input code to googlecode/.

Removed unnecessary usleep now that PAD_Init is fixed.
Changed N64_B button to map to wiimote MINUS or PLUS buttons for wiimote+nunchuck config.
Changed wiimote+nunchuck to get use buttons _held_ rather than buttons _down_.
Updated wii makefiles.
Added fade message for autosave to all devices when return to menu.
This commit is contained in:
sepp256 2009-11-05 21:48:38 +00:00
parent 0f8a4838ba
commit 1feadbc937
9 changed files with 247 additions and 102 deletions

View file

@ -77,7 +77,8 @@ OBJ_PPC =r4300/ppc/MIPS-to-PPC.o \
OBJ_INPUT =gc_input/main.o \
gc_input/controller-GC.o \
gc_input/controller-Classic.o
gc_input/controller-Classic.o \
gc_input/controller-WiimoteNunchuk.o
OBJ_RSPHLE =rsp_hle-ppc/main.o \
rsp_hle-ppc/jpeg.o \

View file

@ -98,7 +98,8 @@ OBJ_PPC =r4300/ppc/MIPS-to-PPC.o \
OBJ_INPUT =gc_input/main.o \
gc_input/controller-GC.o \
gc_input/controller-Classic.o
gc_input/controller-Classic.o \
gc_input/controller-WiimoteNunchuk.o
OBJ_RSPHLE =rsp_hle-ppc/main.o \
rsp_hle-ppc/jpeg.o \

View file

@ -30,16 +30,15 @@ static int _GetKeys(int Control, BUTTONS * Keys )
BUTTONS* c = Keys;
int b = wpad->exp.classic.btns;
c->R_DPAD = (b & CLASSIC_CTRL_BUTTON_RIGHT) ? 1 : 0;
c->L_DPAD = (b & CLASSIC_CTRL_BUTTON_LEFT) ? 1 : 0;
c->D_DPAD = (b & CLASSIC_CTRL_BUTTON_DOWN) ? 1 : 0;
c->U_DPAD = (b & CLASSIC_CTRL_BUTTON_UP) ? 1 : 0;
c->START_BUTTON = (b & CLASSIC_CTRL_BUTTON_PLUS) ? 1 : 0;
c->B_BUTTON = (b & CLASSIC_CTRL_BUTTON_B) ? 1 : 0;
c->A_BUTTON = (b & CLASSIC_CTRL_BUTTON_A) ? 1 : 0;
c->R_DPAD = (b & CLASSIC_CTRL_BUTTON_RIGHT) ? 1 : 0;
c->L_DPAD = (b & CLASSIC_CTRL_BUTTON_LEFT) ? 1 : 0;
c->D_DPAD = (b & CLASSIC_CTRL_BUTTON_DOWN) ? 1 : 0;
c->U_DPAD = (b & CLASSIC_CTRL_BUTTON_UP) ? 1 : 0;
c->START_BUTTON = (b & CLASSIC_CTRL_BUTTON_PLUS) ? 1 : 0;
c->B_BUTTON = (b & CLASSIC_CTRL_BUTTON_B) ? 1 : 0;
c->A_BUTTON = (b & CLASSIC_CTRL_BUTTON_A) ? 1 : 0;
c->Z_TRIG = (b & CLASSIC_CTRL_BUTTON_ZR) ? 1 : 0;
c->Z_TRIG |= (b & CLASSIC_CTRL_BUTTON_ZL) ? 1 : 0;
c->R_TRIG = (b & CLASSIC_CTRL_BUTTON_FULL_R) ? 1 : 0;
c->L_TRIG = (b & CLASSIC_CTRL_BUTTON_FULL_L) ? 1 : 0;
@ -85,13 +84,13 @@ controller_t controller_Classic =
};
static void init(void){
int i, ret;
int i;
WPAD_ScanPads();
for(i=0; i<4; ++i){
WPADData wpad;
ret = WPAD_ReadEvent(i, &wpad);
WPADData* wpad = WPAD_Data(i);
// Only use a connected classic controller
if(!ret && wpad.err == WPAD_ERR_NONE &&
wpad.exp.type == WPAD_EXP_CLASSIC){
if(wpad->err == WPAD_ERR_NONE &&
wpad->exp.type == WPAD_EXP_CLASSIC){
controller_Classic.available[i] = 1;
WPAD_SetDataFormat(i, WPAD_DATA_EXPANSION);
} else

View file

@ -9,7 +9,7 @@ static int _GetKeys(int Control, BUTTONS * Keys )
{
if(padNeedScan){ PAD_ScanPads(); padNeedScan = 0; }
BUTTONS* c = Keys;
int b = PAD_ButtonsHeld(Control);
c->R_DPAD = (b & PAD_BUTTON_RIGHT) ? 1 : 0;
c->L_DPAD = (b & PAD_BUTTON_LEFT) ? 1 : 0;
@ -30,10 +30,10 @@ static int _GetKeys(int Control, BUTTONS * Keys )
s8 substickY = PAD_SubStickY(Control);
c->D_CBUTTON = (substickY < -64) ? 1 : 0;
c->U_CBUTTON = (substickY > 64) ? 1 : 0;
c->X_AXIS = PAD_StickX(Control);
c->Y_AXIS = PAD_StickY(Control);
// X+Y quits to menu
return (b & PAD_BUTTON_X) && (b & PAD_BUTTON_Y);
}
@ -72,9 +72,17 @@ controller_t controller_GC =
static void init(void){
PAD_Init();
PADStatus status[4];
PAD_Read(status);
do PAD_Read(status);
while((status[0].err != PAD_ERR_NO_CONTROLLER &&
status[0].err != PAD_ERR_NONE) ||
(status[1].err != PAD_ERR_NO_CONTROLLER &&
status[1].err != PAD_ERR_NONE) ||
(status[2].err != PAD_ERR_NO_CONTROLLER &&
status[2].err != PAD_ERR_NONE) ||
(status[3].err != PAD_ERR_NO_CONTROLLER &&
status[3].err != PAD_ERR_NONE));
int i;
for(i=0; i<4; ++i)
controller_GC.available[i] = status[i].err != PAD_ERR_NO_CONTROLLER;

View file

@ -0,0 +1,98 @@
/* controller-WiimoteNunchuk.c - Wiimote + Nunchuk input module
by Mike Slegeir for Mupen64-GC
*/
#include <math.h>
#include <wiiuse/wpad.h>
#include "controller.h"
#ifndef PI
#define PI 3.14159f
#endif
enum { STICK_X, STICK_Y };
static int getStickValue(joystick_t* j, int axis, int maxAbsValue){
double angle = PI * j->ang/180.0f;
double magnitude = (j->mag > 1.0f) ? 1.0f :
(j->mag < -1.0f) ? -1.0f : j->mag;
double value;
if(axis == STICK_X)
value = magnitude * sin( angle );
else
value = magnitude * cos( angle );
return (int)(value * maxAbsValue);
}
static int _GetKeys(int Control, BUTTONS * Keys )
{
if(wpadNeedScan){ WPAD_ScanPads(); wpadNeedScan = 0; }
WPADData* wpad = WPAD_Data(Control);
BUTTONS* c = Keys;
int b = wpad->btns_h;
int d2 = b & WPAD_BUTTON_2;
c->R_DPAD = (b & WPAD_BUTTON_RIGHT && d2) ? 1 : 0;
c->L_DPAD = (b & WPAD_BUTTON_LEFT && d2) ? 1 : 0;
c->D_DPAD = (b & WPAD_BUTTON_DOWN && d2) ? 1 : 0;
c->U_DPAD = (b & WPAD_BUTTON_UP && d2) ? 1 : 0;
c->START_BUTTON = (b & WPAD_BUTTON_HOME) ? 1 : 0;
c->B_BUTTON = (b & (WPAD_BUTTON_MINUS | WPAD_BUTTON_PLUS)) ? 1 : 0;
c->A_BUTTON = (b & WPAD_BUTTON_A) ? 1 : 0;
c->Z_TRIG = (b & WPAD_NUNCHUK_BUTTON_Z) ? 1 : 0;
c->R_TRIG = (b & WPAD_BUTTON_B) ? 1 : 0;
c->L_TRIG = (b & WPAD_NUNCHUK_BUTTON_C) ? 1 : 0;
c->R_CBUTTON = (b & WPAD_BUTTON_RIGHT) ? 1 : 0;
c->L_CBUTTON = (b & WPAD_BUTTON_LEFT) ? 1 : 0;
c->D_CBUTTON = (b & WPAD_BUTTON_DOWN) ? 1 : 0;
c->U_CBUTTON = (b & WPAD_BUTTON_UP) ? 1 : 0;
c->X_AXIS = getStickValue(&wpad->exp.nunchuk.js, STICK_X, 127);
c->Y_AXIS = getStickValue(&wpad->exp.nunchuk.js, STICK_Y, 127);
// 1+2 quits to menu
return (b & WPAD_BUTTON_1) && (b & WPAD_BUTTON_2);
}
static void pause(int Control){ }
static void resume(int Control){ }
static void rumble(int Control, int rumble){ }
static void configure(int Control){
// Don't know how this should be integrated
}
static void assign(int p, int v){
// TODO: Light up the LEDs appropriately
}
static void init(void);
controller_t controller_WiimoteNunchuk =
{ _GetKeys,
configure,
init,
assign,
pause,
resume,
rumble,
{0, 0, 0, 0}
};
static void init(void){
int i;
WPAD_ScanPads();
for(i=0; i<4; ++i){
WPADData* wpad = WPAD_Data(i);
// Only use a connected nunchuk
if(wpad->err == WPAD_ERR_NONE &&
wpad->exp.type == WPAD_EXP_NUNCHUK){
controller_WiimoteNunchuk.available[i] = 1;
WPAD_SetDataFormat(i, WPAD_DATA_EXPANSION);
} else
controller_WiimoteNunchuk.available[i] = 0;
}
}

View file

@ -31,4 +31,33 @@ typedef struct {
char available[4];
} controller_t;
typedef struct _virtualControllers_t {
BOOL inUse; // This virtual controller is being controlled
controller_t* control; // The type of controller being used
int number; // The physical controller number
} virtualControllers_t;
extern virtualControllers_t virtualControllers[4];
// List of all the defined controller_t's
#if defined(WII) && !defined(NO_BT)
#define num_controller_t 3
extern controller_t controller_GC;
extern controller_t controller_Classic;
extern controller_t controller_WiimoteNunchuk;
extern controller_t* controller_ts[num_controller_t];
#else // WII && !NO_BT
#define num_controller_t 1
extern controller_t controller_GC;
controller_t* controller_ts[num_controller_t];
#endif // WII && !NO_BT
void init_controller_ts(void);
void assign_controller(int whichVirtual, controller_t*, int whichPhysical);
void unassign_controller(int whichVirtual);
#endif

View file

@ -15,19 +15,26 @@
#ifdef USE_GUI
#endif
static CONTROL_INFO control_info;
static BOOL lastData[4];
static struct {
BOOL inUse;
controller_t* control;
int number;
} controllers[4];
virtualControllers_t virtualControllers[4];
controller_t* controller_ts[num_controller_t] =
#if defined(WII) && !defined(NO_BT)
{ &controller_GC, &controller_Classic,
&controller_WiimoteNunchuk,
};
#else
{ &controller_GC,
};
#endif
// Use to invoke func on the mapped controller with args
#define DO_CONTROL(Control,func,args...) \
controllers[Control].control->func(controllers[Control].number, ## args)
virtualControllers[Control].control->func( \
virtualControllers[Control].number, ## args)
unsigned char mempack_crc(unsigned char *data);
@ -35,13 +42,13 @@ static BYTE writePak(int Control, BYTE* Command){
// From N-Rage Plugin by Norbert Wladyka
BYTE* data = &Command[2];
unsigned int dwAddress = (Command[0] << 8) + (Command[1] & 0xE0);
if( dwAddress == PAK_IO_RUMBLE ){
DO_CONTROL(Control, rumble, *data);
} else if( dwAddress >= 0x8000 && dwAddress < 0x9000 ){
lastData[Control] = (*data) ? TRUE : FALSE;
}
data[32] = mempack_crc(data);
return RD_OK;
}
@ -50,13 +57,13 @@ static BYTE readPak(int Control, BYTE* Command){
// From N-Rage Plugin by Norbert Wladyka
BYTE* data = &Command[2];
unsigned int dwAddress = (Command[0] << 8) + (Command[1] & 0xE0);
int i;
if( ((dwAddress >= 0x8000) && (dwAddress < 0x9000)) && lastData[Control] )
for(i=0; i<32; ++i) data[i] = 0x80;
else
for(i=0; i<32; ++i) data[i] = 0;
data[32] = mempack_crc(data);
return RD_OK;
}
@ -67,25 +74,25 @@ static BYTE readPak(int Control, BYTE* Command){
down allowing the dll to de-initialise.
input: none
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL CloseDLL (void)
{
}
/******************************************************************
Function: ControllerCommand
Purpose: To process the raw data that has just been sent to a
Purpose: To process the raw data that has just been sent to a
specific controller.
input: - Controller Number (0 to 3) and -1 signalling end of
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
note: This function is only needed if the DLL is allowing raw
data, or the plugin is set to raw
the data that is being processed looks like this:
initilize controller: 01 03 00 FF FF FF
initilize controller: 01 03 00 FF FF FF
read controller: 01 04 01 FF FF FF FF
*******************************************************************/
EXPORT void CALL ControllerCommand ( int Control, BYTE * Command)
@ -101,11 +108,11 @@ EXPORT void CALL ControllerCommand ( int Control, BYTE * Command)
to give further information about the DLL.
input: a handle to the window that calls this function
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL DllAbout ( HWND hParent )
{
#ifdef USE_GUI
#else
char s[] = "Input plugin for Mupen64 emulator for GC\n\tby Mike Slegeir\n";
printf(s);
@ -118,7 +125,7 @@ EXPORT void CALL DllAbout ( HWND hParent )
to allow the user to configure the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL DllConfig ( HWND hParent )
{
}
@ -129,7 +136,7 @@ EXPORT void CALL DllConfig ( HWND hParent )
to allow the user to test the dll
input: a handle to the window that calls this function
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL DllTest ( HWND hParent )
{
}
@ -141,7 +148,7 @@ EXPORT void CALL DllTest ( HWND hParent )
input: a pointer to a PLUGIN_INFO stucture that needs to be
filled by the function. (see def above)
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL GetDllInfo ( PLUGIN_INFO * PluginInfo )
{
PluginInfo->Version = 0x0101;
@ -153,11 +160,11 @@ EXPORT void CALL GetDllInfo ( PLUGIN_INFO * PluginInfo )
Function: GetKeys
Purpose: To get the current state of the controllers buttons.
input: - Controller Number (0 to 3)
- A pointer to a BUTTONS structure to be filled with
- A pointer to a BUTTONS structure to be filled with
the controller state.
output: none
*******************************************************************/
extern int stop;
*******************************************************************/
extern int stop;
EXPORT void CALL GetKeys(int Control, BUTTONS * Keys )
{
if( DO_CONTROL(Control, GetKeys, Keys) ) stop = 1;
@ -165,40 +172,23 @@ EXPORT void CALL GetKeys(int Control, BUTTONS * Keys )
/******************************************************************
Function: InitiateControllers
Purpose: This function initialises how each of the controllers
Purpose: This function initialises how each of the controllers
should be handled.
input: - The handle to the main window.
- A controller structure that needs to be filled for
- A controller structure that needs to be filled for
the emulator to know how to handle each controller.
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL InitiateControllers (CONTROL_INFO ControlInfo)
{
int i,t,w;
control_info = ControlInfo;
// List of all the defined controller_t's
#if defined(WII) && !defined(NO_BT)
#define num_controller_t 2
extern controller_t controller_GC;
extern controller_t controller_Classic;
controller_t* controller_ts[num_controller_t] =
{ &controller_GC, &controller_Classic,
};
int num_assigned[num_controller_t] = { 0, 0 };
#else
#define num_controller_t 1
extern controller_t controller_GC;
controller_t* controller_ts[num_controller_t] =
{ &controller_GC,
};
int num_assigned[num_controller_t] = { 0 };
#endif
// Init all our controllers
for(i=0; i<num_controller_t; ++i)
controller_ts[i]->init();
init_controller_ts();
int num_assigned[num_controller_t];
memset(num_assigned, 0, sizeof(num_assigned));
// Map controllers in the priority given
// Outer loop: virtual controllers
for(i=0; i<4; ++i){
@ -209,26 +199,18 @@ EXPORT void CALL InitiateControllers (CONTROL_INFO ControlInfo)
for(w=num_assigned[t]; w<4 && !type->available[w]; ++w, ++num_assigned[t]);
// If we've exhausted this type, move on
if(w == 4) continue;
controllers[i].control = type;
controllers[i].inUse = 1;
controllers[i].number = w;
controllers[i].control->assign(w,i);
control_info.Controls[i].Present = 1;
if (pakMode[i] == PAKMODE_MEMPAK) control_info.Controls[i].Plugin = PLUGIN_MEMPAK;
else control_info.Controls[i].Plugin = PLUGIN_RAW;
assign_controller(i, type, w);
// Don't assign the next type over this one or the same controller
++num_assigned[t];
break;
break;
}
if(t == num_controller_t)
break;
}
// 'Initialize' the unmapped virtual controllers
for(; i<4; ++i){
controllers[i].control = NULL;
controllers[i].inUse = 0;
controllers[i].number = -1;
control_info.Controls[i].Present = 0;
control_info.Controls[i].Plugin = PLUGIN_NONE;
unassign_controller(i);
}
}
@ -236,17 +218,17 @@ EXPORT void CALL InitiateControllers (CONTROL_INFO ControlInfo)
Function: ReadController
Purpose: To process the raw data in the pif ram that is about to
be read.
input: - Controller Number (0 to 3) and -1 signalling end of
input: - Controller Number (0 to 3) and -1 signalling end of
processing the pif ram.
- Pointer of data to be processed.
output: none
output: none
note: This function is only needed if the DLL is allowing raw
data.
*******************************************************************/
EXPORT void CALL ReadController ( int Control, BYTE * Command )
{
if(Control < 0 || !Command) return;
// From N-Rage Plugin by Norbert Wladyka
switch(Command[2]){
case RD_RESETCONTROLLER:
@ -290,52 +272,79 @@ EXPORT void CALL ReadController ( int Control, BYTE * Command )
Purpose: This function is called when a rom is closed.
input: none
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL RomClosed (void)
{
}
/******************************************************************
Function: RomOpen
Purpose: This function is called when a rom is open. (from the
Purpose: This function is called when a rom is open. (from the
emulation thread)
input: none
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL RomOpen (void)
{
}
/******************************************************************
Function: WM_KeyDown
Purpose: To pass the WM_KeyDown message from the emulator to the
Purpose: To pass the WM_KeyDown message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL WM_KeyDown( WPARAM wParam, LPARAM lParam )
{
}
/******************************************************************
Function: WM_KeyUp
Purpose: To pass the WM_KEYUP message from the emulator to the
Purpose: To pass the WM_KEYUP message from the emulator to the
plugin.
input: wParam and lParam of the WM_KEYDOWN message.
output: none
*******************************************************************/
*******************************************************************/
EXPORT void CALL WM_KeyUp( WPARAM wParam, LPARAM lParam )
{
}
void pauseInput(void){
int i;
for(i=0; i<4; ++i)
if(controllers[i].inUse) DO_CONTROL(i, pause);
if(virtualControllers[i].inUse) DO_CONTROL(i, pause);
}
void resumeInput(void){
int i;
for(i=0; i<4; ++i)
if(controllers[i].inUse) DO_CONTROL(i, resume);
if(virtualControllers[i].inUse) DO_CONTROL(i, resume);
}
void init_controller_ts(void){
int i;
for(i=0; i<num_controller_t; ++i)
controller_ts[i]->init();
}
void assign_controller(int wv, controller_t* type, int wp){
virtualControllers[wv].control = type;
virtualControllers[wv].inUse = 1;
virtualControllers[wv].number = wp;
type->assign(wp,wv);
control_info.Controls[wv].Present = 1;
if (pakMode[wv] == PAKMODE_MEMPAK) control_info.Controls[wv].Plugin = PLUGIN_MEMPAK;
else control_info.Controls[wv].Plugin = PLUGIN_RAW;
}
void unassign_controller(int wv){
virtualControllers[wv].control = NULL;
virtualControllers[wv].inUse = 0;
virtualControllers[wv].number = -1;
control_info.Controls[wv].Present = 0;
control_info.Controls[wv].Plugin = PLUGIN_NONE;
}

View file

@ -149,7 +149,7 @@ void ConfigurePaksFrame::activateSubmenu(int submenu)
{
Component* defaultFocus = this;
usleep(1000); //This sleep prevents the PAD_Init() from failing
// usleep(1000); //This sleep prevents the PAD_Init() from failing
control_info_init(); //TODO: This controller poll might need rethinking when we implement Input Configuration
//All buttons: hide; unselect

View file

@ -196,7 +196,7 @@ void Func_PlayGame()
menu::Gui::getInstance().gfx->clearEFB((GXColor){0, 0, 0, 0xFF}, 0x000000);
usleep(1000); //This sleep prevents the PAD_Init() from failing
// usleep(1000); //This sleep prevents the PAD_Init() from failing
control_info_init(); //TODO: This controller re-poll might need rethinking when we implement reconfigurable input
//Wait until 'A' button released before play/resume game
@ -269,13 +269,13 @@ void Func_PlayGame()
menu::MessageBox::getInstance().fadeMessage("Automatically saved to SD card");
break;
case NATIVESAVEDEVICE_USB:
menu::MessageBox::getInstance().setMessage("Automatically saved to USB device");
menu::MessageBox::getInstance().fadeMessage("Automatically saved to USB device");
break;
case NATIVESAVEDEVICE_CARDA:
menu::MessageBox::getInstance().setMessage("Automatically saved to memcard in Slot A");
menu::MessageBox::getInstance().fadeMessage("Automatically saved to memcard in Slot A");
break;
case NATIVESAVEDEVICE_CARDB:
menu::MessageBox::getInstance().setMessage("Automatically saved to memcard in Slot B");
menu::MessageBox::getInstance().fadeMessage("Automatically saved to memcard in Slot B");
break;
}
flashramWritten = sramWritten = eepromWritten = mempakWritten = 0; //nothing new written since save