Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/Common/Input/InputState.h
5654 views
1
#pragma once
2
3
// For more detailed and configurable input, implement NativeTouch, NativeKey and NativeAxis and do your
4
// own mapping. Might later move the mapping system from PPSSPP to native.
5
6
#include <unordered_map>
7
#include <vector>
8
#include <string>
9
10
#include "Common/Common.h"
11
#include "Common/Input/KeyCodes.h"
12
#include "Common/Log.h"
13
14
// Default device IDs
15
16
enum InputDeviceID {
17
DEVICE_ID_ANY = -1, // Represents any device ID
18
DEVICE_ID_DEFAULT = 0, // Old Android
19
DEVICE_ID_KEYBOARD = 1, // PC keyboard, android keyboards
20
DEVICE_ID_MOUSE = 2, // PC mouse only (not touchscreen!)
21
DEVICE_ID_PAD_0 = 10, // Generic joypads
22
DEVICE_ID_PAD_1 = 11, // these should stay as contiguous numbers
23
DEVICE_ID_PAD_2 = 12,
24
DEVICE_ID_PAD_3 = 13,
25
DEVICE_ID_PAD_4 = 14,
26
DEVICE_ID_PAD_5 = 15,
27
DEVICE_ID_PAD_6 = 16,
28
DEVICE_ID_PAD_7 = 17,
29
DEVICE_ID_PAD_8 = 18,
30
DEVICE_ID_PAD_9 = 19,
31
DEVICE_ID_XINPUT_0 = 20, // XInput joypads
32
DEVICE_ID_XINPUT_1 = 21,
33
DEVICE_ID_XINPUT_2 = 22,
34
DEVICE_ID_XINPUT_3 = 23,
35
DEVICE_ID_ACCELEROMETER = 30, // no longer used
36
DEVICE_ID_XR_CONTROLLER_LEFT = 40,
37
DEVICE_ID_XR_CONTROLLER_RIGHT = 41,
38
DEVICE_ID_TOUCH = 42,
39
DEVICE_ID_COUNT,
40
};
41
42
inline InputDeviceID operator +(InputDeviceID deviceID, int addend) {
43
return (InputDeviceID)((int)deviceID + addend);
44
}
45
46
//number of contiguous generic joypad IDs
47
const int MAX_NUM_PADS = 10;
48
49
const char *GetDeviceName(int deviceId);
50
51
#ifndef MAX_KEYQUEUESIZE
52
#define MAX_KEYQUEUESIZE 20
53
#endif
54
55
// Represents a single bindable key
56
static const int AXIS_BIND_NKCODE_START = 4000;
57
58
inline int TranslateKeyCodeToAxis(int keyCode, int *direction) {
59
if (keyCode < AXIS_BIND_NKCODE_START)
60
return 0;
61
int k = keyCode - AXIS_BIND_NKCODE_START;
62
// Even/odd for direction.
63
if (direction)
64
*direction = k & 1 ? -1 : 1;
65
return k / 2;
66
}
67
68
class InputMapping {
69
private:
70
static inline int TranslateKeyCodeFromAxis(int axisId, int direction) {
71
return AXIS_BIND_NKCODE_START + axisId * 2 + (direction < 0 ? 1 : 0);
72
}
73
public:
74
InputMapping() : deviceId(DEVICE_ID_DEFAULT), keyCode(0) {}
75
// From a key mapping
76
InputMapping(InputDeviceID _deviceId, int key) : deviceId(_deviceId), keyCode(key) {}
77
// From an axis
78
InputMapping(InputDeviceID _deviceId, int axis, int direction) : deviceId(_deviceId), keyCode(TranslateKeyCodeFromAxis(axis, direction)) {
79
_dbg_assert_(direction != 0);
80
}
81
82
static InputMapping FromConfigString(std::string_view str);
83
std::string ToConfigString() const;
84
85
InputDeviceID deviceId;
86
int keyCode; // Can also represent an axis with direction, if encoded properly.
87
88
bool IsAxis() const {
89
return keyCode >= AXIS_BIND_NKCODE_START;
90
}
91
92
int Axis(int *direction) const {
93
_dbg_assert_(IsAxis());
94
return TranslateKeyCodeToAxis(keyCode, direction);
95
}
96
97
InputMapping FlipDirection() const {
98
_dbg_assert_(IsAxis());
99
InputMapping other = *this;
100
other.keyCode ^= 1;
101
return other;
102
}
103
104
// If you want to use std::find and match ANY, you need to perform an explicit search for that.
105
bool operator < (const InputMapping &other) const {
106
if (deviceId < other.deviceId) return true;
107
if (deviceId > other.deviceId) return false;
108
if (keyCode < other.keyCode) return true;
109
return false;
110
}
111
// Needed for composition.
112
bool operator > (const InputMapping &other) const {
113
if (deviceId > other.deviceId) return true;
114
if (deviceId < other.deviceId) return false;
115
if (keyCode > other.keyCode) return true;
116
return false;
117
}
118
119
// This one is iffy with the != ANY checks. Should probably be a named method.
120
bool operator == (const InputMapping &other) const {
121
if (deviceId != other.deviceId && deviceId != DEVICE_ID_ANY && other.deviceId != DEVICE_ID_ANY) return false;
122
if (keyCode != other.keyCode) return false;
123
return true;
124
}
125
bool operator != (const InputMapping &other) const {
126
return !(*this == other);
127
}
128
129
void FormatDebug(char *buffer, size_t bufSize) const;
130
};
131
132
// Be careful about changing these values as some are set on the Android java side!
133
enum class TouchInputFlags {
134
MOVE = 1 << 0,
135
DOWN = 1 << 1,
136
UP = 1 << 2,
137
CANCEL = 1 << 3, // Sent by scrollviews to their children when they detect a scroll
138
WHEEL = 1 << 4, // Scrollwheel event. Usually only affects Y but can potentially affect X.
139
MOUSE = 1 << 5, // Identifies that this touch event came from a mouse. Id is now set to the mouse button for DOWN/UP commands.
140
RELEASE_ALL = 1 << 6, // Useful for app focus switches when events may be lost.
141
HOVER = 1 << 7,
142
143
// These are the Android getToolType() codes, shifted by 10. Unused currently.
144
// TOOL_MASK = 7 << 10,
145
// TOOL_UNKNOWN = 0 << 10,
146
// TOOL_FINGER = 1 << 10,
147
// TOOL_STYLUS = 2 << 10,
148
// TOOL_MOUSE = 3 << 10,
149
// TOOL_ERASER = 4 << 10,
150
};
151
ENUM_CLASS_BITOPS(TouchInputFlags);
152
153
constexpr int TOUCH_MAX_POINTERS = 10;
154
155
// Used for asynchronous touch input.
156
// DOWN is always on its own.
157
// MOVE and UP can be combined.
158
// TODO: As this handles both mouse and touch, should probably rename to PointerInput or something.
159
struct TouchInput {
160
float x;
161
float y;
162
int id; // Needs to be <= GestureDetector::MAX_PTRS (10.)
163
int buttons; // bit mask
164
TouchInputFlags flags;
165
double timestamp;
166
};
167
168
enum class KeyInputFlags {
169
DOWN = 1 << 0,
170
UP = 1 << 1,
171
HAS_WHEEL_DELTA = 1 << 2,
172
IS_REPEAT = 1 << 3,
173
CHAR = 1 << 4, // Unicode character input. Cannot detect keyups of these so KeyInputFlags::DOWN and KeyInputFlags::UP are zero when this is set.
174
};
175
ENUM_CLASS_BITOPS(KeyInputFlags);
176
177
struct KeyInput {
178
KeyInput() {}
179
KeyInput(InputDeviceID devId, InputKeyCode code, KeyInputFlags fl) : deviceId(devId), keyCode(code), flags(fl) {}
180
KeyInput(InputDeviceID devId, int unicode) : deviceId(devId), unicodeChar(unicode), flags(KeyInputFlags::CHAR) {}
181
InputDeviceID deviceId;
182
union {
183
InputKeyCode keyCode; // Android keycodes are the canonical keycodes, everyone else map to them.
184
int unicodeChar; // for KeyInputFlags::CHAR
185
};
186
KeyInputFlags flags;
187
188
// Used by mousewheel events. The delta is packed in the upper 16 bits of flags.
189
// TODO: Move mousewheel events to TouchInput?
190
int Delta() const {
191
return (s32)flags >> 16;
192
}
193
};
194
195
struct AxisInput {
196
InputDeviceID deviceId;
197
InputAxis axisId;
198
float value;
199
};
200
201
// Is there a nicer place for this stuff? It's here to avoid dozens of linking errors in UnitTest..
202
extern std::vector<InputMapping> dpadKeys;
203
extern std::vector<InputMapping> confirmKeys;
204
extern std::vector<InputMapping> cancelKeys;
205
extern std::vector<InputMapping> infoKeys;
206
extern std::vector<InputMapping> tabLeftKeys;
207
extern std::vector<InputMapping> tabRightKeys;
208
void SetDPadKeys(const std::vector<InputMapping> &leftKey, const std::vector<InputMapping> &rightKey,
209
const std::vector<InputMapping> &upKey, const std::vector<InputMapping> &downKey);
210
void SetConfirmCancelKeys(const std::vector<InputMapping> &confirm, const std::vector<InputMapping> &cancel);
211
void SetTabLeftRightKeys(const std::vector<InputMapping> &tabLeft, const std::vector<InputMapping> &tabRight);
212
void SetInfoKeys(const std::vector<InputMapping> &info);
213
214
// 0 means unknown (attempt autodetect), -1 means flip, 1 means original direction.
215
void SetAnalogFlipY(const std::unordered_map<InputDeviceID, int> &flipYByDeviceId);
216
int GetAnalogYDirection(InputDeviceID deviceId);
217
218
// Gross hack unfortunately.
219
extern bool g_IsMappingMouseInput;
220
221