1/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
2/* If you are missing that file, acquire a complete release at teeworlds.com. */
3#ifndef ENGINE_INPUT_H
4#define ENGINE_INPUT_H
5
6#include "kernel.h"
7
8#include <base/types.h>
9#include <base/vmath.h>
10
11#include <chrono>
12#include <cstdint>
13#include <functional>
14#include <string>
15#include <vector>
16
17class IInput : public IInterface
18{
19 MACRO_INTERFACE("input")
20public:
21 class CEvent
22 {
23 public:
24 int m_Flags;
25 int m_Key;
26 uint32_t m_InputCount;
27 char m_aText[32]; // SDL_TEXTINPUTEVENT_TEXT_SIZE
28 };
29
30 enum
31 {
32 FLAG_PRESS = 1 << 0,
33 FLAG_RELEASE = 1 << 1,
34 FLAG_TEXT = 1 << 2,
35 /**
36 * Combined with @link FLAG_PRESS @endlink for key press events that
37 * are being repeated when a key is held down.
38 */
39 FLAG_REPEAT = 1 << 3,
40 };
41 enum ECursorType
42 {
43 CURSOR_NONE,
44 CURSOR_MOUSE,
45 CURSOR_JOYSTICK,
46 };
47
48 // events
49 virtual void ConsumeEvents(std::function<void(const CEvent &Event)> Consumer) const = 0;
50 /**
51 * Clears the events and @link KeyPress @endlink state for this frame. Must be called at the end of each frame.
52 */
53 virtual void Clear() = 0;
54
55 /**
56 * @return Rolling average of the time in seconds between
57 * calls of the Update function.
58 */
59 virtual float GetUpdateTime() const = 0;
60
61 // keys
62 virtual bool ModifierIsPressed() const = 0;
63 virtual bool ShiftIsPressed() const = 0;
64 virtual bool AltIsPressed() const = 0;
65 /**
66 * Returns whether the given key is currently pressed down. This directly represents the state of pressed keys
67 * based on all handled input events.
68 *
69 * This function should be used to trigger behavior continuously while a specific key is held down, e.g. for
70 * showing a list of all keys that are currently being pressed.
71 *
72 * @param Key The key code (see `keys.h`).
73 *
74 * @return `true` if key is currently pressed down, `false` otherwise.
75 */
76 virtual bool KeyIsPressed(int Key) const = 0;
77 /**
78 * Returns whether the given key was pressed down during input updates for current frame. This state is
79 * cleared at the end of each frame by calling the @link Clear @endlink function.
80 *
81 * This function should be used to trigger behavior only once per key press event per frame, e.g. for menu
82 * hotkeys that should activate behavior once per key press.
83 *
84 * @param Key The key code (see `keys.h`).
85 *
86 * @return `true` if key was pressed down during input updates for the current frame, `false` otherwise.
87 */
88 virtual bool KeyPress(int Key) const = 0;
89 virtual const char *KeyName(int Key) const = 0;
90 virtual int FindKeyByName(const char *pKeyName) const = 0;
91
92 // joystick
93 class IJoystick
94 {
95 public:
96 virtual ~IJoystick() = default;
97 virtual int GetIndex() const = 0;
98 virtual const char *GetName() const = 0;
99 virtual int GetNumAxes() const = 0;
100 virtual int GetNumButtons() const = 0;
101 virtual int GetNumBalls() const = 0;
102 virtual int GetNumHats() const = 0;
103 virtual float GetAxisValue(int Axis) = 0;
104 virtual void GetHatValue(int Hat, int (&aHatKeys)[2]) = 0;
105 virtual bool Relative(float *pX, float *pY) = 0;
106 virtual bool Absolute(float *pX, float *pY) = 0;
107 };
108 virtual size_t NumJoysticks() const = 0;
109 virtual IJoystick *GetJoystick(size_t Index) = 0;
110 virtual IJoystick *GetActiveJoystick() = 0;
111 virtual void SetActiveJoystick(size_t Index) = 0;
112
113 // mouse
114 virtual vec2 NativeMousePos() const = 0;
115 virtual bool NativeMousePressed(int Index) const = 0;
116 virtual void MouseModeRelative() = 0;
117 virtual void MouseModeAbsolute() = 0;
118 virtual bool MouseRelative(float *pX, float *pY) = 0;
119
120 // touch
121 /**
122 * Represents a unique finger for a current touch event. If there are multiple touch input devices, they
123 * are handled transparently like different fingers. The concrete values of the member variables of this
124 * class are arbitrary based on the touch device driver and should only be used to uniquely identify touch
125 * fingers. Note that once a finger has been released, the same finger value may also be reused again.
126 */
127 class CTouchFinger
128 {
129 friend class CInput;
130
131 int64_t m_DeviceId;
132 int64_t m_FingerId;
133
134 public:
135 bool operator==(const CTouchFinger &Other) const { return m_DeviceId == Other.m_DeviceId && m_FingerId == Other.m_FingerId; }
136 bool operator!=(const CTouchFinger &Other) const { return !(*this == Other); }
137 };
138 /**
139 * Represents the state of a particular touch finger currently being pressed down on a touch device.
140 */
141 class CTouchFingerState
142 {
143 public:
144 /**
145 * The unique finger which this state is associated with.
146 */
147 CTouchFinger m_Finger;
148 /**
149 * The current position of the finger. The x- and y-components of the position are normalized to the
150 * range `0.0f`-`1.0f` representing the absolute position of the finger on the current touch device.
151 */
152 vec2 m_Position;
153 /**
154 * The current delta of the finger. The x- and y-components of the delta are normalized to the
155 * range `-1.0f`-`1.0f` representing the absolute delta of the finger on the current touch device.
156 *
157 * @remark This is reset to zero at the end of each frame.
158 */
159 vec2 m_Delta;
160 /**
161 * The time when this finger was first pressed down.
162 */
163 std::chrono::nanoseconds m_PressTime;
164 };
165 /**
166 * Returns a vector of the states of all touch fingers currently being pressed down on touch devices.
167 * Note that this only contains fingers which are pressed down, i.e. released fingers are never stored.
168 * The order of the fingers in this vector is based on the order in which the fingers where pressed.
169 *
170 * @return vector of all touch finger states
171 */
172 virtual const std::vector<CTouchFingerState> &TouchFingerStates() const = 0;
173 /**
174 * Must be called after the touch finger states have been used during the client update to ensure that
175 * touch deltas are only accumulated until the next update. If the touch states are only used during
176 * rendering, i.e. for user interfaces, then this is called automatically by calling @link Clear @endlink.
177 */
178 virtual void ClearTouchDeltas() = 0;
179
180 // clipboard
181 virtual std::string GetClipboardText() = 0;
182 virtual void SetClipboardText(const char *pText) = 0;
183
184 // text editing
185 virtual void StartTextInput() = 0;
186 virtual void StopTextInput() = 0;
187 virtual void EnsureScreenKeyboardShown() = 0;
188 virtual const char *GetComposition() const = 0;
189 virtual bool HasComposition() const = 0;
190 virtual int GetCompositionCursor() const = 0;
191 virtual int GetCompositionLength() const = 0;
192 virtual const char *GetCandidate(int Index) const = 0;
193 virtual int GetCandidateCount() const = 0;
194 virtual int GetCandidateSelectedIndex() const = 0;
195 virtual void SetCompositionWindowPosition(float X, float Y, float H) = 0;
196
197 virtual bool GetDropFile(char *aBuf, int Len) = 0;
198
199 ECursorType CursorRelative(float *pX, float *pY)
200 {
201 if(MouseRelative(pX, pY))
202 return CURSOR_MOUSE;
203 IJoystick *pJoystick = GetActiveJoystick();
204 if(pJoystick && pJoystick->Relative(pX, pY))
205 return CURSOR_JOYSTICK;
206 return CURSOR_NONE;
207 }
208};
209
210class IEngineInput : public IInput
211{
212 MACRO_INTERFACE("engineinput")
213public:
214 virtual void Init() = 0;
215 void Shutdown() override = 0;
216 virtual int Update() = 0;
217};
218
219extern IEngineInput *CreateEngineInput();
220
221#endif
222