1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "Event.h"
22
23#include "filesystem/DroppedFile.h"
24#include "filesystem/Filesystem.h"
25#include "keyboard/sdl/Keyboard.h"
26#include "joystick/JoystickModule.h"
27#include "joystick/sdl/Joystick.h"
28#include "touch/sdl/Touch.h"
29#include "graphics/Graphics.h"
30#include "window/Window.h"
31#include "common/Exception.h"
32#include "audio/Audio.h"
33#include "common/config.h"
34#include "timer/Timer.h"
35
36#include <cmath>
37
38namespace love
39{
40namespace event
41{
42namespace sdl
43{
44
45// SDL reports mouse coordinates in the window coordinate system in OS X, but
46// we want them in pixel coordinates (may be different with high-DPI enabled.)
47static void windowToDPICoords(double *x, double *y)
48{
49 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
50 if (window)
51 window->windowToDPICoords(x, y);
52}
53
54#ifndef LOVE_MACOSX
55static void normalizedToDPICoords(double *x, double *y)
56{
57 double w = 1.0, h = 1.0;
58
59 auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
60 if (window)
61 {
62 w = window->getWidth();
63 h = window->getHeight();
64 window->windowToDPICoords(&w, &h);
65 }
66
67 if (x)
68 *x = ((*x) * w);
69 if (y)
70 *y = ((*y) * h);
71}
72#endif
73
74// SDL's event watch callbacks trigger when the event is actually posted inside
75// SDL, unlike with SDL_PollEvents. This is useful for some events which require
76// handling inside the function which triggered them on some backends.
77static int SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event)
78{
79 auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
80
81 switch (event->type)
82 {
83 // On iOS, calling any OpenGL ES function after the function which triggers
84 // SDL_APP_DIDENTERBACKGROUND is called will kill the app, so we handle it
85 // with an event watch callback, which will be called inside that function.
86 case SDL_APP_DIDENTERBACKGROUND:
87 case SDL_APP_WILLENTERFOREGROUND:
88 if (gfx)
89 gfx->setActive(event->type == SDL_APP_WILLENTERFOREGROUND);
90 break;
91 default:
92 break;
93 }
94
95 return 1;
96}
97
98const char *Event::getName() const
99{
100 return "love.event.sdl";
101}
102
103Event::Event()
104{
105 if (SDL_InitSubSystem(SDL_INIT_EVENTS) < 0)
106 throw love::Exception("Could not initialize SDL events subsystem (%s)", SDL_GetError());
107
108 SDL_AddEventWatch(watchAppEvents, this);
109}
110
111Event::~Event()
112{
113 SDL_DelEventWatch(watchAppEvents, this);
114 SDL_QuitSubSystem(SDL_INIT_EVENTS);
115}
116
117void Event::pump()
118{
119 exceptionIfInRenderPass("love.event.pump");
120
121 SDL_Event e;
122
123 while (SDL_PollEvent(&e))
124 {
125 Message *msg = convert(e);
126 if (msg)
127 {
128 push(msg);
129 msg->release();
130 }
131 }
132}
133
134Message *Event::wait()
135{
136 exceptionIfInRenderPass("love.event.wait");
137
138 SDL_Event e;
139
140 if (SDL_WaitEvent(&e) != 1)
141 return nullptr;
142
143 return convert(e);
144}
145
146void Event::clear()
147{
148 exceptionIfInRenderPass("love.event.clear");
149
150 SDL_Event e;
151
152 while (SDL_PollEvent(&e))
153 {
154 // Do nothing with 'e' ...
155 }
156
157 love::event::Event::clear();
158}
159
160void Event::exceptionIfInRenderPass(const char *name)
161{
162 // Some core OS graphics functionality (e.g. swap buffers on some platforms)
163 // happens inside SDL_PumpEvents - which is called by SDL_PollEvent and
164 // friends. It's probably a bad idea to call those functions while a Canvas
165 // is active.
166 auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
167 if (gfx != nullptr && gfx->isCanvasActive())
168 throw love::Exception("%s cannot be called while a Canvas is active in love.graphics.", name);
169}
170
171Message *Event::convert(const SDL_Event &e)
172{
173 Message *msg = nullptr;
174
175 std::vector<Variant> vargs;
176 vargs.reserve(4);
177
178 love::filesystem::Filesystem *filesystem = nullptr;
179
180 love::keyboard::Keyboard::Key key = love::keyboard::Keyboard::KEY_UNKNOWN;
181 love::keyboard::Keyboard::Scancode scancode = love::keyboard::Keyboard::SCANCODE_UNKNOWN;
182
183 const char *txt;
184 const char *txt2;
185 std::map<SDL_Keycode, love::keyboard::Keyboard::Key>::const_iterator keyit;
186
187#ifndef LOVE_MACOSX
188 love::touch::sdl::Touch *touchmodule = nullptr;
189 love::touch::Touch::TouchInfo touchinfo;
190#endif
191
192#ifdef LOVE_LINUX
193 static bool touchNormalizationBug = false;
194#endif
195
196 switch (e.type)
197 {
198 case SDL_KEYDOWN:
199 if (e.key.repeat)
200 {
201 auto kb = Module::getInstance<love::keyboard::Keyboard>(Module::M_KEYBOARD);
202 if (kb && !kb->hasKeyRepeat())
203 break;
204 }
205
206 keyit = keys.find(e.key.keysym.sym);
207 if (keyit != keys.end())
208 key = keyit->second;
209
210 if (!love::keyboard::Keyboard::getConstant(key, txt))
211 txt = "unknown";
212
213 love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.scancode, scancode);
214 if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
215 txt2 = "unknown";
216
217 vargs.emplace_back(txt, strlen(txt));
218 vargs.emplace_back(txt2, strlen(txt2));
219 vargs.emplace_back(e.key.repeat != 0);
220 msg = new Message("keypressed", vargs);
221 break;
222 case SDL_KEYUP:
223 keyit = keys.find(e.key.keysym.sym);
224 if (keyit != keys.end())
225 key = keyit->second;
226
227 if (!love::keyboard::Keyboard::getConstant(key, txt))
228 txt = "unknown";
229
230 love::keyboard::sdl::Keyboard::getConstant(e.key.keysym.scancode, scancode);
231 if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
232 txt2 = "unknown";
233
234 vargs.emplace_back(txt, strlen(txt));
235 vargs.emplace_back(txt2, strlen(txt2));
236 msg = new Message("keyreleased", vargs);
237 break;
238 case SDL_TEXTINPUT:
239 txt = e.text.text;
240 vargs.emplace_back(txt, strlen(txt));
241 msg = new Message("textinput", vargs);
242 break;
243 case SDL_TEXTEDITING:
244 txt = e.edit.text;
245 vargs.emplace_back(txt, strlen(txt));
246 vargs.emplace_back((double) e.edit.start);
247 vargs.emplace_back((double) e.edit.length);
248 msg = new Message("textedited", vargs);
249 break;
250 case SDL_MOUSEMOTION:
251 {
252 double x = (double) e.motion.x;
253 double y = (double) e.motion.y;
254 double xrel = (double) e.motion.xrel;
255 double yrel = (double) e.motion.yrel;
256 windowToDPICoords(&x, &y);
257 windowToDPICoords(&xrel, &yrel);
258 vargs.emplace_back(x);
259 vargs.emplace_back(y);
260 vargs.emplace_back(xrel);
261 vargs.emplace_back(yrel);
262 vargs.emplace_back(e.motion.which == SDL_TOUCH_MOUSEID);
263 msg = new Message("mousemoved", vargs);
264 }
265 break;
266 case SDL_MOUSEBUTTONDOWN:
267 case SDL_MOUSEBUTTONUP:
268 {
269 // SDL uses button 3 for the right mouse button, but we use button 2
270 int button = e.button.button;
271 switch (button)
272 {
273 case SDL_BUTTON_RIGHT:
274 button = 2;
275 break;
276 case SDL_BUTTON_MIDDLE:
277 button = 3;
278 break;
279 }
280
281 double px = (double) e.button.x;
282 double py = (double) e.button.y;
283 windowToDPICoords(&px, &py);
284 vargs.emplace_back(px);
285 vargs.emplace_back(py);
286 vargs.emplace_back((double) button);
287 vargs.emplace_back(e.button.which == SDL_TOUCH_MOUSEID);
288 vargs.emplace_back((double) e.button.clicks);
289
290 bool down = e.type == SDL_MOUSEBUTTONDOWN;
291 msg = new Message(down ? "mousepressed" : "mousereleased", vargs);
292 }
293 break;
294 case SDL_MOUSEWHEEL:
295 vargs.emplace_back((double) e.wheel.x);
296 vargs.emplace_back((double) e.wheel.y);
297 msg = new Message("wheelmoved", vargs);
298 break;
299 case SDL_FINGERDOWN:
300 case SDL_FINGERUP:
301 case SDL_FINGERMOTION:
302 // Touch events are disabled in OS X because we only actually want touch
303 // screen events, but most touch devices in OS X aren't touch screens
304 // (and SDL doesn't differentiate.) Non-screen touch devices like Mac
305 // trackpads won't give touch coords in the window's coordinate-space.
306#ifndef LOVE_MACOSX
307 touchinfo.id = (int64) e.tfinger.fingerId;
308 touchinfo.x = e.tfinger.x;
309 touchinfo.y = e.tfinger.y;
310 touchinfo.dx = e.tfinger.dx;
311 touchinfo.dy = e.tfinger.dy;
312 touchinfo.pressure = e.tfinger.pressure;
313
314#ifdef LOVE_LINUX
315 // FIXME: hacky workaround for SDL not normalizing touch coordinates in
316 // its X11 backend: https://bugzilla.libsdl.org/show_bug.cgi?id=2307
317 if (touchNormalizationBug || fabs(touchinfo.x) >= 1.5 || fabs(touchinfo.y) >= 1.5 || fabs(touchinfo.dx) >= 1.5 || fabs(touchinfo.dy) >= 1.5)
318 {
319 touchNormalizationBug = true;
320 windowToDPICoords(&touchinfo.x, &touchinfo.y);
321 windowToDPICoords(&touchinfo.dx, &touchinfo.dy);
322 }
323 else
324#endif
325 {
326 // SDL's coords are normalized to [0, 1], but we want screen coords.
327 normalizedToDPICoords(&touchinfo.x, &touchinfo.y);
328 normalizedToDPICoords(&touchinfo.dx, &touchinfo.dy);
329 }
330
331 // We need to update the love.touch.sdl internal state from here.
332 touchmodule = (touch::sdl::Touch *) Module::getInstance("love.touch.sdl");
333 if (touchmodule)
334 touchmodule->onEvent(e.type, touchinfo);
335
336 // This is a bit hackish and we lose the higher 32 bits of the id on
337 // 32-bit systems, but SDL only ever gives id's that at most use as many
338 // bits as can fit in a pointer (for now.)
339 // We use lightuserdata instead of a lua_Number (double) because doubles
340 // can't represent all possible id values on 64-bit systems.
341 vargs.emplace_back((void *) (intptr_t) touchinfo.id);
342 vargs.emplace_back(touchinfo.x);
343 vargs.emplace_back(touchinfo.y);
344 vargs.emplace_back(touchinfo.dx);
345 vargs.emplace_back(touchinfo.dy);
346 vargs.emplace_back(touchinfo.pressure);
347
348 if (e.type == SDL_FINGERDOWN)
349 txt = "touchpressed";
350 else if (e.type == SDL_FINGERUP)
351 txt = "touchreleased";
352 else
353 txt = "touchmoved";
354 msg = new Message(txt, vargs);
355#endif
356 break;
357 case SDL_JOYBUTTONDOWN:
358 case SDL_JOYBUTTONUP:
359 case SDL_JOYAXISMOTION:
360 case SDL_JOYBALLMOTION:
361 case SDL_JOYHATMOTION:
362 case SDL_JOYDEVICEADDED:
363 case SDL_JOYDEVICEREMOVED:
364 case SDL_CONTROLLERBUTTONDOWN:
365 case SDL_CONTROLLERBUTTONUP:
366 case SDL_CONTROLLERAXISMOTION:
367 msg = convertJoystickEvent(e);
368 break;
369 case SDL_WINDOWEVENT:
370 msg = convertWindowEvent(e);
371 break;
372#if SDL_VERSION_ATLEAST(2, 0, 9)
373 case SDL_DISPLAYEVENT:
374 if (e.display.event == SDL_DISPLAYEVENT_ORIENTATION)
375 {
376 auto orientation = window::Window::ORIENTATION_UNKNOWN;
377 switch ((SDL_DisplayOrientation) e.display.data1)
378 {
379 case SDL_ORIENTATION_UNKNOWN:
380 default:
381 orientation = window::Window::ORIENTATION_UNKNOWN;
382 break;
383 case SDL_ORIENTATION_LANDSCAPE:
384 orientation = window::Window::ORIENTATION_LANDSCAPE;
385 break;
386 case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
387 orientation = window::Window::ORIENTATION_LANDSCAPE_FLIPPED;
388 break;
389 case SDL_ORIENTATION_PORTRAIT:
390 orientation = window::Window::ORIENTATION_PORTRAIT;
391 break;
392 case SDL_ORIENTATION_PORTRAIT_FLIPPED:
393 orientation = window::Window::ORIENTATION_PORTRAIT_FLIPPED;
394 break;
395 }
396
397 if (!window::Window::getConstant(orientation, txt))
398 txt = "unknown";
399
400 vargs.emplace_back((double)(e.display.display + 1));
401 vargs.emplace_back(txt, strlen(txt));
402
403 msg = new Message("displayrotated", vargs);
404 }
405 break;
406#endif
407 case SDL_DROPFILE:
408 filesystem = Module::getInstance<filesystem::Filesystem>(Module::M_FILESYSTEM);
409 if (filesystem != nullptr)
410 {
411 // Allow mounting any dropped path, so zips or dirs can be mounted.
412 filesystem->allowMountingForPath(e.drop.file);
413
414 if (filesystem->isRealDirectory(e.drop.file))
415 {
416 vargs.emplace_back(e.drop.file, strlen(e.drop.file));
417 msg = new Message("directorydropped", vargs);
418 }
419 else
420 {
421 auto *file = new love::filesystem::DroppedFile(e.drop.file);
422 vargs.emplace_back(&love::filesystem::DroppedFile::type, file);
423 msg = new Message("filedropped", vargs);
424 file->release();
425 }
426 }
427 SDL_free(e.drop.file);
428 break;
429 case SDL_QUIT:
430 case SDL_APP_TERMINATING:
431 msg = new Message("quit");
432 break;
433 case SDL_APP_LOWMEMORY:
434 msg = new Message("lowmemory");
435 break;
436 default:
437 break;
438 }
439
440 return msg;
441}
442
443Message *Event::convertJoystickEvent(const SDL_Event &e) const
444{
445 auto joymodule = Module::getInstance<joystick::JoystickModule>(Module::M_JOYSTICK);
446 if (!joymodule)
447 return nullptr;
448
449 Message *msg = nullptr;
450
451 std::vector<Variant> vargs;
452 vargs.reserve(4);
453
454 love::Type *joysticktype = &love::joystick::Joystick::type;
455 love::joystick::Joystick *stick = nullptr;
456 love::joystick::Joystick::Hat hat;
457 love::joystick::Joystick::GamepadButton padbutton;
458 love::joystick::Joystick::GamepadAxis padaxis;
459 const char *txt;
460
461 switch (e.type)
462 {
463 case SDL_JOYBUTTONDOWN:
464 case SDL_JOYBUTTONUP:
465 stick = joymodule->getJoystickFromID(e.jbutton.which);
466 if (!stick)
467 break;
468
469 vargs.emplace_back(joysticktype, stick);
470 vargs.emplace_back((double)(e.jbutton.button+1));
471 msg = new Message((e.type == SDL_JOYBUTTONDOWN) ?
472 "joystickpressed" : "joystickreleased",
473 vargs);
474 break;
475 case SDL_JOYAXISMOTION:
476 {
477 stick = joymodule->getJoystickFromID(e.jaxis.which);
478 if (!stick)
479 break;
480
481 vargs.emplace_back(joysticktype, stick);
482 vargs.emplace_back((double)(e.jaxis.axis+1));
483 float value = joystick::Joystick::clampval(e.jaxis.value / 32768.0f);
484 vargs.emplace_back((double) value);
485 msg = new Message("joystickaxis", vargs);
486 }
487 break;
488 case SDL_JOYHATMOTION:
489 if (!joystick::sdl::Joystick::getConstant(e.jhat.value, hat) || !joystick::Joystick::getConstant(hat, txt))
490 break;
491
492 stick = joymodule->getJoystickFromID(e.jhat.which);
493 if (!stick)
494 break;
495
496 vargs.emplace_back(joysticktype, stick);
497 vargs.emplace_back((double)(e.jhat.hat+1));
498 vargs.emplace_back(txt, strlen(txt));
499 msg = new Message("joystickhat", vargs);
500 break;
501 case SDL_CONTROLLERBUTTONDOWN:
502 case SDL_CONTROLLERBUTTONUP:
503 if (!joystick::sdl::Joystick::getConstant((SDL_GameControllerButton) e.cbutton.button, padbutton))
504 break;
505
506 if (!joystick::Joystick::getConstant(padbutton, txt))
507 break;
508
509 stick = joymodule->getJoystickFromID(e.cbutton.which);
510 if (!stick)
511 break;
512
513 vargs.emplace_back(joysticktype, stick);
514 vargs.emplace_back(txt, strlen(txt));
515 msg = new Message(e.type == SDL_CONTROLLERBUTTONDOWN ?
516 "gamepadpressed" : "gamepadreleased", vargs);
517 break;
518 case SDL_CONTROLLERAXISMOTION:
519 if (joystick::sdl::Joystick::getConstant((SDL_GameControllerAxis) e.caxis.axis, padaxis))
520 {
521 if (!joystick::Joystick::getConstant(padaxis, txt))
522 break;
523
524 stick = joymodule->getJoystickFromID(e.caxis.which);
525 if (!stick)
526 break;
527
528 vargs.emplace_back(joysticktype, stick);
529 vargs.emplace_back(txt, strlen(txt));
530 float value = joystick::Joystick::clampval(e.caxis.value / 32768.0f);
531 vargs.emplace_back((double) value);
532 msg = new Message("gamepadaxis", vargs);
533 }
534 break;
535 case SDL_JOYDEVICEADDED:
536 // jdevice.which is the joystick device index.
537 stick = joymodule->addJoystick(e.jdevice.which);
538 if (stick)
539 {
540 vargs.emplace_back(joysticktype, stick);
541 msg = new Message("joystickadded", vargs);
542 }
543 break;
544 case SDL_JOYDEVICEREMOVED:
545 // jdevice.which is the joystick instance ID now.
546 stick = joymodule->getJoystickFromID(e.jdevice.which);
547 if (stick)
548 {
549 joymodule->removeJoystick(stick);
550 vargs.emplace_back(joysticktype, stick);
551 msg = new Message("joystickremoved", vargs);
552 }
553 break;
554 default:
555 break;
556 }
557
558 return msg;
559}
560
561Message *Event::convertWindowEvent(const SDL_Event &e)
562{
563 Message *msg = nullptr;
564
565 std::vector<Variant> vargs;
566 vargs.reserve(4);
567
568 window::Window *win = nullptr;
569 graphics::Graphics *gfx = nullptr;
570
571 if (e.type != SDL_WINDOWEVENT)
572 return nullptr;
573
574 switch (e.window.event)
575 {
576 case SDL_WINDOWEVENT_FOCUS_GAINED:
577 case SDL_WINDOWEVENT_FOCUS_LOST:
578 vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_FOCUS_GAINED);
579 msg = new Message("focus", vargs);
580 break;
581 case SDL_WINDOWEVENT_ENTER:
582 case SDL_WINDOWEVENT_LEAVE:
583 vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_ENTER);
584 msg = new Message("mousefocus", vargs);
585 break;
586 case SDL_WINDOWEVENT_SHOWN:
587 case SDL_WINDOWEVENT_HIDDEN:
588 vargs.emplace_back(e.window.event == SDL_WINDOWEVENT_SHOWN);
589 msg = new Message("visible", vargs);
590 break;
591 case SDL_WINDOWEVENT_RESIZED:
592 {
593 double width = e.window.data1;
594 double height = e.window.data2;
595
596 gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
597 win = Module::getInstance<window::Window>(Module::M_WINDOW);
598
599 // WINDOWEVENT_SIZE_CHANGED will always occur before RESIZED.
600 // The size values in the Window aren't necessarily the same as the
601 // graphics size, which is what we want to output.
602 if (gfx)
603 {
604 width = gfx->getWidth();
605 height = gfx->getHeight();
606 }
607 else if (win)
608 {
609 width = win->getWidth();
610 height = win->getHeight();
611 windowToDPICoords(&width, &height);
612 }
613
614 vargs.emplace_back(width);
615 vargs.emplace_back(height);
616 msg = new Message("resize", vargs);
617 }
618 break;
619 case SDL_WINDOWEVENT_SIZE_CHANGED:
620 win = Module::getInstance<window::Window>(Module::M_WINDOW);
621 if (win)
622 win->onSizeChanged(e.window.data1, e.window.data2);
623 break;
624 case SDL_WINDOWEVENT_MINIMIZED:
625 case SDL_WINDOWEVENT_RESTORED:
626#ifdef LOVE_ANDROID
627 if (auto audio = Module::getInstance<audio::Audio>(Module::M_AUDIO))
628 {
629 if (e.window.event == SDL_WINDOWEVENT_MINIMIZED)
630 audio->pauseContext();
631 else if (e.window.event == SDL_WINDOWEVENT_RESTORED)
632 audio->resumeContext();
633 }
634#endif
635 break;
636 }
637
638 return msg;
639}
640
641std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::createKeyMap()
642{
643 using love::keyboard::Keyboard;
644
645 std::map<SDL_Keycode, Keyboard::Key> k;
646
647 k[SDLK_UNKNOWN] = Keyboard::KEY_UNKNOWN;
648
649 k[SDLK_RETURN] = Keyboard::KEY_RETURN;
650 k[SDLK_ESCAPE] = Keyboard::KEY_ESCAPE;
651 k[SDLK_BACKSPACE] = Keyboard::KEY_BACKSPACE;
652 k[SDLK_TAB] = Keyboard::KEY_TAB;
653 k[SDLK_SPACE] = Keyboard::KEY_SPACE;
654 k[SDLK_EXCLAIM] = Keyboard::KEY_EXCLAIM;
655 k[SDLK_QUOTEDBL] = Keyboard::KEY_QUOTEDBL;
656 k[SDLK_HASH] = Keyboard::KEY_HASH;
657 k[SDLK_PERCENT] = Keyboard::KEY_PERCENT;
658 k[SDLK_DOLLAR] = Keyboard::KEY_DOLLAR;
659 k[SDLK_AMPERSAND] = Keyboard::KEY_AMPERSAND;
660 k[SDLK_QUOTE] = Keyboard::KEY_QUOTE;
661 k[SDLK_LEFTPAREN] = Keyboard::KEY_LEFTPAREN;
662 k[SDLK_RIGHTPAREN] = Keyboard::KEY_RIGHTPAREN;
663 k[SDLK_ASTERISK] = Keyboard::KEY_ASTERISK;
664 k[SDLK_PLUS] = Keyboard::KEY_PLUS;
665 k[SDLK_COMMA] = Keyboard::KEY_COMMA;
666 k[SDLK_MINUS] = Keyboard::KEY_MINUS;
667 k[SDLK_PERIOD] = Keyboard::KEY_PERIOD;
668 k[SDLK_SLASH] = Keyboard::KEY_SLASH;
669 k[SDLK_0] = Keyboard::KEY_0;
670 k[SDLK_1] = Keyboard::KEY_1;
671 k[SDLK_2] = Keyboard::KEY_2;
672 k[SDLK_3] = Keyboard::KEY_3;
673 k[SDLK_4] = Keyboard::KEY_4;
674 k[SDLK_5] = Keyboard::KEY_5;
675 k[SDLK_6] = Keyboard::KEY_6;
676 k[SDLK_7] = Keyboard::KEY_7;
677 k[SDLK_8] = Keyboard::KEY_8;
678 k[SDLK_9] = Keyboard::KEY_9;
679 k[SDLK_COLON] = Keyboard::KEY_COLON;
680 k[SDLK_SEMICOLON] = Keyboard::KEY_SEMICOLON;
681 k[SDLK_LESS] = Keyboard::KEY_LESS;
682 k[SDLK_EQUALS] = Keyboard::KEY_EQUALS;
683 k[SDLK_GREATER] = Keyboard::KEY_GREATER;
684 k[SDLK_QUESTION] = Keyboard::KEY_QUESTION;
685 k[SDLK_AT] = Keyboard::KEY_AT;
686
687 k[SDLK_LEFTBRACKET] = Keyboard::KEY_LEFTBRACKET;
688 k[SDLK_BACKSLASH] = Keyboard::KEY_BACKSLASH;
689 k[SDLK_RIGHTBRACKET] = Keyboard::KEY_RIGHTBRACKET;
690 k[SDLK_CARET] = Keyboard::KEY_CARET;
691 k[SDLK_UNDERSCORE] = Keyboard::KEY_UNDERSCORE;
692 k[SDLK_BACKQUOTE] = Keyboard::KEY_BACKQUOTE;
693 k[SDLK_a] = Keyboard::KEY_A;
694 k[SDLK_b] = Keyboard::KEY_B;
695 k[SDLK_c] = Keyboard::KEY_C;
696 k[SDLK_d] = Keyboard::KEY_D;
697 k[SDLK_e] = Keyboard::KEY_E;
698 k[SDLK_f] = Keyboard::KEY_F;
699 k[SDLK_g] = Keyboard::KEY_G;
700 k[SDLK_h] = Keyboard::KEY_H;
701 k[SDLK_i] = Keyboard::KEY_I;
702 k[SDLK_j] = Keyboard::KEY_J;
703 k[SDLK_k] = Keyboard::KEY_K;
704 k[SDLK_l] = Keyboard::KEY_L;
705 k[SDLK_m] = Keyboard::KEY_M;
706 k[SDLK_n] = Keyboard::KEY_N;
707 k[SDLK_o] = Keyboard::KEY_O;
708 k[SDLK_p] = Keyboard::KEY_P;
709 k[SDLK_q] = Keyboard::KEY_Q;
710 k[SDLK_r] = Keyboard::KEY_R;
711 k[SDLK_s] = Keyboard::KEY_S;
712 k[SDLK_t] = Keyboard::KEY_T;
713 k[SDLK_u] = Keyboard::KEY_U;
714 k[SDLK_v] = Keyboard::KEY_V;
715 k[SDLK_w] = Keyboard::KEY_W;
716 k[SDLK_x] = Keyboard::KEY_X;
717 k[SDLK_y] = Keyboard::KEY_Y;
718 k[SDLK_z] = Keyboard::KEY_Z;
719
720 k[SDLK_CAPSLOCK] = Keyboard::KEY_CAPSLOCK;
721
722 k[SDLK_F1] = Keyboard::KEY_F1;
723 k[SDLK_F2] = Keyboard::KEY_F2;
724 k[SDLK_F3] = Keyboard::KEY_F3;
725 k[SDLK_F4] = Keyboard::KEY_F4;
726 k[SDLK_F5] = Keyboard::KEY_F5;
727 k[SDLK_F6] = Keyboard::KEY_F6;
728 k[SDLK_F7] = Keyboard::KEY_F7;
729 k[SDLK_F8] = Keyboard::KEY_F8;
730 k[SDLK_F9] = Keyboard::KEY_F9;
731 k[SDLK_F10] = Keyboard::KEY_F10;
732 k[SDLK_F11] = Keyboard::KEY_F11;
733 k[SDLK_F12] = Keyboard::KEY_F12;
734
735 k[SDLK_PRINTSCREEN] = Keyboard::KEY_PRINTSCREEN;
736 k[SDLK_SCROLLLOCK] = Keyboard::KEY_SCROLLLOCK;
737 k[SDLK_PAUSE] = Keyboard::KEY_PAUSE;
738 k[SDLK_INSERT] = Keyboard::KEY_INSERT;
739 k[SDLK_HOME] = Keyboard::KEY_HOME;
740 k[SDLK_PAGEUP] = Keyboard::KEY_PAGEUP;
741 k[SDLK_DELETE] = Keyboard::KEY_DELETE;
742 k[SDLK_END] = Keyboard::KEY_END;
743 k[SDLK_PAGEDOWN] = Keyboard::KEY_PAGEDOWN;
744 k[SDLK_RIGHT] = Keyboard::KEY_RIGHT;
745 k[SDLK_LEFT] = Keyboard::KEY_LEFT;
746 k[SDLK_DOWN] = Keyboard::KEY_DOWN;
747 k[SDLK_UP] = Keyboard::KEY_UP;
748
749 k[SDLK_NUMLOCKCLEAR] = Keyboard::KEY_NUMLOCKCLEAR;
750 k[SDLK_KP_DIVIDE] = Keyboard::KEY_KP_DIVIDE;
751 k[SDLK_KP_MULTIPLY] = Keyboard::KEY_KP_MULTIPLY;
752 k[SDLK_KP_MINUS] = Keyboard::KEY_KP_MINUS;
753 k[SDLK_KP_PLUS] = Keyboard::KEY_KP_PLUS;
754 k[SDLK_KP_ENTER] = Keyboard::KEY_KP_ENTER;
755 k[SDLK_KP_0] = Keyboard::KEY_KP_0;
756 k[SDLK_KP_1] = Keyboard::KEY_KP_1;
757 k[SDLK_KP_2] = Keyboard::KEY_KP_2;
758 k[SDLK_KP_3] = Keyboard::KEY_KP_3;
759 k[SDLK_KP_4] = Keyboard::KEY_KP_4;
760 k[SDLK_KP_5] = Keyboard::KEY_KP_5;
761 k[SDLK_KP_6] = Keyboard::KEY_KP_6;
762 k[SDLK_KP_7] = Keyboard::KEY_KP_7;
763 k[SDLK_KP_8] = Keyboard::KEY_KP_8;
764 k[SDLK_KP_9] = Keyboard::KEY_KP_9;
765 k[SDLK_KP_PERIOD] = Keyboard::KEY_KP_PERIOD;
766 k[SDLK_KP_COMMA] = Keyboard::KEY_KP_COMMA;
767 k[SDLK_KP_EQUALS] = Keyboard::KEY_KP_EQUALS;
768
769 k[SDLK_APPLICATION] = Keyboard::KEY_APPLICATION;
770 k[SDLK_POWER] = Keyboard::KEY_POWER;
771 k[SDLK_F13] = Keyboard::KEY_F13;
772 k[SDLK_F14] = Keyboard::KEY_F14;
773 k[SDLK_F15] = Keyboard::KEY_F15;
774 k[SDLK_F16] = Keyboard::KEY_F16;
775 k[SDLK_F17] = Keyboard::KEY_F17;
776 k[SDLK_F18] = Keyboard::KEY_F18;
777 k[SDLK_F19] = Keyboard::KEY_F19;
778 k[SDLK_F20] = Keyboard::KEY_F20;
779 k[SDLK_F21] = Keyboard::KEY_F21;
780 k[SDLK_F22] = Keyboard::KEY_F22;
781 k[SDLK_F23] = Keyboard::KEY_F23;
782 k[SDLK_F24] = Keyboard::KEY_F24;
783 k[SDLK_EXECUTE] = Keyboard::KEY_EXECUTE;
784 k[SDLK_HELP] = Keyboard::KEY_HELP;
785 k[SDLK_MENU] = Keyboard::KEY_MENU;
786 k[SDLK_SELECT] = Keyboard::KEY_SELECT;
787 k[SDLK_STOP] = Keyboard::KEY_STOP;
788 k[SDLK_AGAIN] = Keyboard::KEY_AGAIN;
789 k[SDLK_UNDO] = Keyboard::KEY_UNDO;
790 k[SDLK_CUT] = Keyboard::KEY_CUT;
791 k[SDLK_COPY] = Keyboard::KEY_COPY;
792 k[SDLK_PASTE] = Keyboard::KEY_PASTE;
793 k[SDLK_FIND] = Keyboard::KEY_FIND;
794 k[SDLK_MUTE] = Keyboard::KEY_MUTE;
795 k[SDLK_VOLUMEUP] = Keyboard::KEY_VOLUMEUP;
796 k[SDLK_VOLUMEDOWN] = Keyboard::KEY_VOLUMEDOWN;
797
798 k[SDLK_ALTERASE] = Keyboard::KEY_ALTERASE;
799 k[SDLK_SYSREQ] = Keyboard::KEY_SYSREQ;
800 k[SDLK_CANCEL] = Keyboard::KEY_CANCEL;
801 k[SDLK_CLEAR] = Keyboard::KEY_CLEAR;
802 k[SDLK_PRIOR] = Keyboard::KEY_PRIOR;
803 k[SDLK_RETURN2] = Keyboard::KEY_RETURN2;
804 k[SDLK_SEPARATOR] = Keyboard::KEY_SEPARATOR;
805 k[SDLK_OUT] = Keyboard::KEY_OUT;
806 k[SDLK_OPER] = Keyboard::KEY_OPER;
807 k[SDLK_CLEARAGAIN] = Keyboard::KEY_CLEARAGAIN;
808
809 k[SDLK_THOUSANDSSEPARATOR] = Keyboard::KEY_THOUSANDSSEPARATOR;
810 k[SDLK_DECIMALSEPARATOR] = Keyboard::KEY_DECIMALSEPARATOR;
811 k[SDLK_CURRENCYUNIT] = Keyboard::KEY_CURRENCYUNIT;
812 k[SDLK_CURRENCYSUBUNIT] = Keyboard::KEY_CURRENCYSUBUNIT;
813
814 k[SDLK_LCTRL] = Keyboard::KEY_LCTRL;
815 k[SDLK_LSHIFT] = Keyboard::KEY_LSHIFT;
816 k[SDLK_LALT] = Keyboard::KEY_LALT;
817 k[SDLK_LGUI] = Keyboard::KEY_LGUI;
818 k[SDLK_RCTRL] = Keyboard::KEY_RCTRL;
819 k[SDLK_RSHIFT] = Keyboard::KEY_RSHIFT;
820 k[SDLK_RALT] = Keyboard::KEY_RALT;
821 k[SDLK_RGUI] = Keyboard::KEY_RGUI;
822
823 k[SDLK_MODE] = Keyboard::KEY_MODE;
824
825 k[SDLK_AUDIONEXT] = Keyboard::KEY_AUDIONEXT;
826 k[SDLK_AUDIOPREV] = Keyboard::KEY_AUDIOPREV;
827 k[SDLK_AUDIOSTOP] = Keyboard::KEY_AUDIOSTOP;
828 k[SDLK_AUDIOPLAY] = Keyboard::KEY_AUDIOPLAY;
829 k[SDLK_AUDIOMUTE] = Keyboard::KEY_AUDIOMUTE;
830 k[SDLK_MEDIASELECT] = Keyboard::KEY_MEDIASELECT;
831 k[SDLK_WWW] = Keyboard::KEY_WWW;
832 k[SDLK_MAIL] = Keyboard::KEY_MAIL;
833 k[SDLK_CALCULATOR] = Keyboard::KEY_CALCULATOR;
834 k[SDLK_COMPUTER] = Keyboard::KEY_COMPUTER;
835 k[SDLK_AC_SEARCH] = Keyboard::KEY_APP_SEARCH;
836 k[SDLK_AC_HOME] = Keyboard::KEY_APP_HOME;
837 k[SDLK_AC_BACK] = Keyboard::KEY_APP_BACK;
838 k[SDLK_AC_FORWARD] = Keyboard::KEY_APP_FORWARD;
839 k[SDLK_AC_STOP] = Keyboard::KEY_APP_STOP;
840 k[SDLK_AC_REFRESH] = Keyboard::KEY_APP_REFRESH;
841 k[SDLK_AC_BOOKMARKS] = Keyboard::KEY_APP_BOOKMARKS;
842
843 k[SDLK_BRIGHTNESSDOWN] = Keyboard::KEY_BRIGHTNESSDOWN;
844 k[SDLK_BRIGHTNESSUP] = Keyboard::KEY_BRIGHTNESSUP;
845 k[SDLK_DISPLAYSWITCH] = Keyboard::KEY_DISPLAYSWITCH;
846 k[SDLK_KBDILLUMTOGGLE] = Keyboard::KEY_KBDILLUMTOGGLE;
847 k[SDLK_KBDILLUMDOWN] = Keyboard::KEY_KBDILLUMDOWN;
848 k[SDLK_KBDILLUMUP] = Keyboard::KEY_KBDILLUMUP;
849 k[SDLK_EJECT] = Keyboard::KEY_EJECT;
850 k[SDLK_SLEEP] = Keyboard::KEY_SLEEP;
851
852#ifdef LOVE_ANDROID
853 k[SDLK_AC_BACK] = Keyboard::KEY_ESCAPE;
854#endif
855
856 return k;
857}
858
859std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::keys = Event::createKeyMap();
860
861} // sdl
862} // event
863} // love
864