Event.cpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768
  1. /**
  2. * Copyright (c) 2006-2024 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. #include "Event.h"
  21. #include "common/int.h"
  22. #include "filesystem/NativeFile.h"
  23. #include "filesystem/Filesystem.h"
  24. #include "keyboard/sdl/Keyboard.h"
  25. #include "joystick/JoystickModule.h"
  26. #include "touch/sdl/Touch.h"
  27. #include "graphics/Graphics.h"
  28. #include "window/Window.h"
  29. #include "common/Exception.h"
  30. #include "audio/Audio.h"
  31. #include "common/config.h"
  32. #include "timer/Timer.h"
  33. #include "sensor/sdl/Sensor.h"
  34. #include <cmath>
  35. #include "joystick/sdl/Joystick.h"
  36. namespace love
  37. {
  38. namespace event
  39. {
  40. namespace sdl
  41. {
  42. // SDL reports mouse coordinates in the window coordinate system in OS X, but
  43. // we want them in pixel coordinates (may be different with high-DPI enabled.)
  44. static void windowToDPICoords(double *x, double *y)
  45. {
  46. auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
  47. if (window)
  48. window->windowToDPICoords(x, y);
  49. }
  50. static void clampToWindow(double *x, double *y)
  51. {
  52. auto window = Module::getInstance<window::Window>(Module::M_WINDOW);
  53. if (window)
  54. window->clampPositionInWindow(x, y);
  55. }
  56. static void normalizedToDPICoords(double *x, double *y)
  57. {
  58. double w = 1.0, h = 1.0;
  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. if (x)
  67. *x = ((*x) * w);
  68. if (y)
  69. *y = ((*y) * h);
  70. }
  71. // SDL's event watch callbacks trigger when the event is actually posted inside
  72. // SDL, unlike with SDL_PollEvents. This is useful for some events which require
  73. // handling inside the function which triggered them on some backends.
  74. static bool SDLCALL watchAppEvents(void * /*udata*/, SDL_Event *event)
  75. {
  76. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  77. switch (event->type)
  78. {
  79. // On iOS, calling any OpenGL ES function after the function which triggers
  80. // SDL_APP_DIDENTERBACKGROUND is called will kill the app, so we handle it
  81. // with an event watch callback, which will be called inside that function.
  82. case SDL_EVENT_DID_ENTER_BACKGROUND:
  83. case SDL_EVENT_WILL_ENTER_FOREGROUND:
  84. if (gfx)
  85. gfx->setActive(event->type == SDL_EVENT_WILL_ENTER_FOREGROUND);
  86. break;
  87. default:
  88. break;
  89. }
  90. return 1;
  91. }
  92. Event::Event()
  93. : love::event::Event("love.event.sdl")
  94. {
  95. if (!SDL_InitSubSystem(SDL_INIT_EVENTS))
  96. throw love::Exception("Could not initialize SDL events subsystem (%s)", SDL_GetError());
  97. SDL_AddEventWatch(watchAppEvents, this);
  98. }
  99. Event::~Event()
  100. {
  101. SDL_RemoveEventWatch(watchAppEvents, this);
  102. SDL_QuitSubSystem(SDL_INIT_EVENTS);
  103. }
  104. void Event::pump(float waitTimeout)
  105. {
  106. exceptionIfInRenderPass("love.event.pump");
  107. int waitTimeoutMS = 0;
  108. if (std::isinf(waitTimeout) || waitTimeout < 0.0f)
  109. waitTimeoutMS = -1; // Wait forever.
  110. else if (waitTimeout > 0.0f)
  111. waitTimeoutMS = (int)std::min<int64>(LOVE_INT32_MAX, 1000LL * waitTimeout);
  112. // Wait for the first event, if requested.
  113. SDL_Event e;
  114. if (SDL_WaitEventTimeout(&e, waitTimeoutMS))
  115. {
  116. StrongRef<Message> msg(convert(e), Acquire::NORETAIN);
  117. if (msg)
  118. push(msg);
  119. // Fetch any extra events that came in during WaitEvent.
  120. while (SDL_PollEvent(&e))
  121. {
  122. msg.set(convert(e), Acquire::NORETAIN);
  123. if (msg)
  124. push(msg);
  125. }
  126. }
  127. }
  128. Message *Event::wait()
  129. {
  130. exceptionIfInRenderPass("love.event.wait");
  131. SDL_Event e;
  132. if (!SDL_WaitEvent(&e))
  133. return nullptr;
  134. return convert(e);
  135. }
  136. void Event::clear()
  137. {
  138. exceptionIfInRenderPass("love.event.clear");
  139. SDL_Event e;
  140. while (SDL_PollEvent(&e))
  141. {
  142. // Do nothing with 'e' ...
  143. }
  144. love::event::Event::clear();
  145. }
  146. void Event::exceptionIfInRenderPass(const char *name)
  147. {
  148. // Some core OS graphics functionality (e.g. swap buffers on some platforms)
  149. // happens inside SDL_PumpEvents - which is called by SDL_PollEvent and
  150. // friends. It's probably a bad idea to call those functions while a RT
  151. // is active.
  152. auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  153. if (gfx != nullptr && gfx->isRenderTargetActive())
  154. throw love::Exception("%s cannot be called while a render target is active in love.graphics.", name);
  155. }
  156. Message *Event::convert(const SDL_Event &e)
  157. {
  158. Message *msg = nullptr;
  159. std::vector<Variant> vargs;
  160. vargs.reserve(4);
  161. love::filesystem::Filesystem *filesystem = nullptr;
  162. love::sensor::Sensor *sensorInstance = nullptr;
  163. love::keyboard::Keyboard::Key key = love::keyboard::Keyboard::KEY_UNKNOWN;
  164. love::keyboard::Keyboard::Scancode scancode = love::keyboard::Keyboard::SCANCODE_UNKNOWN;
  165. const char *txt;
  166. const char *txt2;
  167. love::touch::sdl::Touch *touchmodule = nullptr;
  168. love::touch::Touch::TouchInfo touchinfo = {};
  169. switch (e.type)
  170. {
  171. case SDL_EVENT_KEY_DOWN:
  172. if (e.key.repeat)
  173. {
  174. auto kb = Module::getInstance<love::keyboard::Keyboard>(Module::M_KEYBOARD);
  175. if (kb && !kb->hasKeyRepeat())
  176. break;
  177. }
  178. love::keyboard::sdl::Keyboard::getConstant(e.key.key, key);
  179. if (!love::keyboard::Keyboard::getConstant(key, txt))
  180. txt = "unknown";
  181. love::keyboard::sdl::Keyboard::getConstant(e.key.scancode, scancode);
  182. if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
  183. txt2 = "unknown";
  184. vargs.emplace_back(txt, strlen(txt));
  185. vargs.emplace_back(txt2, strlen(txt2));
  186. vargs.emplace_back(e.key.repeat != 0);
  187. msg = new Message("keypressed", vargs);
  188. break;
  189. case SDL_EVENT_KEY_UP:
  190. love::keyboard::sdl::Keyboard::getConstant(e.key.key, key);
  191. if (!love::keyboard::Keyboard::getConstant(key, txt))
  192. txt = "unknown";
  193. love::keyboard::sdl::Keyboard::getConstant(e.key.scancode, scancode);
  194. if (!love::keyboard::Keyboard::getConstant(scancode, txt2))
  195. txt2 = "unknown";
  196. vargs.emplace_back(txt, strlen(txt));
  197. vargs.emplace_back(txt2, strlen(txt2));
  198. msg = new Message("keyreleased", vargs);
  199. break;
  200. case SDL_EVENT_TEXT_INPUT:
  201. txt = e.text.text;
  202. vargs.emplace_back(txt, strlen(txt));
  203. msg = new Message("textinput", vargs);
  204. break;
  205. case SDL_EVENT_TEXT_EDITING:
  206. txt = e.edit.text;
  207. vargs.emplace_back(txt, strlen(txt));
  208. vargs.emplace_back((double) e.edit.start);
  209. vargs.emplace_back((double) e.edit.length);
  210. msg = new Message("textedited", vargs);
  211. break;
  212. case SDL_EVENT_MOUSE_MOTION:
  213. {
  214. double x = (double) e.motion.x;
  215. double y = (double) e.motion.y;
  216. double xrel = (double) e.motion.xrel;
  217. double yrel = (double) e.motion.yrel;
  218. // SDL reports mouse coordinates outside the window bounds when click-and-
  219. // dragging. For compatibility we clamp instead since user code may not be
  220. // able to handle out-of-bounds coordinates. SDL has a hint to turn off
  221. // auto capture, but it doesn't report the mouse's position at the edge of
  222. // the window if the mouse moves fast enough when it's off.
  223. clampToWindow(&x, &y);
  224. windowToDPICoords(&x, &y);
  225. windowToDPICoords(&xrel, &yrel);
  226. vargs.emplace_back(x);
  227. vargs.emplace_back(y);
  228. vargs.emplace_back(xrel);
  229. vargs.emplace_back(yrel);
  230. vargs.emplace_back(e.motion.which == SDL_TOUCH_MOUSEID);
  231. msg = new Message("mousemoved", vargs);
  232. }
  233. break;
  234. case SDL_EVENT_MOUSE_BUTTON_DOWN:
  235. case SDL_EVENT_MOUSE_BUTTON_UP:
  236. {
  237. // SDL uses button 3 for the right mouse button, but we use button 2
  238. int button = e.button.button;
  239. switch (button)
  240. {
  241. case SDL_BUTTON_RIGHT:
  242. button = 2;
  243. break;
  244. case SDL_BUTTON_MIDDLE:
  245. button = 3;
  246. break;
  247. }
  248. double px = (double) e.button.x;
  249. double py = (double) e.button.y;
  250. clampToWindow(&px, &py);
  251. windowToDPICoords(&px, &py);
  252. vargs.emplace_back(px);
  253. vargs.emplace_back(py);
  254. vargs.emplace_back((double) button);
  255. vargs.emplace_back(e.button.which == SDL_TOUCH_MOUSEID);
  256. vargs.emplace_back((double) e.button.clicks);
  257. bool down = e.type == SDL_EVENT_MOUSE_BUTTON_DOWN;
  258. msg = new Message(down ? "mousepressed" : "mousereleased", vargs);
  259. }
  260. break;
  261. case SDL_EVENT_MOUSE_WHEEL:
  262. vargs.emplace_back((double) e.wheel.x);
  263. vargs.emplace_back((double) e.wheel.y);
  264. txt = e.wheel.direction == SDL_MOUSEWHEEL_FLIPPED ? "flipped" : "standard";
  265. vargs.emplace_back(txt, strlen(txt));
  266. msg = new Message("wheelmoved", vargs);
  267. break;
  268. case SDL_EVENT_FINGER_DOWN:
  269. case SDL_EVENT_FINGER_UP:
  270. case SDL_EVENT_FINGER_MOTION:
  271. touchinfo.id = (int64)e.tfinger.fingerID;
  272. touchinfo.x = e.tfinger.x;
  273. touchinfo.y = e.tfinger.y;
  274. touchinfo.dx = e.tfinger.dx;
  275. touchinfo.dy = e.tfinger.dy;
  276. touchinfo.pressure = e.tfinger.pressure;
  277. touchinfo.deviceType = love::touch::sdl::Touch::getDeviceType(SDL_GetTouchDeviceType(e.tfinger.touchID));
  278. touchinfo.mouse = e.tfinger.touchID == SDL_MOUSE_TOUCHID;
  279. // SDL's coords are normalized to [0, 1], but we want screen coords for direct touches.
  280. if (touchinfo.deviceType == love::touch::Touch::DEVICE_TOUCHSCREEN)
  281. {
  282. normalizedToDPICoords(&touchinfo.x, &touchinfo.y);
  283. normalizedToDPICoords(&touchinfo.dx, &touchinfo.dy);
  284. }
  285. // We need to update the love.touch.sdl internal state from here.
  286. touchmodule = (touch::sdl::Touch *) Module::getInstance("love.touch.sdl");
  287. if (touchmodule)
  288. touchmodule->onEvent(e.type, touchinfo);
  289. if (!love::touch::Touch::getConstant(touchinfo.deviceType, txt))
  290. txt = "unknown";
  291. // This is a bit hackish and we lose the higher 32 bits of the id on
  292. // 32-bit systems, but SDL only ever gives id's that at most use as many
  293. // bits as can fit in a pointer (for now.)
  294. // We use lightuserdata instead of a lua_Number (double) because doubles
  295. // can't represent all possible id values on 64-bit systems.
  296. vargs.emplace_back((void *)(intptr_t)touchinfo.id);
  297. vargs.emplace_back(touchinfo.x);
  298. vargs.emplace_back(touchinfo.y);
  299. vargs.emplace_back(touchinfo.dx);
  300. vargs.emplace_back(touchinfo.dy);
  301. vargs.emplace_back(touchinfo.pressure);
  302. vargs.emplace_back(txt, strlen(txt));
  303. vargs.emplace_back(touchinfo.mouse);
  304. if (e.type == SDL_EVENT_FINGER_DOWN)
  305. txt = "touchpressed";
  306. else if (e.type == SDL_EVENT_FINGER_UP)
  307. txt = "touchreleased";
  308. else
  309. txt = "touchmoved";
  310. msg = new Message(txt, vargs);
  311. break;
  312. case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
  313. case SDL_EVENT_JOYSTICK_BUTTON_UP:
  314. case SDL_EVENT_JOYSTICK_AXIS_MOTION:
  315. case SDL_EVENT_JOYSTICK_HAT_MOTION:
  316. case SDL_EVENT_JOYSTICK_ADDED:
  317. case SDL_EVENT_JOYSTICK_REMOVED:
  318. case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
  319. case SDL_EVENT_GAMEPAD_BUTTON_UP:
  320. case SDL_EVENT_GAMEPAD_AXIS_MOTION:
  321. case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
  322. msg = convertJoystickEvent(e);
  323. break;
  324. case SDL_EVENT_WINDOW_FOCUS_GAINED:
  325. case SDL_EVENT_WINDOW_FOCUS_LOST:
  326. case SDL_EVENT_WINDOW_MOUSE_ENTER:
  327. case SDL_EVENT_WINDOW_MOUSE_LEAVE:
  328. case SDL_EVENT_WINDOW_SHOWN:
  329. case SDL_EVENT_WINDOW_HIDDEN:
  330. case SDL_EVENT_WINDOW_RESIZED:
  331. case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
  332. case SDL_EVENT_WINDOW_MINIMIZED:
  333. case SDL_EVENT_WINDOW_RESTORED:
  334. case SDL_EVENT_WINDOW_EXPOSED:
  335. case SDL_EVENT_WINDOW_OCCLUDED:
  336. msg = convertWindowEvent(e);
  337. break;
  338. case SDL_EVENT_DISPLAY_ORIENTATION:
  339. {
  340. auto orientation = window::Window::ORIENTATION_UNKNOWN;
  341. switch ((SDL_DisplayOrientation) e.display.data1)
  342. {
  343. case SDL_ORIENTATION_UNKNOWN:
  344. default:
  345. orientation = window::Window::ORIENTATION_UNKNOWN;
  346. break;
  347. case SDL_ORIENTATION_LANDSCAPE:
  348. orientation = window::Window::ORIENTATION_LANDSCAPE;
  349. break;
  350. case SDL_ORIENTATION_LANDSCAPE_FLIPPED:
  351. orientation = window::Window::ORIENTATION_LANDSCAPE_FLIPPED;
  352. break;
  353. case SDL_ORIENTATION_PORTRAIT:
  354. orientation = window::Window::ORIENTATION_PORTRAIT;
  355. break;
  356. case SDL_ORIENTATION_PORTRAIT_FLIPPED:
  357. orientation = window::Window::ORIENTATION_PORTRAIT_FLIPPED;
  358. break;
  359. }
  360. if (!window::Window::getConstant(orientation, txt))
  361. txt = "unknown";
  362. int count = 0;
  363. int displayindex = 0;
  364. SDL_DisplayID *displays = SDL_GetDisplays(&count);
  365. for (int i = 0; i < count; i++)
  366. {
  367. if (displays[i] == e.display.displayID)
  368. {
  369. displayindex = i;
  370. break;
  371. }
  372. }
  373. SDL_free(displays);
  374. vargs.emplace_back((double)(displayindex + 1));
  375. vargs.emplace_back(txt, strlen(txt));
  376. msg = new Message("displayrotated", vargs);
  377. }
  378. break;
  379. case SDL_EVENT_DROP_BEGIN:
  380. msg = new Message("dropbegan", vargs);
  381. break;
  382. case SDL_EVENT_DROP_COMPLETE:
  383. {
  384. double x = e.drop.x;
  385. double y = e.drop.y;
  386. windowToDPICoords(&x, &y);
  387. vargs.emplace_back(x);
  388. vargs.emplace_back(y);
  389. msg = new Message("dropcompleted", vargs);
  390. }
  391. break;
  392. case SDL_EVENT_DROP_POSITION:
  393. {
  394. double x = e.drop.x;
  395. double y = e.drop.y;
  396. windowToDPICoords(&x, &y);
  397. vargs.emplace_back(x);
  398. vargs.emplace_back(y);
  399. msg = new Message("dropmoved", vargs);
  400. }
  401. break;
  402. case SDL_EVENT_DROP_FILE:
  403. filesystem = Module::getInstance<filesystem::Filesystem>(Module::M_FILESYSTEM);
  404. if (filesystem != nullptr)
  405. {
  406. const char *filepath = e.drop.data;
  407. // Allow mounting any dropped path, so zips or dirs can be mounted.
  408. filesystem->allowMountingForPath(filepath);
  409. double x = e.drop.x;
  410. double y = e.drop.y;
  411. windowToDPICoords(&x, &y);
  412. if (filesystem->isRealDirectory(filepath))
  413. {
  414. vargs.emplace_back(filepath, strlen(filepath));
  415. vargs.emplace_back(x);
  416. vargs.emplace_back(y);
  417. msg = new Message("directorydropped", vargs);
  418. }
  419. else
  420. {
  421. auto *file = new love::filesystem::NativeFile(filepath, love::filesystem::File::MODE_CLOSED);
  422. vargs.emplace_back(&love::filesystem::NativeFile::type, file);
  423. vargs.emplace_back(x);
  424. vargs.emplace_back(y);
  425. msg = new Message("filedropped", vargs);
  426. file->release();
  427. }
  428. }
  429. break;
  430. case SDL_EVENT_QUIT:
  431. case SDL_EVENT_TERMINATING:
  432. msg = new Message("quit");
  433. break;
  434. case SDL_EVENT_LOW_MEMORY:
  435. msg = new Message("lowmemory");
  436. break;
  437. case SDL_EVENT_LOCALE_CHANGED:
  438. msg = new Message("localechanged");
  439. break;
  440. case SDL_EVENT_SENSOR_UPDATE:
  441. sensorInstance = Module::getInstance<sensor::Sensor>(M_SENSOR);
  442. if (sensorInstance)
  443. {
  444. std::vector<void*> sensors = sensorInstance->getHandles();
  445. for (void *s: sensors)
  446. {
  447. SDL_Sensor *sensor = (SDL_Sensor *) s;
  448. SDL_SensorID id = SDL_GetSensorID(sensor);
  449. if (e.sensor.which == id)
  450. {
  451. // Found sensor
  452. const char *sensorType;
  453. auto sdltype = SDL_GetSensorType(sensor);
  454. if (!sensor::Sensor::getConstant(sensor::sdl::Sensor::convert(sdltype), sensorType))
  455. sensorType = "unknown";
  456. vargs.emplace_back(sensorType, strlen(sensorType));
  457. // Both accelerometer and gyroscope only pass up to 3 values.
  458. // https://github.com/libsdl-org/SDL/blob/SDL2/include/SDL_sensor.h#L81-L127
  459. vargs.emplace_back(e.sensor.data[0]);
  460. vargs.emplace_back(e.sensor.data[1]);
  461. vargs.emplace_back(e.sensor.data[2]);
  462. msg = new Message("sensorupdated", vargs);
  463. break;
  464. }
  465. }
  466. }
  467. break;
  468. default:
  469. break;
  470. }
  471. return msg;
  472. }
  473. Message *Event::convertJoystickEvent(const SDL_Event &e) const
  474. {
  475. auto joymodule = Module::getInstance<joystick::JoystickModule>(Module::M_JOYSTICK);
  476. if (!joymodule)
  477. return nullptr;
  478. Message *msg = nullptr;
  479. std::vector<Variant> vargs;
  480. vargs.reserve(4);
  481. love::Type *joysticktype = &love::joystick::Joystick::type;
  482. love::joystick::Joystick *stick = nullptr;
  483. love::joystick::Joystick::Hat hat;
  484. love::joystick::Joystick::GamepadButton padbutton;
  485. love::joystick::Joystick::GamepadAxis padaxis;
  486. const char *txt;
  487. switch (e.type)
  488. {
  489. case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
  490. case SDL_EVENT_JOYSTICK_BUTTON_UP:
  491. stick = joymodule->getJoystickFromID(e.jbutton.which);
  492. if (!stick)
  493. break;
  494. vargs.emplace_back(joysticktype, stick);
  495. vargs.emplace_back((double)(e.jbutton.button+1));
  496. msg = new Message((e.type == SDL_EVENT_JOYSTICK_BUTTON_DOWN) ?
  497. "joystickpressed" : "joystickreleased",
  498. vargs);
  499. break;
  500. case SDL_EVENT_JOYSTICK_AXIS_MOTION:
  501. {
  502. stick = joymodule->getJoystickFromID(e.jaxis.which);
  503. if (!stick)
  504. break;
  505. vargs.emplace_back(joysticktype, stick);
  506. vargs.emplace_back((double)(e.jaxis.axis+1));
  507. float value = joystick::Joystick::clampval(e.jaxis.value / 32768.0f);
  508. vargs.emplace_back((double) value);
  509. msg = new Message("joystickaxis", vargs);
  510. }
  511. break;
  512. case SDL_EVENT_JOYSTICK_HAT_MOTION:
  513. if (!joystick::sdl::Joystick::getConstant(e.jhat.value, hat) || !joystick::Joystick::getConstant(hat, txt))
  514. break;
  515. stick = joymodule->getJoystickFromID(e.jhat.which);
  516. if (!stick)
  517. break;
  518. vargs.emplace_back(joysticktype, stick);
  519. vargs.emplace_back((double)(e.jhat.hat+1));
  520. vargs.emplace_back(txt, strlen(txt));
  521. msg = new Message("joystickhat", vargs);
  522. break;
  523. case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
  524. case SDL_EVENT_GAMEPAD_BUTTON_UP:
  525. {
  526. const auto &b = e.gbutton;
  527. if (!joystick::sdl::Joystick::getConstant((SDL_GamepadButton) b.button, padbutton))
  528. break;
  529. if (!joystick::Joystick::getConstant(padbutton, txt))
  530. break;
  531. stick = joymodule->getJoystickFromID(b.which);
  532. if (!stick)
  533. break;
  534. vargs.emplace_back(joysticktype, stick);
  535. vargs.emplace_back(txt, strlen(txt));
  536. msg = new Message(e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN ?
  537. "gamepadpressed" : "gamepadreleased", vargs);
  538. }
  539. break;
  540. case SDL_EVENT_GAMEPAD_AXIS_MOTION:
  541. if (joystick::sdl::Joystick::getConstant((SDL_GamepadAxis) e.gaxis.axis, padaxis))
  542. {
  543. if (!joystick::Joystick::getConstant(padaxis, txt))
  544. break;
  545. const auto &a = e.gaxis;
  546. stick = joymodule->getJoystickFromID(a.which);
  547. if (!stick)
  548. break;
  549. vargs.emplace_back(joysticktype, stick);
  550. vargs.emplace_back(txt, strlen(txt));
  551. float value = joystick::Joystick::clampval(a.value / 32768.0f);
  552. vargs.emplace_back((double) value);
  553. msg = new Message("gamepadaxis", vargs);
  554. }
  555. break;
  556. case SDL_EVENT_JOYSTICK_ADDED:
  557. // jdevice.which is the joystick device index.
  558. stick = joymodule->addJoystick(e.jdevice.which);
  559. if (stick)
  560. {
  561. vargs.emplace_back(joysticktype, stick);
  562. msg = new Message("joystickadded", vargs);
  563. }
  564. break;
  565. case SDL_EVENT_JOYSTICK_REMOVED:
  566. // jdevice.which is the joystick instance ID now.
  567. stick = joymodule->getJoystickFromID(e.jdevice.which);
  568. if (stick)
  569. {
  570. joymodule->removeJoystick(stick);
  571. vargs.emplace_back(joysticktype, stick);
  572. msg = new Message("joystickremoved", vargs);
  573. }
  574. break;
  575. #if defined(LOVE_ENABLE_SENSOR)
  576. case SDL_EVENT_GAMEPAD_SENSOR_UPDATE:
  577. {
  578. const auto &sens = e.gsensor;
  579. stick = joymodule->getJoystickFromID(sens.which);
  580. if (stick)
  581. {
  582. using Sensor = love::sensor::Sensor;
  583. const char *sensorName;
  584. Sensor::SensorType sensorType = love::sensor::sdl::Sensor::convert((SDL_SensorType) sens.sensor);
  585. if (!Sensor::getConstant(sensorType, sensorName))
  586. sensorName = "unknown";
  587. vargs.emplace_back(joysticktype, stick);
  588. vargs.emplace_back(sensorName, strlen(sensorName));
  589. vargs.emplace_back(sens.data[0]);
  590. vargs.emplace_back(sens.data[1]);
  591. vargs.emplace_back(sens.data[2]);
  592. msg = new Message("joysticksensorupdated", vargs);
  593. }
  594. }
  595. break;
  596. #endif // defined(LOVE_ENABLE_SENSOR)
  597. default:
  598. break;
  599. }
  600. return msg;
  601. }
  602. Message *Event::convertWindowEvent(const SDL_Event &e)
  603. {
  604. Message *msg = nullptr;
  605. std::vector<Variant> vargs;
  606. vargs.reserve(4);
  607. window::Window *win = nullptr;
  608. graphics::Graphics *gfx = nullptr;
  609. auto event = e.type;
  610. switch (event)
  611. {
  612. case SDL_EVENT_WINDOW_FOCUS_GAINED:
  613. case SDL_EVENT_WINDOW_FOCUS_LOST:
  614. vargs.emplace_back(event == SDL_EVENT_WINDOW_FOCUS_GAINED);
  615. msg = new Message("focus", vargs);
  616. break;
  617. case SDL_EVENT_WINDOW_MOUSE_ENTER:
  618. case SDL_EVENT_WINDOW_MOUSE_LEAVE:
  619. vargs.emplace_back(event == SDL_EVENT_WINDOW_MOUSE_ENTER);
  620. msg = new Message("mousefocus", vargs);
  621. break;
  622. case SDL_EVENT_WINDOW_SHOWN:
  623. case SDL_EVENT_WINDOW_HIDDEN:
  624. case SDL_EVENT_WINDOW_MINIMIZED:
  625. case SDL_EVENT_WINDOW_RESTORED:
  626. #ifdef LOVE_ANDROID
  627. if (auto audio = Module::getInstance<audio::Audio>(Module::M_AUDIO))
  628. {
  629. if (event == SDL_EVENT_WINDOW_MINIMIZED)
  630. audio->pauseContext();
  631. else if (event == SDL_EVENT_WINDOW_RESTORED)
  632. audio->resumeContext();
  633. }
  634. #endif
  635. // WINDOW_RESTORED can also happen when going from maximized -> unmaximized,
  636. // but there isn't a nice way to avoid sending our event in that situation.
  637. vargs.emplace_back(event == SDL_EVENT_WINDOW_SHOWN || event == SDL_EVENT_WINDOW_RESTORED);
  638. msg = new Message("visible", vargs);
  639. break;
  640. case SDL_EVENT_WINDOW_EXPOSED:
  641. msg = new Message("exposed");
  642. break;
  643. case SDL_EVENT_WINDOW_OCCLUDED:
  644. msg = new Message("occluded");
  645. break;
  646. case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
  647. {
  648. double width = e.window.data1;
  649. double height = e.window.data2;
  650. gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
  651. win = Module::getInstance<window::Window>(Module::M_WINDOW);
  652. if (win)
  653. win->onSizeChanged(e.window.data1, e.window.data2);
  654. // The size values in the Window aren't necessarily the same as the
  655. // graphics size, which is what we want to output.
  656. if (gfx)
  657. {
  658. width = gfx->getWidth();
  659. height = gfx->getHeight();
  660. }
  661. else if (win)
  662. {
  663. width = win->getWidth();
  664. height = win->getHeight();
  665. windowToDPICoords(&width, &height);
  666. }
  667. vargs.emplace_back(width);
  668. vargs.emplace_back(height);
  669. msg = new Message("resize", vargs);
  670. }
  671. break;
  672. }
  673. return msg;
  674. }
  675. } // sdl
  676. } // event
  677. } // love