summaryrefslogtreecommitdiff
path: root/src/input_common/analog_from_button.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common/analog_from_button.cpp')
-rwxr-xr-xsrc/input_common/analog_from_button.cpp195
1 files changed, 122 insertions, 73 deletions
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp
index f8ec179d0..100138d11 100755
--- a/src/input_common/analog_from_button.cpp
+++ b/src/input_common/analog_from_button.cpp
@@ -21,104 +21,153 @@ public:
21 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), 21 : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)),
22 right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), 22 right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_),
23 modifier_angle(modifier_angle_) { 23 modifier_angle(modifier_angle_) {
24 update_thread_running.store(true); 24 Input::InputCallback<bool> callbacks{
25 update_thread = std::thread(&Analog::UpdateStatus, this); 25 [this]([[maybe_unused]] bool status) { UpdateStatus(); }};
26 up->SetCallback(callbacks);
27 down->SetCallback(callbacks);
28 left->SetCallback(callbacks);
29 right->SetCallback(callbacks);
26 } 30 }
27 31
28 ~Analog() override { 32 bool IsAngleGreater(float old_angle, float new_angle) const {
29 if (update_thread_running.load()) { 33 constexpr float TAU = Common::PI * 2.0f;
30 update_thread_running.store(false); 34 // Use wider angle to ease the transition.
31 if (update_thread.joinable()) { 35 constexpr float aperture = TAU * 0.15f;
32 update_thread.join(); 36 const float top_limit = new_angle + aperture;
33 } 37 return (old_angle > new_angle && old_angle <= top_limit) ||
34 } 38 (old_angle + TAU > new_angle && old_angle + TAU <= top_limit);
35 } 39 }
36 40
37 void MoveToDirection(bool enable, float to_angle) { 41 bool IsAngleSmaller(float old_angle, float new_angle) const {
38 if (!enable) {
39 return;
40 }
41 constexpr float TAU = Common::PI * 2.0f; 42 constexpr float TAU = Common::PI * 2.0f;
42 // Use wider angle to ease the transition. 43 // Use wider angle to ease the transition.
43 constexpr float aperture = TAU * 0.15f; 44 constexpr float aperture = TAU * 0.15f;
44 const float top_limit = to_angle + aperture; 45 const float bottom_limit = new_angle - aperture;
45 const float bottom_limit = to_angle - aperture; 46 return (old_angle >= bottom_limit && old_angle < new_angle) ||
46 47 (old_angle - TAU >= bottom_limit && old_angle - TAU < new_angle);
47 if ((angle > to_angle && angle <= top_limit) || 48 }
48 (angle + TAU > to_angle && angle + TAU <= top_limit)) { 49
49 angle -= modifier_angle; 50 float GetAngle(std::chrono::time_point<std::chrono::steady_clock> now) const {
50 if (angle < 0) { 51 constexpr float TAU = Common::PI * 2.0f;
51 angle += TAU; 52 float new_angle = angle;
53
54 auto time_difference = static_cast<float>(
55 std::chrono::duration_cast<std::chrono::microseconds>(now - last_update).count());
56 time_difference /= 1000.0f * 1000.0f;
57 if (time_difference > 0.5f) {
58 time_difference = 0.5f;
59 }
60
61 if (IsAngleGreater(new_angle, goal_angle)) {
62 new_angle -= modifier_angle * time_difference;
63 if (new_angle < 0) {
64 new_angle += TAU;
65 }
66 if (!IsAngleGreater(new_angle, goal_angle)) {
67 return goal_angle;
52 } 68 }
53 } else if ((angle >= bottom_limit && angle < to_angle) || 69 } else if (IsAngleSmaller(new_angle, goal_angle)) {
54 (angle - TAU >= bottom_limit && angle - TAU < to_angle)) { 70 new_angle += modifier_angle * time_difference;
55 angle += modifier_angle; 71 if (new_angle >= TAU) {
56 if (angle >= TAU) { 72 new_angle -= TAU;
57 angle -= TAU; 73 }
74 if (!IsAngleSmaller(new_angle, goal_angle)) {
75 return goal_angle;
58 } 76 }
59 } else { 77 } else {
60 angle = to_angle; 78 return goal_angle;
61 } 79 }
80 return new_angle;
62 } 81 }
63 82
64 void UpdateStatus() { 83 void SetGoalAngle(bool r, bool l, bool u, bool d) {
65 while (update_thread_running.load()) { 84 // Move to the right
66 const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; 85 if (r && !u && !d) {
67 86 goal_angle = 0.0f;
68 bool r = right->GetStatus(); 87 }
69 bool l = left->GetStatus(); 88
70 bool u = up->GetStatus(); 89 // Move to the upper right
71 bool d = down->GetStatus(); 90 if (r && u && !d) {
72 91 goal_angle = Common::PI * 0.25f;
73 // Eliminate contradictory movements 92 }
74 if (r && l) {
75 r = false;
76 l = false;
77 }
78 if (u && d) {
79 u = false;
80 d = false;
81 }
82 93
83 // Move to the right 94 // Move up
84 MoveToDirection(r && !u && !d, 0.0f); 95 if (u && !l && !r) {
96 goal_angle = Common::PI * 0.5f;
97 }
85 98
86 // Move to the upper right 99 // Move to the upper left
87 MoveToDirection(r && u && !d, Common::PI * 0.25f); 100 if (l && u && !d) {
101 goal_angle = Common::PI * 0.75f;
102 }
88 103
89 // Move up 104 // Move to the left
90 MoveToDirection(u && !l && !r, Common::PI * 0.5f); 105 if (l && !u && !d) {
106 goal_angle = Common::PI;
107 }
91 108
92 // Move to the upper left 109 // Move to the bottom left
93 MoveToDirection(l && u && !d, Common::PI * 0.75f); 110 if (l && !u && d) {
111 goal_angle = Common::PI * 1.25f;
112 }
94 113
95 // Move to the left 114 // Move down
96 MoveToDirection(l && !u && !d, Common::PI); 115 if (d && !l && !r) {
116 goal_angle = Common::PI * 1.5f;
117 }
97 118
98 // Move to the bottom left 119 // Move to the bottom right
99 MoveToDirection(l && !u && d, Common::PI * 1.25f); 120 if (r && !u && d) {
121 goal_angle = Common::PI * 1.75f;
122 }
123 }
100 124
101 // Move down 125 void UpdateStatus() {
102 MoveToDirection(d && !l && !r, Common::PI * 1.5f); 126 const float coef = modifier->GetStatus() ? modifier_scale : 1.0f;
103 127
104 // Move to the bottom right 128 bool r = right->GetStatus();
105 MoveToDirection(r && !u && d, Common::PI * 1.75f); 129 bool l = left->GetStatus();
130 bool u = up->GetStatus();
131 bool d = down->GetStatus();
106 132
107 // Move if a key is pressed 133 // Eliminate contradictory movements
108 if (r || l || u || d) { 134 if (r && l) {
109 amplitude = coef; 135 r = false;
110 } else { 136 l = false;
111 amplitude = 0; 137 }
112 } 138 if (u && d) {
139 u = false;
140 d = false;
141 }
113 142
114 // Delay the update rate to 100hz 143 // Move if a key is pressed
115 std::this_thread::sleep_for(std::chrono::milliseconds(10)); 144 if (r || l || u || d) {
145 amplitude = coef;
146 } else {
147 amplitude = 0;
116 } 148 }
149
150 const auto now = std::chrono::steady_clock::now();
151 const auto time_difference = static_cast<u64>(
152 std::chrono::duration_cast<std::chrono::milliseconds>(now - last_update).count());
153
154 if (time_difference < 10) {
155 // Disable analog mode if inputs are too fast
156 SetGoalAngle(r, l, u, d);
157 angle = goal_angle;
158 } else {
159 angle = GetAngle(now);
160 SetGoalAngle(r, l, u, d);
161 }
162
163 last_update = now;
117 } 164 }
118 165
119 std::tuple<float, float> GetStatus() const override { 166 std::tuple<float, float> GetStatus() const override {
120 if (Settings::values.emulate_analog_keyboard) { 167 if (Settings::values.emulate_analog_keyboard) {
121 return std::make_tuple(std::cos(angle) * amplitude, std::sin(angle) * amplitude); 168 const auto now = std::chrono::steady_clock::now();
169 float angle_ = GetAngle(now);
170 return std::make_tuple(std::cos(angle_) * amplitude, std::sin(angle_) * amplitude);
122 } 171 }
123 constexpr float SQRT_HALF = 0.707106781f; 172 constexpr float SQRT_HALF = 0.707106781f;
124 int x = 0, y = 0; 173 int x = 0, y = 0;
@@ -166,9 +215,9 @@ private:
166 float modifier_scale; 215 float modifier_scale;
167 float modifier_angle; 216 float modifier_angle;
168 float angle{}; 217 float angle{};
218 float goal_angle{};
169 float amplitude{}; 219 float amplitude{};
170 std::thread update_thread; 220 std::chrono::time_point<std::chrono::steady_clock> last_update;
171 std::atomic<bool> update_thread_running{};
172}; 221};
173 222
174std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { 223std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) {
@@ -179,7 +228,7 @@ std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::Para
179 auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine)); 228 auto right = Input::CreateDevice<Input::ButtonDevice>(params.Get("right", null_engine));
180 auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine)); 229 auto modifier = Input::CreateDevice<Input::ButtonDevice>(params.Get("modifier", null_engine));
181 auto modifier_scale = params.Get("modifier_scale", 0.5f); 230 auto modifier_scale = params.Get("modifier_scale", 0.5f);
182 auto modifier_angle = params.Get("modifier_angle", 0.035f); 231 auto modifier_angle = params.Get("modifier_angle", 5.5f);
183 return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left), 232 return std::make_unique<Analog>(std::move(up), std::move(down), std::move(left),
184 std::move(right), std::move(modifier), modifier_scale, 233 std::move(right), std::move(modifier), modifier_scale,
185 modifier_angle); 234 modifier_angle);