-
Notifications
You must be signed in to change notification settings - Fork 1
/
pad_manager.h
207 lines (161 loc) · 5.22 KB
/
pad_manager.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
/*
* author : Shuichi TAKANO
* since : Sun Jan 14 2024 03:15:01
*/
#pragma once
#include <cstdint>
#include <cstdlib>
#include <vector>
#include <optional>
#include <array>
#include "pad_translator.h"
#include "pad_state.h"
#include "rot_encoder.h"
#include "serializer.h"
#include <functional>
inline static constexpr size_t N_PAD_STATE_BUTTONS = static_cast<size_t>(PadStateButton::MAX);
class PadManager
{
public:
static constexpr int N_ANALOGS = 9;
static constexpr int N_BUTTONS = 128;
static constexpr int N_PORTS = 3;
static constexpr int N_OUTPUT_PORTS = 2;
enum class StateKind
{
PORT0,
PORT1,
MIDI,
};
static constexpr int VID_MIDI = 0;
static constexpr int PID_MIDI = 1;
struct PadInput
{
int vid;
int pid;
std::array<uint32_t, N_BUTTONS / 32> buttons;
int hat;
std::array<int, N_ANALOGS> analogs;
bool getButton(int i) const { return (buttons[i >> 5] & (1u << (i & 31))); }
PadInput() { reset(); }
void reset()
{
buttons = {};
hat = -1;
analogs = {128, 128, 128, 0, 0, 128, 0, 0, 0};
}
};
using PrintButtonFunc = std::function<void(PadStateButton)>;
using onExitConfigFunc = std::function<void()>;
using onSaveFunc = std::function<void()>;
public:
PadManager();
void reset();
void update(int dclk, bool cnfButton, bool cnfButtonTrigger, bool cnfButtonLong);
void setData(int port, const PadInput &input);
static PadManager &instance()
{
static PadManager inst;
return inst;
}
void resetLatestPadData(int port)
{
latestPadData_[port].reset();
}
uint32_t getButtons(int port) const;
uint32_t getNonRapidButtons(int port) const;
std::array<uint32_t, 2> getNonRapidButtonsEachRapidPhase(int port) const;
uint32_t getRapidFireMask(int port) const;
uint32_t getNonMappedRapidFireMask(int port) const;
void setNonMappedRapidFireMask(int port, uint32_t v);
int getRapidFireDiv(int port) const;
void setRapidFireDiv(int port, int v);
void setRapidFirePhaseMask(uint32_t v);
const PadState::AnalogState &getAnalogState(int port) const;
void setVSyncCount(int count);
void serialize(Serializer &s) const;
void deserialize(Deserializer &s);
void enterNormalMode();
void enterConfigMode();
void setNormalModeLED(bool f) { normalModeLED_ = f; }
bool isConfigMode() const { return mode_ == Mode::CONFIG; }
void setEnableModelChangeByButton(bool f) { enableModeChangeByButton_ = f; }
void setEnableLED(bool f) { enableLED_ = f; }
void setPrintButtonFunc(PrintButtonFunc f) { printButtonFunc_ = f; }
void setOnExitConfigFunc(onExitConfigFunc f) { onExitConfigFunc_ = f; }
void setOnSaveFunc(onSaveFunc f) { onSaveFunc_ = f; }
void resetConfig() { translator_.reset(); }
void setRotEncSetting(int kind, int axis, int scale);
protected:
uint32_t _getButtons(int port) const;
void updateNormalMode(int dclk, bool cnfButton, bool cnfButtonTrigger, bool cnfButtonLong);
void updateConfigMode(int dclk, bool cnfButton, bool cnfButtonTrigger, bool cnfButtonLong);
void setDataNormalMode(int port, const PadInput &input);
void setDataConfigMode(int port, const PadInput &input);
void nextButtonConfig();
void saveConfigAndExit();
void blinkLED(bool reverse, int n);
void setLED(bool on) const;
private:
enum class Mode
{
NORMAL,
CONFIG,
};
std::array<PadInput, N_PORTS> latestPadData_;
std::array<PadState, N_PORTS> padStates_;
RotEncoder rotEncoders_[N_OUTPUT_PORTS][2];
struct ButtonSet
{
// ボタンは N_BUTTONS個まで
std::array<uint32_t, N_BUTTONS / 32> buttons;
// アナログのアサインは1つ
int8_t analogIndex;
PadConfig::AnalogPos analogOn;
PadConfig::AnalogPos analogOff;
// Hat のアサインは1つ
int hat = -1;
public:
ButtonSet() { clear(); }
bool getButton(int i) const { return (buttons[i >> 5] & (1u << (i & 31))); }
bool hasData() const
{
for (auto b : buttons)
{
if (b)
{
return true;
}
}
return analogIndex >= 0 || hat >= 0;
}
void clear()
{
buttons = {};
analogIndex = -1;
hat = -1;
}
};
struct ConfigMode
{
bool waitFirstIdle_ = true; // 最初にボタン入力がない瞬間を待ち中
int port_ = -1;
std::array<int, N_ANALOGS> analogNeutral_[N_PORTS]{};
int vid_ = 0;
int pid_ = 0;
PadStateButton curButton_{}; // 現在設定中のボタン
ButtonSet curButtonSet_;
bool anyButtonOn_ = false;
uint32_t idleCycle_ = 0;
std::vector<ButtonSet> buttonSets_;
};
Mode mode_{};
ConfigMode configMode_;
bool enableModeChangeByButton_ = true;
bool enableLED_ = true;
bool normalModeLED_ = true;
PadTranslator translator_;
PrintButtonFunc printButtonFunc_;
onExitConfigFunc onExitConfigFunc_;
onSaveFunc onSaveFunc_;
};