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 | |
38 | namespace love |
39 | { |
40 | namespace event |
41 | { |
42 | namespace 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.) |
47 | static 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 |
55 | static 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. |
77 | static 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 | |
98 | const char *Event::getName() const |
99 | { |
100 | return "love.event.sdl" ; |
101 | } |
102 | |
103 | Event::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 | |
111 | Event::~Event() |
112 | { |
113 | SDL_DelEventWatch(watchAppEvents, this); |
114 | SDL_QuitSubSystem(SDL_INIT_EVENTS); |
115 | } |
116 | |
117 | void 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 | |
134 | Message *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 | |
146 | void 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 | |
160 | void 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 | |
171 | Message *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 | |
443 | Message *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 | |
561 | Message *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 | |
641 | std::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 | |
859 | std::map<SDL_Keycode, love::keyboard::Keyboard::Key> Event::keys = Event::createKeyMap(); |
860 | |
861 | } // sdl |
862 | } // event |
863 | } // love |
864 | |