Improvements to new emulated wiimote plugin: IR cursor works with mouse or analog stick control. Wiimote mii data is saved/loaded to "User/Wii/mii.bin". Background input checkbox works properly. All reporting modes except the interleaved one should work. Fixed a rumble prob with multiple XInput devices.

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5396 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2010-04-22 07:11:49 +00:00
parent 140332c02e
commit 7c22b83f66
17 changed files with 622 additions and 270 deletions

View File

@ -64,6 +64,7 @@ Device::Device( const XINPUT_CAPABILITIES* const caps, const unsigned int index
: m_index(index), m_subtype(caps->SubType)
{
ZeroMemory( &m_state_out, sizeof(m_state_out) );
ZeroMemory( &m_current_state_out, sizeof(m_current_state_out) );
// XInputGetCaps seems to always claim all capabilities are supported
// but i will leave all this stuff in, incase m$ fixes xinput up a bit
@ -149,10 +150,10 @@ bool Device::UpdateInput()
bool Device::UpdateOutput()
{
// this if statement is to make rumble work better when multiple ControllerInterfaces are using the device
static XINPUT_VIBRATION current_state_out = {0,0};
if ( memcmp( &m_state_out, &current_state_out, sizeof(m_state_out) ) )
// only calls XInputSetState if the state changed
if ( memcmp( &m_state_out, &m_current_state_out, sizeof(m_state_out) ) )
{
current_state_out = m_state_out;
m_current_state_out = m_state_out;
return ( ERROR_SUCCESS == XInputSetState( m_index, &m_state_out ) );
}
else

View File

@ -105,6 +105,7 @@ private:
const unsigned int m_index;
XINPUT_STATE m_state_in;
XINPUT_VIBRATION m_state_out;
XINPUT_VIBRATION m_current_state_out;
const unsigned int m_subtype;
};

View File

@ -76,15 +76,15 @@ void PadSettingCheckBox::UpdateValue()
value = 0.01 * GetValue();
}
PadSettingChoice::PadSettingChoice( wxWindow* const parent, ControlState& _value, int min, int max )
PadSettingChoice::PadSettingChoice( wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const setting )
: wxChoice( parent, -1, wxDefaultPosition, wxSize( 54, -1 ) )
, value(_value)
, value(setting->value)
{
Append( wxT("0") );
for ( ; min<=max; ++min )
for ( unsigned int i = setting->low; i<=setting->high; ++i )
{
std::ostringstream ss;
ss << min;
ss << i;
Append( wxString::FromAscii( ss.str().c_str() ) );
}
@ -124,10 +124,10 @@ ControlDialog::ControlDialog( wxWindow* const parent, ControllerInterface::Contr
control_chooser = new ControlChooser( this, ref, parent );
wxStaticBoxSizer* d_szr = new wxStaticBoxSizer( wxVERTICAL, this, wxT("Device") );
wxStaticBoxSizer* const d_szr = new wxStaticBoxSizer( wxVERTICAL, this, wxT("Device") );
d_szr->Add( device_cbox, 0, wxEXPAND|wxALL, 5 );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* const szr = new wxBoxSizer( wxVERTICAL );
szr->Add( d_szr, 0, wxEXPAND|wxLEFT|wxRIGHT|wxTOP, 5 );
szr->Add( control_chooser, 0, wxEXPAND|wxALL, 5 );
@ -416,7 +416,7 @@ void ControlDialog::SelectControl( wxCommandEvent& event )
if (IsBeingDeleted())
return;
wxListBox* lb = (wxListBox*)event.GetEventObject();
wxListBox* const lb = (wxListBox*)event.GetEventObject();
wxArrayInt sels;
lb->GetSelections( sels );
@ -450,14 +450,15 @@ ControlChooser::ControlChooser( wxWindow* const parent, ControllerInterface::Con
textctrl = new wxTextCtrl( parent, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
_connect_macro_( textctrl, ControlDialog::SetControl, wxEVT_COMMAND_TEXT_ENTER, parent);
wxButton* detect_button = new wxButton( parent, -1, ref->is_input ? wxT("Detect 1") : wxT("Test") );
wxButton* clear_button = new wxButton( parent, -1, wxT("Clear"), wxDefaultPosition );
wxButton* set_button = new wxButton( parent, -1, wxT("Set")/*, wxDefaultPosition, wxSize( 32, -1 )*/ );
wxButton* const detect_button = new wxButton( parent, -1, ref->is_input ? wxT("Detect 1") : wxT("Test") );
wxButton* const clear_button = new wxButton( parent, -1, wxT("Clear"), wxDefaultPosition );
wxButton* const set_button = new wxButton( parent, -1, wxT("Set")/*, wxDefaultPosition, wxSize( 32, -1 )*/ );
control_lbox = new wxListBox( parent, -1, wxDefaultPosition, wxSize( 256, 128 ), wxArrayString(), wxLB_EXTENDED );
_connect_macro_( control_lbox, ControlDialog::SelectControl, wxEVT_COMMAND_LISTBOX_SELECTED, parent);
wxBoxSizer* button_sizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const button_sizer = new wxBoxSizer( wxHORIZONTAL );
button_sizer->Add( detect_button, 1, 0, 5 );
if ( ref->is_input )
for ( unsigned int i = 2; i<5; ++i )
@ -478,18 +479,19 @@ ControlChooser::ControlChooser( wxWindow* const parent, ControllerInterface::Con
_connect_macro_( set_button, ControlDialog::SetControl, wxEVT_COMMAND_BUTTON_CLICKED, parent);
_connect_macro_( range_slider, GamepadPage::AdjustControlOption, wxEVT_SCROLL_CHANGED, eventsink);
wxStaticText* range_label = new wxStaticText( parent, -1, wxT("Range"));
wxStaticText* const range_label = new wxStaticText( parent, -1, wxT("Range"));
m_bound_label = new wxStaticText( parent, -1, wxT("") );
wxBoxSizer* range_sizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const range_sizer = new wxBoxSizer( wxHORIZONTAL );
range_sizer->Add( range_label, 0, wxCENTER|wxLEFT, 5 );
range_sizer->Add( range_slider, 1, wxEXPAND|wxLEFT, 5 );
wxBoxSizer* txtbox_szr = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const txtbox_szr = new wxBoxSizer( wxHORIZONTAL );
txtbox_szr->Add( textctrl, 1, wxEXPAND, 0 );
wxBoxSizer* mode_szr;
Add( range_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
if ( control_reference->is_input )
{
mode_cbox = new wxChoice( parent, -1 );
@ -500,14 +502,12 @@ ControlChooser::ControlChooser( wxWindow* const parent, ControllerInterface::Con
_connect_macro_( mode_cbox, GamepadPage::AdjustControlOption, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
mode_szr = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const mode_szr = new wxBoxSizer( wxHORIZONTAL );
mode_szr->Add( new wxStaticText( parent, -1, wxT("Mode") ), 0, wxCENTER|wxLEFT|wxRIGHT, 5 );
mode_szr->Add( mode_cbox, 0, wxLEFT, 5 );
}
Add( range_sizer, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
if ( control_reference->is_input )
Add( mode_szr, 0, wxEXPAND|wxLEFT|wxRIGHT, 5 );
}
Add( txtbox_szr, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
Add( button_sizer, 0, wxEXPAND|wxBOTTOM|wxLEFT|wxRIGHT, 5 );
Add( control_lbox, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 5 );
@ -633,9 +633,9 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
for ( unsigned int c = 0; c < group->controls.size(); ++c )
{
wxStaticText* label = new wxStaticText( parent, -1, wxString::FromAscii( group->controls[c]->name )/*.append(wxT(" :"))*/ );
wxStaticText* const label = new wxStaticText( parent, -1, wxString::FromAscii( group->controls[c]->name )/*.append(wxT(" :"))*/ );
ControlButton* control_button = new ControlButton( parent, group->controls[c]->control_ref, 80 );
ControlButton* const control_button = new ControlButton( parent, group->controls[c]->control_ref, 80 );
control_button->SetFont(m_SmallFont);
ControlButton* adv_button = new ControlButton( parent, group->controls[c]->control_ref, 18, "+" );
adv_button->SetFont(m_SmallFont);
@ -646,7 +646,7 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
_connect_macro_( control_button, GamepadPage::DetectControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink );
_connect_macro_( adv_button, GamepadPage::ConfigControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink );
wxBoxSizer* control_sizer = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const control_sizer = new wxBoxSizer( wxHORIZONTAL );
control_sizer->AddStretchSpacer( 1 );
control_sizer->Add( label, 0, wxCENTER | wxRIGHT, 5 );
control_sizer->Add( control_button, 0, 0, 0 );
@ -660,6 +660,7 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
{
case GROUP_TYPE_STICK :
case GROUP_TYPE_TILT :
case GROUP_TYPE_CURSOR :
{
wxBitmap bitmap(64, 64);
wxMemoryDC dc;
@ -669,22 +670,21 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* deadzone_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 50 );
PadSettingChoice* diagonal_cbox = new PadSettingChoice( parent, group->settings[1]->value, 1, 100 );
std::vector< ControllerEmu::ControlGroup::Setting* >::const_iterator
i = group->settings.begin(),
e = group->settings.end();
_connect_macro_( deadzone_cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
_connect_macro_( diagonal_cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
wxBoxSizer* const szr = new wxBoxSizer( wxVERTICAL );
for ( ; i!=e; ++i )
{
PadSettingChoice* cbox = new PadSettingChoice( parent, *i );
_connect_macro_( cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
options.push_back( cbox );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( (*i)->name ) ) );
szr->Add( cbox, 0, wxLEFT, 0 );
}
options.push_back( deadzone_cbox );
options.push_back( diagonal_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[0]->name ) ) );
szr->Add( deadzone_cbox, 0, wxLEFT, 0 );
szr->Add( new wxStaticText( parent, -1, wxString::FromAscii( group->settings[1]->name ) ) );
szr->Add( diagonal_cbox, 0, wxLEFT, 0 );
wxBoxSizer* h_szr = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const h_szr = new wxBoxSizer( wxHORIZONTAL );
h_szr->Add( szr, 1, 0, 5 );
h_szr->Add( static_bitmap, 0, wxALL|wxCENTER, 5 );
@ -700,12 +700,12 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 99 );
PadSettingChoice* const threshold_cbox = new PadSettingChoice( parent, group->settings[0] );
_connect_macro_( threshold_cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
options.push_back( threshold_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxHORIZONTAL );
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 );
@ -722,12 +722,12 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
dc.SelectObject(wxNullBitmap);
static_bitmap = new wxStaticBitmap( parent, -1, bitmap, wxDefaultPosition, wxDefaultSize, wxBITMAP_TYPE_BMP );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0]->value, 1, 99 );
PadSettingChoice* threshold_cbox = new PadSettingChoice( parent, group->settings[0] );
_connect_macro_( threshold_cbox, GamepadPage::AdjustSetting, wxEVT_COMMAND_CHOICE_SELECTED, eventsink );
options.push_back( threshold_cbox );
wxBoxSizer* szr = new wxBoxSizer( wxHORIZONTAL );
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 );
@ -813,7 +813,7 @@ GamepadPage::GamepadPage( wxWindow* parent, const unsigned int pad_num, ConfigDi
// device chooser
wxStaticBoxSizer* device_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Device") );
wxStaticBoxSizer* const device_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Device") );
device_cbox = new wxComboBox( this, -1, wxT(""), wxDefaultPosition, wxSize(128,-1), 0, 0, wxTE_PROCESS_ENTER );
@ -826,7 +826,7 @@ GamepadPage::GamepadPage( wxWindow* parent, const unsigned int pad_num, ConfigDi
device_sbox->Add( device_cbox, 1, wxLEFT|wxRIGHT, 5 );
device_sbox->Add( refresh_button, 0, wxRIGHT|wxBOTTOM, 5 );
wxStaticBoxSizer* clear_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Clear") );
wxStaticBoxSizer* const clear_sbox = new wxStaticBoxSizer( wxHORIZONTAL, this, wxT("Clear") );
wxButton* all_button = new wxButton( this, -1, wxT("All"), wxDefaultPosition, wxSize(48,-1) );
clear_sbox->Add( all_button, 1, wxLEFT|wxRIGHT, 5 );
@ -847,12 +847,12 @@ GamepadPage::GamepadPage( wxWindow* parent, const unsigned int pad_num, ConfigDi
profile_sbox->Add( psave_btn, 0, 0, 5 );
profile_sbox->Add( pdelete_btn, 0, wxRIGHT|wxBOTTOM, 5 );
wxBoxSizer* dio = new wxBoxSizer( wxHORIZONTAL );
wxBoxSizer* const dio = new wxBoxSizer( wxHORIZONTAL );
dio->Add( device_sbox, 1, wxEXPAND|wxRIGHT, 5 );
dio->Add( clear_sbox, 0, wxEXPAND|wxRIGHT, 5 );
dio->Add( profile_sbox, 1, wxEXPAND|wxRIGHT, 5 );
wxBoxSizer* mapping = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* const mapping = new wxBoxSizer( wxVERTICAL );
mapping->Add( dio, 1, wxEXPAND|wxLEFT|wxTOP|wxBOTTOM, 5 );
mapping->Add( control_group_sizer, 0, wxLEFT|wxEXPAND, 5 );
@ -886,7 +886,8 @@ ConfigDialog::ConfigDialog( wxWindow* const parent, Plugin& plugin, const std::s
UpdateDeviceComboBox();
UpdateProfileComboBox();
wxButton* close_button = new wxButton( this, -1, wxT("Save"));
wxButton* const close_button = new wxButton( this, -1, wxT("Save"));
_connect_macro_(close_button, ConfigDialog::ClickSave, wxEVT_COMMAND_BUTTON_CLICKED, this);
_connect_macro_(close_button, ConfigDialog::ClickSave, wxEVT_COMMAND_BUTTON_CLICKED, this);
wxBoxSizer* btns = new wxBoxSizer( wxHORIZONTAL );
@ -894,7 +895,7 @@ ConfigDialog::ConfigDialog( wxWindow* const parent, Plugin& plugin, const std::s
btns->AddStretchSpacer();
btns->Add( close_button, 0, 0, 0 );
wxBoxSizer* szr = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* const szr = new wxBoxSizer( wxVERTICAL );
szr->Add( m_pad_notebook, 0, wxEXPAND|wxTOP|wxLEFT|wxRIGHT, 5 );
szr->Add( btns, 0, wxEXPAND|wxALL, 5 );

View File

@ -48,7 +48,7 @@ public:
class PadSettingChoice : public wxChoice, public PadSetting
{
public:
PadSettingChoice( wxWindow* const parent, ControlState& _value, int min, int max );
PadSettingChoice( wxWindow* const parent, ControllerEmu::ControlGroup::Setting* const setting );
void UpdateGUI();
void UpdateValue();

View File

@ -26,13 +26,27 @@ void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
{
case GROUP_TYPE_TILT :
case GROUP_TYPE_STICK :
case GROUP_TYPE_CURSOR :
{
float x = 0, y = 0;
// this is starting to be a mess combining all these in one case
float x = 0, y = 0, z = 0;
float xx, yy;
if ( GROUP_TYPE_STICK == (*g)->control_group->type )
switch ((*g)->control_group->type)
{
case GROUP_TYPE_STICK :
((ControllerEmu::AnalogStick*)(*g)->control_group)->GetState( &x, &y, 32.0, 32-1.5 );
else
break;
case GROUP_TYPE_TILT :
((ControllerEmu::Tilt*)(*g)->control_group)->GetState( &x, &y, 32.0, 32-1.5 );
break;
case GROUP_TYPE_CURSOR :
((ControllerEmu::Cursor*)(*g)->control_group)->GetState( &x, &y, &z );
x *= (32-1.5); x+= 32;
y *= (32-1.5); y+= 32;
break;
}
xx = (*g)->control_group->controls[3]->control_ref->State();
xx -= (*g)->control_group->controls[2]->control_ref->State();
@ -49,25 +63,37 @@ void ConfigDialog::UpdateBitmaps(wxTimerEvent& WXUNUSED(event))
// draw the shit
// ir cursor forward movement
if (z)
{
dc.SetPen(*wxRED_PEN);
dc.SetBrush(*wxRED_BRUSH);
dc.DrawRectangle( 0, 64 - z*64, 64, 2);
}
// circle for visual aid for diagonal adjustment
dc.SetPen(*wxLIGHT_GREY_PEN);
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.SetBrush(*wxWHITE_BRUSH);
if ( GROUP_TYPE_STICK == (*g)->control_group->type )
dc.DrawCircle( 32, 32, 32);
else
dc.DrawRectangle( 16, 16, 32, 32 );
// deadzone circle
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.DrawCircle( 32, 32, ((*g)->control_group)->settings[0]->value * 32 );
if ( GROUP_TYPE_CURSOR != (*g)->control_group->type )
{
dc.SetBrush(*wxLIGHT_GREY_BRUSH);
dc.DrawCircle( 32, 32, ((*g)->control_group)->settings[0]->value * 32 );
// raw dot
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
// i like the dot better than the cross i think
dc.DrawRectangle( xx - 2, yy - 2, 4, 4 );
//dc.DrawRectangle( xx-1, 64-yy-4, 2, 8 );
//dc.DrawRectangle( xx-4, 64-yy-1, 8, 2 );
// raw dot
dc.SetPen(*wxGREY_PEN);
dc.SetBrush(*wxGREY_BRUSH);
// i like the dot better than the cross i think
dc.DrawRectangle( xx - 2, yy - 2, 4, 4 );
//dc.DrawRectangle( xx-1, 64-yy-4, 2, 8 );
//dc.DrawRectangle( xx-4, 64-yy-1, 8, 2 );
}
// adjusted dot
if ( x!=32 || y!=32 )

View File

@ -211,7 +211,7 @@ ControllerEmu::AnalogStick::AnalogStick( const char* const _name ) : ControlGrou
controls.push_back( new Input( modifier ) );
settings.push_back( new Setting("Dead Zone", 0 ) );
settings.push_back( new Setting("Dead Zone", 0, 1, 50 ) );
settings.push_back( new Setting("Square Stick", 0 ) );
}
@ -253,6 +253,97 @@ ControllerEmu::Tilt::Tilt( const char* const _name ) : ControlGroup( _name, GROU
controls.push_back( new Input( modifier ) );
settings.push_back( new Setting("Dead Zone", 0 ) );
settings.push_back( new Setting("Dead Zone", 0, 1, 50 ) );
settings.push_back( new Setting("Circle Stick", 0 ) );
}
ControllerEmu::Cursor::Cursor( const char* const _name, const SWiimoteInitialize* const _wiimote_initialize )
: ControlGroup( _name, GROUP_TYPE_CURSOR )
//, z(0)
, wiimote_initialize(_wiimote_initialize)
{
for ( unsigned int i = 0; i < 4; ++i )
controls.push_back( new Input( named_directions[i] ) );
settings.push_back( new Setting("Width", 0.5f ) );
settings.push_back( new Setting("Height", 0.5f ) );
settings.push_back( new Setting("Top", 0.5f ) );
}
//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;
#ifdef _WIN32
// Get the cursor position for the entire screen
POINT point = { 1, 1 };
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
win_width = Rect.right - Rect.left;
win_height = Rect.bottom - Rect.top;
#elif defined(HAVE_X11) && HAVE_X11
int root_x, root_y;
struct
{
int x, y;
} point = { 1, 1 };
// i think this if can be taken out, the plugin will handle that
if (IsFocus())
{
Display* const wm_display = (Display*)wiimote_initialize->hWnd;
Window glwin = *(Window *)wiimote_initialize->pXWindow;
XWindowAttributes win_attribs;
XGetWindowAttributes (wm_display, glwin, &win_attribs);
win_width = win_attribs.width;
win_height = win_attribs.height;
Window root_dummy, child_win;
unsigned int mask;
XQueryPointer(wm_display, glwin, &root_dummy, &child_win, &root_x, &root_y, &point.x, &point.y, &mask);
}
#endif
#if ( defined(_WIN32) || (defined(HAVE_X11) && HAVE_X11))
// Return the mouse position as a range from -1 to 1
x = (float)point.x / (float)win_width * 2 - 1;
y = (float)point.y / (float)win_height * 2 - 1;
#else
x = 0;
y = 0;
#endif
}

View File

@ -27,6 +27,7 @@ enum
GROUP_TYPE_FORCE,
GROUP_TYPE_EXTENSION,
GROUP_TYPE_TILT,
GROUP_TYPE_CURSOR,
};
const char * const named_directions[] =
@ -37,6 +38,8 @@ const char * const named_directions[] =
"Right"
};
void GetMousePos(float& x, float& y, const SWiimoteInitialize* const wiimote_initialize);
class ControllerEmu
{
public:
@ -82,11 +85,18 @@ public:
{
public:
Setting(const char* const _name, const float def_value ) : name(_name), value(def_value), default_value(def_value) {}
Setting(const char* const _name, const ControlState def_value
, const unsigned int _low = 1, const unsigned int _high = 100 )
: name(_name)
, value(def_value)
, default_value(def_value)
, low(_low)
, high(_high){}
const char* const name;
ControlState value;
const ControlState default_value;
const unsigned int low, high;
};
ControlGroup( const char* const _name, const unsigned int _type = GROUP_TYPE_OTHER ) : name(_name), type(_type) {}
@ -274,6 +284,62 @@ public:
}
};
class Cursor : public ControlGroup
{
public:
Cursor( const char* const _name, const SWiimoteInitialize* const _wiimote_initialize );
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
if (controls[5]->control_ref->State() > 0.5f)
{
*x = 10000; *y = 0; *forward = 0;
}
else
{
*forward = z;
float xx, yy;
GetMousePos(xx, yy, wiimote_initialize);
// use mouse cursor, or user defined mapping if they have something mapped
// this if seems horrible
if ( controls[0]->control_ref->control_qualifier.name.size() || controls[1]->control_ref->control_qualifier.name.size() )
yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
else
yy = -yy;
if ( controls[2]->control_ref->control_qualifier.name.size() || controls[3]->control_ref->control_qualifier.name.size() )
xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
// adjust cursor according to settings
if (adjusted)
{
xx *= ( settings[0]->value * 2 );
yy *= ( settings[1]->value * 2 );
yy += ( settings[2]->value - 0.5f );
}
*x = xx;
*y = yy;
}
}
private:
//ControlState z;
const SWiimoteInitialize* const wiimote_initialize;
};
class Extension : public ControlGroup
{
public:
@ -282,7 +348,7 @@ public:
, switch_extension(0)
, active_extension(0) {}
void GetState( u8* const data );
void GetState( u8* const data, const bool focus = true );
std::vector<ControllerEmu*> attachments;
@ -302,7 +368,6 @@ public:
std::vector< ControlGroup* > groups;
ControlGroup* options;
ControllerInterface::DeviceQualifier default_device;

View File

@ -30,7 +30,7 @@ std::string Attachment::GetName() const
}
void ControllerEmu::Extension::GetState( u8* const data )
void ControllerEmu::Extension::GetState( u8* const data, const bool focus )
{
((WiimoteEmu::Attachment*)attachments[ active_extension ])->GetState( data );
((WiimoteEmu::Attachment*)attachments[ active_extension ])->GetState( data, focus );
}

View File

@ -12,7 +12,7 @@ class Attachment : public ControllerEmu
public:
Attachment( const char* const _name );
virtual void GetState( u8* const data ) {}
virtual void GetState( u8* const data, const bool focus = true ) {}
std::string GetName() const;
const char* const name;

View File

@ -96,14 +96,16 @@ Classic::Classic() : Attachment( "Classic Controller" )
memcpy( &reg[0xfa], classic_id, sizeof(classic_id) );
}
void Classic::GetState( u8* const data )
void Classic::GetState( u8* const data, const bool focus )
{
wm_classic_extension* const ccdata = (wm_classic_extension*)data;
// not using calibration data, o well
// left stick
{
u8 x, y;
m_left_stick->GetState( &x, &y, 0x20, 0x1F /*0x15*/ );
m_left_stick->GetState( &x, &y, 0x20, focus ? 0x1F /*0x15*/ : 0 );
ccdata->lx = x;
ccdata->ly = y;
@ -112,7 +114,7 @@ void Classic::GetState( u8* const data )
// right stick
{
u8 x, y;
m_right_stick->GetState( &x, &y, 0x10, 0x0F /*0x0C*/ );
m_right_stick->GetState( &x, &y, 0x10, focus ? 0x0F /*0x0C*/ : 0 );
ccdata->rx1 = x;
ccdata->rx2 = x >> 1;
@ -123,17 +125,20 @@ void Classic::GetState( u8* const data )
//triggers
{
u8 trigs[2];
m_triggers->GetState( &ccdata->bt, classic_trigger_bitmasks, trigs, 0x1F );
m_triggers->GetState( &ccdata->bt, classic_trigger_bitmasks, trigs, focus ? 0x1F : 0 );
ccdata->lt1 = trigs[0];
ccdata->lt2 = trigs[0] >> 3;
ccdata->rt = trigs[1];
}
// buttons
m_buttons->GetState( &ccdata->bt, classic_button_bitmasks );
// dpad
m_dpad->GetState( &ccdata->bt, classic_dpad_bitmasks );
if (focus)
{
// buttons
m_buttons->GetState( &ccdata->bt, classic_button_bitmasks );
// dpad
m_dpad->GetState( &ccdata->bt, classic_dpad_bitmasks );
}
// flip button bits
ccdata->bt ^= 0xFFFF;

View File

@ -7,7 +7,7 @@ class Classic : public Attachment
{
public:
Classic();
void GetState( u8* const data );
void GetState( u8* const data, const bool focus );
private:
Buttons* m_buttons;

View File

@ -55,18 +55,21 @@ Nunchuk::Nunchuk() : Attachment( "Nunchuk" )
memcpy( &reg[0x20], nunchuck_calibration, sizeof(nunchuck_calibration) );
// id
memcpy( &reg[0xfa], nunchuck_id, sizeof(nunchuck_id) );
// this should get set to 0 on disconnect, but it isn't, o well
m_shake_step = 0;
}
void Nunchuk::GetState( u8* const data )
void Nunchuk::GetState( u8* const data, const bool focus )
{
wm_extension* const ncdata = (wm_extension*)data;
// stick / not using calibration data for stick, o well
m_stick->GetState( &ncdata->jx, &ncdata->jy, 0x80, 127 );
m_stick->GetState( &ncdata->jx, &ncdata->jy, 0x80, focus ? 127 : 0 );
// tilt
float x, y;
m_tilt->GetState( &x, &y, 0, (PI / 2) ); // 90 degrees
m_tilt->GetState( &x, &y, 0, focus ? (PI / 2) : 0 ); // 90 degrees
// this isn't doing anything with those low bits in the calib data, o well
@ -84,20 +87,21 @@ void Nunchuk::GetState( u8* const data )
// shake
const unsigned int btns[] = { 0x01, 0x02, 0x04 };
unsigned int shake = 0;
m_shake->GetState( &shake, btns );
static unsigned int shake_step = 0;
if (focus)
m_shake->GetState( &shake, btns );
if (shake)
{
shake_step = (shake_step + 1) % sizeof(shake_data);
for ( unsigned int i=0; i<3; ++i )
if ( shake & (1 << i) )
(&ncdata->ax)[i] = shake_data[shake_step];
(&ncdata->ax)[i] = shake_data[m_shake_step];
m_shake_step = (m_shake_step + 1) % sizeof(shake_data);
}
else
shake_step = 0;
m_shake_step = 0;
// buttons
m_buttons->GetState( &ncdata->bt, nunchuk_button_bitmasks );
if (focus)
m_buttons->GetState( &ncdata->bt, nunchuk_button_bitmasks );
// flip the button bits :/
ncdata->bt ^= 0x3;

View File

@ -8,7 +8,7 @@ class Nunchuk : public Attachment
{
public:
Nunchuk();
void GetState( u8* const data );
void GetState( u8* const data, const bool focus );
private:
Tilt* m_tilt;
@ -18,6 +18,8 @@ private:
Buttons* m_buttons;
AnalogStick* m_stick;
unsigned int m_shake_step;
};
}

View File

@ -33,6 +33,7 @@
#include <string>
#include "Common.h" // Common
#include "FileUtil.h"
#include "pluginspecs_wiimote.h"
#include "WiimoteEmu.h"
@ -52,7 +53,7 @@ u16 convert16bit(const u8* src)
namespace WiimoteEmu
{
void Wiimote::ReportMode(u16 _channelID, wm_report_mode* dr)
void Wiimote::ReportMode(const u16 _channelID, wm_report_mode* dr)
{
//INFO_LOG(WIIMOTE, "Set data report mode");
//DEBUG_LOG(WIIMOTE, " Rumble: %x", dr->rumble);
@ -60,8 +61,7 @@ void Wiimote::ReportMode(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);
// should I use the rumble var in here?
//m_rumble->controls[0]->control_ref->State( dr->rumble );
m_rumble_on = (dr->rumble != 0);
m_reporting_auto = dr->all_the_time;
m_reporting_mode = dr->mode;
@ -70,19 +70,10 @@ void Wiimote::ReportMode(u16 _channelID, wm_report_mode* dr)
if (0 == dr->all_the_time)
PanicAlert("Wiimote: Reporting Always is set to OFF! Everything should be fine, but games never do this.");
// Validation check
switch (dr->mode)
{
case WM_REPORT_CORE :
case WM_REPORT_CORE_ACCEL :
case WM_REPORT_CORE_ACCEL_IR12 :
case WM_REPORT_CORE_ACCEL_EXT16 :
case WM_REPORT_CORE_ACCEL_IR10_EXT6 :
break;
default:
PanicAlert("Wiimote: Unsupported reporting mode 0x%x", dr->mode);
break;
}
if (dr->mode >= WM_REPORT_INTERLEAVE1)
PanicAlert("Wiimote: Unsupported Reporting mode.");
else if (dr->mode < WM_REPORT_CORE)
PanicAlert("Wiimote: Reporting mode < 0x30.");
}
/* Here we process the Output Reports that the Wii sends. Our response will be
@ -98,14 +89,14 @@ void Wiimote::ReportMode(u16 _channelID, wm_report_mode* dr)
The IR enable/disable and speaker enable/disable and mute/unmute values are
bit2: 0 = Disable (0x02), 1 = Enable (0x06)
*/
void Wiimote::HidOutputReport(u16 _channelID, wm_report* sr)
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);
switch (sr->wm)
{
case WM_RUMBLE : // 0x10
m_rumble->controls[0]->control_ref->State( sr->data[0] > 0 );
m_rumble_on = (sr->data[0] != 0);
return; // no ack
break;
@ -175,7 +166,7 @@ void Wiimote::HidOutputReport(u16 _channelID, wm_report* sr)
The first two bytes are the core buttons data,
00 00 means nothing is pressed.
The last byte is the success code 00. */
void Wiimote::SendAck(u16 _channelID, u8 _reportID)
void Wiimote::SendAck(const u16 _channelID, u8 _reportID)
{
u8 data[6];
@ -188,15 +179,18 @@ void Wiimote::SendAck(u16 _channelID, u8 _reportID)
ack->reportID = _reportID;
ack->errorID = 0;
m_wiimote_init->pWiimoteInput( m_index, _channelID, data, sizeof(data));
g_WiimoteInitialize.pWiimoteInput( m_index, _channelID, data, sizeof(data));
}
/* 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(u16 _channelID, wm_request_status* rs, int _Extension)
void Wiimote::RequestStatus(const u16 _channelID, wm_request_status* rs)
{
if (rs)
m_rumble_on = (rs->rumble != 0);
// handle switch extension
if ( m_extension->active_extension != m_extension->switch_extension )
{
@ -224,16 +218,20 @@ void Wiimote::RequestStatus(u16 _channelID, wm_request_status* rs, int _Extensio
*(wm_status_report*)(data + 2) = m_status;
// send report
m_wiimote_init->pWiimoteInput(m_index, _channelID, data, sizeof(data));
g_WiimoteInitialize.pWiimoteInput(m_index, _channelID, data, sizeof(data));
}
/* Write data to Wiimote and Extensions registers. */
void Wiimote::WriteData(u16 _channelID, wm_write_data* wd)
void Wiimote::WriteData(const u16 _channelID, wm_write_data* wd)
{
u32 address = convert24bit(wd->address);
// this is done in ReadDate, but not here in WriteData ?
//u16 size = convert16bit(rd->size);
// ignore the 0x010000 bit
address &= 0xFEFFFF;
m_rumble_on = ( wd->rumble != 0 );
if (wd->size > 16)
{
PanicAlert("WriteData: size is > 16 bytes");
@ -244,13 +242,8 @@ void Wiimote::WriteData(u16 _channelID, wm_write_data* wd)
{
case WM_SPACE_EEPROM :
{
static bool first = true;
if (first)
{
PanicAlert("WriteData: first write to EEPROM");
first = false;
}
// Write to EEPROM
if (address + wd->size > WIIMOTE_EEPROM_SIZE)
{
ERROR_LOG(WIIMOTE, "WriteData: address + size out of bounds!");
@ -258,6 +251,17 @@ void Wiimote::WriteData(u16 _channelID, wm_write_data* wd)
return;
}
memcpy(m_eeprom + address, wd->data, wd->size);
// write mii data to file
// i need to improve this greatly
if (address >= 0x0FCA && address < 0x12C0)
{
// writing the whole mii block each write :/
std::ofstream file;
file.open( (std::string(File::GetUserPath(D_WIIUSER_IDX)) + "mii.bin").c_str(), std::ios::binary | std::ios::out);
file.write((char*)m_eeprom + 0x0FCA, 0x02f0);
file.close();
}
}
break;
case WM_SPACE_REGS1 :
@ -265,9 +269,6 @@ void Wiimote::WriteData(u16 _channelID, wm_write_data* wd)
{
// Write to Control Register
// ignore the 0x010000 bit
address &= 0xFEFFFF;
// ignore second byte for extension area
if (0xA4 == (address >> 16))
address &= 0xFF00FF;
@ -302,11 +303,19 @@ void Wiimote::WriteData(u16 _channelID, wm_write_data* wd)
}
/* Read data from Wiimote and Extensions registers. */
void Wiimote::ReadData(u16 _channelID, wm_read_data* rd)
void Wiimote::ReadData(const u16 _channelID, wm_read_data* rd)
{
u32 address = convert24bit(rd->address);
u16 size = convert16bit(rd->size);
// ignore the 0x010000 bit
address &= 0xFEFFFF;
m_rumble_on = (rd->rumble != 0);
ReadRequest rr;
u8* block = new u8[size];
switch (rd->space)
{
case WM_SPACE_EEPROM :
@ -323,7 +332,20 @@ void Wiimote::ReadData(u16 _channelID, wm_read_data* rd)
// generate a read error
size = 0;
}
SendReadDataReply(_channelID, m_eeprom + address, address, size);
// read mii data from file
// i need to improve this greatly
if (address >= 0x0FCA && address < 0x12C0)
{
// reading the whole mii block :/
std::ifstream file;
file.open( (std::string(File::GetUserPath(D_WIIUSER_IDX)) + "mii.bin").c_str(), std::ios::binary | std::ios::in);
file.read((char*)m_eeprom + 0x0FCA, 0x02f0);
file.close();
}
// read mem to be sent to wii
memcpy( block, m_eeprom + address, size);
}
break;
case WM_SPACE_REGS1 :
@ -331,14 +353,11 @@ void Wiimote::ReadData(u16 _channelID, wm_read_data* rd)
{
// Read from Control Register
// ignore the 0x010000 bit
address &= 0xFEFFFF;
// ignore second byte for extension area
if (0xA4 == (address >> 16))
address &= 0xFF00FF;
u8* const block = new u8[ size ];
// read block to send to wii
m_register.Read( address, block, size );
switch (address >> 16)
@ -364,78 +383,86 @@ void Wiimote::ReadData(u16 _channelID, wm_read_data* rd)
}
break;
}
// Let this function process the message and send it to the Wii
SendReadDataReply(_channelID, block, address, (int)size);
delete[] block;
}
break;
default :
PanicAlert("WmReadData: unimplemented parameters (size: %i, addr: 0x%x)!", size, rd->space);
break;
}
// want the requested address, not the above modified one
rr.address = convert24bit(rd->address);
rr.size = size;
rr.position = 0;
rr.data = block;
// send up to 16 bytes
SendReadDataReply( _channelID, rr );
// if there is more data to be sent, add it to the queue
if (rr.size)
m_read_requests.push( rr );
else
delete[] rr.data;
}
// old comment
/* Here we produce the actual 0x21 Input report that we send to the Wii. The
message is divided into 16 bytes pieces and sent piece by piece. There will
be five formatting bytes at the begging of all reports. A common format is
00 00 f0 00 20, the 00 00 means that no buttons are pressed, the f means 16
bytes in the message, the 0 means no error, the 00 20 means that the message
is at the 00 20 offest in the registry that was read.
_Base: The data beginning at _Base[0]
_Address: The starting address inside the registry, this is used to check for out of bounds reading
_Size: The total size to send
*/
void Wiimote::SendReadDataReply(u16 _channelID, const void* _Base, unsigned int _Address, unsigned int _Size)
void Wiimote::SendReadDataReply(const u16 _channelID, ReadRequest& _request)
{
u8 data[23];
data[0] = 0xA1;
data[1] = WM_READ_DATA_REPLY;
wm_read_data_reply* const reply = (wm_read_data_reply*)(data + 2);
reply->buttons = m_status.buttons;
reply->error = 0;
reply->address = Common::swap16(_request.address);
// generate a read error
// Out of bounds. The real Wiimote generate an error for the first
// request to 0x1770 if we dont't replicate that the game will never
// read the calibration data at the beginning of Eeprom. I think this
// error is supposed to occur when we try to read above the freely
// usable space that ends at 0x16ff.
if (0 == _Size)
if (0 == _request.size)
{
reply->size = 0x0f;
reply->error = 0x08;
reply->address = Common::swap16(_Address);
memset(reply->data, 0, sizeof(reply->data));
m_wiimote_init->pWiimoteInput(m_index, _channelID, data, sizeof(data));
}
while (_Size)
else
{
// Limit the amt to 16 bytes
// AyuanX: the MTU is 640B though... what a waste!
const int amt = std::min( (unsigned int)16, _Size );
const int amt = std::min( (unsigned int)16, _request.size );
// no error
reply->error = 0;
// 0x1 means two bytes, 0xf means 16 bytes
reply->size = amt - 1;
reply->address = Common::swap16(_Address);
// Clear the mem first
memset(reply->data, 0, sizeof(reply->data));
// copy piece of mem
memcpy(reply->data, _Base, amt);
memcpy(reply->data, _request.data + _request.position, amt);
// Send a piece
m_wiimote_init->pWiimoteInput(m_index, _channelID, data, sizeof(data));
// advance pointers
_Size -= amt;
_Base = (u8*)_Base + amt;
_Address += amt;
// update request struct
_request.size -= amt;
_request.position += amt;
_request.address += amt;
}
// Send a piece
g_WiimoteInitialize.pWiimoteInput(m_index, _channelID, data, sizeof(data));
}
}

View File

@ -29,20 +29,53 @@ namespace WiimoteEmu
/* An example of a factory default first bytes of the Eeprom memory. There are differences between
different Wiimotes, my Wiimote had different neutral values for the accelerometer. */
static const u8 eeprom_data_0[] = {
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3,
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, 0x74, 0xD3,
// Accelerometer neutral values
// IR, maybe more
// assuming last 2 bytes are checksum
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00, // messing up the checksum on purpose
0xA1, 0xAA, 0x8B, 0x99, 0xAE, 0x9E, 0x78, 0x30, 0xA7, /*0x74, 0xD3,*/ 0x00, 0x00,
// Accelerometer
// 0g x,y,z, 1g x,y,z, 2 byte checksum
0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E,
0x82, 0x82, 0x82, 0x15, 0x9C, 0x9C, 0x9E, 0x38, 0x40, 0x3E
};
static const u8 eeprom_data_16D0[] = {
0x00, 0x00, 0x00, 0xFF, 0x11, 0xEE, 0x00, 0x00,
0x33, 0xCC, 0x44, 0xBB, 0x00, 0x00, 0x66, 0x99,
0x77, 0x88, 0x00, 0x00, 0x2B, 0x01, 0xE8, 0x13
};
struct ReportFeatures
{
u8 core, accel, ir, ext, size;
} const reporting_mode_features[] =
{
//0x30: Core Buttons
{ 2, 0, 0, 0, 4 },
//0x31: Core Buttons and Accelerometer
{ 2, 4, 0, 0, 7 },
//0x32: Core Buttons with 8 Extension bytes
{ 2, 0, 0, 4, 12 },
//0x33: Core Buttons and Accelerometer with 12 IR bytes
{ 2, 4, 7, 0, 19 },
//0x34: Core Buttons with 19 Extension bytes
{ 2, 0, 0, 4, 23 },
//0x35: Core Buttons and Accelerometer with 16 Extension Bytes
{ 2, 4, 0, 7, 23 },
//0x36: Core Buttons with 10 IR bytes and 9 Extension Bytes
{ 2, 0, 4, 14, 23 },
//0x37: Core Buttons and Accelerometer with 10 IR bytes and 6 Extension Bytes
{ 2, 4, 7, 17, 23 },
//0x3d: 21 Extension Bytes
{ 0, 0, 0, 2, 23 },
//0x3e / 0x3f: Interleaved Core Buttons and Accelerometer with 36 IR bytes
// UNSUPPORTED
{ 0, 0, 0, 0, 23 },
};
// array of accel data to emulate shaking
const u8 shake_data[8] = { 0x80, 0x40, 0x01, 0x40, 0x80, 0xC0, 0xFF, 0xC0 };
const u8 shake_data[8] = { 0x40, 0x01, 0x40, 0x80, 0xC0, 0xFF, 0xC0, 0x80 };
const u16 button_bitmasks[] =
{
@ -76,6 +109,8 @@ void Wiimote::Reset()
m_reporting_channel = 0;
m_reporting_auto = false;
m_rumble_on = 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
m_extension->active_extension = -1;
@ -97,7 +132,7 @@ void Wiimote::Reset()
//m_reg_speaker = &m_register[0xa20000][0];
m_reg_ext = &m_register[0xa40000][0];
//m_reg_motion_plus = &m_register[0xa60000][0];
//m_reg_ir = &m_register[0xB00000][0];
m_reg_ir = &m_register[0xB00000][0];
// status
memset( &m_status, 0, sizeof(m_status) );
@ -107,11 +142,18 @@ void Wiimote::Reset()
// 0x33 - 0x54: level 3
// 0x55 - 0xff: level 4
m_status.battery = 0x5f;
m_shake_step = 0;
// clear read request queue
while (m_read_requests.size())
{
delete[] m_read_requests.front().data;
m_read_requests.pop();
}
}
Wiimote::Wiimote( const unsigned int index, SWiimoteInitialize* const wiimote_initialize )
: m_wiimote_init( wiimote_initialize )
, m_index(index)
Wiimote::Wiimote( const unsigned int index ) : m_index(index)
{
// ---- set up all the controls ----
@ -121,11 +163,9 @@ Wiimote::Wiimote( const unsigned int index, SWiimoteInitialize* const wiimote_in
m_buttons->controls.push_back( new ControlGroup::Input( named_buttons[i] ) );
// ir
//groups.push_back( m_rumble = new ControlGroup( "IR" ) );
//m_rumble->controls.push_back( new ControlGroup::Output( "X" ) );
//m_rumble->controls.push_back( new ControlGroup::Output( "Y" ) );
//m_rumble->controls.push_back( new ControlGroup::Output( "Distance" ) );
//m_rumble->controls.push_back( new ControlGroup::Output( "Hide" ) );
groups.push_back( m_ir = new Cursor( "IR", &g_WiimoteInitialize ) );
m_ir->controls.push_back( new ControlGroup::Input( "Forward" ) );
m_ir->controls.push_back( new ControlGroup::Input( "Hide" ) );
// forces
groups.push_back( m_tilt = new Tilt( "Pitch and Roll" ) );
@ -171,22 +211,52 @@ std::string Wiimote::GetName() const
void Wiimote::Update()
{
const bool is_sideways = options->settings[1]->value > 0;
const bool is_sideways = 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);
// no rumble if no focus
if (false == focus)
m_rumble_on = false;
m_rumble->controls[0]->control_ref->State(m_rumble_on);
// update buttons in status struct
m_status.buttons = 0;
m_buttons->GetState( &m_status.buttons, button_bitmasks );
m_dpad->GetState( &m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks );
if ( focus )
{
m_buttons->GetState( &m_status.buttons, button_bitmasks );
m_dpad->GetState( &m_status.buttons, is_sideways ? dpad_sideways_bitmasks : dpad_bitmasks );
}
// check if there is a read data request
if ( m_read_requests.size() )
{
ReadRequest& rr = m_read_requests.front();
// send up to 16 bytes to the wii
SendReadDataReply(m_reporting_channel, rr);
//SendReadDataReply(rr.channel, rr);
// if there is no more data, remove from queue
if (0 == rr.size)
{
delete[] rr.data;
m_read_requests.pop();
}
// dont send any other reports
return;
}
// -- maybe this should happen before the read request stuff?
// check if a status report needs to be sent
// this happens on wiimote sync and when extensions are switched
if (m_extension->active_extension != m_extension->switch_extension)
{
RequestStatus( m_reporting_channel, NULL );
RequestStatus(m_reporting_channel);
// Wiibrew: Following a connection or disconnection event on the Extension Port,
// data reporting is disabled and the Data Reporting Mode must be reset before new data can arrive.
// after a game receives an unrequested status report,
// it expects data reports to stop until it sets the reporting mode again
m_reporting_auto = false;
@ -196,70 +266,26 @@ void Wiimote::Update()
return;
// figure out what data we need
size_t rpt_size = 0;
size_t rpt_core = 0;
size_t rpt_accel = 0;
size_t rpt_ir = 0;
size_t rpt_ext = 0;
switch ( m_reporting_mode )
{
//(a1) 30 BB BB
case WM_REPORT_CORE :
rpt_size = 2 + 2;
rpt_core = 2;
break;
//(a1) 31 BB BB AA AA AA
case WM_REPORT_CORE_ACCEL :
rpt_size = 2 + 2 + 3;
rpt_core = 2;
rpt_accel = 2 + 2;
break;
//(a1) 33 BB BB AA AA AA II II II II II II II II II II II II
case WM_REPORT_CORE_ACCEL_IR12 :
rpt_size = 2 + 2 + 3 + 12;
rpt_core = 2;
rpt_accel = 2 + 2;
rpt_ir = 2 + 2 + 3;
break;
//(a1) 35 BB BB AA AA AA EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE EE
case WM_REPORT_CORE_ACCEL_EXT16 :
rpt_size = 2 + 2 + 3 + 16;
rpt_core = 2;
rpt_accel = 2 + 2;
rpt_ext = 2 + 2 + 3;
break;
//(a1) 37 BB BB AA AA AA II II II II II II II II II II EE EE EE EE EE EE
case WM_REPORT_CORE_ACCEL_IR10_EXT6 :
rpt_size = 2 + 2 + 3 + 10 + 6;
rpt_core = 2;
rpt_accel = 2 + 2;
rpt_ir = 2 + 2 + 3;
rpt_ext = 2 + 2 + 3 + 10;
break;
default :
//PanicAlert( "Unsupported Reporting Mode" );
return;
break;
}
const ReportFeatures& rpt = reporting_mode_features[m_reporting_mode - WM_REPORT_CORE];
// set up output report
u8* const rpt = new u8[rpt_size];
memset( rpt, 0, rpt_size );
// made data bigger than needed in case the wii specifies the wrong ir mode for a reporting mode
u8 data[46];
memset( data, 0, sizeof(data) );
rpt[0] = 0xA1;
rpt[1] = m_reporting_mode;
data[0] = 0xA1;
data[1] = m_reporting_mode;
// core buttons - always 2
if (rpt_core)
*(wm_core*)(rpt + rpt_core) = m_status.buttons;
// core buttons
if (rpt.core)
*(wm_core*)(data + rpt.core) = m_status.buttons;
// accelerometer
if (rpt_accel)
if (rpt.accel)
{
// tilt
float x, y;
m_tilt->GetState( &x, &y, 0, (PI / 2) ); // 90 degrees
m_tilt->GetState( &x, &y, 0, focus ? (PI / 2) : 0 ); // 90 degrees
// this isn't doing anything with those low bits in the calib data, o well
@ -270,58 +296,144 @@ void Wiimote::Update()
one_g[i] = (&cal->one_g.x)[i] - zero_g[i];
// this math should be good enough :P
rpt[rpt_accel + 2] = u8(sin( (PI / 2) - std::max( abs(x), abs(y) ) ) * one_g[2] + zero_g[2]);
data[rpt.accel + 2] = u8(sin( (PI / 2) - std::max( abs(x), abs(y) ) ) * one_g[2] + zero_g[2]);
if (is_sideways)
{
rpt[rpt_accel + 0] = u8(sin(y) * -one_g[1] + zero_g[1]);
rpt[rpt_accel + 1] = u8(sin(x) * -one_g[0] + zero_g[0]);
data[rpt.accel + 0] = u8(sin(y) * -one_g[1] + zero_g[1]);
data[rpt.accel + 1] = u8(sin(x) * -one_g[0] + zero_g[0]);
}
else
{
rpt[rpt_accel + 0] = u8(sin(x) * -one_g[0] + zero_g[0]);
rpt[rpt_accel + 1] = u8(sin(y) * one_g[1] + zero_g[1]);
data[rpt.accel + 0] = u8(sin(x) * -one_g[0] + zero_g[0]);
data[rpt.accel + 1] = u8(sin(y) * one_g[1] + zero_g[1]);
}
// shake
const unsigned int btns[] = { 0x01, 0x02, 0x04 };
const unsigned int btns[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20 };
unsigned int shake = 0;
m_shake->GetState( &shake, btns );
static unsigned int shake_step = 0;
if (focus)
m_shake->GetState( &shake, btns );
if (shake)
{
shake_step = (shake_step + 1) % sizeof(shake_data);
for ( unsigned int i=0; i<3; ++i )
if ( shake & (1 << i) )
rpt[rpt_accel + i] = shake_data[shake_step];
if (shake & (1 << i))
data[rpt.accel + i] = shake_data[m_shake_step];
m_shake_step = (m_shake_step + 1) % sizeof(shake_data);
}
else
shake_step = 0;
}
m_shake_step = 0;
// swing
//u8 swing[3];
//m_swing->GetState( swing, 0x80, 60 );
//for ( unsigned int i=0; i<3; ++i )
// if ( swing[i] != 0x80 )
// data[rpt.accel + i] = swing[i];
// TODO: IR
if (rpt_ir)
{
}
// extension
if (rpt_ext)
if (rpt.ext)
{
// temporary
m_extension->GetState(rpt + rpt_ext);
wiimote_encrypt(&m_ext_key, rpt + rpt_ext, 0x00, sizeof(wm_extension));
m_extension->GetState(data + rpt.ext, focus);
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, rpt + rpt_ext, sizeof(wm_extension));
memcpy(m_reg_ext + 8, data + rpt.ext, sizeof(wm_extension));
}
// send input report
m_wiimote_init->pWiimoteInput( m_index, m_reporting_channel, rpt, (u32)rpt_size );
// ir
if (rpt.ir)
{
float xx = 10000, yy = 0, zz = 0;
delete[] rpt;
if (focus)
m_ir->GetState(&xx, &yy, &zz, true);
xx *= (-256 * 0.95f);
xx += 512;
yy *= (-256 * 0.90f);
yy += 490;
const unsigned int distance = (unsigned int)(100 + 100 * zz);
// TODO: make roll affect the dot positions
const unsigned int y = (unsigned int)yy;
unsigned int x[4];
x[0] = (unsigned int)(xx - distance);
x[1] = (unsigned int)(xx + distance);
x[2] = (unsigned int)(xx - 1.2f * distance);
x[3] = (unsigned int)(xx + 1.2f * distance);
// ir mode
switch (m_reg_ir[0x33])
{
// basic
case 1 :
{
memset(data + rpt.ir, 0xFF, 10);
wm_ir_basic* const irdata = (wm_ir_basic*)(data + rpt.ir);
if (y < 768)
{
for ( unsigned int i=0; i<2; ++i )
{
if (x[i*2] < 1024)
{
irdata[i].x1 = u8(x[i*2]);
irdata[i].x1hi = x[i*2] >> 8;
irdata[i].y1 = u8(y);
irdata[i].y1hi = y >> 8;
}
if (x[i*2+1] < 1024)
{
irdata[i].x2 = u8(x[i*2+1]);
irdata[i].x2hi = x[i*2+1] >> 8;
irdata[i].y2 = u8(y);
irdata[i].y2hi = y >> 8;
}
}
}
}
break;
// extended
case 3 :
{
memset(data + rpt.ir, 0xFF, 12);
wm_ir_extended* const irdata = (wm_ir_extended*)(data + rpt.ir);
if (y < 768)
{
for ( unsigned int i=0; i<2; ++i )
if (irdata[i].x < 1024)
{
irdata[i].x = u8(x[i]);
irdata[i].xhi = x[i] >> 8;
irdata[i].y = u8(y);
irdata[i].yhi = y >> 8;
irdata[i].size = 10;
}
}
}
break;
// full
case 5 :
// UNSUPPORTED
break;
}
}
// send data report
g_WiimoteInitialize.pWiimoteInput( m_index, m_reporting_channel, data, rpt.size );
}
void Wiimote::ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size)
{
// Check for custom communication
@ -357,7 +469,7 @@ void Wiimote::ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
HidOutputReport(_channelID, (wm_report*)hidp->data);
u8 handshake = HID_HANDSHAKE_SUCCESS;
m_wiimote_init->pWiimoteInput(m_index, _channelID, &handshake, 1);
g_WiimoteInitialize.pWiimoteInput(m_index, _channelID, &handshake, 1);
PanicAlert("HID_TYPE_DATA - OUTPUT: Ambiguous Control Channel Report!");
}
@ -374,7 +486,7 @@ void Wiimote::ControlChannel(u16 _channelID, const void* _pData, u32 _Size)
}
void Wiimote::InterruptChannel(u16 _channelID, const void* _pData, u32 _Size)
void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size)
{
hid_packet* hidp = (hid_packet*)_pData;

View File

@ -7,6 +7,7 @@
#include "Encryption.h"
#include <vector>
#include <queue>
#define PI 3.14159265358979323846
@ -17,6 +18,8 @@
#define WIIMOTE_REG_EXT_SIZE 0x100
#define WIIMOTE_REG_IR_SIZE 0x34
extern SWiimoteInitialize g_WiimoteInitialize;
namespace WiimoteEmu
{
@ -26,31 +29,36 @@ class Wiimote : public ControllerEmu
{
public:
Wiimote( const unsigned int index, SWiimoteInitialize* const wiimote_initialize );
struct ReadRequest
{
unsigned int address, size, position;
u8* data;
};
Wiimote( const unsigned int index );
void Reset();
void Update();
void InterruptChannel(u16 _channelID, const void* _pData, u32 _Size);
void ControlChannel(u16 _channelID, const void* _pData, u32 _Size);
void InterruptChannel(const u16 _channelID, const void* _pData, u32 _Size);
void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size);
void ReportMode(u16 _channelID, wm_report_mode* dr);
void HidOutputReport(u16 _channelID, wm_report* sr);
void SendAck(u16 _channelID, u8 _reportID);
void RequestStatus(u16 _channelID, wm_request_status* rs, int Extension = -1);
void ReportMode(const u16 _channelID, wm_report_mode* dr);
void HidOutputReport(const u16 _channelID, wm_report* sr);
void SendAck(const u16 _channelID, u8 _reportID);
void RequestStatus(const u16 _channelID, wm_request_status* rs = NULL);
void WriteData(u16 _channelID, wm_write_data* wd);
void ReadData(u16 _channelID, wm_read_data* rd);
void SendReadDataReply(u16 _channelID, const void* _Base, unsigned int _Address, unsigned int _Size);
void WriteData(const u16 _channelID, wm_write_data* wd);
void ReadData(const u16 _channelID, wm_read_data* rd);
void SendReadDataReply(const u16 _channelID, ReadRequest& _request);
std::string GetName() const;
private:
SWiimoteInitialize* const m_wiimote_init;
Buttons* m_buttons;
Buttons* m_dpad;
Buttons* m_shake;
Cursor* m_ir;
Tilt* m_tilt;
Force* m_swing;
ControlGroup* m_rumble;
@ -59,10 +67,14 @@ private:
const unsigned int m_index;
bool m_rumble_on;
bool m_reporting_auto;
unsigned int m_reporting_mode;
unsigned int m_reporting_channel;
unsigned int m_shake_step;
wm_status_report m_status;
class Register : public std::map< size_t, std::vector<u8> >
@ -73,12 +85,17 @@ private:
} m_register;
// read data request queue
// maybe it isn't actualy a queue
// 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];
//u8* m_reg_speaker;
//u8* m_reg_motion_plus;
//u8* m_reg_ir;
u8* m_reg_ir;
u8* m_reg_ext;
wiimote_key m_ext_key;

View File

@ -106,7 +106,7 @@ void InitPlugin( void* const hwnd )
{
// add 4 wiimotes
for ( unsigned int i = 0; i<4; ++i )
g_plugin.controllers.push_back( new WiimoteEmu::Wiimote( i, &g_WiimoteInitialize ) );
g_plugin.controllers.push_back( new WiimoteEmu::Wiimote(i) );
// load the saved controller config
g_plugin.LoadConfig();