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