1 /** 2 Event 3 4 Copyright: (c) Enalye 2017 5 License: Zlib 6 Authors: Enalye 7 */ 8 9 module atelier.common.event; 10 11 import std.path; 12 import std..string; 13 import std.conv; 14 import std.utf; 15 16 version (linux) { 17 import core.sys.posix.unistd; 18 import core.sys.posix.signal; 19 } 20 version (Windows) { 21 import core.stdc.signal; 22 } 23 24 import bindbc.sdl; 25 26 import atelier.render; 27 import atelier.ui; 28 import atelier.core; 29 30 import atelier.common.settings; 31 import atelier.common.controller; 32 33 static private { 34 bool[KeyButton.max + 1] _keys1, _keys2; 35 bool[MouseButton.max + 1] _buttons1, _buttons2; 36 Vec2f _mousePosition; 37 Event[] _globalEvents; 38 } 39 40 private shared bool _isRunning = false; 41 42 /// List of mouse buttons. 43 enum MouseButton : ubyte { 44 left = SDL_BUTTON_LEFT, 45 middle = SDL_BUTTON_MIDDLE, 46 right = SDL_BUTTON_RIGHT, 47 x1 = SDL_BUTTON_X1, 48 x2 = SDL_BUTTON_X2, 49 } 50 51 /// List of keyboard buttons. 52 enum KeyButton { 53 unknown = SDL_SCANCODE_UNKNOWN, 54 a = SDL_SCANCODE_A, 55 b = SDL_SCANCODE_B, 56 c = SDL_SCANCODE_C, 57 d = SDL_SCANCODE_D, 58 e = SDL_SCANCODE_E, 59 f = SDL_SCANCODE_F, 60 g = SDL_SCANCODE_G, 61 h = SDL_SCANCODE_H, 62 i = SDL_SCANCODE_I, 63 j = SDL_SCANCODE_J, 64 k = SDL_SCANCODE_K, 65 l = SDL_SCANCODE_L, 66 m = SDL_SCANCODE_M, 67 n = SDL_SCANCODE_N, 68 o = SDL_SCANCODE_O, 69 p = SDL_SCANCODE_P, 70 q = SDL_SCANCODE_Q, 71 r = SDL_SCANCODE_R, 72 s = SDL_SCANCODE_S, 73 t = SDL_SCANCODE_T, 74 u = SDL_SCANCODE_U, 75 v = SDL_SCANCODE_V, 76 w = SDL_SCANCODE_W, 77 x = SDL_SCANCODE_X, 78 y = SDL_SCANCODE_Y, 79 z = SDL_SCANCODE_Z, 80 alpha1 = SDL_SCANCODE_1, 81 alpha2 = SDL_SCANCODE_2, 82 alpha3 = SDL_SCANCODE_3, 83 alpha4 = SDL_SCANCODE_4, 84 alpha5 = SDL_SCANCODE_5, 85 alpha6 = SDL_SCANCODE_6, 86 alpha7 = SDL_SCANCODE_7, 87 alpha8 = SDL_SCANCODE_8, 88 alpha9 = SDL_SCANCODE_9, 89 alpha0 = SDL_SCANCODE_0, 90 enter = SDL_SCANCODE_RETURN, 91 escape = SDL_SCANCODE_ESCAPE, 92 backspace = SDL_SCANCODE_BACKSPACE, 93 tab = SDL_SCANCODE_TAB, 94 space = SDL_SCANCODE_SPACE, 95 minus = SDL_SCANCODE_MINUS, 96 equals = SDL_SCANCODE_EQUALS, 97 leftBracket = SDL_SCANCODE_LEFTBRACKET, 98 rightBracket = SDL_SCANCODE_RIGHTBRACKET, 99 backslash = SDL_SCANCODE_BACKSLASH, 100 nonushash = SDL_SCANCODE_NONUSHASH, 101 semicolon = SDL_SCANCODE_SEMICOLON, 102 apostrophe = SDL_SCANCODE_APOSTROPHE, 103 grave = SDL_SCANCODE_GRAVE, 104 comma = SDL_SCANCODE_COMMA, 105 period = SDL_SCANCODE_PERIOD, 106 slash = SDL_SCANCODE_SLASH, 107 capslock = SDL_SCANCODE_CAPSLOCK, 108 f1 = SDL_SCANCODE_F1, 109 f2 = SDL_SCANCODE_F2, 110 f3 = SDL_SCANCODE_F3, 111 f4 = SDL_SCANCODE_F4, 112 f5 = SDL_SCANCODE_F5, 113 f6 = SDL_SCANCODE_F6, 114 f7 = SDL_SCANCODE_F7, 115 f8 = SDL_SCANCODE_F8, 116 f9 = SDL_SCANCODE_F9, 117 f10 = SDL_SCANCODE_F10, 118 f11 = SDL_SCANCODE_F11, 119 f12 = SDL_SCANCODE_F12, 120 printScreen = SDL_SCANCODE_PRINTSCREEN, 121 scrollLock = SDL_SCANCODE_SCROLLLOCK, 122 pause = SDL_SCANCODE_PAUSE, 123 insert = SDL_SCANCODE_INSERT, 124 home = SDL_SCANCODE_HOME, 125 pageup = SDL_SCANCODE_PAGEUP, 126 remove = SDL_SCANCODE_DELETE, 127 end = SDL_SCANCODE_END, 128 pagedown = SDL_SCANCODE_PAGEDOWN, 129 right = SDL_SCANCODE_RIGHT, 130 left = SDL_SCANCODE_LEFT, 131 down = SDL_SCANCODE_DOWN, 132 up = SDL_SCANCODE_UP, 133 numLockclear = SDL_SCANCODE_NUMLOCKCLEAR, 134 numDivide = SDL_SCANCODE_KP_DIVIDE, 135 numMultiply = SDL_SCANCODE_KP_MULTIPLY, 136 numMinus = SDL_SCANCODE_KP_MINUS, 137 numPlus = SDL_SCANCODE_KP_PLUS, 138 numEnter = SDL_SCANCODE_KP_ENTER, 139 num1 = SDL_SCANCODE_KP_1, 140 num2 = SDL_SCANCODE_KP_2, 141 num3 = SDL_SCANCODE_KP_3, 142 num4 = SDL_SCANCODE_KP_4, 143 num5 = SDL_SCANCODE_KP_5, 144 num6 = SDL_SCANCODE_KP_6, 145 num7 = SDL_SCANCODE_KP_7, 146 num8 = SDL_SCANCODE_KP_8, 147 num9 = SDL_SCANCODE_KP_9, 148 num0 = SDL_SCANCODE_KP_0, 149 numPeriod = SDL_SCANCODE_KP_PERIOD, 150 nonusBackslash = SDL_SCANCODE_NONUSBACKSLASH, 151 application = SDL_SCANCODE_APPLICATION, 152 power = SDL_SCANCODE_POWER, 153 numEquals = SDL_SCANCODE_KP_EQUALS, 154 f13 = SDL_SCANCODE_F13, 155 f14 = SDL_SCANCODE_F14, 156 f15 = SDL_SCANCODE_F15, 157 f16 = SDL_SCANCODE_F16, 158 f17 = SDL_SCANCODE_F17, 159 f18 = SDL_SCANCODE_F18, 160 f19 = SDL_SCANCODE_F19, 161 f20 = SDL_SCANCODE_F20, 162 f21 = SDL_SCANCODE_F21, 163 f22 = SDL_SCANCODE_F22, 164 f23 = SDL_SCANCODE_F23, 165 f24 = SDL_SCANCODE_F24, 166 execute = SDL_SCANCODE_EXECUTE, 167 help = SDL_SCANCODE_HELP, 168 menu = SDL_SCANCODE_MENU, 169 select = SDL_SCANCODE_SELECT, 170 stop = SDL_SCANCODE_STOP, 171 again = SDL_SCANCODE_AGAIN, 172 undo = SDL_SCANCODE_UNDO, 173 cut = SDL_SCANCODE_CUT, 174 copy = SDL_SCANCODE_COPY, 175 paste = SDL_SCANCODE_PASTE, 176 find = SDL_SCANCODE_FIND, 177 mute = SDL_SCANCODE_MUTE, 178 volumeUp = SDL_SCANCODE_VOLUMEUP, 179 volumeDown = SDL_SCANCODE_VOLUMEDOWN, 180 numComma = SDL_SCANCODE_KP_COMMA, 181 numEqualsAs400 = SDL_SCANCODE_KP_EQUALSAS400, 182 international1 = SDL_SCANCODE_INTERNATIONAL1, 183 international2 = SDL_SCANCODE_INTERNATIONAL2, 184 international3 = SDL_SCANCODE_INTERNATIONAL3, 185 international4 = SDL_SCANCODE_INTERNATIONAL4, 186 international5 = SDL_SCANCODE_INTERNATIONAL5, 187 international6 = SDL_SCANCODE_INTERNATIONAL6, 188 international7 = SDL_SCANCODE_INTERNATIONAL7, 189 international8 = SDL_SCANCODE_INTERNATIONAL8, 190 international9 = SDL_SCANCODE_INTERNATIONAL9, 191 lang1 = SDL_SCANCODE_LANG1, 192 lang2 = SDL_SCANCODE_LANG2, 193 lang3 = SDL_SCANCODE_LANG3, 194 lang4 = SDL_SCANCODE_LANG4, 195 lang5 = SDL_SCANCODE_LANG5, 196 lang6 = SDL_SCANCODE_LANG6, 197 lang7 = SDL_SCANCODE_LANG7, 198 lang8 = SDL_SCANCODE_LANG8, 199 lang9 = SDL_SCANCODE_LANG9, 200 alterase = SDL_SCANCODE_ALTERASE, 201 sysreq = SDL_SCANCODE_SYSREQ, 202 cancel = SDL_SCANCODE_CANCEL, 203 clear = SDL_SCANCODE_CLEAR, 204 prior = SDL_SCANCODE_PRIOR, 205 enter2 = SDL_SCANCODE_RETURN2, 206 separator = SDL_SCANCODE_SEPARATOR, 207 out_ = SDL_SCANCODE_OUT, 208 oper = SDL_SCANCODE_OPER, 209 clearAgain = SDL_SCANCODE_CLEARAGAIN, 210 crsel = SDL_SCANCODE_CRSEL, 211 exsel = SDL_SCANCODE_EXSEL, 212 num00 = SDL_SCANCODE_KP_00, 213 num000 = SDL_SCANCODE_KP_000, 214 thousandSeparator = SDL_SCANCODE_THOUSANDSSEPARATOR, 215 decimalSeparator = SDL_SCANCODE_DECIMALSEPARATOR, 216 currencyUnit = SDL_SCANCODE_CURRENCYUNIT, 217 currencySubunit = SDL_SCANCODE_CURRENCYSUBUNIT, 218 numLeftParenthesis = SDL_SCANCODE_KP_LEFTPAREN, 219 numRightParenthesis = SDL_SCANCODE_KP_RIGHTPAREN, 220 numLeftBrace = SDL_SCANCODE_KP_LEFTBRACE, 221 numRightBrace = SDL_SCANCODE_KP_RIGHTBRACE, 222 numTab = SDL_SCANCODE_KP_TAB, 223 numBackspace = SDL_SCANCODE_KP_BACKSPACE, 224 numA = SDL_SCANCODE_KP_A, 225 numB = SDL_SCANCODE_KP_B, 226 numC = SDL_SCANCODE_KP_C, 227 numD = SDL_SCANCODE_KP_D, 228 numE = SDL_SCANCODE_KP_E, 229 numF = SDL_SCANCODE_KP_F, 230 numXor = SDL_SCANCODE_KP_XOR, 231 numPower = SDL_SCANCODE_KP_POWER, 232 numPercent = SDL_SCANCODE_KP_PERCENT, 233 numLess = SDL_SCANCODE_KP_LESS, 234 numGreater = SDL_SCANCODE_KP_GREATER, 235 numAmpersand = SDL_SCANCODE_KP_AMPERSAND, 236 numDblAmpersand = SDL_SCANCODE_KP_DBLAMPERSAND, 237 numVerticalBar = SDL_SCANCODE_KP_VERTICALBAR, 238 numDblVerticalBar = SDL_SCANCODE_KP_DBLVERTICALBAR, 239 numColon = SDL_SCANCODE_KP_COLON, 240 numHash = SDL_SCANCODE_KP_HASH, 241 numSpace = SDL_SCANCODE_KP_SPACE, 242 numAt = SDL_SCANCODE_KP_AT, 243 numExclam = SDL_SCANCODE_KP_EXCLAM, 244 numMemStore = SDL_SCANCODE_KP_MEMSTORE, 245 numMemRecall = SDL_SCANCODE_KP_MEMRECALL, 246 numMemClear = SDL_SCANCODE_KP_MEMCLEAR, 247 numMemAdd = SDL_SCANCODE_KP_MEMADD, 248 numMemSubtract = SDL_SCANCODE_KP_MEMSUBTRACT, 249 numMemMultiply = SDL_SCANCODE_KP_MEMMULTIPLY, 250 numMemDivide = SDL_SCANCODE_KP_MEMDIVIDE, 251 numPlusMinus = SDL_SCANCODE_KP_PLUSMINUS, 252 numClear = SDL_SCANCODE_KP_CLEAR, 253 numClearEntry = SDL_SCANCODE_KP_CLEARENTRY, 254 numBinary = SDL_SCANCODE_KP_BINARY, 255 numOctal = SDL_SCANCODE_KP_OCTAL, 256 numDecimal = SDL_SCANCODE_KP_DECIMAL, 257 numHexadecimal = SDL_SCANCODE_KP_HEXADECIMAL, 258 leftControl = SDL_SCANCODE_LCTRL, 259 leftShift = SDL_SCANCODE_LSHIFT, 260 leftAlt = SDL_SCANCODE_LALT, 261 leftGUI = SDL_SCANCODE_LGUI, 262 rightControl = SDL_SCANCODE_RCTRL, 263 rightShift = SDL_SCANCODE_RSHIFT, 264 rightAlt = SDL_SCANCODE_RALT, 265 rightGUI = SDL_SCANCODE_RGUI, 266 mode = SDL_SCANCODE_MODE, 267 audioNext = SDL_SCANCODE_AUDIONEXT, 268 audioPrev = SDL_SCANCODE_AUDIOPREV, 269 audioStop = SDL_SCANCODE_AUDIOSTOP, 270 audioPlay = SDL_SCANCODE_AUDIOPLAY, 271 audioMute = SDL_SCANCODE_AUDIOMUTE, 272 mediaSelect = SDL_SCANCODE_MEDIASELECT, 273 www = SDL_SCANCODE_WWW, 274 mail = SDL_SCANCODE_MAIL, 275 calculator = SDL_SCANCODE_CALCULATOR, 276 computer = SDL_SCANCODE_COMPUTER, 277 acSearch = SDL_SCANCODE_AC_SEARCH, 278 acHome = SDL_SCANCODE_AC_HOME, 279 acBack = SDL_SCANCODE_AC_BACK, 280 acForward = SDL_SCANCODE_AC_FORWARD, 281 acStop = SDL_SCANCODE_AC_STOP, 282 acRefresh = SDL_SCANCODE_AC_REFRESH, 283 acBookmarks = SDL_SCANCODE_AC_BOOKMARKS, 284 brightnessDown = SDL_SCANCODE_BRIGHTNESSDOWN, 285 brightnessUp = SDL_SCANCODE_BRIGHTNESSUP, 286 displaysWitch = SDL_SCANCODE_DISPLAYSWITCH, 287 kbdIllumToggle = SDL_SCANCODE_KBDILLUMTOGGLE, 288 kbdIllumDown = SDL_SCANCODE_KBDILLUMDOWN, 289 kbdIllumUp = SDL_SCANCODE_KBDILLUMUP, 290 eject = SDL_SCANCODE_EJECT, 291 sleep = SDL_SCANCODE_SLEEP, 292 app1 = SDL_SCANCODE_APP1, 293 app2 = SDL_SCANCODE_APP2 294 } 295 296 /// Event structure passed on onEvent() methods. 297 struct Event { 298 /// Type of event 299 enum Type : uint { 300 keyUp, 301 keyDown, 302 keyInput, 303 keyDelete, 304 keyEnter, 305 keyDir, 306 mouseUp, 307 mouseDown, 308 mouseUpdate, 309 mouseWheel, 310 quit, 311 dropFile, 312 resize, 313 modalOpen, 314 modalClose, 315 modalApply, 316 modalCancel, 317 callback, 318 custom 319 } 320 321 /// Ctor from basic type. 322 this(Type type_) { 323 type = type_; 324 } 325 326 /// Base type. 327 Event.Type type; 328 union { 329 /// For base type `keyDown` and `keyUp`. 330 KeyEvent key; 331 /// For base type `mouseDown`, `mouseUp` and `mouseUpdate`. 332 MouseEvent mouse; 333 /// For base type `mouseWheel`. 334 MouseWheelEvent scroll; 335 /// For base type `keyInput`. 336 TextInputEvent input; 337 /// For base type `dropFile`. 338 DropFileEvent drop; 339 /// For base type `keyDelete`. 340 TextDeleteEvent textDelete; 341 /// For base type `keyDir`. 342 KeyMoveEvent keyMove; 343 /// For base type `resize`. 344 WindowEvent window; 345 /// For base type `custom`. 346 CustomEvent custom; 347 } 348 349 /// For base type `keyDown` and `keyUp`. 350 struct KeyEvent { 351 /// Which button was active 352 KeyButton button; 353 /// Was it repeated 354 bool isRepeated; 355 } 356 357 /// For base type `mouseDown`, `mouseUp` and `mouseUpdate`. 358 struct MouseEvent { 359 /// Mouse position relative to its canvas. (Not an absolute position) 360 Vec2f position; 361 /// Button pressed or not. 362 MouseButton button; 363 /// How many time the button was pressed. 364 uint clicks; 365 } 366 367 /// For base type `mouseWheel`. 368 struct MouseWheelEvent { 369 /// Direction of scrolling. 370 Vec2f delta; 371 } 372 373 /// For base type `dropFile`. 374 struct DropFileEvent { 375 /// Full path of the file dropped. 376 string filePath; 377 } 378 379 /// For base type `keyInput`. 380 struct TextInputEvent { 381 /// Text written by the user. 382 string text; 383 } 384 385 /// For base type `keyDelete`. 386 struct TextDeleteEvent { 387 /// 1 = delete right char, \ 388 /// -1 = delete left char. 389 int direction; 390 } 391 392 /// For base type `keyDir`. 393 struct KeyMoveEvent { 394 /// Arrow keys movement. 395 Vec2f direction; 396 } 397 398 /// For base type `resize`. 399 struct WindowEvent { 400 /// New size of the window. 401 Vec2i size; 402 } 403 404 /// Custom event 405 struct CustomEvent { 406 /// Identifier 407 string id; 408 /// User defined data 409 void* data; 410 } 411 } 412 413 /// Check whether the key associated with the ID is pressed. \ 414 /// Do not reset the value. 415 bool isButtonDown(KeyButton button) { 416 return _keys1[button]; 417 } 418 419 /// Check whether the key associated with the ID is pressed. \ 420 /// This function resets the value to false. 421 bool getButtonDown(KeyButton button) { 422 const bool value = _keys2[button]; 423 _keys2[button] = false; 424 return value; 425 } 426 427 /// Check whether the mouse button associated with the ID is pressed. \ 428 /// Do not reset the value. 429 bool isButtonDown(MouseButton button) { 430 return _buttons1[button]; 431 } 432 433 /// Check whether the mouse button associated with the ID is pressed. \ 434 /// This function resets the value to false. 435 bool getButtonDown(MouseButton button) { 436 const bool value = _buttons2[button]; 437 _buttons2[button] = false; 438 return value; 439 } 440 441 /// Returns the position of the mouse relative to the window. 442 Vec2f getMousePos() { 443 return _mousePosition; 444 } 445 446 /// Tells the application to finish. 447 void stopApplication() { 448 _isRunning = false; 449 } 450 451 /// Check if the application's still running. 452 bool isRunning() { 453 return _isRunning; 454 } 455 456 /// Dispatch an event to GUIs. 457 void sendEvent(Event.Type eventType) { 458 Event event = Event(eventType); 459 _globalEvents ~= event; 460 } 461 462 /// Dispatch an event to GUIs. 463 void sendEvent(Event event) { 464 _globalEvents ~= event; 465 } 466 467 /// Send a custom event. 468 void sendCustomEvent(string id, void* data = null) { 469 Event event; 470 event.type = Event.Type.custom; 471 event.custom.id = id; 472 event.custom.data = data; 473 _globalEvents ~= event; 474 } 475 476 /// Capture interruptions. 477 extern (C) void signalHandler(int sig) nothrow @nogc @system { 478 cast(void) sig; 479 _isRunning = false; 480 } 481 482 /// Initialize everything mouse, keyboard or controller related. 483 void initializeEvents() { 484 signal(SIGINT, &signalHandler); 485 _isRunning = true; 486 _mousePosition = Vec2f.zero; 487 initializeControllers(); 488 } 489 490 /// Closes everything mouse, keyboard or controller related. 491 void destroyEvents() { 492 destroyControllers(); 493 } 494 495 /// Updates everything mouse, keyboard or controller related. 496 void updateEvents(float deltaTime) { 497 updateControllers(deltaTime); 498 } 499 500 /// Process and dispatch window, input, etc events. 501 bool processEvents() { 502 Event event; 503 SDL_Event sdlEvent; 504 505 if (!_isRunning) { 506 event.type = Event.Type.quit; 507 handleGuiElementEvent(event); 508 destroyWindow(); 509 return false; 510 } 511 512 //Used to start receiving SDL_TEXTINPUT events 513 //SDL_StartTextInput(); 514 515 while (SDL_PollEvent(&sdlEvent)) { 516 switch (sdlEvent.type) { 517 case SDL_QUIT: 518 _isRunning = false; 519 event.type = Event.Type.quit; 520 handleGuiElementEvent(event); 521 destroyWindow(); 522 //No operation involving the SDL after this. 523 return false; 524 case SDL_KEYDOWN: 525 if (sdlEvent.key.keysym.scancode >= _keys1.length) 526 break; 527 if (!sdlEvent.key.repeat) { 528 _keys1[sdlEvent.key.keysym.scancode] = true; 529 _keys2[sdlEvent.key.keysym.scancode] = true; 530 } 531 532 { // KeyDown Event 533 event.type = Event.Type.keyDown; 534 event.key.button = cast(KeyButton) sdlEvent.key.keysym.scancode; 535 event.key.isRepeated = sdlEvent.key.repeat > 0; 536 handleGuiElementEvent(event); 537 } 538 switch (sdlEvent.key.keysym.scancode) { 539 case SDL_SCANCODE_DELETE: 540 event.type = Event.Type.keyDelete; 541 event.textDelete.direction = 1; 542 handleGuiElementEvent(event); 543 break; 544 case SDL_SCANCODE_BACKSPACE: 545 event.type = Event.Type.keyDelete; 546 event.textDelete.direction = -1; 547 handleGuiElementEvent(event); 548 break; 549 case SDL_SCANCODE_RETURN: 550 event.type = Event.Type.keyEnter; 551 handleGuiElementEvent(event); 552 break; 553 case SDL_SCANCODE_UP: 554 event.type = Event.Type.keyDir; 555 event.keyMove.direction = Vec2f(0f, -1f); 556 handleGuiElementEvent(event); 557 break; 558 case SDL_SCANCODE_DOWN: 559 event.type = Event.Type.keyDir; 560 event.keyMove.direction = Vec2f(0f, 1f); 561 handleGuiElementEvent(event); 562 break; 563 case SDL_SCANCODE_LEFT: 564 event.type = Event.Type.keyDir; 565 event.keyMove.direction = Vec2f(-1f, 0f); 566 handleGuiElementEvent(event); 567 break; 568 case SDL_SCANCODE_RIGHT: 569 event.type = Event.Type.keyDir; 570 event.keyMove.direction = Vec2f(1f, 0f); 571 handleGuiElementEvent(event); 572 break; 573 default: 574 break; 575 } 576 break; 577 case SDL_KEYUP: 578 if (sdlEvent.key.keysym.scancode >= _keys1.length) 579 break; 580 _keys1[sdlEvent.key.keysym.scancode] = false; 581 _keys2[sdlEvent.key.keysym.scancode] = false; 582 583 { // KeyUp Event 584 event.type = Event.Type.keyUp; 585 event.key.button = cast(KeyButton) sdlEvent.key.keysym.scancode; 586 event.key.isRepeated = sdlEvent.key.repeat > 0; 587 handleGuiElementEvent(event); 588 } 589 break; 590 case SDL_TEXTINPUT: 591 string text = to!string(sdlEvent.text.text); 592 text.length = stride(text); 593 event.type = Event.Type.keyInput; 594 event.input.text = text; 595 handleGuiElementEvent(event); 596 break; 597 case SDL_MOUSEMOTION: 598 _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y); 599 _mousePosition = transformCanvasSpace(_mousePosition); 600 601 event.type = Event.Type.mouseUpdate; 602 event.mouse.position = _mousePosition; 603 604 handleGuiElementEvent(event); 605 break; 606 case SDL_MOUSEBUTTONDOWN: 607 _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y); 608 _mousePosition = transformCanvasSpace(_mousePosition); 609 if (sdlEvent.button.button >= _buttons1.length) 610 break; 611 _buttons1[sdlEvent.button.button] = true; 612 _buttons2[sdlEvent.button.button] = true; 613 614 event.type = Event.Type.mouseDown; 615 event.mouse.position = _mousePosition; 616 event.mouse.button = cast(MouseButton) sdlEvent.button.button; 617 event.mouse.clicks = sdlEvent.button.clicks; 618 619 handleGuiElementEvent(event); 620 break; 621 case SDL_MOUSEBUTTONUP: 622 _mousePosition.set(cast(float) sdlEvent.motion.x, cast(float) sdlEvent.motion.y); 623 _mousePosition = transformCanvasSpace(_mousePosition); 624 if (sdlEvent.button.button >= _buttons1.length) 625 break; 626 _buttons1[sdlEvent.button.button] = false; 627 _buttons2[sdlEvent.button.button] = false; 628 629 event.type = Event.Type.mouseUp; 630 event.mouse.position = _mousePosition; 631 event.mouse.button = cast(MouseButton) sdlEvent.button.button; 632 event.mouse.clicks = sdlEvent.button.clicks; 633 634 handleGuiElementEvent(event); 635 break; 636 case SDL_MOUSEWHEEL: 637 event.type = Event.Type.mouseWheel; 638 event.scroll.delta = Vec2f(sdlEvent.wheel.x, sdlEvent.wheel.y); 639 handleGuiElementEvent(event); 640 break; 641 case SDL_WINDOWEVENT: 642 switch (sdlEvent.window.event) { 643 case SDL_WINDOWEVENT_RESIZED: 644 event.type = Event.Type.resize; 645 event.window.size = Vec2i(sdlEvent.window.data1, sdlEvent.window.data2); 646 resizeWindow(event.window.size); 647 handleGuiElementEvent(event); 648 break; 649 case SDL_WINDOWEVENT_SIZE_CHANGED: 650 break; 651 default: 652 break; 653 } 654 break; 655 case SDL_DROPFILE: 656 string path = to!string(fromStringz(sdlEvent.drop.file)); 657 size_t index; 658 while (-1 != (index = path.indexOfAny("%"))) { 659 if ((index + 3) > path.length) 660 break; 661 string str = path[index + 1 .. index + 3]; 662 const int utfValue = parse!int(str, 16); 663 const char utfChar = to!char(utfValue); 664 665 if (index == 0) 666 path = utfChar ~ path[3 .. $]; 667 else if ((index + 3) == path.length) 668 path = path[0 .. index] ~ utfChar; 669 else 670 path = path[0 .. index] ~ utfChar ~ path[index + 3 .. $]; 671 } 672 673 event.type = Event.Type.dropFile; 674 event.drop.filePath = path; 675 handleGuiElementEvent(event); 676 677 SDL_free(sdlEvent.drop.file); 678 break; 679 case SDL_CONTROLLERDEVICEADDED: 680 addController(sdlEvent.cdevice.which); 681 break; 682 case SDL_CONTROLLERDEVICEREMOVED: 683 removeController(sdlEvent.cdevice.which); 684 break; 685 case SDL_CONTROLLERDEVICEREMAPPED: 686 remapController(sdlEvent.cdevice.which); 687 break; 688 case SDL_CONTROLLERAXISMOTION: 689 setControllerAxis(cast(SDL_GameControllerAxis) sdlEvent.caxis.axis, 690 sdlEvent.caxis.value); 691 break; 692 case SDL_CONTROLLERBUTTONDOWN: 693 setControllerButton(cast(SDL_GameControllerButton) sdlEvent.cbutton.button, true); 694 break; 695 case SDL_CONTROLLERBUTTONUP: 696 setControllerButton(cast(SDL_GameControllerButton) sdlEvent.cbutton.button, false); 697 break; 698 default: 699 break; 700 } 701 } 702 703 foreach (Event globalEvent; _globalEvents) { 704 switch (globalEvent.type) with (Event.Type) { 705 case quit: 706 _isRunning = false; 707 handleGuiElementEvent(globalEvent); 708 destroyWindow(); 709 return false; 710 default: 711 handleGuiElementEvent(globalEvent); 712 break; 713 } 714 } 715 _globalEvents.length = 0; 716 717 return true; 718 } 719 720 /// Check if the clipboard isn't empty 721 bool hasClipboard() { 722 return cast(bool) SDL_HasClipboardText(); 723 } 724 725 /// Returns the content of the clipboard 726 string getClipboard() { 727 auto clipboard = SDL_GetClipboardText(); 728 if (clipboard) { 729 string text = to!string(fromStringz(clipboard)); 730 SDL_free(clipboard); 731 return text; 732 } 733 return ""; 734 } 735 736 /// Fill the clipboard 737 void setClipboard(string text) { 738 SDL_SetClipboardText(toStringz(text)); 739 }