Pioneer
Input.h
Go to the documentation of this file.
1 // Copyright © 2008-2023 Pioneer Developers. See AUTHORS.txt for details
2 // Licensed under the terms of the GPL v3. See licenses/GPL-3.txt
3 
4 #ifndef INPUT_H
5 #define INPUT_H
6 
7 #include "InputBindings.h"
8 #include "SDL_joystick.h"
9 #include "utils.h"
10 
11 #include <algorithm>
12 #include <array>
13 
14 class IniConfig;
15 
16 // Macro to simplify registering input bindings in the codebase
17 // TODO: evaluate if registering key bindings via lua / json file works better
18 #define REGISTER_INPUT_BINDING(name) \
19  namespace name##Input \
20  { \
21  void Register(Input::Manager *input); \
22  bool name##Registered = Input::AddBindingRegistrar(&Register); \
23  } \
24  void name##Input::Register(Input::Manager *input)
25 
26 namespace Input {
27  class Manager;
28 
29  // The Page->Group->Binding system serves as a thin veneer for the UI to make
30  // sane reasonings about how to structure the Options dialog.
31  struct BindingGroup {
32  enum EntryType : uint8_t {
35  };
36 
37  std::map<std::string, EntryType> bindings;
38  };
39 
40  struct BindingPage {
41  BindingGroup *GetBindingGroup(std::string id) { return &groups[id]; }
42 
43  std::map<std::string, BindingGroup> groups;
44  };
45 
46  struct InputFrame {
49 
50  InputFrame(Input::Manager *man, bool modal = false) :
51  manager(man),
52  modal(modal)
53  {}
54 
55  std::vector<Action *> actions;
56  std::vector<Axis *> axes;
57 
58  // Must set this to a valid Input::Manager instance before using AddAction / AddAxis
59  Manager *manager = nullptr;
60  bool active = false;
61  bool modal = false;
62 
63  // Call this at startup to register all the bindings associated with the frame.
64  virtual void RegisterBindings(){};
65 
66  // Called when the frame is added to the stack.
67  sigc::signal<void, InputFrame *> onFrameAdded;
68 
69  // Called when the frame is removed from the stack.
70  sigc::signal<void, InputFrame *> onFrameRemoved;
71 
72  Action *AddAction(std::string id);
73  Axis *AddAxis(std::string id);
74  };
75 
76  struct JoystickInfo {
77  struct Axis {
78  float value = 0.0;
79  float deadzone = 0.1;
80  float curve = 1.0;
81  bool zeroToOne = false;
82  };
83 
84  SDL_Joystick *joystick;
85  SDL_JoystickGUID guid;
86  std::string name;
87 
88  std::vector<bool> buttons;
89  std::vector<int> hats;
90 
91  std::vector<Axis> axes;
92  };
93 
94  void InitJoysticks(IniConfig *config);
95  std::vector<JoystickInfo> &GetJoysticks();
96 
97  // User display name for the joystick from the API/OS.
98  std::string JoystickName(int joystick);
99  // fetch the GUID for the named joystick
100  SDL_JoystickGUID JoystickGUID(int joystick);
101  std::string JoystickGUIDString(int joystick);
102  // update the joystick's saved configuration
103  void SaveJoystickConfig(uint32_t joystick, IniConfig *config);
104 
105  // reverse map a JoystickGUID to the actual internal ID.
106  int JoystickFromGUIDString(const std::string &guid);
107  int JoystickFromGUIDString(const char *guid);
108  int JoystickFromGUID(SDL_JoystickGUID guid);
109 
110  int JoystickFromID(SDL_JoystickID id);
111  // map SDL joystick instance ID to internal ID
112  void AddJoystickID(SDL_JoystickID sdl_id, uint32_t internal_id);
113 
114  // An adapter to decouple input frame creation from input binding registration.
115  // The functions registered via AddBindingRegistrar should be thread-safe and
116  // should not depend on anything but the manager object being passed in.
117  // The registrars are guaranteed to be called after static initialization has finished.
118  std::vector<sigc::slot<void, Input::Manager *>> &GetBindingRegistration();
119  bool AddBindingRegistrar(sigc::slot<void, Input::Manager *> &&fn);
120 } // namespace Input
121 
123 public:
124  Manager(IniConfig *config, SDL_Window *window);
125  void InitGame();
126 
127  // Call this at the start of a frame, before passing SDL events in
128  void NewFrame();
129 
130  // Call once per SDL event, handles updating all internal state
131  void HandleSDLEvent(SDL_Event &ev);
132 
133  // Call immediately after processing events, dispatches events to Action / Axis bindings.
134  void DispatchEvents();
135 
136  // When enable is false, this prevents the input system from writing to the config file.
137  void EnableConfigSaving(bool enable) { m_enableConfigSaving = enable; }
138 
139  BindingPage *GetBindingPage(std::string id) { return &bindingPages[id]; }
140  std::map<std::string, BindingPage> GetBindingPages() { return bindingPages; }
141 
142  // Pushes an InputFrame onto the input stack.
143  bool AddInputFrame(InputFrame *frame);
144 
145  // Get a read-only list of input frames.
146  const std::vector<InputFrame *> &GetInputFrames() { return m_inputFrames; }
147 
148  // Check if a specific input frame is currently on the stack.
150  {
151  return std::count(m_inputFrames.begin(), m_inputFrames.end(), frame) > 0;
152  }
153 
154  // Remove an arbitrary input frame from the input stack.
155  void RemoveInputFrame(InputFrame *frame);
156 
157  // Inform the input system that a binding or frame was changed this frame.
158  void MarkBindingsDirty() { m_frameListChanged = true; }
159 
160  // Creates a new action binding, copying the provided binding.
161  // The returned binding pointer points to the actual binding.
162  InputBindings::Action *AddActionBinding(std::string id, BindingGroup *group, InputBindings::Action &&binding);
163  InputBindings::Action *GetActionBinding(std::string id);
164 
165  // Creates a new axis binding, copying the provided binding.
166  // The returned binding pointer points to the actual binding.
167  InputBindings::Axis *AddAxisBinding(std::string id, BindingGroup *group, InputBindings::Axis &&binding);
168  InputBindings::Axis *GetAxisBinding(std::string id);
169 
170  // Call EnableBindings() to temporarily disable handling input bindings while
171  // you're recording a new input binding or are in a modal window.
172  void EnableBindings(bool enabled) { m_enableBindings = enabled; }
173 
174  bool KeyState(SDL_Keycode k) { return IsKeyDown(k); }
175 
176  // returns true if key K is currently pressed
177  bool IsKeyDown(SDL_Keycode k) { return keyState[k] & 0x3; }
178 
179  // returns true if key K was pressed this frame
180  bool IsKeyPressed(SDL_Keycode k) { return keyState[k] == 1; }
181 
182  // returns true if key K was released this frame
183  bool IsKeyReleased(SDL_Keycode k) { return keyState[k] == 4; }
184 
185  int KeyModState() { return keyModState; }
186 
187  int JoystickButtonState(int joystick, int button);
188  int JoystickHatState(int joystick, int hat);
189  float JoystickAxisState(int joystick, int axis);
190 
191  bool IsJoystickEnabled() { return joystickEnabled; }
192  void SetJoystickEnabled(bool state);
193 
194  bool IsMouseYInvert() { return mouseYInvert; }
195  void SetMouseYInvert(bool state);
196 
197  bool IsMouseButtonPressed(int button) { return mouseButton[button] == 1; }
198  bool IsMouseButtonReleased(int button) { return mouseButton[button] == 4; }
199 
200  bool MouseButtonState(int button) { return mouseButton[button] & 3; }
201  void SetMouseButtonState(int button, bool state) { mouseButton[button] = state; }
202 
203  void GetMousePosition(int position[2]);
204 
205  void GetMouseMotion(int motion[2])
206  {
207  std::copy_n(mouseMotion.data(), mouseMotion.size(), motion);
208  }
209 
210  int GetMouseWheel() { return mouseWheel; }
211 
212  // Capturing the mouse hides the cursor, puts the mouse into relative mode,
213  // and passes all mouse inputs to the input system, regardless of whether
214  // ImGui is using them or not.
215  bool IsCapturingMouse() const { return m_capturingMouse; }
216 
217  // Set whether the application would like to capture the mouse.
218  // To avoid contention between different classes, please only call this when the state
219  // has actually changed.
220  void SetCapturingMouse(bool enabled);
221  void ClearMouse();
222 
223  sigc::signal<void, SDL_Keysym *> onKeyPress;
224  sigc::signal<void, SDL_Keysym *> onKeyRelease;
225  sigc::signal<void, int, int, int> onMouseButtonUp;
226  sigc::signal<void, int, int, int> onMouseButtonDown;
227  sigc::signal<void, bool> onMouseWheel;
228 
229 private:
230  void RebuildInputFrames();
231  bool GetModifierState(InputBindings::KeyChord *key);
232  bool GetBindingState(InputBindings::KeyBinding &key);
233  float GetAxisState(InputBindings::JoyAxis &axis);
234 
235  SDL_Window *m_window;
236  IniConfig *m_config;
237  bool m_enableConfigSaving;
238 
239  std::map<SDL_Keycode, uint8_t> keyState;
240  int keyModState;
241  std::array<char, 6> mouseButton;
242  std::array<int, 2> mouseMotion;
243  int mouseWheel;
244  bool m_capturingMouse;
245 
246  bool joystickEnabled;
247  bool mouseYInvert;
248 
249  std::map<std::string, BindingPage> bindingPages;
250  std::map<std::string, InputBindings::Action> actionBindings;
251  std::map<std::string, InputBindings::Axis> axisBindings;
252  bool m_enableBindings;
253 
254  std::vector<InputFrame *> m_inputFrames;
255  bool m_frameListChanged;
256 
257  std::vector<InputBindings::Action *> m_activeActions;
258  std::vector<InputBindings::Axis *> m_activeAxes;
259 
260  std::map<InputBindings::KeyBinding, bool> m_modifiers;
261  std::vector<InputBindings::KeyChord *> m_chords;
262 };
263 
264 #endif
Definition: IniConfig.h:16
Definition: Input.h:122
InputBindings::Action * AddActionBinding(std::string id, BindingGroup *group, InputBindings::Action &&binding)
Definition: Input.cpp:362
void DispatchEvents()
Definition: Input.cpp:776
bool KeyState(SDL_Keycode k)
Definition: Input.h:174
Manager(IniConfig *config, SDL_Window *window)
Definition: Input.cpp:242
sigc::signal< void, int, int, int > onMouseButtonUp
Definition: Input.h:225
bool AddInputFrame(InputFrame *frame)
Definition: Input.cpp:304
void ClearMouse()
Definition: Input.cpp:841
void GetMousePosition(int position[2])
Definition: Input.cpp:503
bool IsMouseButtonReleased(int button)
Definition: Input.h:198
bool IsKeyPressed(SDL_Keycode k)
Definition: Input.h:180
void SetCapturingMouse(bool enabled)
Definition: Input.cpp:830
bool IsMouseYInvert()
Definition: Input.h:194
int KeyModState()
Definition: Input.h:185
BindingPage * GetBindingPage(std::string id)
Definition: Input.h:139
bool IsMouseButtonPressed(int button)
Definition: Input.h:197
float JoystickAxisState(int joystick, int axis)
Definition: Input.cpp:473
sigc::signal< void, bool > onMouseWheel
Definition: Input.h:227
void MarkBindingsDirty()
Definition: Input.h:158
void NewFrame()
Definition: Input.cpp:514
void SetJoystickEnabled(bool state)
Definition: Input.cpp:485
bool IsKeyDown(SDL_Keycode k)
Definition: Input.h:177
bool MouseButtonState(int button)
Definition: Input.h:200
bool HasInputFrame(InputFrame *frame)
Definition: Input.h:149
void SetMouseYInvert(bool state)
Definition: Input.cpp:494
bool IsJoystickEnabled()
Definition: Input.h:191
sigc::signal< void, SDL_Keysym * > onKeyPress
Definition: Input.h:223
void GetMouseMotion(int motion[2])
Definition: Input.h:205
int GetMouseWheel()
Definition: Input.h:210
const std::vector< InputFrame * > & GetInputFrames()
Definition: Input.h:146
InputBindings::Axis * AddAxisBinding(std::string id, BindingGroup *group, InputBindings::Axis &&binding)
Definition: Input.cpp:380
void RemoveInputFrame(InputFrame *frame)
Definition: Input.cpp:349
void EnableBindings(bool enabled)
Definition: Input.h:172
InputBindings::Axis * GetAxisBinding(std::string id)
Definition: Input.cpp:403
bool IsCapturingMouse() const
Definition: Input.h:215
void EnableConfigSaving(bool enable)
Definition: Input.h:137
void HandleSDLEvent(SDL_Event &ev)
Definition: Input.cpp:626
sigc::signal< void, SDL_Keysym * > onKeyRelease
Definition: Input.h:224
bool IsKeyReleased(SDL_Keycode k)
Definition: Input.h:183
int JoystickButtonState(int joystick, int button)
Definition: Input.cpp:449
InputBindings::Action * GetActionBinding(std::string id)
Definition: Input.cpp:398
void InitGame()
Definition: Input.cpp:259
void SetMouseButtonState(int button, bool state)
Definition: Input.h:201
std::map< std::string, BindingPage > GetBindingPages()
Definition: Input.h:140
sigc::signal< void, int, int, int > onMouseButtonDown
Definition: Input.h:226
int JoystickHatState(int joystick, int hat)
Definition: Input.cpp:461
Definition: Input.cpp:21
std::string JoystickName(int joystick)
Definition: Input.cpp:54
SDL_JoystickGUID JoystickGUID(int joystick)
Definition: Input.cpp:101
void InitJoysticks(IniConfig *config)
Definition: Input.cpp:182
int JoystickFromGUIDString(const std::string &guid)
Definition: Input.cpp:69
bool AddBindingRegistrar(sigc::slot< void, Input::Manager * > &&fn)
Definition: Input.cpp:29
int JoystickFromGUID(SDL_JoystickGUID guid)
Definition: Input.cpp:82
std::vector< JoystickInfo > & GetJoysticks()
Definition: Input.cpp:231
int JoystickFromID(SDL_JoystickID id)
Definition: Input.cpp:94
std::vector< sigc::slot< void, Input::Manager * > > & GetBindingRegistration()
Definition: Input.cpp:24
void AddJoystickID(SDL_JoystickID sdl_id, uint32_t internal_id)
Definition: Input.cpp:173
std::string JoystickGUIDString(int joystick)
Definition: Input.cpp:59
void SaveJoystickConfig(uint32_t joystick, IniConfig *config)
Definition: Input.cpp:154
Definition: InputBindings.h:142
Definition: InputBindings.h:166
Definition: InputBindings.h:87
Definition: InputBindings.h:21
Definition: InputBindings.h:107
Definition: Input.h:31
std::map< std::string, EntryType > bindings
Definition: Input.h:37
EntryType
Definition: Input.h:32
@ ENTRY_ACTION
Definition: Input.h:33
@ ENTRY_AXIS
Definition: Input.h:34
Definition: Input.h:40
BindingGroup * GetBindingGroup(std::string id)
Definition: Input.h:41
std::map< std::string, BindingGroup > groups
Definition: Input.h:43
Definition: Input.h:46
virtual void RegisterBindings()
Definition: Input.h:64
InputFrame(Input::Manager *man, bool modal=false)
Definition: Input.h:50
Manager * manager
Definition: Input.h:59
bool active
Definition: Input.h:60
std::vector< Action * > actions
Definition: Input.h:55
Action * AddAction(std::string id)
Definition: Input.cpp:284
sigc::signal< void, InputFrame * > onFrameRemoved
Definition: Input.h:70
Axis * AddAxis(std::string id)
Definition: Input.cpp:294
bool modal
Definition: Input.h:61
std::vector< Axis * > axes
Definition: Input.h:56
sigc::signal< void, InputFrame * > onFrameAdded
Definition: Input.h:64
Definition: Input.h:77
float deadzone
Definition: Input.h:79
bool zeroToOne
Definition: Input.h:81
float value
Definition: Input.h:78
float curve
Definition: Input.h:80
Definition: Input.h:76
SDL_Joystick * joystick
Definition: Input.h:84
std::vector< bool > buttons
Definition: Input.h:88
std::string name
Definition: Input.h:86
std::vector< Axis > axes
Definition: Input.h:91
SDL_JoystickGUID guid
Definition: Input.h:85
std::vector< int > hats
Definition: Input.h:89