diff --git a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp index 16d39289c0..a2b6c638c9 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp +++ b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp @@ -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, ¤t_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 diff --git a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h index 8ac77d6c7d..194a9c19fd 100644 --- a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h +++ b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h @@ -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; }; diff --git a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp index ac49a0951a..72738c9164 100644 --- a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp +++ b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.cpp @@ -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 ); diff --git a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.h b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.h index 31033a8384..9a2219b228 100644 --- a/Source/Plugins/InputPluginCommon/Src/ConfigDiag.h +++ b/Source/Plugins/InputPluginCommon/Src/ConfigDiag.h @@ -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(); diff --git a/Source/Plugins/InputPluginCommon/Src/ConfigDiagBitmaps.cpp b/Source/Plugins/InputPluginCommon/Src/ConfigDiagBitmaps.cpp index 7f97249c17..04061098e8 100644 --- a/Source/Plugins/InputPluginCommon/Src/ConfigDiagBitmaps.cpp +++ b/Source/Plugins/InputPluginCommon/Src/ConfigDiagBitmaps.cpp @@ -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 ) diff --git a/Source/Plugins/InputPluginCommon/Src/ControllerEmu.cpp b/Source/Plugins/InputPluginCommon/Src/ControllerEmu.cpp index b97aecca04..8d4fad8813 100644 --- a/Source/Plugins/InputPluginCommon/Src/ControllerEmu.cpp +++ b/Source/Plugins/InputPluginCommon/Src/ControllerEmu.cpp @@ -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 + +} diff --git a/Source/Plugins/InputPluginCommon/Src/ControllerEmu.h b/Source/Plugins/InputPluginCommon/Src/ControllerEmu.h index 3026828f09..13b6b27d6c 100644 --- a/Source/Plugins/InputPluginCommon/Src/ControllerEmu.h +++ b/Source/Plugins/InputPluginCommon/Src/ControllerEmu.h @@ -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 + 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 attachments; @@ -302,7 +368,6 @@ public: std::vector< ControlGroup* > groups; - ControlGroup* options; ControllerInterface::DeviceQualifier default_device; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.cpp index 172ac6f975..7e8471f9bb 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.cpp @@ -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 ); } diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.h b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.h index 9a6cfed9b5..94175a2634 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.h +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Attachment.h @@ -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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.cpp index 3938e59360..bd9fb1baf6 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.cpp @@ -96,14 +96,16 @@ Classic::Classic() : Attachment( "Classic Controller" ) memcpy( ®[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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.h b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.h index 71124c9d2c..df5c9c9f65 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.h +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Classic.h @@ -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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.cpp index cb60dca575..22128f1ee6 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.cpp @@ -55,18 +55,21 @@ Nunchuk::Nunchuk() : Attachment( "Nunchuk" ) memcpy( ®[0x20], nunchuck_calibration, sizeof(nunchuck_calibration) ); // id memcpy( ®[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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.h b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.h index 34f8590130..9d42dc55ea 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.h +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/Attachment/Nunchuk.h @@ -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; }; } diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/EmuSubroutines.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/EmuSubroutines.cpp index 4e2737fded..93f4e2585f 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/EmuSubroutines.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/EmuSubroutines.cpp @@ -33,6 +33,7 @@ #include #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)); } } diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.cpp index e4c303b454..d698dfb6b5 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.cpp @@ -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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.h b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.h index a6bc9e9266..b55f3293bf 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.h +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteEmu/WiimoteEmu.h @@ -7,6 +7,7 @@ #include "Encryption.h" #include +#include #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 > @@ -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; diff --git a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp index 0d241551ea..0c8bd136ff 100644 --- a/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp +++ b/Source/Plugins/Plugin_WiimoteNew/Src/WiimoteNew.cpp @@ -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();