mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
(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
This commit is contained in:
375
Source/Core/InputCommon/Src/ControllerEmu.cpp
Normal file
375
Source/Core/InputCommon/Src/ControllerEmu.cpp
Normal file
@ -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
|
||||
|
||||
}
|
438
Source/Core/InputCommon/Src/ControllerEmu.h
Normal file
438
Source/Core/InputCommon/Src/ControllerEmu.h
Normal file
@ -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
|
69
Source/Core/InputCommon/Src/InputConfig.cpp
Normal file
69
Source/Core/InputCommon/Src/InputConfig.cpp
Normal file
@ -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);
|
||||
}
|
53
Source/Core/InputCommon/Src/InputConfig.h
Normal file
53
Source/Core/InputCommon/Src/InputConfig.h
Normal file
@ -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
|
@ -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'
|
||||
|
Reference in New Issue
Block a user