/
inputsystem.h
244 lines (202 loc) · 6.79 KB
/
inputsystem.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
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
/** @file inputsystem.h Input subsystem.
*
* @authors Copyright © 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2014 Daniel Swanson <danij@dengine.net>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/
#ifndef CLIENT_INPUTSYSTEM_H
#define CLIENT_INPUTSYSTEM_H
#include <functional>
#include <de/types.h>
#include <de/Action>
#include <de/Error>
#include <de/System>
#include "dd_input.h" // ddevent_t
#include "SettingsRegister"
class BindContext;
class InputDevice;
struct cbinding_t;
struct dbinding_t;
#define DEFAULT_BINDING_CONTEXT_NAME "game"
#define CONSOLE_BINDING_CONTEXT_NAME "console"
#define UI_BINDING_CONTEXT_NAME "deui"
#define GLOBAL_BINDING_CONTEXT_NAME "global"
/**
* Input devices and events. @ingroup ui
*
* @todo Input drivers belong in this system.
*/
class InputSystem : public de::System
{
public:
InputSystem();
SettingsRegister &settings();
// System.
void timeChanged(de::Clock const &);
/**
* Lookup an InputDevice by it's unique @a id.
*/
InputDevice &device(int id) const;
/**
* Lookup an InputDevice by it's unique @a id.
*
* @return Pointer to the associated InputDevice; otherwise @c nullptr.
*/
InputDevice *devicePtr(int id) const;
/**
* Iterate through all the InputDevices.
*/
de::LoopResult forAllDevices(std::function<de::LoopResult (InputDevice &)> func) const;
/**
* (Re)initialize the input device models, returning all controls to their
* default states.
*/
void initAllDevices();
/**
* Returns @c true if the shift key of the keyboard is thought to be down.
* @todo: Refactor away
*/
bool shiftDown() const;
public: // Event processing --------------------------------------------------
/**
* Clear the input event queue.
*/
void clearEvents();
bool ignoreEvents(bool yes = true);
/**
* @param ev A copy is made.
*/
void postEvent(ddevent_t *ev);
/**
* Process all incoming input for the given timestamp.
* This is called only in the main thread, and also from the busy loop.
*
* This gets called at least 35 times per second. Usually more frequently
* than that.
*/
void processEvents(timespan_t ticLength);
void processSharpEvents(timespan_t ticLength);
/**
* Update the input devices.
*/
void trackEvent(ddevent_t *ev);
public:
static bool convertEvent(ddevent_t const *ddEvent, event_t *ev);
/**
* Converts a libcore Event into an old-fashioned ddevent_t.
*
* @param event Event instance.
* @param ddEvent ddevent_t instance.
*/
static void convertEvent(de::Event const &event, ddevent_t *ddEvent);
public: // Binding (context) management --------------------------------------
/**
* Try to make a new command binding.
*
* @param eventDesc Textual descriptor for the event.
* @param command Console command(s) which the binding will execute when
* triggered, if a binding is created.
*
* @return Resultant command binding.
*/
cbinding_t *bindCommand(char const *eventDesc, char const *command);
bool unbindCommand(char const *command);
/**
* Try to make a new (player) control binding.
*
* @param controlDesc ?
* @param deviceDesc ?
*/
dbinding_t *bindControl(char const *controlDesc, char const *deviceDesc);
/**
* Try to remove the one unique binding associated with @a id.
*
* @return @c true if that binding was removed.
*/
bool removeBinding(int id);
// ---
/// Required/referenced binding context is missing. @ingroup errors
DENG2_ERROR(MissingContextError);
/**
* Enable the contexts for the initial state.
*/
void initialContextActivations();
/**
* Destroy all binding contexts and the bindings within the contexts.
*/
void clearAllContexts();
/**
* Returns the total number of binding contexts in the system.
*/
int contextCount() const;
/**
* Returns @c true if the symbolic @a name references a known context.
*/
bool hasContext(de::String const &name) const;
/**
* Lookup a binding context by symbolic @a name.
*/
BindContext &context(de::String const &name) const;
BindContext *contextPtr(de::String const &name) const;
/**
* Lookup a binding context by stack @a position.
*/
BindContext &contextAt(int position) const;
/**
* Returns the stack position of the specified binding @a context.
*/
int contextPositionOf(BindContext *context) const;
/**
* Creates a new binding context. The new context has the highest priority
* of all existing contexts, and is inactive.
*/
BindContext *newContext(de::String const &name);
/**
* Finds the action bound to a given event, iterating through all enabled
* binding contexts.
*
* @param event Event to match against.
*
* @return Action instance (caller gets ownership), or @c nullptr if not found.
*/
de::Action *actionForEvent(ddevent_t const &event) const;
/**
* Iterate through all the BindContexts from highest to lowest priority.
*/
de::LoopResult forAllContexts(std::function<de::LoopResult (BindContext &)> func) const;
/**
* Marks all device states with the highest-priority binding context to which they have
* a connection via device bindings. This ensures that if a high-priority context is
* using a particular device state, lower-priority contexts will not be using the same
* state for their own controls.
*
* Called automatically whenever a context is activated or deactivated.
*
* @todo make private.
*/
void updateAllDeviceStateAssociations();
/**
* Write all bindings in all contexts to a text (cfg) file. Outputs console commands.
*/
void writeAllBindingsTo(FILE *file);
public:
/**
* Register the console commands and variables of this module.
*/
static void consoleRegister();
private:
DENG2_PRIVATE(d)
};
#endif // CLIENT_INPUTSYSTEM_H