1 /++ 2 A module for listening to incoming events from the window manager for their 3 subsequent processing. 4 5 Such a layer does not admit events directly to the data, but whether it can show 6 what is happening at the moment, which can serve as a cross-plotter tracking 7 of events. 8 9 Using the IEventHandler.nextEvent function, you can scroll through the queue of 10 events that can be processed and at each queue, the programmer needs to track 11 the events he needs by the functions of the same interface: 12 --- 13 while (event.nextEvent()) { 14 if (event.keyDown == Key.Space) foo(); 15 } 16 --- 17 As you can see, we loop through each event and read what happened. 18 19 Macros: 20 LREF = <a href="#$1">$1</a> 21 HREF = <a href="$1">$2</a> 22 23 Authors: $(HREF https://github.com/TodNaz,TodNaz) 24 Copyright: Copyright (c) 2020 - 2021, TodNaz. 25 License: $(HREF https://github.com/TodNaz/Tida/blob/master/LICENSE,MIT) 26 +/ 27 module tida.event; 28 29 enum DeprecatedMethodSize = 30 "This function is useless. Use the parameters `IWindow.width/IWindow.height`."; 31 32 /// Mouse keys. 33 enum MouseButton 34 { 35 unknown = 0, /// Unknown mouse button 36 left = 1, /// Left mouse button 37 right = 3, /// Right mouse button 38 middle = 2 /// Middle mouse button 39 } 40 41 /++ 42 Interaction interface and receiving information from the joystick. 43 +/ 44 interface IJoystick 45 { 46 import tida.vector; 47 48 enum maximumAxes = vec!float(32767, 32767); 49 50 /++ 51 A method that returns the value of all axes of the controller. 52 The maximum number of axes can be checked using the `.length` property: 53 --- 54 writeln("Axless count: ", joystick.axless.length); 55 --- 56 +/ 57 @property int[] axless() @safe; 58 59 /++ 60 A method that returns the maximum number of buttons on the controller. 61 +/ 62 @property uint maxButtons() @safe; 63 64 /++ 65 A method that returns the name of the controller. 66 +/ 67 @property string name() @safe; 68 69 /++ 70 Method showing which button was pressed/released in the current event. 71 +/ 72 @property int button() @safe; 73 74 /++ 75 Shows the state when any button was pressed. 76 +/ 77 @property bool isButtonDown() @safe; 78 79 /++ 80 Shows the state when any button was released.. 81 +/ 82 @property bool isButtonUp() @safe; 83 84 /++ 85 Shows the state when any one of the axes has changed its state. 86 +/ 87 @property bool isAxisMove() @safe; 88 89 /++ 90 Shows the value of the first axis on the controller. 91 The value ranges from -1.0 to 1.0. 92 +/ 93 final @property Vector!float xy() @safe 94 { 95 return vec!float(axless[0], axless[1]) / maximumAxes; 96 } 97 98 /++ 99 Shows the value of the second axis on the controller. 100 The value ranges from -1.0 to 1.0. 101 +/ 102 final @property Vector!float zr() @safe 103 { 104 return vec!float(axless[2], axless[3]) / maximumAxes; 105 } 106 107 /++ 108 Shows the value of the third axis on the controller. 109 The value ranges from -1.0 to 1.0. 110 +/ 111 final @property Vector!float uv() @safe 112 { 113 return vec!float(axless[4], axless[5]) / maximumAxes; 114 } 115 116 /++ 117 Shows the currently pressed key. 118 +/ 119 final @property int buttonDown() @safe 120 { 121 return isButtonDown ? button : -1; 122 } 123 124 /++ 125 Shows the currently released key. 126 +/ 127 final @property int buttonUp() @safe 128 { 129 return isButtonUp ? button : -1; 130 } 131 } 132 133 version(Windows) 134 class Joystick : IJoystick 135 { 136 import core.sys.windows.windows; 137 import tida.vector; 138 139 private: 140 EventHandler event; 141 142 public: 143 int id; // identificator 144 int numAxes; // Max axes 145 int numButtons; // Max buttons 146 int[] axisMin; // Minimum axes values 147 int[] axisMax; // Maximum axes values 148 int[] axisOffset; // Axes offset values 149 float[] axisScale; // Axes scale values 150 string namely; 151 152 int[] axesState; // Axes state 153 int[int] buttons; 154 155 int[] _axis; 156 157 static immutable(int[]) jid = 158 [ 159 JOYSTICKID1, 160 JOYSTICKID2 161 ]; 162 163 static immutable(int[]) jbuttondown = 164 [ 165 MM_JOY1BUTTONDOWN, 166 MM_JOY2BUTTONDOWN 167 ]; 168 169 static immutable(int[]) jbuttonup = 170 [ 171 MM_JOY1BUTTONUP, 172 MM_JOY2BUTTONUP 173 ]; 174 175 static immutable(int[]) jmove = 176 [ 177 MM_JOY1MOVE, 178 MM_JOY2MOVE 179 ]; 180 181 static immutable defAxisMin = -32768; 182 static immutable defAxisMax = 32767; 183 static immutable defAxisThreshold = (defAxisMax - defAxisMin) / 256; 184 185 @safe: 186 this(int id, EventHandler event) 187 { 188 this.event = event; 189 this.id = id; 190 } 191 192 override: 193 @property int[] axless() 194 { 195 return axesState; 196 } 197 198 @property uint maxButtons() 199 { 200 return numButtons; 201 } 202 203 @property string name() 204 { 205 return namely; 206 } 207 208 @property bool isButtonDown() 209 { 210 if (event.currJEvent !is null) 211 return event.currJEvent.type == EventHandler.JoystickEventType.buttonPressed; 212 else 213 return false; 214 } 215 216 @property bool isButtonUp() 217 { 218 if (event.currJEvent !is null) 219 return event.currJEvent.type == EventHandler.JoystickEventType.buttonReleased; 220 else 221 return false; 222 } 223 224 @property bool isAxisMove() 225 { 226 if (event.currJEvent !is null) 227 return event.currJEvent.type == EventHandler.JoystickEventType.axisMove; 228 else 229 return false; 230 } 231 232 @property int button() 233 { 234 if (event.currJEvent !is null) 235 return event.currJEvent.value; 236 else 237 return -1; 238 } 239 } 240 241 version(Posix) 242 class Joystick : IJoystick 243 { 244 import std.stdio : File; 245 import core.sys.posix.sys.ioctl; 246 import tida.vector; 247 248 private: 249 int descriptor; 250 251 public: 252 int id; // identificator 253 string namely; 254 255 int numAxes; // Max axes 256 int numButtons; // Max buttons 257 258 int[] _axis; 259 260 // linux/joystick.h 261 enum JSIOCGAXES = _IOR!ubyte('j', 0x11); 262 enum JSIOCGBUTTONS = _IOR!ubyte('j', 0x12); 263 enum JSIOCGNAME(T) = _IOC!T(_IOC_READ, 'j', 0x13); 264 265 enum JS_EVENT_BUTTON = 0x01; /* button pressed/released */ 266 enum JS_EVENT_AXIS = 0x02; /* joystick moved */ 267 enum JS_EVENT_INIT = 0x80; /* initial state of device */ 268 269 struct js_event 270 { 271 uint time; /* event timestamp in milliseconds */ 272 short value; /* value */ 273 ubyte type; /* event type */ 274 ubyte number; /* axis/button number */ 275 276 ubyte trueType() @safe nothrow pure 277 { 278 return type & ~JS_EVENT_INIT; 279 } 280 } 281 282 js_event* currJEvent; 283 284 @safe: 285 package(tida) @property int fd() 286 { 287 return descriptor; 288 } 289 290 this(int descriptor, int id) @trusted 291 { 292 import std.conv : to; 293 294 this.descriptor = descriptor; 295 this.id = id; 296 297 char[80] __name; 298 299 ioctl(descriptor, JSIOCGAXES, &numAxes); 300 ioctl(descriptor, JSIOCGBUTTONS, &numButtons); 301 ioctl(descriptor, JSIOCGNAME!(char[80]), &__name); 302 303 namely = __name.to!string; 304 305 _axis = new int[](numAxes); 306 } 307 308 ~this() @trusted 309 { 310 import core.sys.posix.unistd; 311 312 close(descriptor); 313 descriptor = -2; 314 } 315 316 override: 317 @property int[] axless() 318 { 319 return _axis; 320 } 321 322 @property uint maxButtons() 323 { 324 return numButtons; 325 } 326 327 @property string name() 328 { 329 return namely; 330 } 331 332 @property int button() 333 { 334 if (currJEvent !is null) 335 return currJEvent.number; 336 else 337 return -1; 338 } 339 340 @property bool isButtonDown() 341 { 342 if (currJEvent !is null) 343 return currJEvent.trueType == JS_EVENT_BUTTON && currJEvent.value == 1; 344 else 345 return false; 346 } 347 348 @property bool isButtonUp() 349 { 350 if (currJEvent !is null) 351 return currJEvent.trueType == JS_EVENT_BUTTON && currJEvent.value == 0; 352 else 353 return false; 354 } 355 356 @property bool isAxisMove() 357 { 358 if (currJEvent !is null) 359 return currJEvent.trueType == JS_EVENT_AXIS; 360 else 361 return false; 362 } 363 } 364 365 /++ 366 Interface for cross-platform listening for events from the window manager. 367 +/ 368 interface IEventHandler 369 { 370 @safe: 371 /++ 372 Moves to the next event. If there are no more events, it returns false, 373 otherwise, it throws true and the programmer can safely check which event 374 s in the current queue. 375 +/ 376 bool nextEvent(); 377 378 /++ 379 Checking if any key is pressed in the current event. 380 +/ 381 bool isKeyDown(); 382 383 /++ 384 Checking if any key is released in the current event. 385 +/ 386 bool isKeyUp(); 387 388 /++ 389 Will return the key that was pressed. Returns zero if no key is pressed 390 in the current event. 391 +/ 392 @property int key(); 393 394 /++ 395 Returns the key at the moment the key was pressed, 396 otherwise it returns zero. 397 +/ 398 @property final int keyDown() 399 { 400 return isKeyDown ? key : 0; 401 } 402 403 /++ 404 Returns the key at the moment the key was released, 405 otherwise it returns zero. 406 +/ 407 @property final int keyUp() 408 { 409 return isKeyUp ? key : 0; 410 } 411 412 /++ 413 Check if the mouse button is pressed in the current event. 414 +/ 415 bool isMouseDown(); 416 417 /++ 418 Check if the mouse button is released in the current event. 419 +/ 420 bool isMouseUp(); 421 422 /++ 423 Returns the currently pressed or released mouse button. 424 +/ 425 @property MouseButton mouseButton(); 426 427 /++ 428 Returns the mouse button at the moment the key was pressed; 429 otherwise, it returns zero. 430 +/ 431 @property final MouseButton mouseDownButton() 432 { 433 return isMouseDown ? mouseButton : MouseButton.unknown; 434 } 435 436 /++ 437 Returns the mouse button at the moment the key was released; 438 otherwise, it returns zero. 439 +/ 440 @property final MouseButton mouseUpButton() 441 { 442 return isMouseUp ? mouseButton : MouseButton.unknown; 443 } 444 445 /++ 446 Returns the position of the mouse in the window. 447 +/ 448 @property int[2] mousePosition(); 449 450 /++ 451 Returns in which direction the user is turning the mouse wheel. 452 1 - down, -1 - up, 0 - does not twist. 453 454 This iteration is convenient for multiplying with some real movement coefficient. 455 +/ 456 @property int mouseWheel(); 457 458 /++ 459 Indicates whether the window has been resized in this event. 460 +/ 461 bool isResize(); 462 463 /++ 464 Returns the new size of the window 465 466 deprecated: 467 although this will already be available directly in the 468 window structure itself. 469 +/ 470 deprecated(DeprecatedMethodSize) 471 uint[2] newSizeWindow(); 472 473 /++ 474 Indicates whether the user is attempting to exit the program. 475 +/ 476 bool isQuit(); 477 478 /++ 479 Indicates whether the user has entered text information. 480 +/ 481 bool isInputText(); 482 483 /++ 484 User entered data. 485 +/ 486 @property string inputChar(); 487 488 @property wstring inputWChar(); 489 490 /++ 491 Returns an array of the interface for controlling joysticks. 492 If its length is zero, no joysticks were found. 493 494 It is checked once, if one controller has been disabled, then it is recommended 495 to zero the array as shown below and call again to rescan the joysticks. 496 --- 497 event.joysticks.length = 0; 498 --- 499 +/ 500 @property Joystick[] joysticks(); 501 502 @trusted: 503 final int opApply(scope int delegate(ref int) dg) 504 { 505 int count = 0; 506 507 while (this.nextEvent()) 508 { 509 dg(++count); 510 } 511 512 return 0; 513 } 514 } 515 516 version(Posix) 517 class EventHandler : IEventHandler 518 { 519 import x11.X, x11.Xlib, x11.Xutil; 520 import tida.window, tida.runtime; 521 522 private: 523 struct JoystickEvent 524 { 525 int id; 526 Joystick.js_event data; 527 } 528 529 tida.window.Window[] windows; 530 Atom destroyWindowEvent; 531 _XIC* ic; 532 Joystick[] _joysticks; 533 JoystickEvent[] jevents; 534 535 public: 536 XEvent event; 537 538 @trusted: 539 this(tida.window.Window window) 540 { 541 this.windows ~= window; 542 543 this.destroyWindowEvent = XInternAtom(runtime.display, "WM_DELETE_WINDOW", 0); 544 545 ic = XCreateIC( XOpenIM(runtime.display, null, null, null), 546 XNInputStyle, XIMPreeditNothing | XIMStatusNothing, 547 XNClientWindow, this.windows[0].handle, null); 548 XSetICFocus(ic); 549 XSetLocaleModifiers("@im=none"); 550 } 551 552 void appendWindow(tida.window.Window window) 553 { 554 this.windows ~= window; 555 } 556 557 @property tida.window.IWindow windowEvent() 558 { 559 foreach (window; windows) 560 { 561 if (window.handle == this.event.xany.window) 562 return window; 563 } 564 565 return null; 566 } 567 568 int joyHandle() 569 { 570 import core.sys.posix.unistd; 571 572 int count = 0; 573 foreach (ref e; _joysticks) 574 { 575 Joystick.js_event eEvent; 576 immutable bytes = read(e.fd(), &eEvent, Joystick.js_event.sizeof); 577 578 if (eEvent.type != 0 && 579 ((eEvent.type & Joystick.JS_EVENT_INIT) != Joystick.JS_EVENT_INIT)) 580 { 581 jevents ~= JoystickEvent(e.id, eEvent); 582 count++; 583 } 584 } 585 586 return count; 587 } 588 589 void validateJoysticks() 590 { 591 import std.algorithm : remove; 592 import core.sys.posix.fcntl; 593 594 foreach (size_t i, ref e; _joysticks) 595 { 596 if (fcntl(e.fd(), F_GETFD) == -1) 597 { 598 _joysticks = _joysticks.remove(i); 599 } 600 } 601 } 602 603 override: 604 bool nextEvent() 605 { 606 joyHandle(); 607 immutable pen = XPending(runtime.display); 608 609 if (pen != 0) 610 { 611 XNextEvent(runtime.display, &this.event); 612 613 return pen != 0; 614 } else 615 { 616 if (jevents.length != 0) 617 { 618 auto currEvent = &jevents[0]; 619 jevents = jevents[1 .. $]; 620 621 foreach (ref e; _joysticks) 622 { 623 if (e.id == currEvent.id) 624 { 625 e.currJEvent = &currEvent.data; 626 if (currEvent.data.trueType == Joystick.JS_EVENT_AXIS) 627 { 628 e._axis[currEvent.data.number] = e.currJEvent.value; 629 } 630 } else 631 { 632 e.currJEvent = null; 633 } 634 } 635 636 return true; 637 } else 638 { 639 foreach (ref e; _joysticks) 640 { 641 e.currJEvent = null; 642 } 643 644 return false; 645 } 646 } 647 } 648 649 bool isKeyDown() 650 { 651 return this.event.type == KeyPress; 652 } 653 654 bool isKeyUp() 655 { 656 return this.event.type == KeyRelease; 657 } 658 659 @property int key() 660 { 661 return this.event.xkey.keycode; 662 } 663 664 bool isMouseDown() 665 { 666 return this.event.type == ButtonPress; 667 } 668 669 bool isMouseUp() 670 { 671 return this.event.type == ButtonRelease; 672 } 673 674 @property MouseButton mouseButton() 675 { 676 return cast(MouseButton) this.event.xbutton.button; 677 } 678 679 @property int[2] mousePosition() @trusted 680 { 681 return [this.event.xmotion.x, this.event.xmotion.y]; 682 } 683 684 @property int mouseWheel() 685 { 686 return this.isMouseDown ? 687 (this.mouseButton == 4 ? -1 : (this.mouseButton == 5 ? 1 : 0)) : 0; 688 } 689 690 bool isResize() 691 { 692 return this.event.type == ConfigureNotify && 693 this.event.xconfigure.type == 22 && 694 !this.event.xconfigure.send_event; 695 } 696 697 uint[2] newSizeWindow() 698 { 699 XWindowAttributes attr; 700 XGetWindowAttributes( runtime.display, 701 (cast(tida.window.Window) this.windows[0]).handle, &attr); 702 703 return [attr.width, attr.height]; 704 } 705 706 bool isQuit() 707 { 708 return this.event.xclient.data.l[0] == this.destroyWindowEvent; 709 } 710 711 bool isInputText() 712 { 713 return this.isKeyDown; 714 } 715 716 @property string inputChar() 717 { 718 int count; 719 string buf = new string(20); 720 KeySym ks; 721 Status status = 0; 722 723 count = Xutf8LookupString( this.ic, cast(XKeyPressedEvent*) &this.event.xkey, 724 cast(char*) buf.ptr, 20, &ks, &status); 725 726 return buf[0 .. count]; 727 } 728 729 @property wstring inputWChar() 730 { 731 import std.utf : toUTF16; 732 733 int count; 734 string buf = new string(20); 735 KeySym ks; 736 Status status = 0; 737 738 count = Xutf8LookupString( this.ic, cast(XKeyPressedEvent*) &this.event.xkey, 739 cast(char*) buf.ptr, 20, &ks, &status); 740 741 return buf[0 .. count].toUTF16; 742 } 743 744 @property Joystick[] joysticks() 745 { 746 import core.sys.posix.fcntl; 747 import std.conv : to; 748 749 if (_joysticks.length != 0) 750 { 751 validateJoysticks(); 752 return _joysticks; 753 } 754 755 foreach (i; 0 .. 2) 756 { 757 int fd = open(("/dev/input/js" ~ i.to!string).ptr, 0); 758 if (fd == -1) 759 continue; 760 761 immutable flags = fcntl(fd, F_GETFL, 0); 762 fcntl(fd, F_SETFL, flags | O_NONBLOCK); 763 764 _joysticks ~= new Joystick(fd, i); 765 } 766 767 return _joysticks; 768 } 769 } 770 771 version(Windows) 772 class EventHandler : IEventHandler 773 { 774 import tida.window, tida.runtime; 775 import core.sys.windows.windows; 776 777 private: 778 tida.window.Window window; 779 Joystick[] _joysticks; 780 781 public: 782 MSG msg; 783 784 enum JoystickEventType 785 { 786 axisMove, 787 buttonPressed, 788 buttonReleased 789 } 790 791 enum JoystickAxis 792 { 793 X = JOY_RETURNX, 794 Y = JOY_RETURNY, 795 Z = JOY_RETURNZ, 796 R = JOY_RETURNR, 797 U = JOY_RETURNU, 798 V = JOY_RETURNV 799 } 800 801 struct JoystickEvent 802 { 803 int id; 804 JoystickEventType type; 805 int value; 806 807 JoystickAxis axis; 808 } 809 810 JoystickEvent[] jEvents; 811 JoystickEvent* currJEvent = null; 812 813 @safe: 814 this(tida.window.Window window) 815 { 816 this.window = window; 817 } 818 819 @trusted: 820 void joyPeek() 821 { 822 immutable flagsAxis = [ 823 JOY_RETURNX, 824 JOY_RETURNY, 825 JOY_RETURNZ, 826 JOY_RETURNR, 827 JOY_RETURNU, 828 JOY_RETURNV 829 ]; 830 831 foreach (ref e; _joysticks) 832 { 833 JOYINFOEX joyInfo; 834 joyInfo.dwSize = joyInfo.sizeof; 835 joyInfo.dwFlags = JOY_RETURNALL; 836 837 joyGetPosEx(Joystick.jid[e.id], &joyInfo); 838 839 immutable axisPos = [ 840 joyInfo.dwXpos, 841 joyInfo.dwYpos, 842 joyInfo.dwZpos, 843 joyInfo.dwRpos, 844 joyInfo.dwUpos, 845 joyInfo.dwVpos 846 ]; 847 848 foreach (i; 0 .. e.numAxes) 849 { 850 if (!(joyInfo.dwFlags & flagsAxis[i])) 851 continue; 852 853 immutable int value = cast(int) (cast(float) (axisPos[i]) + e.axisOffset[i] * e.axisScale[i]); 854 immutable change = (value - e._axis[i]); 855 856 if (change > -Joystick.defAxisThreshold && 857 change < Joystick.defAxisThreshold) 858 continue; 859 860 e._axis[i] = value; 861 e.axesState[i] = !(value < 300 && value > -300) ? value : 0; 862 863 JoystickEvent jevent; 864 jevent.id = e.id; 865 jevent.type = JoystickEventType.axisMove; 866 jevent.axis = cast(JoystickAxis) flagsAxis[i]; 867 jevent.value = !(value < 300 && value > -300) ? value : 0; 868 jEvents ~= jevent; 869 } 870 871 if (joyInfo.dwFlags & JOY_RETURNBUTTONS) 872 { 873 foreach (i; 0 .. e.numButtons) 874 { 875 int pressed = joyInfo.dwButtons & (1 << i); 876 877 if (pressed == 0) 878 { 879 if (1 << i in e.buttons) 880 if (e.buttons[1 << i] != 0) 881 { 882 JoystickEvent jevent; 883 jevent.id = e.id; 884 jevent.type = JoystickEventType.buttonReleased; 885 jevent.value = 1 << i; 886 jEvents ~= jevent; 887 e.buttons[1 << i] = 0; 888 } 889 890 continue; 891 } 892 893 if (1 << i in e.buttons) 894 { 895 if(e.buttons[1 << i] != 0) 896 continue; 897 } 898 899 e.buttons[1 << i] = 1; 900 JoystickEvent jevent; 901 jevent.id = e.id; 902 jevent.type = JoystickEventType.buttonPressed; 903 jevent.value = 1 << i; 904 jEvents ~= jevent; 905 } 906 } 907 } 908 } 909 910 bool nextEvent() 911 { 912 TranslateMessage(&this.msg); 913 DispatchMessage(&this.msg); 914 915 joyPeek(); 916 if (PeekMessage(&this.msg, this.window.handle, 0, 0, PM_REMOVE) == 0) 917 { 918 if (jEvents.length == 0) 919 { 920 currJEvent = null; 921 return false; 922 } 923 else 924 { 925 currJEvent = &jEvents[0]; 926 jEvents = jEvents[1 .. $]; 927 928 return true; 929 } 930 } else 931 { 932 return true; 933 } 934 } 935 936 bool isKeyDown() 937 { 938 return this.msg.message == WM_KEYDOWN; 939 } 940 941 bool isKeyUp() 942 { 943 return this.msg.message == WM_KEYUP; 944 } 945 946 @property int key() 947 { 948 return cast(int) this.msg.wParam; 949 } 950 951 bool isMouseDown() 952 { 953 return this.msg.message == WM_LBUTTONDOWN || 954 this.msg.message == WM_RBUTTONDOWN || 955 this.msg.message == WM_MBUTTONDOWN; 956 } 957 958 bool isMouseUp() 959 { 960 return this.msg.message == WM_LBUTTONUP || 961 this.msg.message == WM_RBUTTONUP || 962 this.msg.message == WM_MBUTTONUP; 963 } 964 965 @property MouseButton mouseButton() 966 { 967 if (this.msg.message == WM_LBUTTONUP || this.msg.message == WM_LBUTTONDOWN) 968 return MouseButton.left; 969 970 if (this.msg.message == WM_RBUTTONUP || this.msg.message == WM_RBUTTONDOWN) 971 return MouseButton.right; 972 973 if (this.msg.message == WM_MBUTTONUP || this.msg.message == WM_MBUTTONDOWN) 974 return MouseButton.middle; 975 976 return MouseButton.unknown; 977 } 978 979 @property int[2] mousePosition() 980 { 981 POINT p; 982 GetCursorPos(&p); 983 ScreenToClient((cast(Window) this.window).handle, &p); 984 985 return [p.x, p.y]; 986 } 987 988 @property int mouseWheel() 989 { 990 if (this.msg.message != WM_MOUSEWHEEL) return 0; 991 992 return (cast(int) this.msg.wParam) > 0 ? -1 : 1; 993 } 994 995 bool isResize() 996 { 997 bool isResize = window.isResize; 998 window.isResize = false; 999 1000 return isResize; 1001 } 1002 1003 uint[2] newSizeWindow() 1004 { 1005 RECT rect; 1006 GetWindowRect((cast(Window) this.window).handle, &rect); 1007 1008 return [rect.right, rect.bottom]; 1009 } 1010 1011 bool isQuit() 1012 { 1013 return window.isClose; 1014 } 1015 1016 bool isInputText() 1017 { 1018 return this.msg.message == WM_CHAR; 1019 } 1020 1021 string inputChar() 1022 { 1023 import std.utf : toUTF8; 1024 1025 wstring text = []; 1026 text = [cast(wchar) msg.wParam]; 1027 1028 string utftext = text.toUTF8; 1029 1030 return [utftext[0]]; 1031 } 1032 1033 wstring inputWChar() 1034 { 1035 return [cast(wchar) msg.wParam]; 1036 } 1037 1038 @property Joystick[] joysticks() @trusted 1039 { 1040 import std.conv : to; 1041 1042 if (_joysticks.length != 0) 1043 return _joysticks; 1044 1045 immutable numDevs = joyGetNumDevs(); 1046 if (numDevs == 0) 1047 return []; 1048 1049 foreach (i; 0 .. 2) 1050 { 1051 JOYINFOEX jInfo; 1052 JOYCAPS jCaps; 1053 1054 if (joyGetPosEx(Joystick.jid[i], &jInfo) == JOYERR_UNPLUGGED) 1055 { 1056 continue; 1057 } 1058 1059 if (joySetCapture(window.handle, Joystick.jid[i], 0, true)) 1060 { 1061 continue; 1062 } 1063 1064 joyGetDevCaps(Joystick.jid[i], &jCaps, jCaps.sizeof); 1065 1066 auto jj = new Joystick(i, this); 1067 jj.numAxes = jCaps.wNumAxes; 1068 jj.numButtons = jCaps.wNumButtons; 1069 jj.axesState = new int[](jj.numAxes); 1070 jj.namely = jCaps.szPname.to!string; 1071 1072 immutable wAxisMin = [ 1073 jCaps.wXmin, 1074 jCaps.wYmin, 1075 jCaps.wZmin, 1076 jCaps.wRmin, 1077 jCaps.wUmin, 1078 jCaps.wVmin 1079 ]; 1080 1081 immutable wAxisMax = [ 1082 jCaps.wXmax, 1083 jCaps.wYmax, 1084 jCaps.wZmax, 1085 jCaps.wRmax, 1086 jCaps.wUmax, 1087 jCaps.wVmax 1088 ]; 1089 1090 foreach (j; 0 .. jj.numAxes) 1091 { 1092 jj._axis ~= 0; 1093 jj.axisMin ~= wAxisMin[i]; 1094 jj.axisMax ~= wAxisMax[i]; 1095 jj.axisOffset ~= Joystick.defAxisMin - wAxisMin[i]; 1096 jj.axisScale ~= (cast(float) Joystick.defAxisMax - cast(float) (Joystick.defAxisMin)) / (cast(float) wAxisMax[i] - cast(float) wAxisMin[i]); 1097 } 1098 1099 _joysticks ~= jj; 1100 } 1101 1102 return _joysticks; 1103 } 1104 } 1105 1106 version(Posix)/// 1107 static enum Key 1108 { 1109 Escape = 9, 1110 F1 = 67, 1111 F2 = 68, 1112 F3 = 69, 1113 F4 = 70, 1114 F5 = 71, 1115 F6 = 72, 1116 F7 = 73, 1117 F8 = 74, 1118 F9 = 75, 1119 F10 = 76, 1120 F11 = 95, 1121 F12 = 96, 1122 PrintScrn = 111, 1123 ScrollLock = 78, 1124 Pause = 110, 1125 Backtick = 49, 1126 K1 = 10, 1127 K2 = 11, 1128 K3 = 12, 1129 K4 = 13, 1130 K5 = 14, 1131 K6 = 15, 1132 K7 = 16, 1133 K8 = 17, 1134 K9 = 18, 1135 K0 = 19, 1136 Minus = 20, 1137 Equal = 21, 1138 Backspace = 22, 1139 Insert = 106, 1140 Home = 97, 1141 PageUp = 99, 1142 NumLock = 77, 1143 KPSlash = 112, 1144 KPStar = 63, 1145 KPMinus = 82, 1146 Tab = 23, 1147 Q = 24, 1148 W = 25, 1149 E = 26, 1150 R = 27, 1151 T = 28, 1152 Y = 29, 1153 U = 30, 1154 I = 31, 1155 O = 32, 1156 P = 33, 1157 1158 SqBrackLeft = 34, 1159 SqBrackRight = 35, 1160 SquareBracketLeft = 34, 1161 SquareBracketRight = 35, 1162 1163 Return = 36, 1164 Delete = 107, 1165 End = 103, 1166 PageDown = 105, 1167 1168 KP7 = 79, 1169 KP8 = 80, 1170 KP9 = 81, 1171 1172 CapsLock = 66, 1173 A = 38, 1174 S = 39, 1175 D = 40, 1176 F = 41, 1177 G = 42, 1178 H = 43, 1179 J = 44, 1180 K = 45, 1181 L = 46, 1182 Semicolons = 47, 1183 Apostrophe = 48, 1184 1185 KP4 = 83, 1186 KP5 = 84, 1187 KP6 = 85, 1188 1189 ShiftLeft = 50, 1190 International = 94, 1191 1192 Z = 52, 1193 X = 53, 1194 C = 54, 1195 V = 55, 1196 B = 56, 1197 N = 57, 1198 M = 58, 1199 Comma = 59, 1200 Point = 60, 1201 Slash = 61, 1202 1203 ShiftRight = 62, 1204 1205 BackSlash = 51, 1206 Up = 111, 1207 1208 KP1 = 87, 1209 KP2 = 88, 1210 KP3 = 89, 1211 1212 KPEnter = 108, 1213 CtrlLeft = 37, 1214 SuperLeft = 115, 1215 AltLeft = 64, 1216 Space = 65, 1217 AltRight = 113, 1218 LogoRight = 116, 1219 Menu = 117, 1220 CtrlRight = 109, 1221 Left = 113, 1222 Down = 116, 1223 Right = 114, 1224 KP0 = 90, 1225 KPPoint = 91 1226 } 1227 1228 version(Windows)/// 1229 static enum Key 1230 { 1231 Escape = 0x1B, 1232 F1 = 0x70, 1233 F2 = 0x71, 1234 F3 = 0x72, 1235 F4 = 0x73, 1236 F5 = 0x74, 1237 F6 = 0x75, 1238 F7 = 0x76, 1239 F8 = 0x77, 1240 F9 = 0x78, 1241 F10 = 0x79, 1242 F11 = 0x7A, 1243 F12 = 0x7B, 1244 PrintScrn = 0x2A, 1245 ScrollLock = 0x91, 1246 Pause = 0x13, 1247 Backtick = 0xC0, 1248 K1 = 0x31, 1249 K2 = 0x32, 1250 K3 = 0x33, 1251 K4 = 0x34, 1252 K5 = 0x35, 1253 K6 = 0x36, 1254 K7 = 0x37, 1255 K8 = 0x38, 1256 K9 = 0x39, 1257 K0 = 0x30, 1258 Minus = 0xBD, 1259 Equal = 0xBB, 1260 Backspace = 0x08, 1261 Insert = 0x2D, 1262 Home = 0x24, 1263 PageUp = 0x21, 1264 NumLock = 0x90, 1265 KPSlash = 0x6F, 1266 KPStar = 0xBB, 1267 KPMinus = 0xBD, 1268 Tab = 0x09, 1269 Q = 0x51, 1270 W = 0x57, 1271 E = 0x45, 1272 R = 0x52, 1273 T = 0x54, 1274 Y = 0x59, 1275 U = 0x55, 1276 I = 0x49, 1277 O = 0x4F, 1278 P = 0x50, 1279 1280 SqBrackLeft = 0xDB, 1281 SqBrackRight = 0xDD, 1282 SquareBracketLeft = 0x30, 1283 SquareBracketRight = 0xBD, 1284 1285 Return = 0x0D, 1286 Delete = 0x2E, 1287 End = 0x23, 1288 PageDown = 0x22, 1289 1290 KP7 = 0x67, 1291 KP8 = 0x68, 1292 KP9 = 0x69, 1293 1294 CapsLock = 0x14, 1295 A = 0x41, 1296 S = 0x53, 1297 D = 0x44, 1298 F = 0x46, 1299 G = 0x47, 1300 H = 0x48, 1301 J = 0x4A, 1302 K = 0x4B, 1303 L = 0x4C, 1304 Semicolons = 0xBA, 1305 Apostrophe = 0xBF, 1306 1307 KP4 = 0x64, 1308 KP5 = 0x65, 1309 KP6 = 0x66, 1310 1311 ShiftLeft = 0xA0, 1312 International = 0xA4, 1313 1314 Z = 0x5A, 1315 X = 0x58, 1316 C = 0x43, 1317 V = 0x56, 1318 B = 0x42, 1319 N = 0x4E, 1320 M = 0x4D, 1321 Comma = 0xBC, 1322 Point = 0xBE, 1323 Slash = 0xBF, 1324 1325 ShiftRight = 0xA1, 1326 1327 BackSlash = 0xE2, 1328 Up = 0x26, 1329 1330 KP1 = 0x61, 1331 KP2 = 0x62, 1332 KP3 = 0x63, 1333 1334 KPEnter = 0x6A, 1335 CtrlLeft = 0xA2, 1336 SuperLeft = 0xA4, 1337 AltLeft = 0xA4, 1338 Space = 0x20, 1339 AltRight = 0xA5, 1340 SuperRight = 0xA5, 1341 Menu = 0, 1342 CtrlRight = 0xA3, 1343 Left = 0x25, 1344 Down = 0x28, 1345 Right = 0x27, 1346 KP0 = 0x60, 1347 KPPoint = 0x6F 1348 }