/
MouseMapper.h
160 lines (159 loc) · 5.84 KB
/
MouseMapper.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
#pragma once
#include "stdafx.h"
#include "MouseMoveThread.h"
#include "ThumbstickToDelay.h"
#include "MouseInputPoller.h"
#include "Utilities.h"
namespace sds
{
/// <summary>
/// Handles achieving smooth, expected mouse movements.
/// This class starts a running thread that is used to process the XINPUT_STATE structure and use those values to determine if it should move the mouse cursor, and if so how much.
/// The class has an internal MouseInputPoller() instance that fetches controller information via the XInputGetState() function and associated lib.
/// It also has public functions for getting and setting the sensitivity as well as setting which thumbstick to use.
/// </summary>
class MouseMapper
{
using InternalType = int;
using LambdaRunnerType = sds::CPPRunnerGeneric<InternalType>;
using lock = LambdaRunnerType::ScopedLockType;
std::atomic<StickMap> m_stickmap_info{ StickMap::NEITHER_STICK };
std::atomic<SHORT> m_thread_x{ 0 };
std::atomic<SHORT> m_thread_y{0};
std::atomic<int> m_mouse_sensitivity{ MouseSettings::SENSITIVITY_DEFAULT };
sds::MousePlayerInfo m_local_player{};
sds::MouseInputPoller m_poller{};
std::unique_ptr<LambdaRunnerType> m_workThread{};
void InitWorkThread() noexcept
{
m_workThread =
std::make_unique<LambdaRunnerType>
([this](const sds::LambdaArgs::LambdaArg1& stopCondition, sds::LambdaArgs::LambdaArg2& mut, int& protectedData) { workThread(stopCondition, mut, protectedData); });
}
public:
/// <summary>Ctor for default configuration</summary>
MouseMapper() noexcept
{
InitWorkThread();
}
/// <summary>Ctor allows setting a custom MousePlayerInfo</summary>
explicit MouseMapper(const sds::MousePlayerInfo& player) noexcept : m_local_player(player) { InitWorkThread(); }
MouseMapper(const MouseMapper& other) = delete;
MouseMapper(MouseMapper&& other) = delete;
MouseMapper& operator=(const MouseMapper& other) = delete;
MouseMapper& operator=(MouseMapper&& other) = delete;
~MouseMapper() = default;
/// <summary>Use this function to establish one stick or the other as the one controlling the mouse movements.
/// Set to NEITHER_STICK for no thumbstick mouse movement. Options are RIGHT_STICK, LEFT_STICK, NEITHER_STICK
/// This will start processing if the stick is something other than "NEITHER"
/// **Arbitrary values outside of the enum constants will not be processed successfully.**</summary>
/// <param name="info"> a StickMap enum</param>
void SetStick(const StickMap info) noexcept
{
if (m_stickmap_info != info)
{
this->Stop();
m_stickmap_info = info;
if (info != StickMap::NEITHER_STICK)
{
m_poller.Start();
m_workThread->StartThread();
}
else
{
m_poller.Stop();
m_workThread->StopThread();
}
}
}
StickMap GetStick() const
{
return m_stickmap_info;
}
/// <summary>Setter for sensitivity value.</summary>
/// <returns> returns a std::string containing an error message
/// if there is an error, empty string otherwise. </returns>
std::string SetSensitivity(const int new_sens) noexcept
{
if (!MouseSettings::IsValidSensitivityValue(new_sens))
{
return "Error in sds::XinMouseMapper::SetSensitivity(), int new_sens out of range.";
}
Stop();
m_mouse_sensitivity = new_sens;
Start();
return "";
}
/// <summary>Getter for sensitivity value</summary>
[[nodiscard]] int GetSensitivity() const noexcept
{
return m_mouse_sensitivity;
}
[[nodiscard]] bool IsControllerConnected() const noexcept
{
return m_poller.IsControllerConnected();
}
[[nodiscard]] bool IsRunning() const noexcept
{
bool workRunning = false;
if (m_workThread != nullptr)
workRunning = m_workThread->IsRunning();
return m_poller.IsRunning() && workRunning;
}
void Start() const noexcept
{
m_poller.Start();
if(m_workThread != nullptr)
m_workThread->StartThread();
}
void Stop() const noexcept
{
m_poller.Stop();
if(m_workThread != nullptr)
m_workThread->StopThread();
}
protected:
/// <summary>Worker thread, protected visibility, gets updated data from ProcessState() function to use.
/// Accesses the std::atomic m_thread_x and m_thread_y members. chrono lib instances may throw exceptions.</summary>
void workThread(const sds::LambdaArgs::LambdaArg1& stopCondition, sds::LambdaArgs::LambdaArg2&, int&)
{
ThumbstickToDelay xThread(this->GetSensitivity(), m_local_player, m_stickmap_info, true);
ThumbstickToDelay yThread(this->GetSensitivity(), m_local_player, m_stickmap_info, false);
MouseMoveThread mover;
//thread main loop
while (!stopCondition)
{
ProcessState(m_poller.GetUpdatedState());
//store the returned delay from axisthread for each axis
//then pass the delays on to MouseMoveThread, along with some information like
//is X or Y negative, and if the axis is moving
const SHORT tx = m_thread_x;
const SHORT ty = m_thread_y;
const size_t xDelay = xThread.GetDelayFromThumbstickValue(tx, ty);
const size_t yDelay = yThread.GetDelayFromThumbstickValue(tx, ty);
const bool ixp = tx > 0;
const bool iyp = ty > 0;
mover.UpdateState(xDelay, yDelay, ixp, iyp, xThread.DoesAxisRequireMoveAlt(tx, ty), yThread.DoesAxisRequireMoveAlt(tx, ty));
std::this_thread::sleep_for(std::chrono::milliseconds(MouseSettings::THREAD_DELAY_POLLER));
}
}
private:
/// <summary>Updates local atomic values with XINPUT_STATE info from the MouseInputPoller</summary>
void ProcessState(const XINPUT_STATE& state) noexcept
{
if (m_stickmap_info == StickMap::NEITHER_STICK)
return;
if (m_stickmap_info == StickMap::RIGHT_STICK)
{
//Give worker thread new values.
m_thread_x = state.Gamepad.sThumbRX;
m_thread_y = state.Gamepad.sThumbRY;
}
else if(m_stickmap_info == StickMap::LEFT_STICK)
{
m_thread_x = state.Gamepad.sThumbLX;
m_thread_y = state.Gamepad.sThumbLY;
}
}
};
}