FifeGUI 0.2.0
A C++ GUI library designed for games.
input.cpp
1// SPDX-License-Identifier: LGPL-2.1-or-later OR BSD-3-Clause
2// SPDX-FileCopyrightText: 2004 - 2008 Olof Naessén and Per Larsson
3// SPDX-FileCopyrightText: 2013 - 2026 Fifengine contributors
4
5#include "fifechan/backends/sdl2/input.hpp"
6
7#include <string>
8#include <vector>
9
10#include "fifechan/exception.hpp"
11#include "fifechan/util/utf8/utf8.hpp"
12
13namespace fcn::sdl2
14{
16
18 {
19 return mKeyInputQueue.empty();
20 }
21
23 {
24 KeyInput keyInput;
25
26 if (mKeyInputQueue.empty()) {
27 throwException("The queue is empty.");
28 }
29
30 keyInput = mKeyInputQueue.front();
31 mKeyInputQueue.pop();
32
33 return keyInput;
34 }
35
37 {
38 return mMouseInputQueue.empty();
39 }
40
42 {
43 MouseInput mouseInput{};
44
45 if (mMouseInputQueue.empty()) {
46 throwException("The queue is empty.");
47 }
48
49 mouseInput = mMouseInputQueue.front();
50 mMouseInputQueue.pop();
51
52 return mouseInput;
53 }
54
55 void Input::pushInput(SDL_Event event)
56 {
57 KeyInput keyInput{};
58 MouseInput mouseInput{};
59
60 switch (event.type) {
61 case SDL_KEYDOWN: {
62 int const value = convertSDLEventToFifechanKeyValue(event);
63
64 keyInput.setKey(Key(value));
65 keyInput.setType(KeyInput::Type::Pressed);
66 keyInput.setShiftPressed((event.key.keysym.mod & KMOD_SHIFT) != 0);
67 keyInput.setControlPressed((event.key.keysym.mod & KMOD_CTRL) != 0);
68 keyInput.setAltPressed((event.key.keysym.mod & KMOD_ALT) != 0);
69 keyInput.setMetaPressed((event.key.keysym.mod & KMOD_GUI) != 0);
70 keyInput.setNumericPad((event.key.keysym.mod & KMOD_NUM) != 0);
71 mKeyInputQueue.push(keyInput);
72 break;
73 }
74
75 case SDL_KEYUP: {
76 int value = convertSDLEventToFifechanKeyValue(event);
77
78 if (value == -1) {
79 value = static_cast<int>(event.key.keysym.sym);
80 }
81
82 keyInput.setKey(Key(value));
83 keyInput.setType(KeyInput::Type::Released);
84 keyInput.setShiftPressed((event.key.keysym.mod & KMOD_SHIFT) != 0);
85 keyInput.setControlPressed((event.key.keysym.mod & KMOD_CTRL) != 0);
86 keyInput.setAltPressed((event.key.keysym.mod & KMOD_ALT) != 0);
87 keyInput.setMetaPressed((event.key.keysym.mod & KMOD_GUI) != 0);
88 keyInput.setNumericPad((event.key.keysym.mod & KMOD_NUM) != 0);
89 mKeyInputQueue.push(keyInput);
90 break;
91 }
92
93 case SDL_MOUSEBUTTONDOWN: {
94 mMouseDown = true;
95 mouseInput.setX(event.button.x);
96 mouseInput.setY(event.button.y);
97 mouseInput.setButton(convertMouseButton(event.button.button));
98 mouseInput.setType(MouseInput::Type::Pressed);
99 mouseInput.setTimeStamp(SDL_GetTicks());
100 mMouseInputQueue.push(mouseInput);
101 break;
102 }
103
104 case SDL_MOUSEBUTTONUP: {
105 mMouseDown = false;
106 mouseInput.setX(event.button.x);
107 mouseInput.setY(event.button.y);
108 mouseInput.setButton(convertMouseButton(event.button.button));
109 mouseInput.setType(MouseInput::Type::Released);
110 mouseInput.setTimeStamp(SDL_GetTicks());
111 mMouseInputQueue.push(mouseInput);
112 break;
113 }
114
115 case SDL_MOUSEMOTION: {
116 mouseInput.setX(event.motion.x);
117 mouseInput.setY(event.motion.y);
118 mouseInput.setButton(MouseInput::Button::Empty);
119 mouseInput.setType(MouseInput::Type::Moved);
120 mouseInput.setTimeStamp(SDL_GetTicks());
121 mMouseInputQueue.push(mouseInput);
122 break;
123 }
124
125 case SDL_MOUSEWHEEL: {
126 /*if (event.wheel.y > 0 || (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED && event.wheel.y < 0)) {
127 mouseInput.setType(MouseInput::WheelMovedUp);
128 } else if (event.wheel.y < 0 || (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED && event.wheel.y > 0)) {
129 mouseInput.setType(MouseInput::WheelMovedDown);
130 }*/
131 /*if (event.wheel.x > 0 || (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED && event.wheel.x < 0)) {
132 mouseInput.setType(MouseInput::WheelMovedRight);
133 } else if (event.wheel.x < 0 || (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED && event.wheel.x > 0)) {
134 mouseInput.setType(MouseInput::WheelMovedLeft);
135 }*/
136 if (event.wheel.y > 0) {
137 mouseInput.setType(MouseInput::Type::WheelMovedUp);
138 } else if (event.wheel.y < 0) {
139 mouseInput.setType(MouseInput::Type::WheelMovedDown);
140 }
141 if (event.wheel.x > 0) {
142 mouseInput.setType(MouseInput::Type::WheelMovedRight);
143 } else if (event.wheel.x < 0) {
144 mouseInput.setType(MouseInput::Type::WheelMovedLeft);
145 }
146 int x = 0;
147 int y = 0;
148 SDL_GetMouseState(&x, &y);
149 mouseInput.setX(x);
150 mouseInput.setY(y);
151 mouseInput.setButton(convertMouseButton(SDL_BUTTON_LEFT));
152 mouseInput.setTimeStamp(SDL_GetTicks());
153 mMouseInputQueue.push(mouseInput);
154 break;
155 }
156
157 // case SDL_TEXTEDITING:
158 case SDL_TEXTINPUT: {
159 std::string text(static_cast<char const *>(event.text.text));
160 if (!text.empty()) {
161 // hack to transport text
162 std::vector<char16_t> result;
163 utf8::utf8to16(text.begin(), text.end(), std::back_inserter(result));
164 int const value = result[0];
165
166 keyInput.setKey(Key(value));
167 keyInput.setType(KeyInput::Type::Pressed);
168 keyInput.setShiftPressed((event.key.keysym.mod & KMOD_SHIFT) != 0);
169 keyInput.setControlPressed((event.key.keysym.mod & KMOD_CTRL) != 0);
170 keyInput.setAltPressed((event.key.keysym.mod & KMOD_ALT) != 0);
171 keyInput.setMetaPressed((event.key.keysym.mod & KMOD_GUI) != 0);
172 keyInput.setNumericPad((event.key.keysym.mod & KMOD_NUM) != 0);
173 mKeyInputQueue.push(keyInput);
174 }
175 break;
176 }
177
178 case SDL_WINDOWEVENT: {
179 /*
180 * This occurs when the mouse enters/leaves the window
181 * and the gui application gains/loses its mousefocus.
182 */
183 if (event.window.event == SDL_WINDOWEVENT_ENTER) {
184 mMouseInWindow = true;
185 } else if (event.window.event == SDL_WINDOWEVENT_LEAVE) {
186 mMouseInWindow = false;
187 // Why???
188 /*if (!mMouseDown) {
189 mouseInput.setX(-1);
190 mouseInput.setY(-1);
191 mouseInput.setButton(MouseInput::Empty);
192 mouseInput.setType(MouseInput::Moved);
193 mMouseInputQueue.push(mouseInput);
194 }*/
195 }
196 break;
197 }
198
199 default:
200 break;
201 }
202
203 } // end switch
204
205 MouseInput::Button Input::convertMouseButton(int button)
206 {
207 switch (button) {
208 case SDL_BUTTON_LEFT:
209 return MouseInput::Button::Left;
210 break;
211 case SDL_BUTTON_RIGHT:
212 return MouseInput::Button::Right;
213 break;
214 case SDL_BUTTON_MIDDLE:
215 return MouseInput::Button::Middle;
216 break;
217 case SDL_BUTTON_X1:
218 return MouseInput::Button::X1;
219 break;
220 case SDL_BUTTON_X2:
221 return MouseInput::Button::X2;
222 break;
223 default:
224 return MouseInput::Button::Empty;
225 }
226 }
227
229 {
230 int value = -1;
231
232 switch (event.key.keysym.sym) {
233 case SDLK_TAB:
234 value = Key::Tab;
235 break;
236 case SDLK_LALT:
237 value = Key::LeftAlt;
238 break;
239 case SDLK_RALT:
240 value = Key::RightAlt;
241 break;
242 case SDLK_LSHIFT:
243 value = Key::LeftShift;
244 break;
245 case SDLK_RSHIFT:
246 value = Key::RightShift;
247 break;
248 case SDLK_LCTRL:
249 value = Key::LeftControl;
250 break;
251 case SDLK_RCTRL:
252 value = Key::RightControl;
253 break;
254 case SDLK_BACKSPACE:
255 value = Key::Backspace;
256 break;
257 case SDLK_PAUSE:
258 value = Key::Pause;
259 break;
260 case SDLK_SPACE:
261 // Special characters like ~ (tilde) ends up
262 // with the keysym.sym SDLK_SPACE which
263 // without this check would be lost. The check
264 // is only valid on key up events in SDL.
265 // if (event.type == SDL_KEYUP || event.key.keysym.unicode == ' ')
266 if (event.type == SDL_KEYUP) {
267 value = Key::Space;
268 }
269 break;
270 case SDLK_ESCAPE:
271 value = Key::Escape;
272 break;
273 case SDLK_DELETE:
274 value = Key::Delete;
275 break;
276 case SDLK_INSERT:
277 value = Key::Insert;
278 break;
279 case SDLK_HOME:
280 value = Key::Home;
281 break;
282 case SDLK_END:
283 value = Key::End;
284 break;
285 case SDLK_PAGEUP:
286 value = Key::PageUp;
287 break;
288 case SDLK_PRINTSCREEN:
289 value = Key::PrintScreen;
290 break;
291 case SDLK_PAGEDOWN:
292 value = Key::PageDown;
293 break;
294 case SDLK_F1:
295 value = Key::F1;
296 break;
297 case SDLK_F2:
298 value = Key::F2;
299 break;
300 case SDLK_F3:
301 value = Key::F3;
302 break;
303 case SDLK_F4:
304 value = Key::F4;
305 break;
306 case SDLK_F5:
307 value = Key::F5;
308 break;
309 case SDLK_F6:
310 value = Key::F6;
311 break;
312 case SDLK_F7:
313 value = Key::F7;
314 break;
315 case SDLK_F8:
316 value = Key::F8;
317 break;
318 case SDLK_F9:
319 value = Key::F9;
320 break;
321 case SDLK_F10:
322 value = Key::F10;
323 break;
324 case SDLK_F11:
325 value = Key::F11;
326 break;
327 case SDLK_F12:
328 value = Key::F12;
329 break;
330 case SDLK_F13:
331 value = Key::F13;
332 break;
333 case SDLK_F14:
334 value = Key::F14;
335 break;
336 case SDLK_F15:
337 value = Key::F15;
338 break;
339 case SDLK_NUMLOCKCLEAR:
340 value = Key::NumLock;
341 break;
342 case SDLK_CAPSLOCK:
343 value = Key::CapsLock;
344 break;
345 case SDLK_SCROLLLOCK:
346 value = Key::ScrollLock;
347 break;
348 case SDLK_LGUI:
349 value = Key::LeftSuper;
350 break;
351 case SDLK_RGUI:
352 value = Key::RightSuper;
353 break;
354 case SDLK_MODE:
355 value = Key::AltGr;
356 break;
357 case SDLK_UP:
358 value = Key::Up;
359 break;
360 case SDLK_DOWN:
361 value = Key::Down;
362 break;
363 case SDLK_LEFT:
364 value = Key::Left;
365 break;
366 case SDLK_RIGHT:
367 value = Key::Right;
368 break;
369 case SDLK_RETURN:
370 case SDLK_KP_ENTER:
371 value = Key::Enter;
372 break;
373
374 default:
375 break;
376 }
377
378 if ((event.key.keysym.mod & KMOD_NUM) == 0) {
379 switch (event.key.keysym.sym) {
380 case SDLK_KP_0:
381 value = Key::Insert;
382 break;
383 case SDLK_KP_1:
384 value = Key::End;
385 break;
386 case SDLK_KP_2:
387 value = Key::Down;
388 break;
389 case SDLK_KP_3:
390 value = Key::PageDown;
391 break;
392 case SDLK_KP_4:
393 value = Key::Left;
394 break;
395 case SDLK_KP_5:
396 value = 0;
397 break;
398 case SDLK_KP_6:
399 value = Key::Right;
400 break;
401 case SDLK_KP_7:
402 value = Key::Home;
403 break;
404 case SDLK_KP_8:
405 value = Key::Up;
406 break;
407 case SDLK_KP_9:
408 value = Key::PageUp;
409 break;
410 default:
411 break;
412 }
413 }
414
415 return value;
416 }
417} // namespace fcn::sdl2
Internal class representing raw keyboard input data.
Definition keyinput.hpp:28
void setType(Type type)
Sets the type of the key input.
Definition keyinput.cpp:13
void setAltPressed(bool pressed)
Sets the alt to be pressed at the same time as the key, or not.
Definition keyinput.cpp:58
void setNumericPad(bool numpad)
Sets the key to be pressed at the numeric pad.
Definition keyinput.cpp:78
void setControlPressed(bool pressed)
Sets control to be pressed at the same time as the key, or not.
Definition keyinput.cpp:48
void setKey(Key const &key)
Sets the key of the key input.
Definition keyinput.cpp:23
void setMetaPressed(bool pressed)
Sets meta to be pressed at the same time as the key, or not.
Definition keyinput.cpp:68
void setShiftPressed(bool pressed)
Sets shift to be pressed at the same time as the key, or not.
Definition keyinput.cpp:38
Represents a keyboard key or character code.
Definition key.hpp:20
Internal class representing raw mouse input data.
void setX(int x)
Sets the x coordinate of the mouse input.
void setTimeStamp(int timeStamp)
Sets the timestamp for the mouse input.
void setY(int y)
Sets the y coordinate of the mouse input.
void setType(Type type)
Sets the type of the mouse input.
void setButton(Button button)
Sets the button pressed.
MouseInput dequeueMouseInput() override
Dequeues the mouse input queue.
Definition input.cpp:41
int convertSDLEventToFifechanKeyValue(SDL_Event event)
Converts an SDL event to a FifeGUI key value.
Definition input.cpp:228
Input()
Constructor.
Definition input.cpp:15
MouseInput::Button convertMouseButton(int button)
Converts a mouse button from SDL to a FifeGUI mouse button.
Definition input.cpp:205
std::queue< KeyInput > mKeyInputQueue
Queue of key inputs waiting to be processed.
bool isKeyQueueEmpty() override
Checks if the key queue is empty, or not.
Definition input.cpp:17
virtual void pushInput(SDL_Event event)
Pushes an SDL event.
Definition input.cpp:55
KeyInput dequeueKeyInput() override
Dequeues the key input queue.
Definition input.cpp:22
std::queue< MouseInput > mMouseInputQueue
Queue of mouse inputs waiting to be processed.
bool isMouseQueueEmpty() override
Checks if the mouse queue is empyt, or not.
Definition input.cpp:36
bool mMouseDown
True if a mouse button is currently held down.
bool mMouseInWindow
True if the mouse cursor is currently within the application window.
Unified header for the SDL backend.