More improvements to new wiimote plugin: Added emulated Drums/Guitar extensions. Wiimote rumble now handled for every output report. Fixed some mem leaks. Hopefully fixed a floating point exception in Linux, thanks to glennrics.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5403 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2010-04-24 00:44:10 +00:00
parent 1d8db5ce3f
commit 23689387e1
24 changed files with 540 additions and 166 deletions

View File

@ -57,6 +57,7 @@ public:
{
public:
virtual std::string GetName() const = 0;
virtual ~Control() {}
};
//
@ -138,6 +139,8 @@ public:
public:
ControlQualifier() {};
ControlQualifier( const std::string& _name ) : name(_name) {}
virtual ~ControlQualifier() {}
virtual bool operator==(const Device::Control* const in) const;
void FromControl(const Device::Control* const in);
@ -184,6 +187,7 @@ public:
{
public:
ControlReference( const bool _is_input ) : range(1), is_input(_is_input), device(NULL) {}
virtual ~ControlReference() {}
virtual ControlState State( const ControlState state = 0 ) = 0;
virtual bool Detect( const unsigned int ms, const unsigned int count = 1 ) = 0;

View File

@ -48,7 +48,7 @@ void Plugin::SaveConfig()
(*i)->SaveConfig( inifile[ (*i)->GetName() ] );
// dont need to save empty values
inifile.Clean();
//inifile.Clean();
std::ofstream file;
file.open( (std::string(File::GetUserPath(D_CONFIG_IDX)) + ini_name + ".ini" ).c_str() );

View File

@ -714,24 +714,36 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
}
break;
case GROUP_TYPE_MIXED_TRIGGERS :
case GROUP_TYPE_TRIGGERS :
{
wxBitmap bitmap(64+12+1, int(6*group->controls.size())+1);
int height = (int)(6 * group->controls.size());
int width = 64+12+1;
if (GROUP_TYPE_TRIGGERS == group->type)
{
height *= 2;
width = 64;
}
wxBitmap bitmap(width, height+1);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0] );
_connect_macro_( threshold_cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
std::vector<ControllerEmu::ControlGroup::Setting*>::const_iterator
i = group->settings.begin(),
e = group->settings.end();
for ( ; i!=e; ++i )
{
PadSettingChoice* cbox = new PadSettingChoice( parent, *i );
_connect_macro_( cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
options.push_back( cbox );
wxBoxSizer* const szr = new wxBoxSizer( wxHORIZONTAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( (*i)->name ) ), 0, wxCENTER|wxRIGHT, 5 );
szr->Add( cbox, 0, wxRIGHT, 5 );
Add( szr, 0, wxALL|wxCENTER, 5 );
}
options.push_back( threshold_cbox );
wxBoxSizer* const szr = new wxBoxSizer( wxHORIZONTAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[0]->name ) ), 0, wxCENTER|wxRIGHT, 5 );
szr->Add( threshold_cbox, 0, wxRIGHT, 5 );
Add( szr, 0, wxALL|wxCENTER, 5 );
Add( static_bitmap, 0, wxALL|wxCENTER, 5 );
}
break;

View File

@ -79,9 +79,9 @@ void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
else
dc.DrawRectangle( 16, 16, 32, 32 );
// deadzone circle
if ( GROUP_TYPE_CURSOR != (*g)->control_group->type )
{
// deadzone circle
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.DrawCircle( 32, 32, ((*g)->control_group)->settings[0]->value * 32 );
@ -166,7 +166,52 @@ void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
(*g)->static_bitmap->SetBitmap( bitmap );
}
break;
case GROUP_TYPE_TRIGGERS :
{
const unsigned int trigger_count = ((unsigned int)((*g)->control_group->controls.size()));
// setup
wxBitmap bitmap( 64, 12*trigger_count+1);
wxMemoryDC dc;
dc.SelectObject(bitmap);
dc.Clear();
// draw the shit
dc.SetPen(*wxGREY_PEN);
ControlState deadzone = (*g)->control_group->settings[0]->value;
unsigned int* const trigs = new unsigned int[trigger_count];
((ControllerEmu::Triggers*)(*g)->control_group)->GetState( trigs, 64 );
for ( unsigned int n = 0; n < trigger_count; ++n )
{
ControlState trig_r = (*g)->control_group->controls[n]->control_ref->State();
dc.SetBrush(*wxGREY_BRUSH);
dc.DrawRectangle(0, n*12, trig_r*64, 14);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle(0, n*12, trigs[n], 14);
}
delete[] trigs;
// deadzone box
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, deadzone*64, trigger_count*14);
// box outline
// Windows XP color
dc.SetPen(wxPen(_T("#7f9db9")));
dc.DrawRectangle(0, 0, bitmap.GetWidth(), bitmap.GetHeight());
// done drawing
dc.SelectObject(wxNullBitmap);
// set the shit
(*g)->static_bitmap->SetBitmap( bitmap );
}
break;
case GROUP_TYPE_MIXED_TRIGGERS :
{
const unsigned int trigger_count = ((unsigned int)((*g)->control_group->controls.size() / 2));
@ -194,6 +239,9 @@ void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
dc.DrawRectangle(trig_a*64, n*12, 64+20, 14);
dc.DrawRectangle(64, n*12, 32, 14);
}
// threshold box
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(thresh*64, 0, 128, trigger_count*14);

