| 
									
										
										
										
											2015-05-24 06:55:12 +02:00
										 |  |  | // Copyright 2010 Dolphin Emulator Project
 | 
					
						
							| 
									
										
										
										
											2015-05-18 01:08:10 +02:00
										 |  |  | // Licensed under GPLv2+
 | 
					
						
							| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-06-12 17:15:16 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | #pragma once
 | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <algorithm>
 | 
					
						
							| 
									
										
										
										
											2010-06-13 09:26:00 +00:00
										 |  |  | #include <cmath>
 | 
					
						
							| 
									
										
										
										
											2014-02-01 17:20:35 -05:00
										 |  |  | #include <memory>
 | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  | #include <mutex>
 | 
					
						
							| 
									
										
										
										
											2010-06-13 09:26:00 +00:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include <vector>
 | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/IniFile.h"
 | 
					
						
							| 
									
										
										
										
											2016-07-09 14:29:41 +02:00
										 |  |  | #include "Common/MathUtil.h"
 | 
					
						
							| 
									
										
										
										
											2014-07-11 10:42:44 -04:00
										 |  |  | #include "Core/ConfigManager.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "InputCommon/ControllerInterface/ControllerInterface.h"
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #include "InputCommon/GCPadStatus.h"
 | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | #define sign(x) ((x) ? (x) < 0 ? -1 : 1 : 0)
 | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   GROUP_TYPE_OTHER, | 
					
						
							|  |  |  |   GROUP_TYPE_STICK, | 
					
						
							|  |  |  |   GROUP_TYPE_MIXED_TRIGGERS, | 
					
						
							|  |  |  |   GROUP_TYPE_BUTTONS, | 
					
						
							|  |  |  |   GROUP_TYPE_FORCE, | 
					
						
							|  |  |  |   GROUP_TYPE_EXTENSION, | 
					
						
							|  |  |  |   GROUP_TYPE_TILT, | 
					
						
							|  |  |  |   GROUP_TYPE_CURSOR, | 
					
						
							|  |  |  |   GROUP_TYPE_TRIGGERS, | 
					
						
							|  |  |  |   GROUP_TYPE_SLIDER | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-10 09:27:33 +01:00
										 |  |  | enum | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   SETTING_RADIUS, | 
					
						
							|  |  |  |   SETTING_DEADZONE, | 
					
						
							| 
									
										
										
										
											2011-11-10 09:27:33 +01:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | const char* const named_directions[] = {"Up", "Down", "Left", "Right"}; | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | class ControllerEmu | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   class ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     class Control | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     protected: | 
					
						
							|  |  |  |       Control(ControllerInterface::ControlReference* const _ref, const std::string& _name) | 
					
						
							|  |  |  |           : control_ref(_ref), name(_name) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |       virtual ~Control() {} | 
					
						
							|  |  |  |       std::unique_ptr<ControllerInterface::ControlReference> const control_ref; | 
					
						
							|  |  |  |       const std::string name; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Input : public Control | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |       Input(const std::string& _name) : Control(new ControllerInterface::InputReference, _name) {} | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class Output : public Control | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							|  |  |  |       Output(const std::string& _name) : Control(new ControllerInterface::OutputReference, _name) {} | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |     enum class SettingType | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       NORMAL,   // normal settings are saved to configuration files
 | 
					
						
							|  |  |  |       VIRTUAL,  // virtual settings are not saved at all
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     class NumericSetting | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2016-07-18 19:30:47 +02:00
										 |  |  |       NumericSetting(const std::string& setting_name, const ControlState default_value, | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |                      const unsigned int low = 0, const unsigned int high = 100, | 
					
						
							| 
									
										
										
										
											2016-07-18 19:30:47 +02:00
										 |  |  |                      const SettingType setting_type = SettingType::NORMAL) | 
					
						
							|  |  |  |           : m_type(setting_type), m_name(setting_name), m_default_value(default_value), m_low(low), | 
					
						
							|  |  |  |             m_high(high) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       ControlState GetValue() const { return m_value; } | 
					
						
							|  |  |  |       void SetValue(ControlState value) { m_value = value; } | 
					
						
							|  |  |  |       const SettingType m_type; | 
					
						
							|  |  |  |       const std::string m_name; | 
					
						
							|  |  |  |       const ControlState m_default_value; | 
					
						
							|  |  |  |       const unsigned int m_low, m_high; | 
					
						
							|  |  |  |       ControlState m_value; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |     class BooleanSetting | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2016-07-18 19:30:47 +02:00
										 |  |  |       BooleanSetting(const std::string& setting_name, const bool default_value, | 
					
						
							|  |  |  |                      const SettingType setting_type = SettingType::NORMAL) | 
					
						
							|  |  |  |           : m_type(setting_type), m_name(setting_name), m_default_value(default_value) | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       virtual bool GetValue() const { return m_value; } | 
					
						
							|  |  |  |       virtual void SetValue(bool value) { m_value = value; } | 
					
						
							|  |  |  |       const SettingType m_type; | 
					
						
							|  |  |  |       const std::string m_name; | 
					
						
							|  |  |  |       const bool m_default_value; | 
					
						
							|  |  |  |       bool m_value; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |     class BackgroundInputSetting : public BooleanSetting | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     { | 
					
						
							|  |  |  |     public: | 
					
						
							| 
									
										
										
										
											2016-07-18 19:30:47 +02:00
										 |  |  |       BackgroundInputSetting(const std::string& setting_name) | 
					
						
							|  |  |  |           : BooleanSetting(setting_name, false, SettingType::VIRTUAL) | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       { | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       bool GetValue() const override { return SConfig::GetInstance().m_BackgroundInput; } | 
					
						
							|  |  |  |       void SetValue(bool value) override | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         m_value = value; | 
					
						
							|  |  |  |         SConfig::GetInstance().m_BackgroundInput = value; | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ControlGroup(const std::string& _name, const unsigned int _type = GROUP_TYPE_OTHER) | 
					
						
							|  |  |  |         : name(_name), ui_name(_name), type(_type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ControlGroup(const std::string& _name, const std::string& _ui_name, | 
					
						
							|  |  |  |                  const unsigned int _type = GROUP_TYPE_OTHER) | 
					
						
							|  |  |  |         : name(_name), ui_name(_ui_name), type(_type) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     virtual ~ControlGroup() {} | 
					
						
							|  |  |  |     virtual void LoadConfig(IniFile::Section* sec, const std::string& defdev = "", | 
					
						
							|  |  |  |                             const std::string& base = ""); | 
					
						
							|  |  |  |     virtual void SaveConfig(IniFile::Section* sec, const std::string& defdev = "", | 
					
						
							|  |  |  |                             const std::string& base = ""); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void SetControlExpression(int index, const std::string& expression); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const std::string name; | 
					
						
							|  |  |  |     const std::string ui_name; | 
					
						
							|  |  |  |     const unsigned int type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::vector<std::unique_ptr<Control>> controls; | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |     std::vector<std::unique_ptr<NumericSetting>> numeric_settings; | 
					
						
							|  |  |  |     std::vector<std::unique_ptr<BooleanSetting>> boolean_settings; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class AnalogStick : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     // The GameCube controller and Wiimote attachments have a different default radius
 | 
					
						
							|  |  |  |     AnalogStick(const char* const _name, ControlState default_radius); | 
					
						
							|  |  |  |     AnalogStick(const char* const _name, const char* const _ui_name, ControlState default_radius); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* const x, ControlState* const y) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); | 
					
						
							|  |  |  |       ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       ControlState radius = numeric_settings[SETTING_RADIUS]->GetValue(); | 
					
						
							|  |  |  |       ControlState deadzone = numeric_settings[SETTING_DEADZONE]->GetValue(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       ControlState m = controls[4]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ControlState ang = atan2(yy, xx); | 
					
						
							|  |  |  |       ControlState ang_sin = sin(ang); | 
					
						
							|  |  |  |       ControlState ang_cos = cos(ang); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ControlState dist = sqrt(xx * xx + yy * yy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // dead zone code
 | 
					
						
							|  |  |  |       dist = std::max(0.0, dist - deadzone); | 
					
						
							|  |  |  |       dist /= (1 - deadzone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // radius
 | 
					
						
							|  |  |  |       dist *= radius; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // The modifier halves the distance by 50%, which is useful
 | 
					
						
							|  |  |  |       // for keyboard controls.
 | 
					
						
							|  |  |  |       if (m) | 
					
						
							|  |  |  |         dist *= 0.5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); | 
					
						
							|  |  |  |       xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       *y = yy; | 
					
						
							|  |  |  |       *x = xx; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Buttons : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Buttons(const std::string& _name); | 
					
						
							| 
									
										
										
										
											2016-11-18 02:03:06 -05:00
										 |  |  |     Buttons(const std::string& ini_name, const std::string& group_name); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     template <typename C> | 
					
						
							|  |  |  |     void GetState(C* const buttons, const C* bitmasks) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       for (auto& control : controls) | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |         if (control->control_ref->State() > numeric_settings[0]->GetValue())  // threshold
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |           *buttons |= *bitmasks; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         bitmasks++; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-23 11:03:19 +02:00
										 |  |  |   class ModifySettingsButton : public Buttons | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     ModifySettingsButton(std::string button_name); | 
					
						
							|  |  |  |     void AddInput(std::string button_name, bool toggle = false); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     const std::vector<bool>& isSettingToggled() const { return associated_settings_toggle; } | 
					
						
							|  |  |  |     const std::vector<bool>& getSettingsModifier() const { return associated_settings; } | 
					
						
							|  |  |  |   private: | 
					
						
							|  |  |  |     std::vector<bool> threshold_exceeded;  // internal calculation (if "state" was above threshold)
 | 
					
						
							|  |  |  |     std::vector<bool> associated_settings_toggle;  // is setting toggled or hold?
 | 
					
						
							|  |  |  |     std::vector<bool> associated_settings;         // result
 | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   class MixedTriggers : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     MixedTriggers(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(u16* const digital, const u16* bitmasks, ControlState* analog) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       const unsigned int trig_count = ((unsigned int)(controls.size() / 2)); | 
					
						
							|  |  |  |       for (unsigned int i = 0; i < trig_count; ++i, ++bitmasks, ++analog) | 
					
						
							|  |  |  |       { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |         if (controls[i]->control_ref->State() > numeric_settings[0]->GetValue())  // threshold
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |         { | 
					
						
							|  |  |  |           *analog = 1.0; | 
					
						
							|  |  |  |           *digital |= *bitmasks; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           *analog = controls[i + trig_count]->control_ref->State(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Triggers : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Triggers(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* analog) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       const unsigned int trig_count = ((unsigned int)(controls.size())); | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       const ControlState deadzone = numeric_settings[0]->GetValue(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       for (unsigned int i = 0; i < trig_count; ++i, ++analog) | 
					
						
							|  |  |  |         *analog = std::max(controls[i]->control_ref->State() - deadzone, 0.0) / (1 - deadzone); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Slider : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Slider(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* const slider) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       const ControlState deadzone = numeric_settings[0]->GetValue(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       const ControlState state = | 
					
						
							|  |  |  |           controls[1]->control_ref->State() - controls[0]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (fabs(state) > deadzone) | 
					
						
							|  |  |  |         *slider = (state - (deadzone * sign(state))) / (1 - deadzone); | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |         *slider = 0; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Force : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Force(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* axis) | 
					
						
							|  |  |  |     { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       const ControlState deadzone = numeric_settings[0]->GetValue(); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       for (unsigned int i = 0; i < 6; i += 2) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         ControlState tmpf = 0; | 
					
						
							|  |  |  |         const ControlState state = | 
					
						
							|  |  |  |             controls[i + 1]->control_ref->State() - controls[i]->control_ref->State(); | 
					
						
							|  |  |  |         if (fabs(state) > deadzone) | 
					
						
							|  |  |  |           tmpf = ((state - (deadzone * sign(state))) / (1 - deadzone)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         ControlState& ax = m_swing[i >> 1]; | 
					
						
							|  |  |  |         *axis++ = (tmpf - ax); | 
					
						
							|  |  |  |         ax = tmpf; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private: | 
					
						
							|  |  |  |     ControlState m_swing[3]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Tilt : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Tilt(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* const x, ControlState* const y, const bool step = true) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       // this is all a mess
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); | 
					
						
							|  |  |  |       ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |       ControlState deadzone = numeric_settings[0]->GetValue(); | 
					
						
							|  |  |  |       ControlState circle = numeric_settings[1]->GetValue(); | 
					
						
							|  |  |  |       auto const angle = numeric_settings[2]->GetValue() / 1.8; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       ControlState m = controls[4]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // deadzone / circle stick code
 | 
					
						
							|  |  |  |       // this section might be all wrong, but its working good enough, I think
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ControlState ang = atan2(yy, xx); | 
					
						
							|  |  |  |       ControlState ang_sin = sin(ang); | 
					
						
							|  |  |  |       ControlState ang_cos = cos(ang); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // the amt a full square stick would have at current angle
 | 
					
						
							|  |  |  |       ControlState square_full = | 
					
						
							|  |  |  |           std::min(ang_sin ? 1 / fabs(ang_sin) : 2, ang_cos ? 1 / fabs(ang_cos) : 2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // the amt a full stick would have that was (user setting circular) at current angle
 | 
					
						
							|  |  |  |       // I think this is more like a pointed circle rather than a rounded square like it should be
 | 
					
						
							|  |  |  |       ControlState stick_full = (square_full * (1 - circle)) + (circle); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       ControlState dist = sqrt(xx * xx + yy * yy); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // dead zone code
 | 
					
						
							|  |  |  |       dist = std::max(0.0, dist - deadzone * stick_full); | 
					
						
							|  |  |  |       dist /= (1 - deadzone); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // circle stick code
 | 
					
						
							|  |  |  |       ControlState amt = dist / stick_full; | 
					
						
							|  |  |  |       dist += (square_full - 1) * amt * circle; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (m) | 
					
						
							|  |  |  |         dist *= 0.5; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       yy = std::max(-1.0, std::min(1.0, ang_sin * dist)); | 
					
						
							|  |  |  |       xx = std::max(-1.0, std::min(1.0, ang_cos * dist)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // this is kinda silly here
 | 
					
						
							|  |  |  |       // gui being open will make this happen 2x as fast, o well
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // silly
 | 
					
						
							|  |  |  |       if (step) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         if (xx > m_tilt[0]) | 
					
						
							|  |  |  |           m_tilt[0] = std::min(m_tilt[0] + 0.1, xx); | 
					
						
							|  |  |  |         else if (xx < m_tilt[0]) | 
					
						
							|  |  |  |           m_tilt[0] = std::max(m_tilt[0] - 0.1, xx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (yy > m_tilt[1]) | 
					
						
							|  |  |  |           m_tilt[1] = std::min(m_tilt[1] + 0.1, yy); | 
					
						
							|  |  |  |         else if (yy < m_tilt[1]) | 
					
						
							|  |  |  |           m_tilt[1] = std::max(m_tilt[1] - 0.1, yy); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       *y = m_tilt[1] * angle; | 
					
						
							|  |  |  |       *x = m_tilt[0] * angle; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   private: | 
					
						
							|  |  |  |     ControlState m_tilt[2]; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Cursor : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Cursor(const std::string& _name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     void GetState(ControlState* const x, ControlState* const y, ControlState* const z, | 
					
						
							|  |  |  |                   const bool adjusted = false) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |       const ControlState zz = controls[4]->control_ref->State() - controls[5]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // silly being here
 | 
					
						
							|  |  |  |       if (zz > m_z) | 
					
						
							|  |  |  |         m_z = std::min(m_z + 0.1, zz); | 
					
						
							|  |  |  |       else if (zz < m_z) | 
					
						
							|  |  |  |         m_z = std::max(m_z - 0.1, zz); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       *z = m_z; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       // hide
 | 
					
						
							|  |  |  |       if (controls[6]->control_ref->State() > 0.5) | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         *x = 10000; | 
					
						
							|  |  |  |         *y = 0; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       else | 
					
						
							|  |  |  |       { | 
					
						
							|  |  |  |         ControlState yy = controls[0]->control_ref->State() - controls[1]->control_ref->State(); | 
					
						
							|  |  |  |         ControlState xx = controls[3]->control_ref->State() - controls[2]->control_ref->State(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         // adjust cursor according to settings
 | 
					
						
							|  |  |  |         if (adjusted) | 
					
						
							|  |  |  |         { | 
					
						
							| 
									
										
										
										
											2016-07-11 19:35:32 +02:00
										 |  |  |           xx *= (numeric_settings[1]->GetValue() * 2); | 
					
						
							|  |  |  |           yy *= (numeric_settings[2]->GetValue() * 2); | 
					
						
							|  |  |  |           yy += (numeric_settings[0]->GetValue() - 0.5); | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-09 14:29:41 +02:00
										 |  |  |         // relative input
 | 
					
						
							|  |  |  |         if (boolean_settings[0]->GetValue()) | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           const ControlState deadzone = numeric_settings[3]->GetValue(); | 
					
						
							|  |  |  |           // deadzone to avoid the cursor slowly drifting
 | 
					
						
							|  |  |  |           if (std::abs(xx) > deadzone) | 
					
						
							|  |  |  |             m_x = MathUtil::Clamp(m_x + xx * SPEED_MULTIPLIER, -1.0, 1.0); | 
					
						
							|  |  |  |           if (std::abs(yy) > deadzone) | 
					
						
							|  |  |  |             m_y = MathUtil::Clamp(m_y + yy * SPEED_MULTIPLIER, -1.0, 1.0); | 
					
						
							| 
									
										
										
										
											2016-07-17 14:32:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |           // recenter
 | 
					
						
							|  |  |  |           if (controls[7]->control_ref->State() > 0.5) | 
					
						
							|  |  |  |           { | 
					
						
							|  |  |  |             m_x = 0.0; | 
					
						
							|  |  |  |             m_y = 0.0; | 
					
						
							|  |  |  |           } | 
					
						
							| 
									
										
										
										
											2016-07-09 14:29:41 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |         else | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |           m_x = xx; | 
					
						
							|  |  |  |           m_y = yy; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         *x = m_x; | 
					
						
							|  |  |  |         *y = m_y; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ControlState m_z; | 
					
						
							| 
									
										
										
										
											2016-07-09 14:29:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   private: | 
					
						
							|  |  |  |     // This is used to reduce the cursor speed for relative input
 | 
					
						
							|  |  |  |     // to something that makes sense with the default range.
 | 
					
						
							|  |  |  |     static constexpr double SPEED_MULTIPLIER = 0.04; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ControlState m_x = 0.0; | 
					
						
							|  |  |  |     ControlState m_y = 0.0; | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   class Extension : public ControlGroup | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |   public: | 
					
						
							|  |  |  |     Extension(const std::string& _name) | 
					
						
							|  |  |  |         : ControlGroup(_name, GROUP_TYPE_EXTENSION), switch_extension(0), active_extension(0) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ~Extension() {} | 
					
						
							|  |  |  |     void GetState(u8* const data); | 
					
						
							|  |  |  |     bool IsButtonPressed() const; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     std::vector<std::unique_ptr<ControllerEmu>> attachments; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     int switch_extension; | 
					
						
							|  |  |  |     int active_extension; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   virtual ~ControllerEmu() {} | 
					
						
							|  |  |  |   virtual std::string GetName() const = 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   virtual void LoadDefaults(const ControllerInterface& ciface); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   virtual void LoadConfig(IniFile::Section* sec, const std::string& base = ""); | 
					
						
							|  |  |  |   virtual void SaveConfig(IniFile::Section* sec, const std::string& base = ""); | 
					
						
							|  |  |  |   void UpdateDefaultDevice(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void UpdateReferences(ControllerInterface& devi); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-07-14 17:45:59 +02:00
										 |  |  |   // This returns a lock that should be held before calling State() on any control
 | 
					
						
							|  |  |  |   // references and GetState(), by extension. This prevents a race condition
 | 
					
						
							|  |  |  |   // which happens while handling a hotplug event because a control reference's State()
 | 
					
						
							|  |  |  |   // could be called before we have finished updating the reference.
 | 
					
						
							|  |  |  |   static std::unique_lock<std::recursive_mutex> GetStateLock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-24 10:43:46 +02:00
										 |  |  |   std::vector<std::unique_ptr<ControlGroup>> groups; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ciface::Core::DeviceQualifier default_device; | 
					
						
							| 
									
										
										
										
											2010-06-03 18:05:08 +00:00
										 |  |  | }; |