summaryrefslogtreecommitdiff
path: root/Source/Core/InputCommon/Src/ControllerInterface
diff options
context:
space:
mode:
authorMatthew Parlane <parlane@gmail.com>2013-08-16 19:17:07 +1200
committerMatthew Parlane <parlane@gmail.com>2013-08-16 19:17:07 +1200
commit9de7611ff940d24551bc77a5e29b86911e3fa749 (patch)
tree7615ec4cfd3aaba63d96ef1cb3cc33fd0efa516a /Source/Core/InputCommon/Src/ControllerInterface
parent417552b21e30aee3dc2b720d65c2cd757997a33e (diff)
parentbff2bc1288fa4309e1b2aef1486845ba01311100 (diff)
Merge branch 'master' into wii-network
Conflicts: CMakeLists.txt Source/Core/Core/Core.vcxproj Source/Core/DolphinWX/Dolphin.vcxproj Source/Core/DolphinWX/Dolphin.vcxproj.filters Source/Dolphin_2010.sln Source/VSProps/Dolphin.Win32.props Source/VSProps/Dolphin.x64.props
Diffstat (limited to 'Source/Core/InputCommon/Src/ControllerInterface')
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Android/Android.cpp27
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Android/Android.h17
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp318
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h194
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp19
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.h4
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp21
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h13
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp17
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.h6
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Device.cpp193
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Device.h171
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.cpp577
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.h69
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.h4
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.mm9
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.h4
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.mm3
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.h4
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.mm3
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp11
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h10
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp7
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h14
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.cpp378
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.h124
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp2
-rw-r--r--Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.h6
28 files changed, 1654 insertions, 571 deletions
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.cpp b/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.cpp
index 2d01d38f23..ef95f9b363 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.cpp
@@ -23,7 +23,7 @@ namespace ciface
namespace Android
{
-void Init( std::vector<ControllerInterface::Device*>& devices )
+void Init( std::vector<Core::Device*>& devices )
{
devices.push_back(new Touchscreen());
}
@@ -48,6 +48,20 @@ Touchscreen::Touchscreen()
AddInput(new Button(ButtonManager::BUTTON_A));
AddInput(new Button(ButtonManager::BUTTON_B));
AddInput(new Button(ButtonManager::BUTTON_START));
+ AddInput(new Button(ButtonManager::BUTTON_X));
+ AddInput(new Button(ButtonManager::BUTTON_Y));
+ AddInput(new Button(ButtonManager::BUTTON_Z));
+ AddInput(new Button(ButtonManager::BUTTON_UP));
+ AddInput(new Button(ButtonManager::BUTTON_DOWN));
+ AddInput(new Button(ButtonManager::BUTTON_LEFT));
+ AddInput(new Button(ButtonManager::BUTTON_RIGHT));
+ AddAnalogInputs(new Axis(ButtonManager::STICK_MAIN_LEFT), new Axis(ButtonManager::STICK_MAIN_RIGHT));
+ AddAnalogInputs(new Axis(ButtonManager::STICK_MAIN_UP), new Axis(ButtonManager::STICK_MAIN_DOWN));
+ AddAnalogInputs(new Axis(ButtonManager::STICK_C_UP), new Axis(ButtonManager::STICK_C_DOWN));
+ AddAnalogInputs(new Axis(ButtonManager::STICK_C_LEFT), new Axis(ButtonManager::STICK_C_RIGHT));
+ AddAnalogInputs(new Axis(ButtonManager::TRIGGER_L), new Axis(ButtonManager::TRIGGER_L));
+ AddAnalogInputs(new Axis(ButtonManager::TRIGGER_R), new Axis(ButtonManager::TRIGGER_R));
+
}
// Buttons and stuff
@@ -62,6 +76,17 @@ ControlState Touchscreen::Button::GetState() const
{
return ButtonManager::GetButtonPressed(m_index);
}
+std::string Touchscreen::Axis::GetName() const
+{
+ std::ostringstream ss;
+ ss << "Axis " << (int)m_index;
+ return ss.str();
+}
+
+ControlState Touchscreen::Axis::GetState() const
+{
+ return ButtonManager::GetAxisValue(m_index);
+}
}
}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.h b/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.h
index 9bdb52a61d..e38c6a221a 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Android/Android.h
@@ -17,7 +17,7 @@
#ifndef _CIFACE_ANDROID_H_
#define _CIFACE_ANDROID_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#include "Android/ButtonManager.h"
namespace ciface
@@ -25,8 +25,8 @@ namespace ciface
namespace Android
{
-void Init( std::vector<ControllerInterface::Device*>& devices );
-class Touchscreen : public ControllerInterface::Device
+void Init( std::vector<Core::Device*>& devices );
+class Touchscreen : public Core::Device
{
private:
class Button : public Input
@@ -36,7 +36,16 @@ private:
Button(ButtonManager::ButtonType index) : m_index(index) {}
ControlState GetState() const;
private:
- const ButtonManager::ButtonType m_index;
+ const ButtonManager::ButtonType m_index;
+ };
+ class Axis : public Input
+ {
+ public:
+ std::string GetName() const;
+ Axis(ButtonManager::ButtonType index) : m_index(index) {}
+ ControlState GetState() const;
+ private:
+ const ButtonManager::ButtonType m_index;
};
public:
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
index 6db79605a7..d2982bba24 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.cpp
@@ -8,6 +8,9 @@
#endif
#ifdef CIFACE_USE_XLIB
#include "Xlib/Xlib.h"
+ #ifdef CIFACE_USE_X11_XINPUT2
+ #include "Xlib/XInput2.h"
+ #endif
#endif
#ifdef CIFACE_USE_OSX
#include "OSX/OSX.h"
@@ -21,6 +24,8 @@
#include "Thread.h"
+using namespace ciface::ExpressionParser;
+
namespace
{
const float INPUT_DETECT_THRESHOLD = 0.55f;
@@ -46,6 +51,9 @@ void ControllerInterface::Initialize()
#endif
#ifdef CIFACE_USE_XLIB
ciface::Xlib::Init(m_devices, m_hwnd);
+ #ifdef CIFACE_USE_X11_XINPUT2
+ ciface::XInput2::Init(m_devices, m_hwnd);
+ #endif
#endif
#ifdef CIFACE_USE_OSX
ciface::OSX::Init(m_devices, m_hwnd);
@@ -180,56 +188,6 @@ bool ControllerInterface::UpdateOutput(const bool force)
}
//
-// Device :: ~Device
-//
-// Destructor, delete all inputs/outputs on device destruction
-//
-ControllerInterface::Device::~Device()
-{
- {
- // delete inputs
- std::vector<Device::Input*>::iterator
- i = m_inputs.begin(),
- e = m_inputs.end();
- for ( ;i!=e; ++i)
- delete *i;
- }
-
- {
- // delete outputs
- std::vector<Device::Output*>::iterator
- o = m_outputs.begin(),
- e = m_outputs.end();
- for ( ;o!=e; ++o)
- delete *o;
- }
-}
-
-void ControllerInterface::Device::AddInput(Input* const i)
-{
- m_inputs.push_back(i);
-}
-
-void ControllerInterface::Device::AddOutput(Output* const o)
-{
- m_outputs.push_back(o);
-}
-
-//
-// Device :: ClearInputState
-//
-// Device classes should override this function
-// ControllerInterface will call this when the device returns failure during UpdateInput
-// used to try to set all buttons and axes to their default state when user unplugs a gamepad during play
-// buttons/axes that were held down at the time of unplugging should be seen as not pressed after unplugging
-//
-void ControllerInterface::Device::ClearInputState()
-{
- // this is going to be called for every UpdateInput call that fails
- // kinda slow but, w/e, should only happen when user unplugs a device while playing
-}
-
-//
// InputReference :: State
//
// get the state of an input reference
@@ -237,48 +195,10 @@ void ControllerInterface::Device::ClearInputState()
//
ControlState ControllerInterface::InputReference::State( const ControlState ignore )
{
- //if (NULL == device)
- //return 0;
-
- ControlState state = 0;
-
- std::vector<DeviceControl>::const_iterator
- ci = m_controls.begin(),
- ce = m_controls.end();
-
- // bit of hax for "NOT" to work at start of expression
- if (ci != ce)
- {
- if (ci->mode == 2)
- state = 1;
- }
-
- for (; ci!=ce; ++ci)
- {
- const ControlState istate = ci->control->ToInput()->GetState();
-
- switch (ci->mode)
- {
- // OR
- case 0 :
- state = std::max(state, istate);
- break;
- // AND
- case 1 :
- state = std::min(state, istate);
- break;
- // NOT
- case 2 :
- state = std::max(std::min(state, 1.0f - istate), 0.0f);
- break;
- // ADD
- case 3 :
- state += istate;
- break;
- }
- }
-
- return std::min(1.0f, state * range);
+ if (parsed_expression)
+ return parsed_expression->GetValue();
+ else
+ return 0.0f;
}
//
@@ -290,83 +210,9 @@ ControlState ControllerInterface::InputReference::State( const ControlState igno
//
ControlState ControllerInterface::OutputReference::State(const ControlState state)
{
- const ControlState tmp_state = std::min(1.0f, state * range);
-
- // output ref just ignores the modes ( |&!... )
-
- std::vector<DeviceControl>::iterator
- ci = m_controls.begin(),
- ce = m_controls.end();
- for (; ci != ce; ++ci)
- ci->control->ToOutput()->SetState(tmp_state);
-
- return state; // just return the output, watever
-}
-
-//
-// DeviceQualifier :: ToString
-//
-// get string from a device qualifier / serialize
-//
-std::string ControllerInterface::DeviceQualifier::ToString() const
-{
- if (source.empty() && (cid < 0) && name.empty())
- return "";
- std::ostringstream ss;
- ss << source << '/';
- if ( cid > -1 )
- ss << cid;
- ss << '/' << name;
- return ss.str();
-}
-
-//
-// DeviceQualifier :: FromString
-//
-// set a device qualifier from a string / unserialize
-//
-void ControllerInterface::DeviceQualifier::FromString(const std::string& str)
-{
- std::istringstream ss(str);
-
- std::getline(ss, source = "", '/');
-
- // silly
- std::getline(ss, name, '/');
- std::istringstream(name) >> (cid = -1);
-
- std::getline(ss, name = "");
-}
-
-//
-// DeviceQualifier :: FromDevice
-//
-// set a device qualifier from a device
-//
-void ControllerInterface::DeviceQualifier::FromDevice(const ControllerInterface::Device* const dev)
-{
- name = dev->GetName();
- cid = dev->GetId();
- source= dev->GetSource();
-}
-
-bool ControllerInterface::DeviceQualifier::operator==(const ControllerInterface::Device* const dev) const
-{
- if (dev->GetId() == cid)
- if (dev->GetName() == name)
- if (dev->GetSource() == source)
- return true;
- return false;
-}
-
-bool ControllerInterface::DeviceQualifier::operator==(const ControllerInterface::DeviceQualifier& devq) const
-{
- if (cid == devq.cid)
- if (name == devq.name)
- if (source == devq.source)
- return true;
-
- return false;
+ if (parsed_expression)
+ parsed_expression->SetValue(state);
+ return 0.0f;
}
//
@@ -376,79 +222,13 @@ bool ControllerInterface::DeviceQualifier::operator==(const ControllerInterface:
// need to call this to re-parse a control reference's expression after changing it
//
void ControllerInterface::UpdateReference(ControllerInterface::ControlReference* ref
- , const ControllerInterface::DeviceQualifier& default_device) const
-{
- ref->m_controls.clear();
-
- // adding | to parse the last item, silly
- std::istringstream ss(ref->expression + '|');
-
- const std::string mode_chars("|&!^");
-
- ControlReference::DeviceControl devc;
-
- std::string dev_str;
- std::string ctrl_str;
-
- char c = 0;
- while (ss.read(&c, 1))
- {
- const size_t f = mode_chars.find(c);
-
- if (mode_chars.npos != f)
- {
- // add ctrl
- if (ctrl_str.size())
- {
- DeviceQualifier devq;
-
- // using default device or alterate device inside `backticks`
- if (dev_str.empty())
- devq = default_device;
- else
- devq.FromString(dev_str);
-
- // find device
- Device* const def_device = FindDevice(devq);
-
- if (def_device)
- {
- if (ref->is_input)
- devc.control = FindInput(ctrl_str, def_device);
- else
- devc.control = FindOutput(ctrl_str, def_device);
-
- if (devc.control)
- ref->m_controls.push_back(devc);
- }
- }
- // reset stuff for next ctrl
- devc.mode = (int)f;
- ctrl_str.clear();
- }
- else if ('`' == c)
- {
- // different device
- if (std::getline(ss, dev_str, '`').eof())
- break; // no terminating '`' character
- }
- else
- {
- ctrl_str += c;
- }
- }
-}
-
-ControllerInterface::Device* ControllerInterface::FindDevice(const ControllerInterface::DeviceQualifier& devq) const
+ , const DeviceQualifier& default_device) const
{
- std::vector<ControllerInterface::Device*>::const_iterator
- di = m_devices.begin(),
- de = m_devices.end();
- for (; di!=de; ++di)
- if (devq == *di)
- return *di;
+ delete ref->parsed_expression;
+ ref->parsed_expression = NULL;
- return NULL;
+ ControlFinder finder(*this, default_device, ref->is_input);
+ ref->parse_error = ParseExpression(ref->expression, finder, &ref->parsed_expression);
}
//
@@ -461,7 +241,7 @@ ControllerInterface::Device* ControllerInterface::FindDevice(const ControllerInt
// upon input, return pointer to detected Control
// else return NULL
//
-ControllerInterface::Device::Control* ControllerInterface::InputReference::Detect(const unsigned int ms, Device* const device)
+Device::Control* ControllerInterface::InputReference::Detect(const unsigned int ms, Device* const device)
{
unsigned int time = 0;
std::vector<bool> states(device->Inputs().size());
@@ -511,12 +291,12 @@ ControllerInterface::Device::Control* ControllerInterface::InputReference::Detec
//
// set all binded outputs to <range> power for x milliseconds return false
//
-ControllerInterface::Device::Control* ControllerInterface::OutputReference::Detect(const unsigned int ms, Device* const device)
+Device::Control* ControllerInterface::OutputReference::Detect(const unsigned int ms, Device* const device)
{
// ignore device
// don't hang if we don't even have any controls mapped
- if (m_controls.size())
+ if (BoundCount() > 0)
{
State(1);
unsigned int slept = 0;
@@ -534,55 +314,3 @@ ControllerInterface::Device::Control* ControllerInterface::OutputReference::Dete
}
return NULL;
}
-
-ControllerInterface::Device::Input* ControllerInterface::Device::FindInput(const std::string &name) const
-{
- std::vector<Input*>::const_iterator
- it = m_inputs.begin(),
- itend = m_inputs.end();
- for (; it != itend; ++it)
- if ((*it)->GetName() == name)
- return *it;
-
- return NULL;
-}
-
-ControllerInterface::Device::Output* ControllerInterface::Device::FindOutput(const std::string &name) const
-{
- std::vector<Output*>::const_iterator
- it = m_outputs.begin(),
- itend = m_outputs.end();
- for (; it != itend; ++it)
- if ((*it)->GetName() == name)
- return *it;
-
- return NULL;
-}
-
-ControllerInterface::Device::Input* ControllerInterface::FindInput(const std::string& name, const Device* def_dev) const
-{
- if (def_dev)
- {
- Device::Input* const inp = def_dev->FindInput(name);
- if (inp)
- return inp;
- }
-
- std::vector<Device*>::const_iterator
- di = m_devices.begin(),
- de = m_devices.end();
- for (; di != de; ++di)
- {
- Device::Input* const i = (*di)->FindInput(name);
-
- if (i)
- return i;
- }
-
- return NULL;
-}
-
-ControllerInterface::Device::Output* ControllerInterface::FindOutput(const std::string& name, const Device* def_dev) const
-{
- return def_dev->FindOutput(name);
-}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h
index 8c1a044860..00b4b2c07d 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/ControllerInterface.h
@@ -9,22 +9,21 @@
#include "Common.h"
#include "Thread.h"
+#include "ExpressionParser.h"
+#include "Device.h"
// enable disable sources
#ifdef _WIN32
#define CIFACE_USE_XINPUT
- #define CIFACE_USE_DINPUT_JOYSTICK
- #define CIFACE_USE_DINPUT_KBM
#define CIFACE_USE_DINPUT
-//#ifndef CIFACE_USE_DINPUT_JOYSTICK
-// enable SDL 1.2 in addition to DirectInput on windows,
-// to support a few gamepads that aren't behaving with DInput
#define CIFACE_USE_SDL
-//#endif
#endif
#if defined(HAVE_X11) && HAVE_X11
#define CIFACE_USE_XLIB
#define CIFACE_USE_SDL
+ #if defined(HAVE_X11_XINPUT2) && HAVE_X11_XINPUT2
+ #define CIFACE_USE_X11_XINPUT2
+ #endif
#endif
#if defined(__APPLE__)
#define CIFACE_USE_OSX
@@ -32,9 +31,8 @@
#ifdef ANDROID
#define CIFACE_USE_ANDROID
#endif
-
-// idk in case I wanted to change it to double or something, idk what's best
-typedef float ControlState;
+
+using namespace ciface::Core;
//
// ControllerInterface
@@ -42,148 +40,10 @@ typedef float ControlState;
// some crazy shit I made to control different device inputs and outputs
// from lots of different sources, hopefully more easily
//
-class ControllerInterface
+class ControllerInterface : public DeviceContainer
{
public:
- // Forward declarations
- class DeviceQualifier;
-
- //
- // Device
- //
- // a device class
- //
- class Device
- {
- public:
- class Input;
- class Output;
-
- //
- // Control
- //
- // control includes inputs and outputs
- //
- class Control // input or output
- {
- public:
- virtual std::string GetName() const = 0;
- virtual ~Control() {}
-
- virtual Input* ToInput() { return NULL; }
- virtual Output* ToOutput() { return NULL; }
- };
-
- //
- // Input
- //
- // an input on a device
- //
- class Input : public Control
- {
- public:
- // things like absolute axes/ absolute mouse position will override this
- virtual bool IsDetectable() { return true; }
-
- virtual ControlState GetState() const = 0;
-
- Input* ToInput() { return this; }
- };
-
- //
- // Output
- //
- // an output on a device
- //
- class Output : public Control
- {
- public:
- virtual ~Output() {}
-
- virtual void SetState(ControlState state) = 0;
-
- Output* ToOutput() { return this; }
- };
-
- virtual ~Device();
-
- virtual std::string GetName() const = 0;
- virtual int GetId() const = 0;
- virtual std::string GetSource() const = 0;
- virtual bool UpdateInput() = 0;
- virtual bool UpdateOutput() = 0;
-
- virtual void ClearInputState();
-
- const std::vector<Input*>& Inputs() const { return m_inputs; }
- const std::vector<Output*>& Outputs() const { return m_outputs; }
-
- Input* FindInput(const std::string& name) const;
- Output* FindOutput(const std::string& name) const;
-
- protected:
- void AddInput(Input* const i);
- void AddOutput(Output* const o);
-
- class FullAnalogSurface : public Input
- {
- public:
- FullAnalogSurface(Input* low, Input* high)
- : m_low(*low), m_high(*high)
- {}
-
- ControlState GetState() const
- {
- return (1 + m_high.GetState() - m_low.GetState()) / 2;
- }
-
- std::string GetName() const
- {
- return m_low.GetName() + *m_high.GetName().rbegin();
- }
-
- private:
- Input& m_low;
- Input& m_high;
- };
-
- void AddAnalogInputs(Input* low, Input* high)
- {
- AddInput(low);
- AddInput(high);
- AddInput(new FullAnalogSurface(low, high));
- AddInput(new FullAnalogSurface(high, low));
- }
-
- private:
- std::vector<Input*> m_inputs;
- std::vector<Output*> m_outputs;
- };
-
- //
- // DeviceQualifier
- //
- // device qualifier used to match devices
- // currently has ( source, id, name ) properties which match a device
- //
- class DeviceQualifier
- {
- public:
- DeviceQualifier() : cid(-1) {}
- DeviceQualifier(const std::string& _source, const int _id, const std::string& _name)
- : source(_source), cid(_id), name(_name) {}
- void FromDevice(const Device* const dev);
- void FromString(const std::string& str);
- std::string ToString() const;
- bool operator==(const DeviceQualifier& devq) const;
- bool operator==(const Device* const dev) const;
-
- std::string source;
- int cid;
- std::string name;
- };
-
//
// ControlReference
//
@@ -197,30 +57,29 @@ public:
class ControlReference
{
friend class ControllerInterface;
-
public:
- virtual ~ControlReference() {}
-
virtual ControlState State(const ControlState state = 0) = 0;
virtual Device::Control* Detect(const unsigned int ms, Device* const device) = 0;
- size_t BoundCount() const { return m_controls.size(); }
- ControlState range;
+ ControlState range;
std::string expression;
const bool is_input;
+ ciface::ExpressionParser::ExpressionParseStatus parse_error;
- protected:
- ControlReference(const bool _is_input) : range(1), is_input(_is_input) {}
-
- struct DeviceControl
- {
- DeviceControl() : control(NULL), mode(0) {}
+ virtual ~ControlReference() {
+ delete parsed_expression;
+ }
- Device::Control* control;
- int mode;
- };
+ int BoundCount() {
+ if (parsed_expression)
+ return parsed_expression->num_controls;
+ else
+ return 0;
+ }
- std::vector<DeviceControl> m_controls;
+ protected:
+ ControlReference(const bool _is_input) : range(1), is_input(_is_input), parsed_expression(NULL) {}
+ ciface::ExpressionParser::Expression *parsed_expression;
};
//
@@ -260,22 +119,13 @@ public:
bool UpdateInput(const bool force = false);
bool UpdateOutput(const bool force = false);
- Device::Input* FindInput(const std::string& name, const Device* def_dev) const;
- Device::Output* FindOutput(const std::string& name, const Device* def_dev) const;
-
- const std::vector<Device*>& Devices() const { return m_devices; }
- Device* FindDevice(const DeviceQualifier& devq) const;
-
std::recursive_mutex update_lock;
private:
bool m_is_init;
- std::vector<Device*> m_devices;
void* m_hwnd;
};
-typedef std::vector<ControllerInterface::Device*> DeviceList;
-
extern ControllerInterface g_controller_interface;
#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
index 01baf9cf1a..6b7b492ea9 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.cpp
@@ -1,17 +1,10 @@
-#include "../ControllerInterface.h"
-
-#ifdef CIFACE_USE_DINPUT
#include "DInput.h"
#include "StringUtil.h"
-#ifdef CIFACE_USE_DINPUT_JOYSTICK
- #include "DInputJoystick.h"
-#endif
-#ifdef CIFACE_USE_DINPUT_KBM
- #include "DInputKeyboardMouse.h"
-#endif
+#include "DInputJoystick.h"
+#include "DInputKeyboardMouse.h"
#pragma comment(lib, "Dinput8.lib")
#pragma comment(lib, "dxguid.lib")
@@ -55,18 +48,14 @@ std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device)
return result;
}
-void Init(std::vector<ControllerInterface::Device*>& devices, HWND hwnd)
+void Init(std::vector<Core::Device*>& devices, HWND hwnd)
{
IDirectInput8* idi8;
if (FAILED(DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (LPVOID*)&idi8, NULL)))
return;
-#ifdef CIFACE_USE_DINPUT_KBM
InitKeyboardMouse(idi8, devices, hwnd);
-#endif
-#ifdef CIFACE_USE_DINPUT_JOYSTICK
InitJoystick(idi8, devices, hwnd);
-#endif
idi8->Release();
@@ -74,5 +63,3 @@ void Init(std::vector<ControllerInterface::Device*>& devices, HWND hwnd)
}
}
-
-#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.h b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.h
index 9ee48c190f..86452c23ab 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInput.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_DINPUT_H_
#define _CIFACE_DINPUT_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#define DINPUT_SOURCE_NAME "DInput"
@@ -23,7 +23,7 @@ BOOL CALLBACK DIEnumDeviceObjectsCallback(LPCDIDEVICEOBJECTINSTANCE lpddoi, LPVO
BOOL CALLBACK DIEnumDevicesCallback(LPCDIDEVICEINSTANCE lpddi, LPVOID pvRef);
std::string GetDeviceName(const LPDIRECTINPUTDEVICE8 device);
-void Init(std::vector<ControllerInterface::Device*>& devices, HWND hwnd);
+void Init(std::vector<Core::Device*>& devices, HWND hwnd);
}
}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp
index 916d142149..fa33595ee8 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.cpp
@@ -1,10 +1,14 @@
-#include "../ControllerInterface.h"
-
-#ifdef CIFACE_USE_DINPUT_JOYSTICK
#include "DInputJoystick.h"
#include "DInput.h"
+#include <map>
+#include <sstream>
+#include <algorithm>
+
+#include <wbemidl.h>
+#include <oleauto.h>
+
namespace ciface
{
namespace DInput
@@ -36,7 +40,6 @@ static const struct
#define DATA_BUFFER_SIZE 32
-#ifdef NO_DUPLICATE_DINPUT_XINPUT
//-----------------------------------------------------------------------------
// Modified some MSDN code to get all the XInput device GUID.Data1 values in a vector,
// faster than checking all the devices for each DirectInput device, like MSDN says to do
@@ -140,9 +143,8 @@ LCleanup:
if( bCleanupCOM )
CoUninitialize();
}
-#endif
-void InitJoystick(IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices, HWND hwnd)
+void InitJoystick(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND hwnd)
{
std::list<DIDEVICEINSTANCE> joysticks;
idi8->EnumDevices( DI8DEVCLASS_GAMECTRL, DIEnumDevicesCallback, (LPVOID)&joysticks, DIEDFL_ATTACHEDONLY );
@@ -151,21 +153,18 @@ void InitJoystick(IDirectInput8* const idi8, std::vector<ControllerInterface::De
// multiple joysticks with the same name shall get unique ids starting at 0
std::map< std::basic_string<TCHAR>, int> name_counts;
-#ifdef NO_DUPLICATE_DINPUT_XINPUT
std::vector<DWORD> xinput_guids;
GetXInputGUIDS( xinput_guids );
-#endif
std::list<DIDEVICEINSTANCE>::iterator
i = joysticks.begin(),
e = joysticks.end();
for ( ; i!=e; ++i )
{
-#ifdef NO_DUPLICATE_DINPUT_XINPUT
// skip XInput Devices
if ( std::find( xinput_guids.begin(), xinput_guids.end(), i->guidProduct.Data1 ) != xinput_guids.end() )
continue;
-#endif
+
LPDIRECTINPUTDEVICE8 js_device;
if (SUCCEEDED(idi8->CreateDevice(i->guidInstance, &js_device, NULL)))
{
@@ -599,5 +598,3 @@ Joystick::Force<P>::Force(u8 index, EffectState& state)
}
}
-
-#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h
index a783381154..ad383bd764 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputJoystick.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_DINPUT_JOYSTICK_H_
#define _CIFACE_DINPUT_JOYSTICK_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#define DIRECTINPUT_VERSION 0x0800
#define WIN32_LEAN_AND_MEAN
@@ -11,21 +11,14 @@
#include <list>
-#ifdef CIFACE_USE_XINPUT
- // this takes so long, idk if it should be enabled :(
- #define NO_DUPLICATE_DINPUT_XINPUT
- #include <wbemidl.h>
- #include <oleauto.h>
-#endif
-
namespace ciface
{
namespace DInput
{
-void InitJoystick(IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices, HWND hwnd);
+void InitJoystick(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND hwnd);
-class Joystick : public ControllerInterface::Device
+class Joystick : public Core::Device
{
private:
struct EffectState
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp
index ea6452376d..850ff27281 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.cpp
@@ -1,6 +1,3 @@
-#include "../ControllerInterface.h"
-
-#ifdef CIFACE_USE_DINPUT_KBM
#include "DInputKeyboardMouse.h"
#include "DInput.h"
@@ -42,7 +39,7 @@ static const struct
// lil silly
static HWND hwnd;
-void InitKeyboardMouse(IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices, HWND _hwnd)
+void InitKeyboardMouse(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND _hwnd)
{
hwnd = _hwnd;
@@ -252,16 +249,6 @@ std::string KeyboardMouse::GetSource() const
return DINPUT_SOURCE_NAME;
}
-//ControlState KeyboardMouse::GetInputState(const ControllerInterface::Device::Input* const input) const
-//{
-// return (((Input*)input)->GetState(&m_state_in));
-//}
-//
-//void KeyboardMouse::SetOutputState(const ControllerInterface::Device::Output* const output, const ControlState state)
-//{
-// ((Output*)output)->SetState(state, m_state_out);
-//}
-
// names
std::string KeyboardMouse::Key::GetName() const
{
@@ -322,5 +309,3 @@ void KeyboardMouse::Light::SetState(const ControlState state)
}
}
-
-#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.h b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.h
index cacef516b0..73398ca1b1 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/DInput/DInputKeyboardMouse.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_DINPUT_KBM_H_
#define _CIFACE_DINPUT_KBM_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#define DIRECTINPUT_VERSION 0x0800
#define WIN32_LEAN_AND_MEAN
@@ -14,9 +14,9 @@ namespace ciface
namespace DInput
{
-void InitKeyboardMouse(IDirectInput8* const idi8, std::vector<ControllerInterface::Device*>& devices, HWND _hwnd);
+void InitKeyboardMouse(IDirectInput8* const idi8, std::vector<Core::Device*>& devices, HWND _hwnd);
-class KeyboardMouse : public ControllerInterface::Device
+class KeyboardMouse : public Core::Device
{
private:
struct State
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Device.cpp b/Source/Core/InputCommon/Src/ControllerInterface/Device.cpp
new file mode 100644
index 0000000000..965ecfc817
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Device.cpp
@@ -0,0 +1,193 @@
+
+#include "Device.h"
+
+#include <string>
+#include <sstream>
+
+namespace ciface
+{
+namespace Core
+{
+
+//
+// Device :: ~Device
+//
+// Destructor, delete all inputs/outputs on device destruction
+//
+Device::~Device()
+{
+ {
+ // delete inputs
+ std::vector<Device::Input*>::iterator
+ i = m_inputs.begin(),
+ e = m_inputs.end();
+ for ( ;i!=e; ++i)
+ delete *i;
+ }
+
+ {
+ // delete outputs
+ std::vector<Device::Output*>::iterator
+ o = m_outputs.begin(),
+ e = m_outputs.end();
+ for ( ;o!=e; ++o)
+ delete *o;
+ }
+}
+
+void Device::AddInput(Device::Input* const i)
+{
+ m_inputs.push_back(i);
+}
+
+void Device::AddOutput(Device::Output* const o)
+{
+ m_outputs.push_back(o);
+}
+
+Device::Input* Device::FindInput(const std::string &name) const
+{
+ std::vector<Input*>::const_iterator
+ it = m_inputs.begin(),
+ itend = m_inputs.end();
+ for (; it != itend; ++it)
+ if ((*it)->GetName() == name)
+ return *it;
+
+ return NULL;
+}
+
+Device::Output* Device::FindOutput(const std::string &name) const
+{
+ std::vector<Output*>::const_iterator
+ it = m_outputs.begin(),
+ itend = m_outputs.end();
+ for (; it != itend; ++it)
+ if ((*it)->GetName() == name)
+ return *it;
+
+ return NULL;
+}
+
+//
+// Device :: ClearInputState
+//
+// Device classes should override this function
+// ControllerInterface will call this when the device returns failure during UpdateInput
+// used to try to set all buttons and axes to their default state when user unplugs a gamepad during play
+// buttons/axes that were held down at the time of unplugging should be seen as not pressed after unplugging
+//
+void Device::ClearInputState()
+{
+ // this is going to be called for every UpdateInput call that fails
+ // kinda slow but, w/e, should only happen when user unplugs a device while playing
+}
+
+//
+// DeviceQualifier :: ToString
+//
+// get string from a device qualifier / serialize
+//
+std::string DeviceQualifier::ToString() const
+{
+ if (source.empty() && (cid < 0) && name.empty())
+ return "";
+ std::ostringstream ss;
+ ss << source << '/';
+ if ( cid > -1 )
+ ss << cid;
+ ss << '/' << name;
+ return ss.str();
+}
+
+//
+// DeviceQualifier :: FromString
+//
+// set a device qualifier from a string / unserialize
+//
+void DeviceQualifier::FromString(const std::string& str)
+{
+ std::istringstream ss(str);
+
+ std::getline(ss, source = "", '/');
+
+ // silly
+ std::getline(ss, name, '/');
+ std::istringstream(name) >> (cid = -1);
+
+ std::getline(ss, name = "");
+}
+
+//
+// DeviceQualifier :: FromDevice
+//
+// set a device qualifier from a device
+//
+void DeviceQualifier::FromDevice(const Device* const dev)
+{
+ name = dev->GetName();
+ cid = dev->GetId();
+ source= dev->GetSource();
+}
+
+bool DeviceQualifier::operator==(const Device* const dev) const
+{
+ if (dev->GetId() == cid)
+ if (dev->GetName() == name)
+ if (dev->GetSource() == source)
+ return true;
+ return false;
+}
+
+bool DeviceQualifier::operator==(const DeviceQualifier& devq) const
+{
+ if (cid == devq.cid)
+ if (name == devq.name)
+ if (source == devq.source)
+ return true;
+
+ return false;
+}
+
+Device* DeviceContainer::FindDevice(const DeviceQualifier& devq) const
+{
+ std::vector<Device*>::const_iterator
+ di = m_devices.begin(),
+ de = m_devices.end();
+ for (; di!=de; ++di)
+ if (devq == *di)
+ return *di;
+
+ return NULL;
+}
+
+Device::Input* DeviceContainer::FindInput(const std::string& name, const Device* def_dev) const
+{
+ if (def_dev)
+ {
+ Device::Input* const inp = def_dev->FindInput(name);
+ if (inp)
+ return inp;
+ }
+
+ std::vector<Device*>::const_iterator
+ di = m_devices.begin(),
+ de = m_devices.end();
+ for (; di != de; ++di)
+ {
+ Device::Input* const i = (*di)->FindInput(name);
+
+ if (i)
+ return i;
+ }
+
+ return NULL;
+}
+
+Device::Output* DeviceContainer::FindOutput(const std::string& name, const Device* def_dev) const
+{
+ return def_dev->FindOutput(name);
+}
+
+}
+}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Device.h b/Source/Core/InputCommon/Src/ControllerInterface/Device.h
new file mode 100644
index 0000000000..a7c26b867d
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Device.h
@@ -0,0 +1,171 @@
+
+#ifndef _DEVICE_H_
+#define _DEVICE_H_
+
+#include <string>
+#include <vector>
+
+#include "Common.h"
+
+// idk in case I wanted to change it to double or something, idk what's best
+typedef float ControlState;
+
+namespace ciface
+{
+namespace Core
+{
+
+// Forward declarations
+class DeviceQualifier;
+
+//
+// Device
+//
+// a device class
+//
+class Device
+{
+public:
+ class Input;
+ class Output;
+
+ //
+ // Control
+ //
+ // control includes inputs and outputs
+ //
+ class Control // input or output
+ {
+ public:
+ virtual std::string GetName() const = 0;
+ virtual ~Control() {}
+
+ virtual Input* ToInput() { return NULL; }
+ virtual Output* ToOutput() { return NULL; }
+ };
+
+ //
+ // Input
+ //
+ // an input on a device
+ //
+ class Input : public Control
+ {
+ public:
+ // things like absolute axes/ absolute mouse position will override this
+ virtual bool IsDetectable() { return true; }
+
+ virtual ControlState GetState() const = 0;
+
+ Input* ToInput() { return this; }
+ };
+
+ //
+ // Output
+ //
+ // an output on a device
+ //
+ class Output : public Control
+ {
+ public:
+ virtual ~Output() {}
+
+ virtual void SetState(ControlState state) = 0;
+
+ Output* ToOutput() { return this; }
+ };
+
+ virtual ~Device();
+
+ virtual std::string GetName() const = 0;
+ virtual int GetId() const = 0;
+ virtual std::string GetSource() const = 0;
+ virtual bool UpdateInput() = 0;
+ virtual bool UpdateOutput() = 0;
+
+ virtual void ClearInputState();
+
+ const std::vector<Input*>& Inputs() const { return m_inputs; }
+ const std::vector<Output*>& Outputs() const { return m_outputs; }
+
+ Input* FindInput(const std::string& name) const;
+ Output* FindOutput(const std::string& name) const;
+
+protected:
+ void AddInput(Input* const i);
+ void AddOutput(Output* const o);
+
+ class FullAnalogSurface : public Input
+ {
+ public:
+ FullAnalogSurface(Input* low, Input* high)
+ : m_low(*low), m_high(*high)
+ {}
+
+ ControlState GetState() const
+ {
+ return (1 + m_high.GetState() - m_low.GetState()) / 2;
+ }
+
+ std::string GetName() const
+ {
+ return m_low.GetName() + *m_high.GetName().rbegin();
+ }
+
+ private:
+ Input& m_low;
+ Input& m_high;
+ };
+
+ void AddAnalogInputs(Input* low, Input* high)
+ {
+ AddInput(low);
+ AddInput(high);
+ AddInput(new FullAnalogSurface(low, high));
+ AddInput(new FullAnalogSurface(high, low));
+ }
+
+private:
+ std::vector<Input*> m_inputs;
+ std::vector<Output*> m_outputs;
+};
+
+//
+// DeviceQualifier
+//
+// device qualifier used to match devices
+// currently has ( source, id, name ) properties which match a device
+//
+class DeviceQualifier
+{
+public:
+ DeviceQualifier() : cid(-1) {}
+ DeviceQualifier(const std::string& _source, const int _id, const std::string& _name)
+ : source(_source), cid(_id), name(_name) {}
+ void FromDevice(const Device* const dev);
+ void FromString(const std::string& str);
+ std::string ToString() const;
+ bool operator==(const DeviceQualifier& devq) const;
+ bool operator==(const Device* const dev) const;
+
+ std::string source;
+ int cid;
+ std::string name;
+};
+
+class DeviceContainer
+{
+public:
+ Device::Input* FindInput(const std::string& name, const Device* def_dev) const;
+ Device::Output* FindOutput(const std::string& name, const Device* def_dev) const;
+
+ const std::vector<Device*>& Devices() const { return m_devices; }
+ Device* FindDevice(const DeviceQualifier& devq) const;
+protected:
+ std::vector<Device*> m_devices;
+};
+
+}
+}
+
+#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.cpp b/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.cpp
new file mode 100644
index 0000000000..d91fbc587c
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.cpp
@@ -0,0 +1,577 @@
+
+#include "ExpressionParser.h"
+
+#include <cassert>
+#include <iostream>
+#include <string>
+#include <map>
+#include <vector>
+
+using namespace ciface::Core;
+
+namespace ciface
+{
+namespace ExpressionParser
+{
+
+enum TokenType
+{
+ TOK_DISCARD,
+ TOK_INVALID,
+ TOK_EOF,
+ TOK_LPAREN,
+ TOK_RPAREN,
+ TOK_AND,
+ TOK_OR,
+ TOK_NOT,
+ TOK_ADD,
+ TOK_CONTROL,
+};
+
+inline std::string OpName(TokenType op)
+{
+ switch (op)
+ {
+ case TOK_AND:
+ return "And";
+ case TOK_OR:
+ return "Or";
+ case TOK_NOT:
+ return "Not";
+ case TOK_ADD:
+ return "Add";
+ default:
+ assert(false);
+ return "";
+ }
+}
+
+class Token
+{
+public:
+ TokenType type;
+ ControlQualifier qualifier;
+
+ Token(TokenType type_) : type(type_) {}
+ Token(TokenType type_, ControlQualifier qualifier_) : type(type_), qualifier(qualifier_) {}
+
+ operator std::string()
+ {
+ switch (type)
+ {
+ case TOK_INVALID:
+ return "Invalid";
+ case TOK_DISCARD:
+ return "Discard";
+ case TOK_EOF:
+ return "EOF";
+ case TOK_LPAREN:
+ return "(";
+ case TOK_RPAREN:
+ return ")";
+ case TOK_AND:
+ return "&";
+ case TOK_OR:
+ return "|";
+ case TOK_NOT:
+ return "!";
+ case TOK_ADD:
+ return "+";
+ case TOK_CONTROL:
+ return "Device(" + (std::string)qualifier + ")";
+ }
+ }
+};
+
+class Lexer {
+public:
+ std::string expr;
+ std::string::iterator it;
+
+ Lexer(std::string expr_) : expr(expr_)
+ {
+ it = expr.begin();
+ }
+
+ bool FetchBacktickString(std::string &value, char otherDelim = 0)
+ {
+ value = "";
+ while (it != expr.end())
+ {
+ char c = *it;
+ it++;
+ if (c == '`')
+ return false;
+ if (c > 0 && c == otherDelim)
+ return true;
+ value += c;
+ }
+ return false;
+ }
+
+ Token GetFullyQualifiedControl()
+ {
+ ControlQualifier qualifier;
+ std::string value;
+
+ if (FetchBacktickString(value, ':'))
+ {
+ // Found colon, this is the device name
+ qualifier.has_device = true;
+ qualifier.device_qualifier.FromString(value);
+ FetchBacktickString(value);
+ }
+
+ qualifier.control_name = value;
+
+ return Token(TOK_CONTROL, qualifier);
+ }
+
+ Token GetBarewordsControl(char c)
+ {
+ std::string name;
+ name += c;
+
+ while (it != expr.end()) {
+ c = *it;
+ if (!isalpha(c))
+ break;
+ name += c;
+ it++;
+ }
+
+ ControlQualifier qualifier;
+ qualifier.control_name = name;
+ return Token(TOK_CONTROL, qualifier);
+ }
+
+ Token NextToken()
+ {
+ if (it == expr.end())
+ return Token(TOK_EOF);
+
+ char c = *it++;
+ switch (c)
+ {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ return Token(TOK_DISCARD);
+ case '(':
+ return Token(TOK_LPAREN);
+ case ')':
+ return Token(TOK_RPAREN);
+ case '&':
+ return Token(TOK_AND);
+ case '|':
+ return Token(TOK_OR);
+ case '!':
+ return Token(TOK_NOT);
+ case '+':
+ return Token(TOK_ADD);
+ case '`':
+ return GetFullyQualifiedControl();
+ default:
+ if (isalpha(c))
+ return GetBarewordsControl(c);
+ else
+ return Token(TOK_INVALID);
+ }
+ }
+
+ ExpressionParseStatus Tokenize(std::vector<Token> &tokens)
+ {
+ while (true)
+ {
+ Token tok = NextToken();
+
+ if (tok.type == TOK_DISCARD)
+ continue;
+
+ if (tok.type == TOK_INVALID)
+ {
+ tokens.clear();
+ return EXPRESSION_PARSE_SYNTAX_ERROR;
+ }
+
+ tokens.push_back(tok);
+
+ if (tok.type == TOK_EOF)
+ break;
+ }
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+};
+
+class ExpressionNode
+{
+public:
+ virtual ~ExpressionNode() {}
+ virtual ControlState GetValue() { return 0; }
+ virtual void SetValue(ControlState state) {}
+ virtual int CountNumControls() { return 0; }
+ virtual operator std::string() { return ""; }
+};
+
+class ControlExpression : public ExpressionNode
+{
+public:
+ ControlQualifier qualifier;
+ Device::Control *control;
+
+ ControlExpression(ControlQualifier qualifier_, Device::Control *control_) : qualifier(qualifier_), control(control_) {}
+
+ virtual ControlState GetValue()
+ {
+ return control->ToInput()->GetState();
+ }
+
+ virtual void SetValue(ControlState value)
+ {
+ control->ToOutput()->SetState(value);
+ }
+
+ virtual int CountNumControls()
+ {
+ return 1;
+ }
+
+ virtual operator std::string()
+ {
+ return "`" + (std::string)qualifier + "`";
+ }
+};
+
+class BinaryExpression : public ExpressionNode
+{
+public:
+ TokenType op;
+ ExpressionNode *lhs;
+ ExpressionNode *rhs;
+
+ BinaryExpression(TokenType op_, ExpressionNode *lhs_, ExpressionNode *rhs_) : op(op_), lhs(lhs_), rhs(rhs_) {}
+ virtual ~BinaryExpression()
+ {
+ delete lhs;
+ delete rhs;
+ }
+
+ virtual ControlState GetValue()
+ {
+ ControlState lhsValue = lhs->GetValue();
+ ControlState rhsValue = rhs->GetValue();
+ switch (op)
+ {
+ case TOK_AND:
+ return std::min(lhsValue, rhsValue);
+ case TOK_OR:
+ return std::max(lhsValue, rhsValue);
+ case TOK_ADD:
+ return std::min(lhsValue + rhsValue, 1.0f);
+ default:
+ assert(false);
+ return 0;
+ }
+ }
+
+ virtual void SetValue(ControlState value)
+ {
+ // Don't do anything special with the op we have.
+ // Treat "A & B" the same as "A | B".
+ lhs->SetValue(value);
+ rhs->SetValue(value);
+ }
+
+ virtual int CountNumControls()
+ {
+ return lhs->CountNumControls() + rhs->CountNumControls();
+ }
+
+ virtual operator std::string()
+ {
+ return OpName(op) + "(" + (std::string)(*lhs) + ", " + (std::string)(*rhs) + ")";
+ }
+};
+
+class UnaryExpression : public ExpressionNode
+{
+public:
+ TokenType op;
+ ExpressionNode *inner;
+
+ UnaryExpression(TokenType op_, ExpressionNode *inner_) : op(op_), inner(inner_) {}
+ virtual ~UnaryExpression()
+ {
+ delete inner;
+ }
+
+ virtual ControlState GetValue()
+ {
+ ControlState value = inner->GetValue();
+ switch (op)
+ {
+ case TOK_NOT:
+ return 1.0f - value;
+ default:
+ assert(false);
+ return 0;
+ }
+ }
+
+ virtual void SetValue(ControlState value)
+ {
+ switch (op)
+ {
+ case TOK_NOT:
+ inner->SetValue(1.0f - value);
+ default:
+ assert(false);
+ }
+ }
+
+ virtual int CountNumControls()
+ {
+ return inner->CountNumControls();
+ }
+
+ virtual operator std::string()
+ {
+ return OpName(op) + "(" + (std::string)(*inner) + ")";
+ }
+};
+
+Device *ControlFinder::FindDevice(ControlQualifier qualifier)
+{
+ if (qualifier.has_device)
+ return container.FindDevice(qualifier.device_qualifier);
+ else
+ return container.FindDevice(default_device);
+}
+
+Device::Control *ControlFinder::FindControl(ControlQualifier qualifier)
+{
+ Device *device = FindDevice(qualifier);
+ if (!device)
+ return NULL;
+
+ if (is_input)
+ return device->FindInput(qualifier.control_name);
+ else
+ return device->FindOutput(qualifier.control_name);
+}
+
+class Parser
+{
+public:
+
+ Parser(std::vector<Token> tokens_, ControlFinder &finder_) : tokens(tokens_), finder(finder_)
+ {
+ m_it = tokens.begin();
+ }
+
+ ExpressionParseStatus Parse(Expression **expr_out)
+ {
+ ExpressionNode *node;
+ ExpressionParseStatus status = Toplevel(&node);
+ if (status != EXPRESSION_PARSE_SUCCESS)
+ return status;
+
+ *expr_out = new Expression(node);
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+
+private:
+ std::vector<Token> tokens;
+ std::vector<Token>::iterator m_it;
+ ControlFinder &finder;
+
+ Token Chew()
+ {
+ return *m_it++;
+ }
+
+ Token Peek()
+ {
+ return *m_it;
+ }
+
+ bool Expects(TokenType type)
+ {
+ Token tok = Chew();
+ return tok.type == type;
+ }
+
+ ExpressionParseStatus Atom(ExpressionNode **expr_out)
+ {
+ Token tok = Chew();
+ switch (tok.type)
+ {
+ case TOK_CONTROL:
+ {
+ Device::Control *control = finder.FindControl(tok.qualifier);
+ if (control == NULL)
+ return EXPRESSION_PARSE_NO_DEVICE;
+
+ *expr_out = new ControlExpression(tok.qualifier, control);
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+ case TOK_LPAREN:
+ return Paren(expr_out);
+ default:
+ return EXPRESSION_PARSE_SYNTAX_ERROR;
+ }
+ }
+
+ bool IsUnaryExpression(TokenType type)
+ {
+ switch (type)
+ {
+ case TOK_NOT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ ExpressionParseStatus Unary(ExpressionNode **expr_out)
+ {
+ ExpressionParseStatus status;
+
+ if (IsUnaryExpression(Peek().type))
+ {
+ Token tok = Chew();
+ ExpressionNode *atom_expr;
+ if ((status = Atom(&atom_expr)) != EXPRESSION_PARSE_SUCCESS)
+ return status;
+ *expr_out = new UnaryExpression(tok.type, atom_expr);
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+
+ return Atom(expr_out);
+ }
+
+ bool IsBinaryToken(TokenType type)
+ {
+ switch (type)
+ {
+ case TOK_AND:
+ case TOK_OR:
+ case TOK_ADD:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ ExpressionParseStatus Binary(ExpressionNode **expr_out)
+ {
+ ExpressionParseStatus status;
+
+ if ((status = Unary(expr_out)) != EXPRESSION_PARSE_SUCCESS)
+ return status;
+
+ while (IsBinaryToken(Peek().type))
+ {
+ Token tok = Chew();
+ ExpressionNode *unary_expr;
+ if ((status = Unary(&unary_expr)) != EXPRESSION_PARSE_SUCCESS)
+ {
+ delete *expr_out;
+ return status;
+ }
+
+ *expr_out = new BinaryExpression(tok.type, *expr_out, unary_expr);
+ }
+
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+
+ ExpressionParseStatus Paren(ExpressionNode **expr_out)
+ {
+ ExpressionParseStatus status;
+
+ // lparen already chewed
+ if ((status = Toplevel(expr_out)) != EXPRESSION_PARSE_SUCCESS)
+ return status;
+
+ if (!Expects(TOK_RPAREN))
+ {
+ delete *expr_out;
+ return EXPRESSION_PARSE_SYNTAX_ERROR;
+ }
+
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+
+ ExpressionParseStatus Toplevel(ExpressionNode **expr_out)
+ {
+ return Binary(expr_out);
+ }
+};
+
+ControlState Expression::GetValue()
+{
+ return node->GetValue();
+}
+
+void Expression::SetValue(ControlState value)
+{
+ node->SetValue(value);
+}
+
+Expression::Expression(ExpressionNode *node_)
+{
+ node = node_;
+ num_controls = node->CountNumControls();
+}
+
+Expression::~Expression()
+{
+ delete node;
+}
+
+ExpressionParseStatus ParseExpressionInner(std::string str, ControlFinder &finder, Expression **expr_out)
+{
+ ExpressionParseStatus status;
+ Expression *expr;
+ *expr_out = NULL;
+
+ if (str == "")
+ return EXPRESSION_PARSE_SUCCESS;
+
+ Lexer l(str);
+ std::vector<Token> tokens;
+ status = l.Tokenize(tokens);
+ if (status != EXPRESSION_PARSE_SUCCESS)
+ return status;
+
+ Parser p(tokens, finder);
+ status = p.Parse(&expr);
+ if (status != EXPRESSION_PARSE_SUCCESS)
+ return status;
+
+ *expr_out = expr;
+ return EXPRESSION_PARSE_SUCCESS;
+}
+
+ExpressionParseStatus ParseExpression(std::string str, ControlFinder &finder, Expression **expr_out)
+{
+ // Add compatibility with old simple expressions, which are simple
+ // barewords control names.
+
+ ControlQualifier qualifier;
+ qualifier.control_name = str;
+ qualifier.has_device = false;
+
+ Device::Control *control = finder.FindControl(qualifier);
+ if (control) {
+ *expr_out = new Expression(new ControlExpression(qualifier, control));
+ return EXPRESSION_PARSE_SUCCESS;
+ }
+
+ return ParseExpressionInner(str, finder, expr_out);
+}
+
+}
+}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.h b/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.h
new file mode 100644
index 0000000000..70cc51373b
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/ExpressionParser.h
@@ -0,0 +1,69 @@
+
+#ifndef _EXPRESSIONPARSER_H_
+#define _EXPRESSIONPARSER_H_
+
+#include <string>
+#include "Device.h"
+
+namespace ciface
+{
+namespace ExpressionParser
+{
+
+class ControlQualifier
+{
+public:
+ bool has_device;
+ Core::DeviceQualifier device_qualifier;
+ std::string control_name;
+
+ ControlQualifier() : has_device(false) {}
+
+ operator std::string()
+ {
+ if (has_device)
+ return device_qualifier.ToString() + ":" + control_name;
+ else
+ return control_name;
+ }
+};
+
+class ControlFinder
+{
+public:
+ ControlFinder(const Core::DeviceContainer &container_, const Core::DeviceQualifier &default_, const bool is_input_) : container(container_), default_device(default_), is_input(is_input_) {}
+ Core::Device::Control *FindControl(ControlQualifier qualifier);
+
+private:
+ Core::Device *FindDevice(ControlQualifier qualifier);
+ const Core::DeviceContainer &container;
+ const Core::DeviceQualifier &default_device;
+ bool is_input;
+};
+
+class ExpressionNode;
+class Expression
+{
+public:
+ Expression() : node(NULL) {}
+ Expression(ExpressionNode *node);
+ ~Expression();
+ ControlState GetValue();
+ void SetValue (ControlState state);
+ int num_controls;
+ ExpressionNode *node;
+};
+
+enum ExpressionParseStatus
+{
+ EXPRESSION_PARSE_SUCCESS = 0,
+ EXPRESSION_PARSE_SYNTAX_ERROR,
+ EXPRESSION_PARSE_NO_DEVICE,
+};
+
+ExpressionParseStatus ParseExpression(std::string expr, ControlFinder &finder, Expression **expr_out);
+
+}
+}
+
+#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.h b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.h
index 225906c35d..a922e3f2dd 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.h
@@ -1,13 +1,13 @@
#pragma once
-#include "../ControllerInterface.h"
+#include "../Device.h"
namespace ciface
{
namespace OSX
{
-void Init(std::vector<ControllerInterface::Device*>& devices, void *window);
+void Init(std::vector<Core::Device*>& devices, void *window);
void DeInit();
void DeviceElementDebugPrint(const void *, void *);
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.mm b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.mm
index aef8f283c1..8a859f46c8 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.mm
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSX.mm
@@ -2,11 +2,12 @@
#include <IOKit/hid/IOHIDLib.h>
#include <Cocoa/Cocoa.h>
-#include "../ControllerInterface.h"
#include "OSX.h"
#include "OSXKeyboard.h"
#include "OSXJoystick.h"
+#include <map>
+
namespace ciface
{
namespace OSX
@@ -145,8 +146,8 @@ static void DeviceMatching_callback(void* inContext,
DeviceDebugPrint(inIOHIDDeviceRef);
- std::vector<ControllerInterface::Device*> *devices =
- (std::vector<ControllerInterface::Device*> *)inContext;
+ std::vector<Core::Device*> *devices =
+ (std::vector<Core::Device*> *)inContext;
// Add to the devices vector if it's of a type we want
if (IOHIDDeviceConformsTo(inIOHIDDeviceRef,
@@ -164,7 +165,7 @@ static void DeviceMatching_callback(void* inContext,
name, joy_name_counts[name]++));
}
-void Init(std::vector<ControllerInterface::Device*>& devices, void *window)
+void Init(std::vector<Core::Device*>& devices, void *window)
{
HIDManager = IOHIDManagerCreate(kCFAllocatorDefault,
kIOHIDOptionsTypeNone);
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.h b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.h
index ecc443ad3a..ebe908522b 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.h
@@ -1,13 +1,13 @@
#include <IOKit/hid/IOHIDLib.h>
-#include "../ControllerInterface.h"
+#include "../Device.h"
namespace ciface
{
namespace OSX
{
-class Joystick : public ControllerInterface::Device
+class Joystick : public Core::Device
{
private:
class Button : public Input
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.mm b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.mm
index 0d89c2e393..ebd713d142 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.mm
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXJoystick.mm
@@ -1,9 +1,10 @@
#include <Foundation/Foundation.h>
#include <IOKit/hid/IOHIDLib.h>
-#include "../ControllerInterface.h"
#include "OSXJoystick.h"
+#include <sstream>
+
namespace ciface
{
namespace OSX
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.h b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.h
index d59651c98a..930f849a17 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.h
@@ -1,13 +1,13 @@
#include <IOKit/hid/IOHIDLib.h>
-#include "../ControllerInterface.h"
+#include "../Device.h"
namespace ciface
{
namespace OSX
{
-class Keyboard : public ControllerInterface::Device
+class Keyboard : public Core::Device
{
private:
class Key : public Input
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.mm b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.mm
index c22e267044..003240d4a9 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.mm
+++ b/Source/Core/InputCommon/Src/ControllerInterface/OSX/OSXKeyboard.mm
@@ -3,9 +3,10 @@
#include <Cocoa/Cocoa.h>
#include <wx/wx.h> // wxWidgets
-#include "../ControllerInterface.h"
#include "OSXKeyboard.h"
+#include <sstream>
+
namespace ciface
{
namespace OSX
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp
index 6c74c55d97..006b82d4ac 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.cpp
@@ -1,10 +1,11 @@
-#include "../ControllerInterface.h"
-
-#ifdef CIFACE_USE_SDL
#include "SDL.h"
#include <StringUtil.h>
+#include <map>
+#include <sstream>
+#include <algorithm>
+
#ifdef _WIN32
#if SDL_VERSION_ATLEAST(1, 3, 0)
#pragma comment(lib, "SDL.1.3.lib")
@@ -27,7 +28,7 @@ std::string GetJoystickName(int index)
#endif
}
-void Init( std::vector<ControllerInterface::Device*>& devices )
+void Init( std::vector<Core::Device*>& devices )
{
// this is used to number the joysticks
// multiple joysticks with the same name shall get unique ids starting at 0
@@ -399,5 +400,3 @@ ControlState Joystick::Hat::GetState() const
}
}
-
-#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h
index fa770c403d..6a65efeedb 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/SDL/SDL.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_SDL_H_
#define _CIFACE_SDL_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#include <list>
@@ -23,9 +23,9 @@ namespace ciface
namespace SDL
{
-void Init( std::vector<ControllerInterface::Device*>& devices );
+void Init( std::vector<Core::Device*>& devices );
-class Joystick : public ControllerInterface::Device
+class Joystick : public Core::Device
{
private:
@@ -40,7 +40,7 @@ private:
};
#endif
- class Button : public Input
+ class Button : public Core::Device::Input
{
public:
std::string GetName() const;
@@ -51,7 +51,7 @@ private:
const u8 m_index;
};
- class Axis : public Input
+ class Axis : public Core::Device::Input
{
public:
std::string GetName() const;
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp
index 3c7f3c48ae..c687bef856 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.cpp
@@ -1,6 +1,3 @@
-#include "../ControllerInterface.h"
-
-#ifdef CIFACE_USE_XINPUT
#include "XInput.h"
@@ -51,7 +48,7 @@ static const char* const named_motors[] =
"Motor R"
};
-void Init(DeviceList& devices)
+void Init(std::vector<Core::Device*>& devices)
{
XINPUT_CAPABILITIES caps;
for (int i = 0; i != 4; ++i)
@@ -210,5 +207,3 @@ void Device::Motor::SetState(ControlState state)
}
}
-
-#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h
index eb51a58779..8fe6dd1dee 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/XInput/XInput.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_XINPUT_H_
#define _CIFACE_XINPUT_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#define NOMINMAX
#include <Windows.h>
@@ -12,12 +12,12 @@ namespace ciface
namespace XInput
{
-void Init(DeviceList& devices);
+void Init(std::vector<Core::Device*>& devices);
-class Device : public ControllerInterface::Device
+class Device : public Core::Device
{
private:
- class Button : public Input
+ class Button : public Core::Device::Input
{
public:
std::string GetName() const;
@@ -28,7 +28,7 @@ private:
u8 m_index;
};
- class Axis : public Input
+ class Axis : public Core::Device::Input
{
public:
std::string GetName() const;
@@ -40,7 +40,7 @@ private:
const u8 m_index;
};
- class Trigger : public Input
+ class Trigger : public Core::Device::Input
{
public:
std::string GetName() const;
@@ -52,7 +52,7 @@ private:
const u8 m_index;
};
- class Motor : public Output
+ class Motor : public Core::Device::Output
{
public:
std::string GetName() const;
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.cpp b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.cpp
new file mode 100644
index 0000000000..b42eda1f21
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.cpp
@@ -0,0 +1,378 @@
+// Copyright 2013 Max Eliaser
+// Licensed under the GNU General Public License, version 2 or higher.
+// Refer to the license.txt file included.
+
+
+#include "XInput2.h"
+#include <X11/XKBlib.h>
+#include <cmath>
+
+// This is an input plugin using the XInput 2.0 extension to the X11 protocol,
+// loosely based on the old XLib plugin. (Has nothing to do with the XInput
+// API on Windows.)
+
+// This plugin creates one KeyboardMouse object for each master pointer/
+// keyboard pair. Each KeyboardMouse object exports four types of controls:
+// * Mouse button controls: hardcoded at five of them, but could be made to
+// support infinitely many mouse buttons in theory; XInput2 has no limit.
+// * Mouse cursor controls: one for each cardinal direction. Calculated by
+// comparing the absolute position of the mouse pointer on screen to the
+// center of the emulator window.
+// * Mouse axis controls: one for each cardinal direction. Calculated using
+// a running average of relative mouse motion on each axis.
+// * Key controls: these correspond to a limited subset of the keyboard
+// keys.
+
+
+// Mouse axis control tuning. Unlike absolute mouse position, relative mouse
+// motion data needs to be tweaked and smoothed out a bit to be usable.
+
+// Mouse axis control output is simply divided by this number. In practice,
+// that just means you can use a smaller "dead zone" if you bind axis controls
+// to a joystick. No real need to make this customizable.
+#define MOUSE_AXIS_SENSITIVITY 8.0f
+
+// The mouse axis controls use a weighted running average. Each frame, the new
+// value is the average of the old value and the amount of relative mouse
+// motion during that frame. The old value is weighted by a ratio of
+// MOUSE_AXIS_SMOOTHING:1 compared to the new value. Increasing
+// MOUSE_AXIS_SMOOTHING makes the controls smoother, decreasing it makes them
+// more responsive. This might be useful as a user-customizable option.
+#define MOUSE_AXIS_SMOOTHING 1.5f
+
+namespace ciface
+{
+namespace XInput2
+{
+
+// This function will add zero or more KeyboardMouse objects to devices.
+void Init(std::vector<Core::Device*>& devices, void* const hwnd)
+{
+ Display* dpy;
+
+ dpy = XOpenDisplay(NULL);
+
+ // xi_opcode is important; it will be used to identify XInput events by
+ // the polling loop in UpdateInput.
+ int xi_opcode, event, error;
+
+ // verify that the XInput extension is available
+ if (!XQueryExtension(dpy, "XInputExtension", &xi_opcode, &event, &error))
+ return;
+
+ // verify that the XInput extension is at at least version 2.0
+ int major = 2, minor = 0;
+
+ if (XIQueryVersion(dpy, &major, &minor) != Success)
+ return;
+
+ // register all master devices with Dolphin
+
+ XIDeviceInfo* all_masters;
+ XIDeviceInfo* current_master;
+ int num_masters;
+
+ all_masters = XIQueryDevice(dpy, XIAllMasterDevices, &num_masters);
+
+ for (int i = 0; i < num_masters; i++)
+ {
+ current_master = &all_masters[i];
+ if (current_master->use == XIMasterPointer)
+ // Since current_master is a master pointer, its attachment must
+ // be a master keyboard.
+ devices.push_back(new KeyboardMouse((Window)hwnd, xi_opcode, current_master->deviceid, current_master->attachment));
+ }
+
+ XCloseDisplay(dpy);
+
+ XIFreeDeviceInfo(all_masters);
+}
+
+// Apply the event mask to the device and all its slaves. Only used in the
+// constructor. Remember, each KeyboardMouse has its own copy of the event
+// stream, which is how multiple event masks can "coexist."
+void KeyboardMouse::SelectEventsForDevice(Window window, XIEventMask *mask, int deviceid)
+{
+ // Set the event mask for the master device.
+
+ mask->deviceid = deviceid;
+ XISelectEvents(m_display, window, mask, 1);
+
+ // Query all the master device's slaves and set the same event mask for
+ // those too. There are two reasons we want to do this. For mouse devices,
+ // we want the raw motion events, and only slaves (i.e. physical hardware
+ // devices) emit those. For keyboard devices, selecting slaves avoids
+ // dealing with key focus.
+
+ XIDeviceInfo* all_slaves;
+ XIDeviceInfo* current_slave;
+ int num_slaves;
+
+ all_slaves = XIQueryDevice(m_display, XIAllDevices, &num_slaves);
+
+ for (int i = 0; i < num_slaves; i++)
+ {
+ current_slave = &all_slaves[i];
+ if ((current_slave->use != XISlavePointer && current_slave->use != XISlaveKeyboard) || current_slave->attachment != deviceid)
+ continue;
+ mask->deviceid = current_slave->deviceid;
+ XISelectEvents(m_display, window, mask, 1);
+ }
+
+ XIFreeDeviceInfo(all_slaves);
+}
+
+KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboard)
+ : m_window(window), xi_opcode(opcode), pointer_deviceid(pointer), keyboard_deviceid(keyboard)
+{
+ memset(&m_state, 0, sizeof(m_state));
+
+ // The cool thing about each KeyboardMouse object having its own Display
+ // is that each one gets its own separate copy of the X11 event stream,
+ // which it can individually filter to get just the events it's interested
+ // in. So be aware that each KeyboardMouse object actually has its own X11
+ // "context."
+ m_display = XOpenDisplay(NULL);
+
+ int min_keycode, max_keycode;
+ XDisplayKeycodes(m_display, &min_keycode, &max_keycode);
+
+ int unused; // should always be 1
+ XIDeviceInfo* pointer_device = XIQueryDevice(m_display, pointer_deviceid, &unused);
+ name = std::string(pointer_device->name);
+ XIFreeDeviceInfo(pointer_device);
+
+ XIEventMask mask;
+ unsigned char mask_buf[(XI_LASTEVENT + 7)/8];
+
+ mask.mask_len = sizeof(mask_buf);
+ mask.mask = mask_buf;
+ memset(mask_buf, 0, sizeof(mask_buf));
+
+ XISetMask(mask_buf, XI_ButtonPress);
+ XISetMask(mask_buf, XI_ButtonRelease);
+ XISetMask(mask_buf, XI_RawMotion);
+ XISetMask(mask_buf, XI_KeyPress);
+ XISetMask(mask_buf, XI_KeyRelease);
+
+ SelectEventsForDevice(DefaultRootWindow(m_display), &mask, pointer_deviceid);
+ SelectEventsForDevice(DefaultRootWindow(m_display), &mask, keyboard_deviceid);
+
+ // Keyboard Keys
+ for (int i = min_keycode; i <= max_keycode; ++i)
+ {
+ Key* temp_key = new Key(m_display, i, m_state.keyboard);
+ if (temp_key->m_keyname.length())
+ AddInput(temp_key);
+ else
+ delete temp_key;
+ }
+
+ // Mouse Buttons
+ for (int i = 0; i < 5; i++)
+ AddInput(new Button(i, m_state.buttons));
+
+ // Mouse Cursor, X-/+ and Y-/+
+ for (int i = 0; i != 4; ++i)
+ AddInput(new Cursor(!!(i & 2), !!(i & 1), (&m_state.cursor.x)[!!(i & 2)]));
+
+ // Mouse Axis, X-/+ and Y-/+
+ for (int i = 0; i != 4; ++i)
+ AddInput(new Axis(!!(i & 2), !!(i & 1), (&m_state.axis.x)[!!(i & 2)]));
+}
+
+KeyboardMouse::~KeyboardMouse()
+{
+ XCloseDisplay(m_display);
+}
+
+// Update the mouse cursor controls
+void KeyboardMouse::UpdateCursor()
+{
+ double root_x, root_y, win_x, win_y;
+ Window root, child;
+
+ // unused-- we're not interested in button presses here, as those are
+ // updated using events
+ XIButtonState button_state;
+ XIModifierState mods;
+ XIGroupState group;
+
+ XIQueryPointer(m_display, pointer_deviceid, m_window, &root, &child, &root_x, &root_y, &win_x, &win_y, &button_state, &mods, &group);
+
+ free (button_state.mask);
+
+ XWindowAttributes win_attribs;
+ XGetWindowAttributes(m_display, m_window, &win_attribs);
+
+ // the mouse position as a range from -1 to 1
+ m_state.cursor.x = win_x / (float)win_attribs.width * 2 - 1;
+ m_state.cursor.y = win_y / (float)win_attribs.height * 2 - 1;
+}
+
+bool KeyboardMouse::UpdateInput()
+{
+ XFlush(m_display);
+
+ // Get the absolute position of the mouse pointer
+ UpdateCursor();
+
+ // for the axis controls
+ float delta_x = 0.0f, delta_y = 0.0f;
+ double delta_delta;
+
+ // Iterate through the event queue - update the axis controls, mouse
+ // button controls, and keyboard controls.
+ XEvent event;
+ while (XPending(m_display))
+ {
+ XNextEvent(m_display, &event);
+
+ if (event.xcookie.type != GenericEvent)
+ continue;
+ if (event.xcookie.extension != xi_opcode)
+ continue;
+ if (!XGetEventData(m_display, &event.xcookie))
+ continue;
+
+ // only one of these will get used
+ XIDeviceEvent* dev_event = (XIDeviceEvent*)event.xcookie.data;
+ XIRawEvent* raw_event = (XIRawEvent*)event.xcookie.data;
+
+ switch (event.xcookie.evtype)
+ {
+ case XI_ButtonPress:
+ m_state.buttons |= 1<<(dev_event->detail-1);
+ break;
+ case XI_ButtonRelease:
+ m_state.buttons &= ~(1<<(dev_event->detail-1));
+ break;
+ case XI_KeyPress:
+ m_state.keyboard[dev_event->detail / 8] |= 1<<(dev_event->detail % 8);
+ break;
+ case XI_KeyRelease:
+ m_state.keyboard[dev_event->detail / 8] &= ~(1<<(dev_event->detail % 8));
+ break;
+ case XI_RawMotion:
+ // always safe because there is always at least one byte in
+ // raw_event->valuators.mask, and if a bit is set in the mask,
+ // then the value in raw_values is also available.
+ if (XIMaskIsSet(raw_event->valuators.mask, 0))
+ {
+ delta_delta = raw_event->raw_values[0];
+ // test for inf and nan
+ if (delta_delta == delta_delta && 1+delta_delta != delta_delta)
+ delta_x += delta_delta;
+ }
+ if (XIMaskIsSet(raw_event->valuators.mask, 1))
+ {
+ delta_delta = raw_event->raw_values[1];
+ // test for inf and nan
+ if (delta_delta == delta_delta && 1+delta_delta != delta_delta)
+ delta_y += delta_delta;
+ }
+ break;
+ }
+
+ XFreeEventData(m_display, &event.xcookie);
+ }
+
+ // apply axis smoothing
+ m_state.axis.x *= MOUSE_AXIS_SMOOTHING;
+ m_state.axis.x += delta_x;
+ m_state.axis.x /= MOUSE_AXIS_SMOOTHING+1.0f;
+ m_state.axis.y *= MOUSE_AXIS_SMOOTHING;
+ m_state.axis.y += delta_y;
+ m_state.axis.y /= MOUSE_AXIS_SMOOTHING+1.0f;
+
+ return true;
+}
+
+bool KeyboardMouse::UpdateOutput()
+{
+ return true;
+}
+
+std::string KeyboardMouse::GetName() const
+{
+ // This is the name string we got from the X server for this master
+ // pointer/keyboard pair.
+ return name;
+}
+
+std::string KeyboardMouse::GetSource() const
+{
+ return "XInput2";
+}
+
+int KeyboardMouse::GetId() const
+{
+ return -1;
+}
+
+KeyboardMouse::Key::Key(Display* const display, KeyCode keycode, const char* keyboard)
+ : m_display(display), m_keyboard(keyboard), m_keycode(keycode)
+{
+ int i = 0;
+ KeySym keysym = 0;
+ do
+ {
+ keysym = XkbKeycodeToKeysym(m_display, keycode, i, 0);
+ i++;
+ }
+ while (keysym == NoSymbol && i < 8);
+
+ // Convert to upper case for the keyname
+ if (keysym >= 97 && keysym <= 122)
+ keysym -= 32;
+
+ // 0x0110ffff is the top of the unicode character range according
+ // to keysymdef.h although it is probably more than we need.
+ if (keysym == NoSymbol || keysym > 0x0110ffff ||
+ XKeysymToString(keysym) == NULL)
+ m_keyname = std::string();
+ else
+ m_keyname = std::string(XKeysymToString(keysym));
+}
+
+ControlState KeyboardMouse::Key::GetState() const
+{
+ return (m_keyboard[m_keycode / 8] & (1 << (m_keycode % 8))) != 0;
+}
+
+KeyboardMouse::Button::Button(unsigned int index, unsigned int& buttons)
+ : m_buttons(buttons), m_index(index)
+{
+ // this will be a problem if we remove the hardcoded five-button limit
+ name = std::string("Click ") + (char)('1' + m_index);
+}
+
+ControlState KeyboardMouse::Button::GetState() const
+{
+ return ((m_buttons & (1 << m_index)) != 0);
+}
+
+KeyboardMouse::Cursor::Cursor(u8 index, bool positive, const float& cursor)
+ : m_cursor(cursor), m_index(index), m_positive(positive)
+{
+ name = std::string("Cursor ") + (char)('X' + m_index) + (m_positive ? '+' : '-');
+}
+
+ControlState KeyboardMouse::Cursor::GetState() const
+{
+ return std::max(0.0f, m_cursor / (m_positive ? 1.0f : -1.0f));
+}
+
+KeyboardMouse::Axis::Axis(u8 index, bool positive, const float& axis)
+ : m_axis(axis), m_index(index), m_positive(positive)
+{
+ name = std::string("Axis ") + (char)('X' + m_index) + (m_positive ? '+' : '-');
+}
+
+ControlState KeyboardMouse::Axis::GetState() const
+{
+ return std::max(0.0f, m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
+}
+
+}
+}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.h b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.h
new file mode 100644
index 0000000000..58a1a38c8c
--- /dev/null
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/XInput2.h
@@ -0,0 +1,124 @@
+// Copyright 2013 Max Eliaser
+// Licensed under the GNU General Public License, version 2 or higher.
+// Refer to the license.txt file included.
+
+// See XInput2.cpp for extensive documentation.
+
+#ifndef _CIFACE_X11_XINPUT2_H_
+#define _CIFACE_X11_XINPUT2_H_
+
+#include "../Device.h"
+
+extern "C" {
+#include <X11/Xlib.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/keysym.h>
+}
+
+namespace ciface
+{
+namespace XInput2
+{
+
+void Init(std::vector<Core::Device*>& devices, void* const hwnd);
+
+class KeyboardMouse : public Core::Device
+{
+
+private:
+ struct State
+ {
+ char keyboard[32];
+ unsigned int buttons;
+ struct
+ {
+ float x, y;
+ } cursor, axis;
+ };
+
+ class Key : public Input
+ {
+ friend class KeyboardMouse;
+ public:
+ std::string GetName() const { return m_keyname; }
+ Key(Display* display, KeyCode keycode, const char* keyboard);
+ ControlState GetState() const;
+
+ private:
+ std::string m_keyname;
+ Display* const m_display;
+ const char* const m_keyboard;
+ const KeyCode m_keycode;
+ };
+
+ class Button : public Input
+ {
+ public:
+ std::string GetName() const { return name; }
+ Button(unsigned int index, unsigned int& buttons);
+ ControlState GetState() const;
+
+ private:
+ const unsigned int& m_buttons;
+ const unsigned int m_index;
+ std::string name;
+ };
+
+ class Cursor : public Input
+ {
+ public:
+ std::string GetName() const { return name; }
+ bool IsDetectable() { return false; }
+ Cursor(u8 index, bool positive, const float& cursor);
+ ControlState GetState() const;
+
+ private:
+ const float& m_cursor;
+ const u8 m_index;
+ const bool m_positive;
+ std::string name;
+ };
+
+ class Axis : public Input
+ {
+ public:
+ std::string GetName() const { return name; }
+ bool IsDetectable() { return false; }
+ Axis(u8 index, bool positive, const float& axis);
+ ControlState GetState() const;
+
+ private:
+ const float& m_axis;
+ const u8 m_index;
+ const bool m_positive;
+ std::string name;
+ };
+
+private:
+ void SelectEventsForDevice(Window window, XIEventMask *mask, int deviceid);
+ void UpdateCursor();
+
+public:
+ bool UpdateInput();
+ bool UpdateOutput();
+
+ KeyboardMouse(Window window, int opcode, int pointer_deviceid, int keyboard_deviceid);
+ ~KeyboardMouse();
+
+ std::string GetName() const;
+ std::string GetSource() const;
+ int GetId() const;
+
+private:
+ Window m_window;
+ Display* m_display;
+ State m_state;
+ int xi_opcode;
+ const int pointer_deviceid, keyboard_deviceid;
+ std::string name;
+};
+
+}
+}
+
+#endif
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp
index dad0c6bbf8..7016c4908b 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.cpp
@@ -7,7 +7,7 @@ namespace ciface
namespace Xlib
{
-void Init(std::vector<ControllerInterface::Device*>& devices, void* const hwnd)
+void Init(std::vector<Core::Device*>& devices, void* const hwnd)
{
devices.push_back(new KeyboardMouse((Window)hwnd));
}
diff --git a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.h b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.h
index 2af95ff7f9..c178f1e9b4 100644
--- a/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.h
+++ b/Source/Core/InputCommon/Src/ControllerInterface/Xlib/Xlib.h
@@ -1,7 +1,7 @@
#ifndef _CIFACE_XLIB_H_
#define _CIFACE_XLIB_H_
-#include "../ControllerInterface.h"
+#include "../Device.h"
#include <X11/Xlib.h>
#include <X11/keysym.h>
@@ -11,9 +11,9 @@ namespace ciface
namespace Xlib
{
-void Init(std::vector<ControllerInterface::Device*>& devices, void* const hwnd);
+void Init(std::vector<Core::Device*>& devices, void* const hwnd);
-class KeyboardMouse : public ControllerInterface::Device
+class KeyboardMouse : public Core::Device
{
private: