diff options
| author | Matthew Parlane <parlane@gmail.com> | 2013-08-16 19:17:07 +1200 |
|---|---|---|
| committer | Matthew Parlane <parlane@gmail.com> | 2013-08-16 19:17:07 +1200 |
| commit | 9de7611ff940d24551bc77a5e29b86911e3fa749 (patch) | |
| tree | 7615ec4cfd3aaba63d96ef1cb3cc33fd0efa516a /Source/Core/InputCommon/Src/ControllerInterface | |
| parent | 417552b21e30aee3dc2b720d65c2cd757997a33e (diff) | |
| parent | bff2bc1288fa4309e1b2aef1486845ba01311100 (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')
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: |