View File

@ -4,11 +4,9 @@
#include <X11/Xlib.h>
#endif
const char modifier[] = "Modifier";
ControllerEmu::~ControllerEmu()
{
// control groups
std::vector<ControlGroup*>::const_iterator
i = groups.begin(),
e = groups.end();
@ -18,12 +16,14 @@ ControllerEmu::~ControllerEmu()
ControllerEmu::ControlGroup::~ControlGroup()
{
// controls
std::vector<Control*>::const_iterator
ci = controls.begin(),
ce = controls.end();
for ( ; ci!=ce; ++ci )
delete *ci;
// settings
std::vector<Setting*>::const_iterator
si = settings.begin(),
se = settings.end();
@ -31,6 +31,20 @@ ControllerEmu::ControlGroup::~ControlGroup()
delete *si;
}
ControllerEmu::Extension::~Extension()
{
// attachments
std::vector<ControllerEmu*>::const_iterator
ai = attachments.begin(),
ae = attachments.end();
for ( ; ai!=ae; ++ai )
delete *ai;
}
ControllerEmu::ControlGroup::Control::~Control()
{
delete control_ref;
}
void ControllerEmu::UpdateReferences( ControllerInterface& devi )
{
std::vector<ControlGroup*>::const_iterator
@ -170,7 +184,7 @@ void ControllerEmu::ControlGroup::SaveConfig( IniFile::Section& sec, const std::
for ( ; ci!=ce; ++ci )
{
// control and dev qualifier
sec[group + (*ci)->name] = (*ci)->control_ref->control_qualifier.name;
sec.Set( group+(*ci)->name, (*ci)->control_ref->control_qualifier.name );
sec.Set( group+(*ci)->name+"/Device", (*ci)->control_ref->device_qualifier.ToString(), defdev );
// range
@ -200,7 +214,7 @@ void ControllerEmu::SaveConfig( IniFile::Section& sec, const std::string& base )
{
const std::string defdev = default_device.ToString();
if ( base.empty() )
sec[ std::string(" ") + base + "Device" ] = defdev;
sec.Set( std::string(" ") + base + "Device", defdev );
std::vector<ControlGroup*>::const_iterator i = groups.begin(),
e = groups.end();
@ -213,7 +227,7 @@ ControllerEmu::AnalogStick::AnalogStick( const char* const _name ) : ControlGrou
for ( unsigned int i = 0; i < 4; ++i )
controls.push_back( new Input( named_directions[i] ) );
controls.push_back( new Input( modifier ) );
controls.push_back( new Input( "Modifier" ) );
settings.push_back( new Setting("Dead Zone", 0, 1, 50 ) );
settings.push_back( new Setting("Square Stick", 0 ) );
@ -230,6 +244,11 @@ ControllerEmu::MixedTriggers::MixedTriggers( const char* const _name ) : Control
settings.push_back( new Setting("Threshold", 0.9f ) );
}
ControllerEmu::Triggers::Triggers( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_TRIGGERS )
{
settings.push_back( new Setting("Dead Zone", 0, 1, 50 ) );
}
ControllerEmu::Force::Force( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_FORCE )
{
controls.push_back( new Input( "X-" ) );
@ -255,7 +274,7 @@ ControllerEmu::Tilt::Tilt( const char* const _name ) : ControlGroup( _name, GROU
controls.push_back( new Input( "Left" ) );
controls.push_back( new Input( "Right" ) );
controls.push_back( new Input( modifier ) );
controls.push_back( new Input( "Modifier" ) );
settings.push_back( new Setting("Dead Zone", 0, 1, 50 ) );
settings.push_back( new Setting("Circle Stick", 0 ) );
@ -275,31 +294,6 @@ ControllerEmu::Cursor::Cursor( const char* const _name, const SWiimoteInitialize
}
//void GetMousePos(float& x, float& y, const SWiimoteInitialize* const wiimote_initialize)
//{
//#ifdef _WIN32
// // Get the cursor position for the entire screen
// POINT point;
// GetCursorPos(&point);
// // Get the cursor position relative to the upper left corner of the rendering window
// ScreenToClient(wiimote_initialize->hWnd, &point);
//
// // Get the size of the rendering window. (In my case Rect.top and Rect.left was zero.)
// RECT Rect;
// GetClientRect(wiimote_initialize->hWnd, &Rect);
// // Width and height is the size of the rendering window
// float WinWidth = (float)(Rect.right - Rect.left);
// float WinHeight = (float)(Rect.bottom - Rect.top);
// float XOffset = 0, YOffset = 0;
// float PictureWidth = WinWidth, PictureHeight = WinHeight;
//#endif
//
// x = ((float)point.x - XOffset) / PictureWidth;
// y = ((float)point.y - YOffset) / PictureHeight;
// x *=2; x-=1;
// y *=2; y-=1;
//}
void GetMousePos(float& x, float& y, const SWiimoteInitialize* const wiimote_initialize)
{
unsigned int win_width = 2, win_height = 2;

View File

@ -28,6 +28,7 @@ enum
GROUP_TYPE_EXTENSION,
GROUP_TYPE_TILT,
GROUP_TYPE_CURSOR,
GROUP_TYPE_TRIGGERS,
};
const char * const named_directions[] =
@ -55,9 +56,7 @@ public:
: control_ref(_ref), name(_name){}
public:
//virtual std::string GetName() const = 0;
virtual ~Control();
ControllerInterface::ControlReference* const control_ref;
const char * const name;
@ -105,7 +104,6 @@ public:
void LoadConfig( IniFile::Section& sec, const std::string& defdev = "", const std::string& base = "" );
void SaveConfig( IniFile::Section& sec, const std::string& defdev = "", const std::string& base = "" );
//const unsigned int type;
const char* const name;
const unsigned int type;
@ -147,7 +145,7 @@ public:
ControlState ang_cos = cos(ang);
// the amt a full square stick would have at current angle
ControlState square_full = std::min( 1/abs(ang_sin), 1/abs(ang_cos) );
ControlState square_full = std::min( ang_sin ? 1/abs(ang_sin) : 2, ang_cos ? 1/abs(ang_cos) : 2 );
// the amt a full stick would have that was ( user setting squareness) at current angle
// i think this is more like a pointed circle rather than a rounded square like it should be
@ -217,6 +215,23 @@ public:
};
class Triggers : public ControlGroup
{
public:
template <typename S>
void GetState( S* analog, const unsigned int range )
{
const unsigned int trig_count = ((unsigned int) (controls.size()));
const ControlState deadzone = settings[0]->value;
for ( unsigned int i=0; i<trig_count; ++i,++analog )
*analog = S( std::max(controls[i]->control_ref->State() - deadzone, 0.0f) / (1 - deadzone) * range );
}
Triggers( const char* const _name );
};
class Force : public ControlGroup
{
public:
@ -259,7 +274,7 @@ public:
ControlState ang_cos = cos(ang);
// the amt a full square stick would have at current angle
ControlState square_full = std::min( 1/abs(ang_sin), 1/abs(ang_cos) );
ControlState square_full = std::min( ang_sin ? 1/abs(ang_sin) : 2, ang_cos ? 1/abs(ang_cos) : 2 );
// the amt a full stick would have that was ( user setting circular ) at current angle
// i think this is more like a pointed circle rather than a rounded square like it should be
@ -292,12 +307,6 @@ public:
template <typename C>
void GetState( C* const x, C* const y, C* const forward, const bool adjusted = false )
{
// this is flawed when GetState() isn't called at regular intervals
//const ControlState zz = controls[4]->control_ref->State();
//if (z < zz)
// z = std::min( z + 0.01f, zz );
//else
// z = std::max( z - 0.01f, zz );
const ControlState z = controls[4]->control_ref->State();
// hide
@ -335,7 +344,6 @@ public:
}
private:
//ControlState z;
const SWiimoteInitialize* const wiimote_initialize;
};
@ -347,6 +355,7 @@ public:
: ControlGroup( _name, GROUP_TYPE_EXTENSION )
, switch_extension(0)
, active_extension(0) {}
~Extension();
void GetState( u8* const data, const bool focus = true );
@ -368,8 +377,6 @@ public:
std::vector< ControlGroup* > groups;
ControlGroup* options;
ControllerInterface::DeviceQualifier default_device;
};

View File

@ -64,8 +64,8 @@ GCPad::GCPad( const unsigned int index ) : m_index(index)
m_dpad->controls.push_back( new ControlGroup::Input( named_directions[i] ) );
// options
groups.push_back( options = new ControlGroup( "Options" ) );
options->settings.push_back( new ControlGroup::Setting( "Background Input", false ) );
groups.push_back( m_options = new ControlGroup( "Options" ) );
m_options->settings.push_back( new ControlGroup::Setting( "Background Input", false ) );
}
@ -76,25 +76,33 @@ std::string GCPad::GetName() const
void GCPad::GetInput( SPADStatus* const pad )
{
std::vector< ControlGroup::Control* >::iterator i,e;
// if window has focus or background input enabled
if (g_PADInitialize->pRendererHasFocus() || m_options[0].settings[0]->value )
{
// buttons
m_buttons->GetState( &pad->button, button_bitmasks );
// buttons
m_buttons->GetState( &pad->button, button_bitmasks );
// TODO: set analog A/B analog to full or w/e, prolly not needed
// TODO: set analog A/B to full or w/e
// dpad
m_dpad->GetState( &pad->button, dpad_bitmasks );
// dpad
m_dpad->GetState( &pad->button, dpad_bitmasks );
// sticks
m_main_stick->GetState( &pad->stickX, &pad->stickY, 0x80, 127 );
m_c_stick->GetState( &pad->substickX, &pad->substickY, 0x80, 127 );
// sticks
m_main_stick->GetState( &pad->stickX, &pad->stickY, 0x80, 127 );
m_c_stick->GetState( &pad->substickX, &pad->substickY, 0x80, 127 );
// triggers
m_triggers->GetState( &pad->button, trigger_bitmasks, &pad->triggerLeft, 0xFF );
// triggers
m_triggers->GetState( &pad->button, trigger_bitmasks, &pad->triggerLeft, 0xFF );
}
else
{
// center sticks
memset( &pad->stickX, 0x80, 4 );
}
}
void GCPad::SetOutput( const bool on )
{
m_rumble->controls[0]->control_ref->State( on );
// only rumble if window has focus or background input is enabled
m_rumble->controls[0]->control_ref->State( on && (g_PADInitialize->pRendererHasFocus() || m_options[0].settings[0]->value) );
}

View File

@ -3,6 +3,8 @@
#include <ControllerEmu.h>
extern SPADInitialize *g_PADInitialize;
class GCPad : public ControllerEmu
{
public:
@ -22,6 +24,7 @@ private:
Buttons* m_dpad;
MixedTriggers* m_triggers;
ControlGroup* m_rumble;
ControlGroup* m_options;
const unsigned int m_index;

View File

@ -161,19 +161,8 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus)
}
_last_numPAD = _numPAD;
// if we want background input or have focus
if ( g_plugin.controllers[_numPAD]->options[0].settings[0]->value || g_PADInitialize->pRendererHasFocus() )
{
// get input
((GCPad*)g_plugin.controllers[ _numPAD ])->GetInput( _pPADStatus );
}
else
{
// center sticks
memset( &_pPADStatus->stickX, 0x80, 4 );
// stop rumble
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( false );
}
// get input
((GCPad*)g_plugin.controllers[ _numPAD ])->GetInput( _pPADStatus );
// leave
g_plugin.controls_crit.Leave();
@ -202,9 +191,9 @@ void PAD_Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
// enter
if ( g_plugin.controls_crit.TryEnter() )
{
// only on/off rumble, if we have focus or background input on
if ( g_plugin.controllers[_numPAD]->options[0].settings[0]->value || g_PADInitialize->pRendererHasFocus() )
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( 1 == _uType && _uStrength > 2 );
// TODO: this has potential to not stop rumble if user is messing with GUI at the perfect time
// set rumble
((GCPad*)g_plugin.controllers[ _numPAD ])->SetOutput( 1 == _uType && _uStrength > 2 );
// leave
g_plugin.controls_crit.Leave();

View File

@ -571,6 +571,22 @@
RelativePath=".\Src\WiimoteEmu\Attachment\Classic.h"
>
</File>
<File
RelativePath=".\Src\WiimoteEmu\Attachment\Drums.cpp"
>
</File>
<File
RelativePath=".\Src\WiimoteEmu\Attachment\Drums.h"
>
</File>
<File
RelativePath=".\Src\WiimoteEmu\Attachment\Guitar.cpp"
>
</File>
<File
RelativePath=".\Src\WiimoteEmu\Attachment\Guitar.h"
>
</File>
<File
RelativePath=".\Src\WiimoteEmu\Attachment\Nunchuk.cpp"
>

View File

@ -11,6 +11,8 @@ files = [
'WiimoteEmu/Attachment/Classic.cpp',
'WiimoteEmu/Attachment/Attachment.cpp',
'WiimoteEmu/Attachment/Nunchuk.cpp',
'WiimoteEmu/Attachment/Drums.cpp',
'WiimoteEmu/Attachment/Guitar.cpp',
'WiimoteEmu/EmuSubroutines.cpp',
'WiimoteEmu/Encryption.cpp',
'WiimoteNew.cpp',

View File

@ -5,8 +5,6 @@ namespace WiimoteEmu
{
// Extension device IDs to be written to the last bytes of the extension reg
static const u8 gh3glp_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x03 };
static const u8 ghwtdrums_id[] = { 0x01, 0x00, 0xa4, 0x20, 0x01, 0x03 };
// The id for nothing inserted
static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e };
// The id for a partially inserted extension

View File

@ -4,7 +4,7 @@
namespace WiimoteEmu
{
static const u8 classic_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01 };
static const u8 classic_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x01 };
/* Classic Controller calibration */
static const u8 classic_calibration[] =
{
@ -68,7 +68,7 @@ const u16 classic_dpad_bitmasks[] =
CLASSIC_PAD_UP, CLASSIC_PAD_DOWN, CLASSIC_PAD_LEFT, CLASSIC_PAD_RIGHT
};
Classic::Classic() : Attachment( "Classic Controller" )
Classic::Classic() : Attachment( "Classic" )
{
// buttons
groups.push_back( m_buttons = new Buttons( "Buttons" ) );

View File

@ -0,0 +1,92 @@
#include "Drums.h"
namespace WiimoteEmu
{
static const u8 drums_id[] = { 0x01, 0x00, 0xa4, 0x20, 0x01, 0x03 };
// drums buttons
#define DRUMS_PLUS 0x04
#define DRUMS_MINUS 0x10
#define DRUMS_BASS 0x0400
#define DRUMS_BLUE 0x0800
#define DRUMS_GREEN 0x1000
#define DRUMS_YELLOW 0x2000
#define DRUMS_RED 0x4000
#define DRUMS_ORANGE 0x8000
const u16 drum_pad_bitmasks[] =
{
DRUMS_RED,
DRUMS_BLUE,
DRUMS_GREEN,
DRUMS_YELLOW,
DRUMS_ORANGE,
DRUMS_BASS,
};
const char* drum_pad_names[] =
{
"Red","Blue","Green","Yellow","Orange","Bass"
};
const u16 drum_button_bitmasks[] =
{
DRUMS_MINUS,
DRUMS_PLUS,
};
Drums::Drums() : Attachment( "Drums" )
{
// pads
groups.push_back( m_pads = new Buttons( "Pads" ) );
for ( unsigned int i = 0; i < sizeof(drum_pad_names)/sizeof(*drum_pad_names); ++i )
m_pads->controls.push_back( new ControlGroup::Input( drum_pad_names[i] ) );
// stick
groups.push_back( m_stick = new AnalogStick( "Stick" ) );
// buttons
groups.push_back( m_buttons = new Buttons( "Buttons" ) );
m_buttons->controls.push_back( new ControlGroup::Input("Minus") );
m_buttons->controls.push_back( new ControlGroup::Input("Plus") );
// set up register
// id
memcpy( &reg[0xfa], drums_id, sizeof(drums_id) );
}
void Drums::GetState(u8* const data, const bool focus)
{
wm_drums_extension* const ddata = (wm_drums_extension*)data;
// calibration data not figured out yet?
// stick
{
u8 x, y;
m_stick->GetState( &x, &y, 0x20, focus ? 0x1F /*0x15*/ : 0 );
ddata->sx = x;
ddata->sy = y;
}
// TODO: softness maybe
data[2] = 0xFF;
data[3] = 0xFF;
if (focus)
{
// buttons
m_buttons->GetState( &ddata->bt, drum_button_bitmasks );
// pads
m_pads->GetState( &ddata->bt, drum_pad_bitmasks );
}
// flip button bits
ddata->bt ^= 0xFFFF;
}
}

View File

@ -0,0 +1,19 @@
#include "Attachment.h"
namespace WiimoteEmu
{
class Drums : public Attachment
{
public:
Drums();
void GetState( u8* const data, const bool focus );
private:
Buttons* m_buttons;
Buttons* m_pads;
AnalogStick* m_stick;
};
}

View File

@ -0,0 +1,113 @@
#include "Guitar.h"
namespace WiimoteEmu
{
static const u8 guitar_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x01, 0x03 };
// guitar buttons
#define GUITAR_PLUS 0x04
#define GUITAR_MINUS 0x10
#define GUITAR_BAR_DOWN 0x40
#define GUITAR_BAR_UP 0x0100
#define GUITAR_YELLOW 0x0800
#define GUITAR_GREEN 0x1000
#define GUITAR_BLUE 0x2000
#define GUITAR_RED 0x4000
#define GUITAR_ORANGE 0x8000
const u16 guitar_fret_bitmasks[] =
{
GUITAR_GREEN,
GUITAR_RED,
GUITAR_YELLOW,
GUITAR_BLUE,
GUITAR_ORANGE,
};
const char* guitar_fret_names[] =
{
"Green","Red","Yellow","Blue","Orange",
};
const u16 guitar_button_bitmasks[] =
{
GUITAR_MINUS,
GUITAR_PLUS,
};
const u16 guitar_strum_bitmasks[] =
{
GUITAR_BAR_UP,
GUITAR_BAR_DOWN,
};
Guitar::Guitar() : Attachment( "Guitar" )
{
// frets
groups.push_back( m_frets = new Buttons( "Frets" ) );
for ( unsigned int i = 0; i < sizeof(guitar_fret_names)/sizeof(*guitar_fret_names); ++i )
m_frets->controls.push_back( new ControlGroup::Input( guitar_fret_names[i] ) );
// stick
groups.push_back( m_stick = new AnalogStick( "Stick" ) );
// strum
groups.push_back( m_strum = new Buttons( "Strum" ) );
m_strum->controls.push_back( new ControlGroup::Input("Up") );
m_strum->controls.push_back( new ControlGroup::Input("Down") );
// whammy
groups.push_back( m_whammy = new Triggers( "Whammy" ) );
m_whammy->controls.push_back( new ControlGroup::Input("Bar") );
// buttons
groups.push_back( m_buttons = new Buttons( "Buttons" ) );
m_buttons->controls.push_back( new ControlGroup::Input("Minus") );
m_buttons->controls.push_back( new ControlGroup::Input("Plus") );
// set up register
// id
memcpy( &reg[0xfa], guitar_id, sizeof(guitar_id) );
}
void Guitar::GetState(u8* const data, const bool focus)
{
wm_guitar_extension* const gdata = (wm_guitar_extension*)data;
// calibration data not figured out yet?
// stick
{
u8 x, y;
m_stick->GetState( &x, &y, 0x20, focus ? 0x1F /*0x15*/ : 0 );
gdata->sx = x;
gdata->sy = y;
}
// TODO: touch bar, probably not
gdata->tb = 0x0F; // not touched
// whammy bar
u8 whammy;
m_whammy->GetState( &whammy, 0x1F );
gdata->whammy = whammy;
if (focus)
{
// buttons
m_buttons->GetState( &gdata->bt, guitar_button_bitmasks );
// frets
m_frets->GetState( &gdata->bt, guitar_fret_bitmasks );
// strum
m_strum->GetState( &gdata->bt, guitar_strum_bitmasks );
}
// flip button bits
gdata->bt ^= 0xFFFF;
}
}

View File

@ -0,0 +1,21 @@
#include "Attachment.h"
namespace WiimoteEmu
{
class Guitar : public Attachment
{
public:
Guitar();
void GetState( u8* const data, const bool focus );
private:
Buttons* m_buttons;
Buttons* m_frets;
Buttons* m_strum;
Triggers* m_whammy;
AnalogStick* m_stick;
};
}

View File

@ -4,7 +4,7 @@
namespace WiimoteEmu
{
static const u8 nunchuck_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x00, 0x00 };
static const u8 nunchuck_id[] = { 0x00, 0x00, 0xa4, 0x20, 0x00, 0x00 };
/* Default calibration for the nunchuck. It should be written to 0x20 - 0x3f of the
extension register. 0x80 is the neutral x and y accelerators and 0xb3 is the
neutral z accelerometer that is adjusted for gravity. */

View File

@ -61,8 +61,6 @@ void Wiimote::ReportMode(const u16 _channelID, wm_report_mode* dr)
//DEBUG_LOG(WIIMOTE, " All The Time: %x", dr->all_the_time);
//DEBUG_LOG(WIIMOTE, " Mode: 0x%02x", dr->mode);
m_rumble_on = (dr->rumble != 0);
m_reporting_auto = dr->all_the_time;
m_reporting_mode = dr->mode;
m_reporting_channel = _channelID;
@ -93,10 +91,14 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
{
INFO_LOG(WIIMOTE, "HidOutputReport (page: %i, cid: 0x%02x, wm: 0x%02x)", m_index, _channelID, sr->wm);
// wiibrew:
// In every single Output Report, bit 0 (0x01) of the first byte controls the Rumble feature.
m_rumble_on = (sr->data[0] & 0x01) != 0;
switch (sr->wm)
{
case WM_RUMBLE : // 0x10
m_rumble_on = (sr->data[0] != 0);
// this is handled above
return; // no ack
break;
@ -116,6 +118,7 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
case WM_SPEAKER_ENABLE : // 0x14
//INFO_LOG(WIIMOTE, "WM Speaker Enable: 0x%02x", sr->data[0]);
//PanicAlert( "WM Speaker Enable: %d", sr->data[0] );
m_status.speaker = (sr->data[0] & 0x04) ? 1 : 0;
break;
@ -135,12 +138,24 @@ void Wiimote::HidOutputReport(const u16 _channelID, wm_report* sr)
case WM_WRITE_SPEAKER_DATA : // 0x18
// TODO: Does this need an ack?
{
// testing
//wm_speaker_data* const sd = (wm_speaker_data*)sr->data;
//unsigned int length = sd->length >> 3;
//PanicAlert( "WM Speaker Data:\nlength: %d\nformat: 0x%x\nrate: 0x%x\nvolume: 0x%x",
//length, m_reg_speaker->format, m_reg_speaker->sample_rate, m_reg_speaker->volume );
//for (unsigned int i=0; i<length; ++i)
// m_speaker_data.push(0);
}
return; // no ack
break;
case WM_SPEAKER_MUTE : // 0x19
//INFO_LOG(WIIMOTE, "WM Speaker Mute: 0x%02x", sr->data[0]);
//m_speaker_mute = (sr->data[0] & 0x04) ? 1 : 0;
//PanicAlert( "WM Speaker Mute: %d", sr->data[0] & 0x04 );
m_speaker_mute = (sr->data[0] & 0x04) ? 1 : 0;
break;
case WM_IR_LOGIC: // 0x1a
@ -182,14 +197,14 @@ void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
g_WiimoteInitialize.pWiimoteInput( m_index, _channelID, data, sizeof(data));
}
// old comment
/* Here we produce a 0x20 status report to send to the Wii. We currently ignore
the status request rs and all its eventual instructions it may include (for
example turn off rumble or something else) and just send the status
report. */
void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
{
if (rs)
m_rumble_on = (rs->rumble != 0);
//if (rs)
// handle switch extension
if ( m_extension->active_extension != m_extension->switch_extension )
@ -230,8 +245,6 @@ void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
// ignore the 0x010000 bit
address &= 0xFEFFFF;
m_rumble_on = ( wd->rumble != 0 );
if (wd->size > 16)
{
PanicAlert("WriteData: size is > 16 bytes");
@ -278,6 +291,10 @@ void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
switch (address >> 16)
{
// speaker
case 0xa2 :
//PanicAlert("Write to speaker!!");
break;
// extension register
case 0xa4 :
{
@ -311,8 +328,6 @@ void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
// ignore the 0x010000 bit
address &= 0xFEFFFF;
m_rumble_on = (rd->rumble != 0);
ReadRequest rr;
u8* block = new u8[size];
@ -322,7 +337,7 @@ void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
{
//PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
// Read from EEPROM
if (address + size > WIIMOTE_EEPROM_FREE_SIZE)
if (address + size >= WIIMOTE_EEPROM_FREE_SIZE)
{
if (address + size > WIIMOTE_EEPROM_SIZE)
{
@ -362,17 +377,20 @@ void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
switch (address >> 16)
{
// speaker
case 0xa2 :
//PanicAlert("read from speaker!!");
break;
// extension
case 0xa4 :
{
// Encrypt data read from extension register
// Check if encrypted reads is on
if ( m_reg_ext[0xf0] == 0xaa )
{
// I probably totally f'ed this up
wiimote_encrypt(&m_ext_key, block, address & 0xffff, (u8)size);
}
}
break;
// motion plus
case 0xa6 :
{
// motion plus crap copied from old wiimote plugin

View File

@ -279,7 +279,7 @@ void wiimote_gen_key(wiimote_key *key, u8 *keydata)
// for homebrew, ft and sb are all 0x97 which is equivalent to 0x17
}
// TODO: is there a reason these can only handle a length of 255?
/* Encrypt data */
void wiimote_encrypt(wiimote_key *key, u8 *data, int addr, u8 len)
{

View File

@ -1,6 +1,8 @@
#include "Attachment/Classic.h"
#include "Attachment/Nunchuk.h"
#include "Attachment/Guitar.h"
#include "Attachment/Drums.h"
#include "WiimoteEmu.h"
#include "WiimoteHid.h"
@ -39,6 +41,7 @@ static const u8 eeprom_data_0[] = {
0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E
};
static const u8 motion_plus_id[] = { 0x00, 0x00, 0xA6, 0x20, 0x00, 0x05 };
static const u8 eeprom_data_16D0[] = {
0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00,
@ -110,6 +113,7 @@ void Wiimote::Reset()
m_reporting_auto = false;
m_rumble_on = false;
m_speaker_mute = false;
// will make the first Update() call send a status request
// the first call to RequestStatus() will then set up the status struct extension bit
@ -129,11 +133,14 @@ void Wiimote::Reset()
m_register[0xa60000].resize(WIIMOTE_REG_EXT_SIZE,0);
m_register[0xB00000].resize(WIIMOTE_REG_IR_SIZE,0);
//m_reg_speaker = &m_register[0xa20000][0];
m_reg_speaker = (SpeakerConfig*)&m_register[0xa20000][0];
m_reg_ext = &m_register[0xa40000][0];
//m_reg_motion_plus = &m_register[0xa60000][0];
m_reg_motion_plus = &m_register[0xa60000][0];
m_reg_ir = &m_register[0xB00000][0];
// testing
//memcpy( m_reg_motion_plus + 0xfa, motion_plus_id, sizeof(motion_plus_id) );
// status
memset( &m_status, 0, sizeof(m_status) );
// Battery levels in voltage
@ -183,7 +190,8 @@ Wiimote::Wiimote( const unsigned int index ) : m_index(index)
m_extension->attachments.push_back( new WiimoteEmu::None() );
m_extension->attachments.push_back( new WiimoteEmu::Nunchuk() );
m_extension->attachments.push_back( new WiimoteEmu::Classic() );
//m_extension->attachments.push_back( new Attachment::GH3() );
m_extension->attachments.push_back( new WiimoteEmu::Guitar() );
m_extension->attachments.push_back( new WiimoteEmu::Drums() );
// dpad
groups.push_back( m_dpad = new Buttons( "D-Pad" ) );
@ -195,9 +203,9 @@ Wiimote::Wiimote( const unsigned int index ) : m_index(index)
m_rumble->controls.push_back( new ControlGroup::Output( "Motor" ) );
// options
groups.push_back( options = new ControlGroup( "Options" ) );
options->settings.push_back( new ControlGroup::Setting( "Background Input", false ) );
options->settings.push_back( new ControlGroup::Setting( "Sideways Wiimote", false ) );
groups.push_back( m_options = new ControlGroup( "Options" ) );
m_options->settings.push_back( new ControlGroup::Setting( "Background Input", false ) );
m_options->settings.push_back( new ControlGroup::Setting( "Sideways Wiimote", false ) );
// --- reset eeprom/register/values to default ---
@ -211,16 +219,29 @@ std::string Wiimote::GetName() const
void Wiimote::Update()
{
const bool is_sideways = options->settings[1]->value > 0;
const bool is_sideways = m_options->settings[1]->value > 0;
// if windows is focused or background input is enabled
const bool focus = g_WiimoteInitialize.pRendererHasFocus() || (options->settings[0]->value != 0);
const bool focus = g_WiimoteInitialize.pRendererHasFocus() || (m_options->settings[0]->value != 0);
// no rumble if no focus
if (false == focus)
m_rumble_on = false;
m_rumble->controls[0]->control_ref->State(m_rumble_on);
// testing speaker stuff
//m_rumble->controls[0]->control_ref->State( m_speaker_data.size() > 0 );
//while ( m_speaker_data.size() )
//{
// std::ofstream file;
// file.open( "test.pcm", std::ios::app | std::ios::out | std::ios::binary );
// file.put(m_speaker_data.front());
// file.close();
// m_speaker_data.pop();
//}
//if ( m_speaker_data.size() )
// m_speaker_data.pop();
// update buttons in status struct
m_status.buttons = 0;
if ( focus )
@ -324,7 +345,7 @@ void Wiimote::Update()
else
m_shake_step = 0;
// swing
// TODO: swing
//u8 swing[3];
//m_swing->GetState( swing, 0x80, 60 );
//for ( unsigned int i=0; i<3; ++i )
@ -337,7 +358,11 @@ void Wiimote::Update()
if (rpt.ext)
{
m_extension->GetState(data + rpt.ext, focus);
wiimote_encrypt(&m_ext_key, data + rpt.ext, 0x00, sizeof(wm_extension));
// both of these ifs work
//if ( m_reg_ext[0xf0] != 0x55 )
if ( m_reg_ext[0xf0] == 0xaa )
wiimote_encrypt(&m_ext_key, data + rpt.ext, 0x00, sizeof(wm_extension));
// i dont think anything accesses the extension data like this, but ill support it
memcpy(m_reg_ext + 8, data + rpt.ext, sizeof(wm_extension));
@ -613,3 +638,4 @@ void Wiimote::Register::Write( size_t address, void* src, size_t length )
}
}

View File

@ -13,7 +13,7 @@
// Registry sizes
#define WIIMOTE_EEPROM_SIZE (16*1024)
#define WIIMOTE_EEPROM_FREE_SIZE 0x16ff
#define WIIMOTE_EEPROM_FREE_SIZE 0x1700
#define WIIMOTE_REG_SPEAKER_SIZE 10
#define WIIMOTE_REG_EXT_SIZE 0x100
#define WIIMOTE_REG_IR_SIZE 0x34
@ -28,20 +28,22 @@ extern const u8 shake_data[8];
class Wiimote : public ControllerEmu
{
public:
Wiimote( const unsigned int index );
std::string GetName() const;
void Update();
void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size);
void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size);
private:
struct ReadRequest
{
unsigned int address, size, position;
u8* data;
};
Wiimote( const unsigned int index );
void Reset();
void Update();
void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size);
void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size);
void ReportMode(const u16 _channelID, wm_report_mode* dr);
void HidOutputReport(const u16 _channelID, wm_report* sr);
void SendAck(const u16 _channelID, u8 _reportID);
@ -51,10 +53,7 @@ public:
void ReadData(const u16 _channelID, wm_read_data* rd);
void SendReadDataReply(const u16 _channelID, ReadRequest& _request);
std::string GetName() const;
private:
// control groups
Buttons* m_buttons;
Buttons* m_dpad;
Buttons* m_shake;
@ -63,11 +62,13 @@ private:
Force* m_swing;
ControlGroup* m_rumble;
Extension* m_extension;
// TODO: add ir
ControlGroup* m_options;
// wiimote index, 0-3
const unsigned int m_index;
bool m_rumble_on;
bool m_speaker_mute;
bool m_reporting_auto;
unsigned int m_reporting_mode;
@ -90,13 +91,20 @@ private:
// maybe read requests cancel any current requests
std::queue< ReadRequest > m_read_requests;
//u8 m_eeprom[WIIMOTE_EEPROM_SIZE];
u8 m_eeprom[WIIMOTE_EEPROM_SIZE];
//std::queue< u8 > m_speaker_data;
//u8* m_reg_speaker;
//u8* m_reg_motion_plus;
u8* m_reg_ir;
u8 m_eeprom[WIIMOTE_EEPROM_SIZE];
u8* m_reg_ext;
u8* m_reg_ir;
u8* m_reg_motion_plus;
struct SpeakerConfig
{
u16 : 16;
u8 format;
u16 sample_rate;
u8 volume;
} *m_reg_speaker;
wiimote_key m_ext_key;
};

View File

@ -99,7 +99,7 @@ struct wm_classic_extension
u16 bt; // byte 4, 5
};
struct wm_GH3_extension
struct wm_guitar_extension
{
u8 sx : 6;
u8 pad1 : 2; // 1 on gh3, 0 on ghwt
@ -113,23 +113,28 @@ struct wm_GH3_extension
u8 whammy : 5;
u8 pad4 : 3; // always 0
u8 pad5 : 2; // always 1
u8 plus : 1;
u8 pad6 : 1; // always 1
u8 minus : 1;
u8 pad7 : 1; // always 1
u8 strumdown : 1;
u8 pad8 : 1; // always 1
u8 strumup : 1;
u8 pad9 : 2; // always 1
u8 yellow : 1;
u8 green : 1;
u8 blue : 1;
u8 red : 1;
u8 orange : 1;
u16 bt; // buttons
};
struct wm_drums_extension
{
u8 sx : 6;
u8 pad1 : 2; // always 0
u8 sy : 6;
u8 pad2 : 2; // always 0
u8 pad3 : 1; // unknown
u8 which : 5;
u8 none : 1;
u8 hhp : 1;
u8 pad4 : 1; // unknown
u8 velocity : 4; // unknown
u8 softness : 3;
u16 bt; // buttons
};
struct wm_report {
u8 wm;
@ -279,7 +284,10 @@ struct wm_report_ext21
#define WM_SPEAKER_ENABLE 0x14
#define WM_SPEAKER_MUTE 0x19
#define WM_WRITE_SPEAKER_DATA 0x18
struct wm_speaker_data {
u8 length; // shifted left by three bits
u8 data[20];
};
// Custom structs

View File

@ -140,13 +140,7 @@ void InitPlugin( void* const hwnd )
void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//PanicAlert( "Wiimote_ControlChannel" );
// TODO: change this to a TryEnter, and make it give empty input on failure
g_plugin.controls_crit.Enter();
((WiimoteEmu::Wiimote*)g_plugin.controllers[ _number ])->ControlChannel( _channelID, _pData, _Size );
g_plugin.controls_crit.Leave();
}
// __________________________________________________________________________________________________
@ -159,13 +153,7 @@ void Wiimote_ControlChannel(int _number, u16 _channelID, const void* _pData, u32
void Wiimote_InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//PanicAlert( "Wiimote_InterruptChannel" );
// TODO: change this to a TryEnter, and make it give empty input on failure
g_plugin.controls_crit.Enter();
((WiimoteEmu::Wiimote*)g_plugin.controllers[ _number ])->InterruptChannel( _channelID, _pData, _Size );
g_plugin.controls_crit.Leave();
}
// __________________________________________________________________________________________________
@ -337,7 +325,7 @@ void Shutdown(void)
//
void DoState(unsigned char **ptr, int mode)
{
// prolly won't need this
// do this later
}
// ___________________________________________________________________________