summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon
diff options
context:
space:
mode:
authorhrydgard <hrydgard@gmail.com>2010-06-12 17:39:33 +0000
committerhrydgard <hrydgard@gmail.com>2010-06-12 17:39:33 +0000
commit1cd25e2406ea370cacfb82ec6dc164153052ca9d (patch)
tree29c06c64c49841b89a83f614c77fb59bda4f6008 /Source/Core/InputCommon
parent3e3aa2364e4ed6c3fe3be9331b7d0827adf9042f (diff)
(cleanup) InputPluginCommon is dead. Long live InputCommon and InputUICommon.
I hope I didn't break the mac+linux builds - if i did, fixing it should be a simple matter of adjusting the sconscripts. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5661 8ced0084-cf51-0410-be5f-012b33b47a6e
Diffstat (limited to 'Source/Core/InputCommon')
-rw-r--r--Source/Core/InputCommon/InputCommon.vcproj18
-rw-r--r--Source/Core/InputCommon/Src/ControllerEmu.cpp375
-rw-r--r--Source/Core/InputCommon/Src/ControllerEmu.h438
-rw-r--r--Source/Core/InputCommon/Src/InputConfig.cpp69
-rw-r--r--Source/Core/InputCommon/Src/InputConfig.h53
-rw-r--r--Source/Core/InputCommon/Src/SConscript2
6 files changed, 954 insertions, 1 deletions
diff --git a/Source/Core/InputCommon/InputCommon.vcproj b/Source/Core/InputCommon/InputCommon.vcproj
index c6a11789e0..92849a1c27 100644
--- a/Source/Core/InputCommon/InputCommon.vcproj
+++ b/Source/Core/InputCommon/InputCommon.vcproj
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
- Version="9.00"
+ Version="9,00"
Name="InputCommon"
ProjectGUID="{C7E5D50A-2916-464B-86A7-E10B3CC88ADA}"
RootNamespace="VideoCommon"
@@ -481,6 +481,14 @@
>
</File>
<File
+ RelativePath=".\Src\ControllerEmu.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Src\ControllerEmu.h"
+ >
+ </File>
+ <File
RelativePath=".\Src\DirectInputBase.cpp"
>
</File>
@@ -509,6 +517,14 @@
>
</File>
<File
+ RelativePath=".\Src\InputConfig.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Src\InputConfig.h"
+ >
+ </File>
+ <File
RelativePath=".\Src\SDL_Util.cpp"
>
</File>
diff --git a/Source/Core/InputCommon/Src/ControllerEmu.cpp b/Source/Core/InputCommon/Src/ControllerEmu.cpp
new file mode 100644
index 0000000000..d696a55c96
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerEmu.cpp
@@ -0,0 +1,375 @@
+// Copyright (C) 2010 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "ControllerEmu.h"
+
+#if defined(HAVE_X11) && HAVE_X11
+#include <X11/Xlib.h>
+#endif
+
+ControllerEmu::~ControllerEmu()
+{
+ // control groups
+ std::vector<ControlGroup*>::const_iterator
+ i = groups.begin(),
+ e = groups.end();
+ for ( ; i!=e; ++i )
+ delete *i;
+}
+
+ControllerEmu::ControlGroup::~ControlGroup()
+{
+ // controls
+ std::vector<Control*>::const_iterator
+ ci = controls.begin(),
+ ce = controls.end();
+ for ( ; ci!=ce; ++ci )
+ delete *ci;
+
+ // settings
+ std::vector<Setting*>::const_iterator
+ si = settings.begin(),
+ se = settings.end();
+ for ( ; si!=se; ++si )
+ delete *si;
+}
+
+ControllerEmu::Extension::~Extension()
+{
+ // attachments
+ std::vector<ControllerEmu*>::const_iterator
+ ai = attachments.begin(),
+ ae = attachments.end();
+ for ( ; ai!=ae; ++ai )
+ delete *ai;
+}
+ControllerEmu::ControlGroup::Control::~Control()
+{
+ delete control_ref;
+}
+
+void ControllerEmu::UpdateReferences( ControllerInterface& devi )
+{
+ std::vector<ControlGroup*>::const_iterator
+ i = groups.begin(),
+ e = groups.end();
+ for ( ; i!=e; ++i )
+ {
+ std::vector<ControlGroup::Control*>::const_iterator
+ ci = (*i)->controls.begin(),
+ ce = (*i)->controls.end();
+ for ( ; ci!=ce; ++ci )
+ devi.UpdateReference( (*ci)->control_ref );
+
+ // extension
+ if ( GROUP_TYPE_EXTENSION == (*i)->type )
+ {
+ std::vector<ControllerEmu*>::const_iterator
+ ai = ((Extension*)*i)->attachments.begin(),
+ ae = ((Extension*)*i)->attachments.end();
+ for ( ; ai!=ae; ++ai )
+ (*ai)->UpdateReferences( devi );
+ }
+ }
+}
+
+void ControllerEmu::UpdateDefaultDevice()
+{
+ std::vector<ControlGroup*>::const_iterator
+ i = groups.begin(),
+ e = groups.end();
+ for ( ; i!=e; ++i )
+ {
+ std::vector<ControlGroup::Control*>::const_iterator
+ ci = (*i)->controls.begin(),
+ ce = (*i)->controls.end();
+ for ( ; ci!=ce; ++ci )
+ (*ci)->control_ref->device_qualifier = default_device;
+
+ // extension
+ if ( GROUP_TYPE_EXTENSION == (*i)->type )
+ {
+ std::vector<ControllerEmu*>::const_iterator
+ ai = ((Extension*)*i)->attachments.begin(),
+ ae = ((Extension*)*i)->attachments.end();
+ for ( ; ai!=ae; ++ai )
+ {
+ (*ai)->default_device = default_device;
+ (*ai)->UpdateDefaultDevice();
+ }
+ }
+ }
+}
+
+void ControllerEmu::ControlGroup::LoadConfig(IniFile::Section *sec, const std::string& defdev, const std::string& base )
+{
+ std::string group( base + name ); group += "/";
+
+ // settings
+ std::vector<ControlGroup::Setting*>::const_iterator
+ si = settings.begin(),
+ se = settings.end();
+ for ( ; si!=se; ++si )
+ {
+ sec->Get((group+(*si)->name).c_str(), &(*si)->value, (*si)->default_value*100);
+ (*si)->value /= 100;
+ }
+
+ // controls
+ std::vector<ControlGroup::Control*>::const_iterator
+ ci = controls.begin(),
+ ce = controls.end();
+ for ( ; ci!=ce; ++ci )
+ {
+ // control and dev qualifier
+ sec->Get((group + (*ci)->name).c_str(), &(*ci)->control_ref->control_qualifier.name, "");
+ std::string dev;
+ sec->Get((group+(*ci)->name+"/Device").c_str(), &dev, defdev.c_str());
+ (*ci)->control_ref->device_qualifier.FromString(dev);
+
+ // range
+ sec->Get( (group+(*ci)->name+"/Range").c_str(), &(*ci)->control_ref->range, 100.0f);
+ (*ci)->control_ref->range /= 100;
+
+ // input mode
+ if ( (*ci)->control_ref->is_input )
+ sec->Get( (group+(*ci)->name+"/Mode").c_str(), &((ControllerInterface::InputReference*)((*ci)->control_ref))->mode, 0 );
+ }
+
+ // extensions
+ if ( GROUP_TYPE_EXTENSION == type )
+ {
+ Extension* const ex = ((Extension*)this);
+
+ ex->switch_extension = 0;
+ unsigned int n = 0;
+ std::string extname;
+ sec->Get((base + name).c_str(), &extname, "");
+
+ std::vector<ControllerEmu*>::const_iterator
+ ai = ((Extension*)this)->attachments.begin(),
+ ae = ((Extension*)this)->attachments.end();
+ for ( ; ai!=ae; ++ai,++n )
+ {
+ (*ai)->default_device.FromString( defdev );
+ (*ai)->LoadConfig( sec, base + (*ai)->GetName() + "/" );
+
+ if ( (*ai)->GetName() == extname )
+ ex->switch_extension = n;
+ }
+ }
+}
+
+void ControllerEmu::LoadConfig( IniFile::Section *sec, const std::string& base )
+{
+ std::string defdev = default_device.ToString();
+ if (base.empty())
+ {
+ sec->Get((base + "Device").c_str(), &defdev, "");
+ default_device.FromString(defdev);
+ }
+ std::vector<ControlGroup*>::const_iterator i = groups.begin(),
+ e = groups.end();
+ for ( ; i!=e; ++i )
+ (*i)->LoadConfig(sec, defdev, base);
+}
+
+void ControllerEmu::ControlGroup::SaveConfig( IniFile::Section *sec, const std::string& defdev, const std::string& base )
+{
+ std::string group( base + name ); group += "/";
+
+ // settings
+ std::vector<ControlGroup::Setting*>::const_iterator
+ si = settings.begin(),
+ se = settings.end();
+ for ( ; si!=se; ++si )
+ sec->Set( (group+(*si)->name).c_str(), (*si)->value*100.0f, (*si)->default_value*100.0f);
+
+ // controls
+ std::vector<ControlGroup::Control*>::const_iterator
+ ci = controls.begin(),
+ ce = controls.end();
+ for ( ; ci!=ce; ++ci )
+ {
+ // control and dev qualifier
+ sec->Set( (group+(*ci)->name).c_str(), (*ci)->control_ref->control_qualifier.name, "");
+ sec->Set( (group+(*ci)->name+"/Device").c_str(), (*ci)->control_ref->device_qualifier.ToString(), defdev);
+
+ // range
+ sec->Set( (group+(*ci)->name+"/Range").c_str(), (*ci)->control_ref->range*100.0f, 100.0f);
+
+ // input mode
+ if ( (*ci)->control_ref->is_input )
+ {
+ const int mode = ((ControllerInterface::InputReference*)((*ci)->control_ref))->mode;
+ if (mode)
+ sec->Set((group+(*ci)->name+"/Mode").c_str(), mode);
+ else
+ sec->Delete((group+(*ci)->name+"/Mode").c_str());
+ }
+ }
+
+ // extensions
+ if ( GROUP_TYPE_EXTENSION == type )
+ {
+ Extension* const ext = ((Extension*)this);
+ sec->Set((base + name).c_str(), ext->attachments[ext->switch_extension]->GetName(), "None");
+
+ std::vector<ControllerEmu*>::const_iterator
+ ai = ((Extension*)this)->attachments.begin(),
+ ae = ((Extension*)this)->attachments.end();
+ for ( ; ai!=ae; ++ai )
+ (*ai)->SaveConfig( sec, base + (*ai)->GetName() + "/" );
+ }
+}
+
+void ControllerEmu::SaveConfig( IniFile::Section *sec, const std::string& base )
+{
+ const std::string defdev = default_device.ToString();
+ if ( base.empty() )
+ sec->Set( (/*std::string(" ") +*/ base + "Device").c_str(), defdev, "");
+
+ std::vector<ControlGroup*>::const_iterator i = groups.begin(),
+ e = groups.end();
+ for ( ; i!=e; ++i )
+ (*i)->SaveConfig( sec, defdev, base );
+}
+
+ControllerEmu::AnalogStick::AnalogStick( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_STICK )
+{
+ for ( unsigned int i = 0; i < 4; ++i )
+ controls.push_back( new Input( named_directions[i] ) );
+
+ controls.push_back( new Input( "Modifier" ) );
+
+ settings.push_back( new Setting("Dead Zone", 0, 0, 50 ) );
+ settings.push_back( new Setting("Square Stick", 0 ) );
+
+}
+
+ControllerEmu::Buttons::Buttons( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_BUTTONS )
+{
+ settings.push_back( new Setting("Threshold", 0.5f ) );
+}
+
+ControllerEmu::MixedTriggers::MixedTriggers( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_MIXED_TRIGGERS )
+{
+ settings.push_back( new Setting("Threshold", 0.9f ) );
+}
+
+ControllerEmu::Triggers::Triggers( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_TRIGGERS )
+{
+ settings.push_back( new Setting("Dead Zone", 0, 0, 50 ) );
+}
+
+ControllerEmu::Force::Force( const char* const _name ) : ControlGroup( _name, GROUP_TYPE_FORCE )
+{
+ controls.push_back( new Input( "Up" ) );
+ controls.push_back( new Input( "Down" ) );
+ controls.push_back( new Input( "Left" ) );
+ controls.push_back( new Input( "Right" ) );
+ controls.push_back( new Input( "Forward" ) );
+ controls.push_back( new Input( "Backward" ) );
+ controls.push_back( new Input( "Modifier" ) );
+
+ settings.push_back( new Setting("Dead Zone", 0, 0, 50 ) );
+}
+
+ControllerEmu::Tilt::Tilt( const char* const _name )
+ : ControlGroup( _name, GROUP_TYPE_TILT )
+{
+ memset(m_tilt, 0, sizeof(m_tilt));
+
+ //for ( unsigned int i = 0; i < 4; ++i )
+ //controls.push_back( new Input( named_directions[i] ) );
+ controls.push_back( new Input( "Forward" ) );
+ controls.push_back( new Input( "Backward" ) );
+ controls.push_back( new Input( "Left" ) );
+ controls.push_back( new Input( "Right" ) );
+
+ controls.push_back( new Input( "Modifier" ) );
+
+ settings.push_back( new Setting("Dead Zone", 0, 0, 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 )
+ , wiimote_initialize(_wiimote_initialize)
+ , m_z(0)
+{
+ for ( unsigned int i = 0; i < 4; ++i )
+ controls.push_back( new Input( named_directions[i] ) );
+ controls.push_back( new Input( "Forward" ) );
+ controls.push_back( new Input( "Backward" ) );
+ controls.push_back( new Input( "Hide" ) );
+
+ settings.push_back( new Setting("Center", 0.5f ) );
+ settings.push_back( new Setting("Width", 0.5f ) );
+ settings.push_back( new Setting("Height", 0.5f ) );
+
+}
+
+void GetMousePos(float& x, float& y, const SWiimoteInitialize* const wiimote_initialize)
+{
+#if ( defined(_WIN32) || (defined(HAVE_X11) && HAVE_X11))
+ unsigned int win_width = 2, win_height = 2;
+#endif
+
+#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 };
+
+ 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/Core/InputCommon/Src/ControllerEmu.h b/Source/Core/InputCommon/Src/ControllerEmu.h
new file mode 100644
index 0000000000..90170c21cd
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerEmu.h
@@ -0,0 +1,438 @@
+// Copyright (C) 2010 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _CONTROLLEREMU_H_
+#define _CONTROLLEREMU_H_
+
+// windows crap
+#define NOMINMAX
+
+#include "pluginspecs_pad.h"
+#include "pluginspecs_wiimote.h"
+#include <math.h>
+
+#include "ControllerInterface/ControllerInterface.h"
+#include "IniFile.h"
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+#define sign(x) ((x)?(x)<0?-1:1:0)
+
+enum
+{
+ GROUP_TYPE_OTHER,
+ GROUP_TYPE_STICK,
+ GROUP_TYPE_MIXED_TRIGGERS,
+ GROUP_TYPE_BUTTONS,
+ GROUP_TYPE_FORCE,
+ GROUP_TYPE_EXTENSION,
+ GROUP_TYPE_TILT,
+ GROUP_TYPE_CURSOR,
+ GROUP_TYPE_TRIGGERS,
+};
+
+const char * const named_directions[] =
+{
+ "Up",
+ "Down",
+ "Left",
+ "Right"
+};
+
+void GetMousePos(float& x, float& y, const SWiimoteInitialize* const wiimote_initialize);
+
+class ControllerEmu
+{
+public:
+
+ class ControlGroup
+ {
+ public:
+
+ class Control
+ {
+ protected:
+ Control( ControllerInterface::ControlReference* const _ref, const char * const _name )
+ : control_ref(_ref), name(_name){}
+ public:
+
+ virtual ~Control();
+ ControllerInterface::ControlReference* const control_ref;
+ const char * const name;
+
+ };
+
+ class Input : public Control
+ {
+ public:
+
+ Input( const char * const _name )
+ : Control( new ControllerInterface::InputReference, _name ) {}
+
+ };
+
+ class Output : public Control
+ {
+ public:
+
+ Output( const char * const _name )
+ : Control( new ControllerInterface::OutputReference, _name ) {}
+
+ };
+
+ class Setting
+ {
+ public:
+
+ Setting(const char* const _name, const ControlState def_value
+ , const unsigned int _low = 0, 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) {}
+ virtual ~ControlGroup();
+
+ void LoadConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
+ void SaveConfig(IniFile::Section *sec, const std::string& defdev = "", const std::string& base = "" );
+
+ const char* const name;
+ const unsigned int type;
+
+ std::vector< Control* > controls;
+ std::vector< Setting* > settings;
+
+ };
+
+ class AnalogStick : public ControlGroup
+ {
+ public:
+
+ template <typename C>
+ void GetState( C* const x, C* const y, const unsigned int base, const unsigned int range )
+ {
+ // this is all a mess
+
+ ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
+ ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
+
+ ControlState deadzone = settings[0]->value;
+ ControlState square = settings[1]->value;
+ ControlState m = controls[4]->control_ref->State();
+
+ // modifier code
+ if ( m )
+ {
+ yy = (abs(yy)>deadzone) * sign(yy) * (m + deadzone/2);
+ xx = (abs(xx)>deadzone) * sign(xx) * (m + deadzone/2);
+ }
+
+ // deadzone / square stick code
+ if ( deadzone || square )
+ {
+ // this section might be all wrong, but its working good enough, i think
+
+ ControlState ang = atan2( yy, xx );
+ ControlState ang_sin = sin(ang);
+ ControlState ang_cos = cos(ang);
+
+ // the amt a full square stick would have at current angle
+ ControlState square_full = std::min( ang_sin ? 1/abs(ang_sin) : 2, ang_cos ? 1/abs(ang_cos) : 2 );
+
+ // the amt a full stick would have that was ( user setting squareness) at current angle
+ // i think this is more like a pointed circle rather than a rounded square like it should be
+ ControlState stick_full = ( 1 + ( square_full - 1 ) * square );
+
+ ControlState dist = sqrt(xx*xx + yy*yy);
+
+ // dead zone code
+ dist = std::max( 0.0f, dist - deadzone * stick_full );
+ dist /= ( 1 - deadzone );
+
+ // square stick code
+ ControlState amt = dist / stick_full;
+ dist -= ((square_full - 1) * amt * square);
+
+ yy = std::max( -1.0f, std::min( 1.0f, ang_sin * dist ) );
+ xx = std::max( -1.0f, std::min( 1.0f, ang_cos * dist ) );
+ }
+
+ *y = C( yy * range + base );
+ *x = C( xx * range + base );
+ }
+
+ AnalogStick( const char* const _name );
+
+ };
+
+ class Buttons : public ControlGroup
+ {
+ public:
+ Buttons( const char* const _name );
+
+ template <typename C>
+ void GetState( C* const buttons, const C* bitmasks )
+ {
+ std::vector<Control*>::iterator i = controls.begin(),
+ e = controls.end();
+ for ( ; i!=e; ++i, ++bitmasks )
+ if ( (*i)->control_ref->State() > settings[0]->value ) // threshold
+ *buttons |= *bitmasks;
+ }
+
+ };
+
+ class MixedTriggers : public ControlGroup
+ {
+ public:
+
+ template <typename C, typename S>
+ void GetState( C* const digital, const C* bitmasks, S* analog, const unsigned int range )
+ {
+ const unsigned int trig_count = ((unsigned int) (controls.size() / 2));
+ for ( unsigned int i=0; i<trig_count; ++i,++bitmasks,++analog )
+ {
+ if ( controls[i]->control_ref->State() > settings[0]->value ) //threshold
+ {
+ *analog = range;
+ *digital |= *bitmasks;
+ }
+ else
+ *analog = S(controls[i+trig_count]->control_ref->State() * range);
+
+ }
+ }
+
+ MixedTriggers( const char* const _name );
+
+ };
+
+ class Triggers : public ControlGroup
+ {
+ public:
+
+ template <typename S>
+ void GetState( S* analog, const unsigned int range )
+ {
+ const unsigned int trig_count = ((unsigned int) (controls.size()));
+ const ControlState deadzone = settings[0]->value;
+ for ( unsigned int i=0; i<trig_count; ++i,++analog )
+ *analog = S( std::max(controls[i]->control_ref->State() - deadzone, 0.0f) / (1 - deadzone) * range );
+ }
+
+ Triggers( const char* const _name );
+
+ };
+
+ class Force : public ControlGroup
+ {
+ public:
+ Force( const char* const _name );
+
+ template <typename C, typename R>
+ void GetState( C* axis, const u8 base, const R range )
+ {
+ const float deadzone = settings[0]->value;
+ for ( unsigned int i=0; i<6; i+=2 )
+ {
+ const float state = controls[i+1]->control_ref->State() - controls[i]->control_ref->State();
+ if (abs(state) > deadzone)
+ *axis++ = (C)((state - (deadzone * sign(state))) / (1 - deadzone) * range + base);
+ //*axis++ = state * range + base;
+ else
+ *axis++ = (C)(base);
+ }
+ }
+ };
+
+ class Tilt : public ControlGroup
+ {
+ public:
+ Tilt( const char* const _name );
+
+ template <typename C, typename R>
+ void GetState( C* const x, C* const y, const unsigned int base, const R range )
+ {
+ // this is all a mess
+
+ ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State();
+ ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State();
+
+ ControlState deadzone = settings[0]->value;
+ ControlState circle = settings[1]->value;
+ ControlState m = controls[4]->control_ref->State();
+
+ // modifier code
+ if ( m )
+ {
+ yy = (abs(yy)>deadzone) * sign(yy) * (m + deadzone/2);
+ xx = (abs(xx)>deadzone) * sign(xx) * (m + deadzone/2);
+ }
+
+ // deadzone / circle stick code
+ if ( deadzone || circle )
+ {
+ // this section might be all wrong, but its working good enough, i think
+
+ ControlState ang = atan2( yy, xx );
+ ControlState ang_sin = sin(ang);
+ ControlState ang_cos = cos(ang);
+
+ // the amt a full square stick would have at current angle
+ ControlState square_full = std::min( ang_sin ? 1/abs(ang_sin) : 2, ang_cos ? 1/abs(ang_cos) : 2 );
+
+ // the amt a full stick would have that was ( user setting circular ) at current angle
+ // i think this is more like a pointed circle rather than a rounded square like it should be
+ ControlState stick_full = (square_full * (1 - circle)) + (circle);
+
+ ControlState dist = sqrt(xx*xx + yy*yy);
+
+ // dead zone code
+ dist = std::max( 0.0f, dist - deadzone * stick_full );
+ dist /= (1 - deadzone);
+
+ // circle stick code
+ ControlState amt = dist / stick_full;
+ dist += (square_full - 1) * amt * circle;
+
+ yy = std::max( -1.0f, std::min( 1.0f, ang_sin * dist ) );
+ xx = std::max( -1.0f, std::min( 1.0f, ang_cos * dist ) );
+ }
+
+ // this is kinda silly here
+ // gui being open will make this happen 2x as fast, o well
+ if (xx > m_tilt[0])
+ m_tilt[0] = std::min(m_tilt[0] + 0.1f, xx);
+ else if (xx < m_tilt[0])
+ m_tilt[0] = std::max(m_tilt[0] - 0.1f, xx);
+
+ if (yy > m_tilt[1])
+ m_tilt[1] = std::min(m_tilt[1] + 0.1f, yy);
+ else if (yy < m_tilt[1])
+ m_tilt[1] = std::max(m_tilt[1] - 0.1f, yy);
+
+ *y = C( m_tilt[1] * range + base );
+ *x = C( m_tilt[0] * range + base );
+ }
+ private:
+ float m_tilt[2];
+ };
+
+ 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 z, const bool adjusted = false )
+ {
+ const float zz = controls[4]->control_ref->State() - controls[5]->control_ref->State();
+
+ // silly being here
+ if (zz > m_z)
+ m_z = std::min(m_z + 0.1f, zz);
+ else if (zz < m_z)
+ m_z = std::max(m_z - 0.1f, zz);
+
+ *z = m_z;
+
+ // hide
+ if (controls[6]->control_ref->State() > 0.5f)
+ {
+ *x = 10000; *y = 0;
+ }
+ else
+ {
+ 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[1]->value * 2 );
+ yy *= ( settings[2]->value * 2 );
+ yy += ( settings[0]->value - 0.5f );
+ }
+
+ *x = xx;
+ *y = yy;
+ }
+ }
+
+ private:
+ const SWiimoteInitialize* const wiimote_initialize;
+
+ float m_z;
+ };
+
+ class Extension : public ControlGroup
+ {
+ public:
+ Extension( const char* const _name )
+ : ControlGroup( _name, GROUP_TYPE_EXTENSION )
+ , switch_extension(0)
+ , active_extension(0) {}
+ ~Extension();
+
+ void GetState( u8* const data, const bool focus = true );
+
+ std::vector<ControllerEmu*> attachments;
+
+ int switch_extension;
+ int active_extension;
+ };
+
+ virtual ~ControllerEmu();
+
+ virtual std::string GetName() const = 0;
+
+ virtual void LoadDefaults() {}
+
+ void LoadConfig(IniFile::Section *sec, const std::string& base = "");
+ void SaveConfig(IniFile::Section *sec, const std::string& base = "");
+ void UpdateDefaultDevice();
+
+ void UpdateReferences( ControllerInterface& devi );
+
+ std::vector< ControlGroup* > groups;
+
+ ControllerInterface::DeviceQualifier default_device;
+
+};
+
+
+#endif
diff --git a/Source/Core/InputCommon/Src/InputConfig.cpp b/Source/Core/InputCommon/Src/InputConfig.cpp
new file mode 100644
index 0000000000..410aecb928
--- /dev/null
+++ b/Source/Core/InputCommon/Src/InputConfig.cpp
@@ -0,0 +1,69 @@
+// Copyright (C) 2010 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#include "InputConfig.h"
+
+Plugin::Plugin( const char* const _ini_name, const char* const _gui_name, const char* const _profile_name )
+ : ini_name(_ini_name)
+ , gui_name(_gui_name)
+ , profile_name(_profile_name)
+{
+ // GCPads
+ //for ( unsigned int i = 0; i<4; ++i )
+ //controllers.push_back( new GCPad( i ) );
+ // Wiimotes / disabled, cause it only the GUI half is done
+ //for ( unsigned int i = 0; i<4; ++i )
+ // controllers.push_back( new Wiimote( i ) );
+};
+
+Plugin::~Plugin()
+{
+ // delete pads
+ std::vector<ControllerEmu*>::const_iterator i = controllers.begin(),
+ e = controllers.end();
+ for ( ; i != e; ++i )
+ delete *i;
+}
+
+bool Plugin::LoadConfig()
+{
+ IniFile inifile;
+ if (false == inifile.Load(std::string(File::GetUserPath(D_CONFIG_IDX)) + ini_name + ".ini"))
+ return false;
+
+ std::vector< ControllerEmu* >::const_iterator
+ i = controllers.begin(),
+ e = controllers.end();
+ for ( ; i!=e; ++i ) {
+ (*i)->LoadConfig(inifile.GetOrCreateSection((*i)->GetName().c_str()));
+ }
+}
+
+void Plugin::SaveConfig()
+{
+ std::string ini_filename = (std::string(File::GetUserPath(D_CONFIG_IDX)) + ini_name + ".ini" );
+
+ IniFile inifile;
+ inifile.Load(ini_filename);
+
+ std::vector< ControllerEmu* >::const_iterator i = controllers.begin(),
+ e = controllers.end();
+ for ( ; i!=e; ++i )
+ (*i)->SaveConfig(inifile.GetOrCreateSection((*i)->GetName().c_str()));
+
+ inifile.Save(ini_filename);
+}
diff --git a/Source/Core/InputCommon/Src/InputConfig.h b/Source/Core/InputCommon/Src/InputConfig.h
new file mode 100644
index 0000000000..6e8d8adef0
--- /dev/null
+++ b/Source/Core/InputCommon/Src/InputConfig.h
@@ -0,0 +1,53 @@
+// Copyright (C) 2010 Dolphin Project.
+
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, version 2.0.
+
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License 2.0 for more details.
+
+// A copy of the GPL 2.0 should have been included with the program.
+// If not, see http://www.gnu.org/licenses/
+
+// Official SVN repository and contact information can be found at
+// http://code.google.com/p/dolphin-emu/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#include "Thread.h"
+#include "FileUtil.h"
+#include "IniFile.h"
+
+#include "ControllerInterface/ControllerInterface.h"
+#include "ControllerEmu.h"
+
+#include <string>
+#include <vector>
+#include <map>
+#include <sstream>
+
+class Plugin
+{
+public:
+
+ Plugin( const char* const _ini_name, const char* const _gui_name, const char* const _profile_name );
+ ~Plugin();
+
+ bool LoadConfig();
+ void SaveConfig();
+
+ std::vector< ControllerEmu* > controllers;
+
+ Common::CriticalSection controls_crit, interface_crit; // lock controls first
+ ControllerInterface controller_interface;
+
+ const char * const ini_name;
+ const char * const gui_name;
+ const char * const profile_name;
+};
+
+#endif
diff --git a/Source/Core/InputCommon/Src/SConscript b/Source/Core/InputCommon/Src/SConscript
index 426d877aac..fad361aadf 100644
--- a/Source/Core/InputCommon/Src/SConscript
+++ b/Source/Core/InputCommon/Src/SConscript
@@ -4,8 +4,10 @@ Import('env')
files = [
'Configuration.cpp',
+ 'ControllerEmu.cpp',
'EventHandler.cpp',
'InputCommon.cpp',
+ 'InputConfig.cpp',
'SDL_Util.cpp',
'ControllerInterface/ControllerInterface.cpp',
'ControllerInterface/SDL/SDL.cpp'