1 /// Translated from C to D 2 module glfw3.input; 3 4 extern(C): @nogc: nothrow: __gshared: 5 import core.stdc.config: c_long, c_ulong; 6 7 //======================================================================== 8 // GLFW 3.3 - www.glfw.org 9 //------------------------------------------------------------------------ 10 // Copyright (c) 2002-2006 Marcus Geelnard 11 // Copyright (c) 2006-2019 Camilla Löwy <elmindreda@glfw.org> 12 // 13 // This software is provided 'as-is', without any express or implied 14 // warranty. In no event will the authors be held liable for any damages 15 // arising from the use of this software. 16 // 17 // Permission is granted to anyone to use this software for any purpose, 18 // including commercial applications, and to alter it and redistribute it 19 // freely, subject to the following restrictions: 20 // 21 // 1. The origin of this software must not be misrepresented; you must not 22 // claim that you wrote the original software. If you use this software 23 // in a product, an acknowledgment in the product documentation would 24 // be appreciated but is not required. 25 // 26 // 2. Altered source versions must be plainly marked as such, and must not 27 // be misrepresented as being the original software. 28 // 29 // 3. This notice may not be removed or altered from any source 30 // distribution. 31 // 32 //======================================================================== 33 // Please use C89 style variable declarations in this file because VS 2010 34 //======================================================================== 35 36 import glfw3.internal; 37 38 import core.stdc.assert_; 39 import core.stdc.math; 40 import core.stdc.stdlib; 41 import core.stdc.string; 42 43 // Internal key state used for sticky keys 44 enum _GLFW_STICK = 3; 45 46 // Internal constants for gamepad mapping source types 47 enum _GLFW_JOYSTICK_AXIS = 1; 48 enum _GLFW_JOYSTICK_BUTTON = 2; 49 enum _GLFW_JOYSTICK_HATBIT = 3; 50 51 // Finds a mapping based on joystick GUID 52 // 53 private _GLFWmapping* findMapping(const(char)* guid) { 54 int i; 55 56 for (i = 0; i < _glfw.mappingCount; i++) 57 { 58 if (strcmp(_glfw.mappings[i].guid.ptr, guid) == 0) 59 return _glfw.mappings + i; 60 } 61 62 return null; 63 } 64 65 // Checks whether a gamepad mapping element is present in the hardware 66 // 67 private GLFWbool isValidElementForJoystick(const(_GLFWmapelement)* e, const(_GLFWjoystick)* js) { 68 if (e.type == _GLFW_JOYSTICK_HATBIT && (e.index >> 4) >= js.hatCount) 69 return GLFW_FALSE; 70 else if (e.type == _GLFW_JOYSTICK_BUTTON && e.index >= js.buttonCount) 71 return GLFW_FALSE; 72 else if (e.type == _GLFW_JOYSTICK_AXIS && e.index >= js.axisCount) 73 return GLFW_FALSE; 74 75 return GLFW_TRUE; 76 } 77 78 // Finds a mapping based on joystick GUID and verifies element indices 79 // 80 private _GLFWmapping* findValidMapping(const(_GLFWjoystick)* js) { 81 _GLFWmapping* mapping = findMapping(js.guid.ptr); 82 if (mapping) 83 { 84 int i; 85 86 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) 87 { 88 if (!isValidElementForJoystick(mapping.buttons.ptr + i, js)) 89 { 90 _glfwInputError(GLFW_INVALID_VALUE, 91 "Invalid button in gamepad mapping %s (%s)", 92 mapping.guid.ptr, 93 mapping.name.ptr); 94 return null; 95 } 96 } 97 98 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) 99 { 100 if (!isValidElementForJoystick(mapping.axes.ptr + i, js)) 101 { 102 _glfwInputError(GLFW_INVALID_VALUE, 103 "Invalid axis in gamepad mapping %s (%s)", 104 mapping.guid.ptr, 105 mapping.name.ptr); 106 return null; 107 } 108 } 109 } 110 111 return mapping; 112 } 113 114 // Parses an SDL_GameControllerDB line and adds it to the mapping list 115 // 116 private GLFWbool parseMapping(_GLFWmapping* mapping, const(char)* string) { 117 const(char)* c = string; 118 size_t i;size_t length; 119 static struct Field { 120 const(char)* name; 121 _GLFWmapelement* element; 122 } 123 Field[22] fields = [ 124 Field("platform", null), 125 Field("a", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_A), 126 Field("b", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_B), 127 Field("x", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_X), 128 Field("y", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_Y), 129 Field("back", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_BACK), 130 Field("start", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_START), 131 Field("guide", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_GUIDE), 132 Field("leftshoulder", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER), 133 Field("rightshoulder", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER), 134 Field("leftstick", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_LEFT_THUMB), 135 Field("rightstick", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB), 136 Field("dpup", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_UP), 137 Field("dpright", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT), 138 Field("dpdown", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_DOWN), 139 Field("dpleft", mapping.buttons.ptr + GLFW_GAMEPAD_BUTTON_DPAD_LEFT), 140 Field("lefttrigger", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER), 141 Field("righttrigger", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER), 142 Field("leftx", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_X), 143 Field("lefty", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_LEFT_Y), 144 Field("rightx", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_X), 145 Field("righty", mapping.axes.ptr + GLFW_GAMEPAD_AXIS_RIGHT_Y), 146 ]; 147 148 length = strcspn(c, ","); 149 if (length != 32 || c[length] != ',') 150 { 151 _glfwInputError(GLFW_INVALID_VALUE, null); 152 return GLFW_FALSE; 153 } 154 155 memcpy(mapping.guid.ptr, c, length); 156 c += length + 1; 157 158 length = strcspn(c, ","); 159 if (length >= typeof(mapping.name).sizeof || c[length] != ',') 160 { 161 _glfwInputError(GLFW_INVALID_VALUE, null); 162 return GLFW_FALSE; 163 } 164 165 memcpy(mapping.name.ptr, c, length); 166 c += length + 1; 167 168 while (*c) 169 { 170 // TODO: Implement output modifiers 171 if (*c == '+' || *c == '-') 172 return GLFW_FALSE; 173 174 for (i = 0; i < fields.sizeof / typeof(fields[0]).sizeof; i++) 175 { 176 length = strlen(fields[i].name); 177 if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':') 178 continue; 179 180 c += length + 1; 181 182 if (fields[i].element) 183 { 184 _GLFWmapelement* e = fields[i].element; 185 byte minimum = -1; 186 byte maximum = 1; 187 188 if (*c == '+') 189 { 190 minimum = 0; 191 c += 1; 192 } 193 else if (*c == '-') 194 { 195 maximum = 0; 196 c += 1; 197 } 198 199 if (*c == 'a') 200 e.type = _GLFW_JOYSTICK_AXIS; 201 else if (*c == 'b') 202 e.type = _GLFW_JOYSTICK_BUTTON; 203 else if (*c == 'h') 204 e.type = _GLFW_JOYSTICK_HATBIT; 205 else 206 break; 207 208 if (e.type == _GLFW_JOYSTICK_HATBIT) 209 { 210 const c_ulong hat = strtoul(c + 1, &c, 10); 211 const c_ulong bit = strtoul(c + 1, &c, 10); 212 e.index = cast(ubyte) ((hat << 4) | bit); 213 } 214 else 215 e.index = cast(ubyte) strtoul(c + 1, &c, 10); 216 217 if (e.type == _GLFW_JOYSTICK_AXIS) 218 { 219 e.axisScale = 2 / (maximum - minimum); 220 e.axisOffset = cast(byte) -(maximum + minimum); 221 222 if (*c == '~') 223 { 224 e.axisScale = cast(byte) -cast(int)e.axisScale; 225 e.axisOffset = cast(byte) -cast(int)e.axisOffset; 226 } 227 } 228 } 229 else 230 { 231 length = strlen(_GLFW_PLATFORM_MAPPING_NAME); 232 if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0) 233 return GLFW_FALSE; 234 } 235 236 break; 237 } 238 239 c += strcspn(c, ","); 240 c += strspn(c, ","); 241 } 242 243 for (i = 0; i < 32; i++) 244 { 245 if (mapping.guid[i] >= 'A' && mapping.guid[i] <= 'F') 246 mapping.guid[i] += 'a' - 'A'; 247 } 248 249 _glfwPlatformUpdateGamepadGUID(mapping.guid.ptr); 250 return GLFW_TRUE; 251 } 252 253 254 ////////////////////////////////////////////////////////////////////////// 255 ////// GLFW event API ////// 256 ////////////////////////////////////////////////////////////////////////// 257 258 // Notifies shared code of a physical key event 259 // 260 void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods) { 261 if (key >= 0 && key <= GLFW_KEY_LAST) 262 { 263 GLFWbool repeated = GLFW_FALSE; 264 265 if (action == GLFW_RELEASE && window.keys[key] == GLFW_RELEASE) 266 return; 267 268 if (action == GLFW_PRESS && window.keys[key] == GLFW_PRESS) 269 repeated = GLFW_TRUE; 270 271 if (action == GLFW_RELEASE && window.stickyKeys) 272 window.keys[key] = _GLFW_STICK; 273 else 274 window.keys[key] = cast(char) action; 275 276 if (repeated) 277 action = GLFW_REPEAT; 278 } 279 280 if (!window.lockKeyMods) 281 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); 282 283 if (window.callbacks.key) 284 window.callbacks.key(cast(GLFWwindow*) window, key, scancode, action, mods); 285 } 286 287 // Notifies shared code of a Unicode codepoint input event 288 // The 'plain' parameter determines whether to emit a regular character event 289 // 290 void _glfwInputChar(_GLFWwindow* window, uint codepoint, int mods, GLFWbool plain) { 291 if (codepoint < 32 || (codepoint > 126 && codepoint < 160)) 292 return; 293 294 if (!window.lockKeyMods) 295 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); 296 297 if (window.callbacks.charmods) 298 window.callbacks.charmods(cast(GLFWwindow*) window, codepoint, mods); 299 300 if (plain) 301 { 302 if (window.callbacks.character) 303 window.callbacks.character(cast(GLFWwindow*) window, codepoint); 304 } 305 } 306 307 // Notifies shared code of a scroll event 308 // 309 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) { 310 if (window.callbacks.scroll) 311 window.callbacks.scroll(cast(GLFWwindow*) window, xoffset, yoffset); 312 } 313 314 // Notifies shared code of a mouse button click event 315 // 316 void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) { 317 if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST) 318 return; 319 320 if (!window.lockKeyMods) 321 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); 322 323 if (action == GLFW_RELEASE && window.stickyMouseButtons) 324 window.mouseButtons[button] = _GLFW_STICK; 325 else 326 window.mouseButtons[button] = cast(char) action; 327 328 if (window.callbacks.mouseButton) 329 window.callbacks.mouseButton(cast(GLFWwindow*) window, button, action, mods); 330 } 331 332 // Notifies shared code of a cursor motion event 333 // The position is specified in content area relative screen coordinates 334 // 335 void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) { 336 if (window.virtualCursorPosX == xpos && window.virtualCursorPosY == ypos) 337 return; 338 339 window.virtualCursorPosX = xpos; 340 window.virtualCursorPosY = ypos; 341 342 if (window.callbacks.cursorPos) 343 window.callbacks.cursorPos(cast(GLFWwindow*) window, xpos, ypos); 344 } 345 346 // Notifies shared code of a cursor enter/leave event 347 // 348 void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) { 349 if (window.callbacks.cursorEnter) 350 window.callbacks.cursorEnter(cast(GLFWwindow*) window, entered); 351 } 352 353 // Notifies shared code of files or directories dropped on a window 354 // 355 void _glfwInputDrop(_GLFWwindow* window, int count, const(char)** paths) { 356 if (window.callbacks.drop) 357 window.callbacks.drop(cast(GLFWwindow*) window, count, paths); 358 } 359 360 // Notifies shared code of a joystick connection or disconnection 361 // 362 void _glfwInputJoystick(_GLFWjoystick* js, int event) { 363 const(int) jid = cast(int) (js - _glfw.joysticks.ptr); 364 365 if (_glfw.callbacks.joystick) 366 _glfw.callbacks.joystick(jid, event); 367 } 368 369 // Notifies shared code of the new value of a joystick axis 370 // 371 void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) { 372 js.axes[axis] = value; 373 } 374 375 // Notifies shared code of the new value of a joystick button 376 // 377 void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) { 378 js.buttons[button] = value; 379 } 380 381 // Notifies shared code of the new value of a joystick hat 382 // 383 void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) { 384 const(int) base = js.buttonCount + hat * 4; 385 386 js.buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; 387 js.buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; 388 js.buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE; 389 js.buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; 390 391 js.hats[hat] = value; 392 } 393 394 395 ////////////////////////////////////////////////////////////////////////// 396 ////// GLFW internal API ////// 397 ////////////////////////////////////////////////////////////////////////// 398 399 // Returns an available joystick object with arrays and name allocated 400 // 401 _GLFWjoystick* _glfwAllocJoystick(const(char)* name, const(char)* guid, int axisCount, int buttonCount, int hatCount) { 402 int jid; 403 _GLFWjoystick* js; 404 405 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) 406 { 407 if (!_glfw.joysticks[jid].present) 408 break; 409 } 410 411 if (jid > GLFW_JOYSTICK_LAST) 412 return null; 413 414 js = _glfw.joysticks.ptr + jid; 415 js.present = GLFW_TRUE; 416 js.name = _glfw_strdup(name); 417 js.axes = cast(float*) calloc(axisCount, float.sizeof); 418 js.buttons = cast(ubyte*) calloc(buttonCount + cast(size_t) hatCount * 4, 1); 419 js.hats = cast(ubyte*) calloc(hatCount, 1); 420 js.axisCount = axisCount; 421 js.buttonCount = buttonCount; 422 js.hatCount = hatCount; 423 424 strncpy(js.guid.ptr, guid, js.guid.length - 1); 425 js.mapping = findValidMapping(js); 426 427 return js; 428 } 429 430 // Frees arrays and name and flags the joystick object as unused 431 // 432 void _glfwFreeJoystick(_GLFWjoystick* js) { 433 free(js.name); 434 free(js.axes); 435 free(js.buttons); 436 free(js.hats); 437 memset(js, 0, _GLFWjoystick.sizeof); 438 } 439 440 // Center the cursor in the content area of the specified window 441 // 442 void _glfwCenterCursorInContentArea(_GLFWwindow* window) { 443 int width;int height; 444 445 _glfwPlatformGetWindowSize(window, &width, &height); 446 _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0); 447 } 448 449 450 ////////////////////////////////////////////////////////////////////////// 451 ////// GLFW public API ////// 452 ////////////////////////////////////////////////////////////////////////// 453 454 int glfwGetInputMode(GLFWwindow* handle, int mode) { 455 _GLFWwindow* window = cast(_GLFWwindow*) handle; 456 assert(window != null); 457 458 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); 459 460 switch (mode) 461 { 462 case GLFW_CURSOR: 463 return window.cursorMode; 464 case GLFW_STICKY_KEYS: 465 return window.stickyKeys; 466 case GLFW_STICKY_MOUSE_BUTTONS: 467 return window.stickyMouseButtons; 468 case GLFW_LOCK_KEY_MODS: 469 return window.lockKeyMods; 470 case GLFW_RAW_MOUSE_MOTION: 471 return window.rawMouseMotion; 472 default: break; 473 } 474 475 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); 476 return 0; 477 } 478 479 void glfwSetInputMode(GLFWwindow* handle, int mode, int value) { 480 _GLFWwindow* window = cast(_GLFWwindow*) handle; 481 assert(window != null); 482 483 mixin(_GLFW_REQUIRE_INIT); 484 485 if (mode == GLFW_CURSOR) 486 { 487 if (value != GLFW_CURSOR_NORMAL && 488 value != GLFW_CURSOR_HIDDEN && 489 value != GLFW_CURSOR_DISABLED) 490 { 491 _glfwInputError(GLFW_INVALID_ENUM, 492 "Invalid cursor mode 0x%08X", 493 value); 494 return; 495 } 496 497 if (window.cursorMode == value) 498 return; 499 500 window.cursorMode = value; 501 502 _glfwPlatformGetCursorPos(window, 503 &window.virtualCursorPosX, 504 &window.virtualCursorPosY); 505 _glfwPlatformSetCursorMode(window, value); 506 } 507 else if (mode == GLFW_STICKY_KEYS) 508 { 509 value = value ? GLFW_TRUE : GLFW_FALSE; 510 if (window.stickyKeys == value) 511 return; 512 513 if (!value) 514 { 515 int i; 516 517 // Release all sticky keys 518 for (i = 0; i <= GLFW_KEY_LAST; i++) 519 { 520 if (window.keys[i] == _GLFW_STICK) 521 window.keys[i] = GLFW_RELEASE; 522 } 523 } 524 525 window.stickyKeys = value; 526 } 527 else if (mode == GLFW_STICKY_MOUSE_BUTTONS) 528 { 529 value = value ? GLFW_TRUE : GLFW_FALSE; 530 if (window.stickyMouseButtons == value) 531 return; 532 533 if (!value) 534 { 535 int i; 536 537 // Release all sticky mouse buttons 538 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) 539 { 540 if (window.mouseButtons[i] == _GLFW_STICK) 541 window.mouseButtons[i] = GLFW_RELEASE; 542 } 543 } 544 545 window.stickyMouseButtons = value; 546 } 547 else if (mode == GLFW_LOCK_KEY_MODS) 548 { 549 window.lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; 550 } 551 else if (mode == GLFW_RAW_MOUSE_MOTION) 552 { 553 if (!_glfwPlatformRawMouseMotionSupported()) 554 { 555 _glfwInputError(GLFW_PLATFORM_ERROR, 556 "Raw mouse motion is not supported on this system"); 557 return; 558 } 559 560 value = value ? GLFW_TRUE : GLFW_FALSE; 561 if (window.rawMouseMotion == value) 562 return; 563 564 window.rawMouseMotion = value; 565 _glfwPlatformSetRawMouseMotion(window, value); 566 } 567 else 568 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); 569 } 570 571 int glfwRawMouseMotionSupported() { 572 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 573 return _glfwPlatformRawMouseMotionSupported(); 574 } 575 576 const(char)* glfwGetKeyName(int key, int scancode) { 577 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 578 579 if (key != GLFW_KEY_UNKNOWN) 580 { 581 if (key != GLFW_KEY_KP_EQUAL && 582 (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && 583 (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) 584 { 585 return null; 586 } 587 588 scancode = _glfwPlatformGetKeyScancode(key); 589 } 590 591 return _glfwPlatformGetScancodeName(scancode); 592 } 593 594 int glfwGetKeyScancode(int key) { 595 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"-1"); 596 597 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) 598 { 599 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); 600 return GLFW_RELEASE; 601 } 602 603 return _glfwPlatformGetKeyScancode(key); 604 } 605 606 int glfwGetKey(GLFWwindow* handle, int key) { 607 _GLFWwindow* window = cast(_GLFWwindow*) handle; 608 assert(window != null); 609 610 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_RELEASE"); 611 612 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) 613 { 614 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); 615 return GLFW_RELEASE; 616 } 617 618 if (window.keys[key] == _GLFW_STICK) 619 { 620 // Sticky mode: release key now 621 window.keys[key] = GLFW_RELEASE; 622 return GLFW_PRESS; 623 } 624 625 return cast(int) window.keys[key]; 626 } 627 628 int glfwGetMouseButton(GLFWwindow* handle, int button) { 629 _GLFWwindow* window = cast(_GLFWwindow*) handle; 630 assert(window != null); 631 632 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_RELEASE"); 633 634 if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) 635 { 636 _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); 637 return GLFW_RELEASE; 638 } 639 640 if (window.mouseButtons[button] == _GLFW_STICK) 641 { 642 // Sticky mode: release mouse button now 643 window.mouseButtons[button] = GLFW_RELEASE; 644 return GLFW_PRESS; 645 } 646 647 return cast(int) window.mouseButtons[button]; 648 } 649 650 void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) { 651 _GLFWwindow* window = cast(_GLFWwindow*) handle; 652 assert(window != null); 653 654 if (xpos) 655 *xpos = 0; 656 if (ypos) 657 *ypos = 0; 658 659 mixin(_GLFW_REQUIRE_INIT); 660 661 if (window.cursorMode == GLFW_CURSOR_DISABLED) 662 { 663 if (xpos) 664 *xpos = window.virtualCursorPosX; 665 if (ypos) 666 *ypos = window.virtualCursorPosY; 667 } 668 else 669 _glfwPlatformGetCursorPos(window, xpos, ypos); 670 } 671 672 void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) { 673 _GLFWwindow* window = cast(_GLFWwindow*) handle; 674 assert(window != null); 675 676 mixin(_GLFW_REQUIRE_INIT); 677 678 if (xpos != xpos || xpos < -double.max || xpos > double.max || 679 ypos != ypos || ypos < -double.max || ypos > double.max) 680 { 681 _glfwInputError(GLFW_INVALID_VALUE, 682 "Invalid cursor position %f %f", 683 xpos, ypos); 684 return; 685 } 686 687 if (!_glfwPlatformWindowFocused(window)) 688 return; 689 690 if (window.cursorMode == GLFW_CURSOR_DISABLED) 691 { 692 // Only update the accumulated position if the cursor is disabled 693 window.virtualCursorPosX = xpos; 694 window.virtualCursorPosY = ypos; 695 } 696 else 697 { 698 // Update system cursor position 699 _glfwPlatformSetCursorPos(window, xpos, ypos); 700 } 701 } 702 703 GLFWcursor* glfwCreateCursor(const(GLFWimage)* image, int xhot, int yhot) { 704 _GLFWcursor* cursor; 705 706 assert(image != null); 707 708 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 709 710 cursor = cast(_GLFWcursor*) calloc(1, _GLFWcursor.sizeof); 711 cursor.next = _glfw.cursorListHead; 712 _glfw.cursorListHead = cursor; 713 714 if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot)) 715 { 716 glfwDestroyCursor(cast(GLFWcursor*) cursor); 717 return null; 718 } 719 720 return cast(GLFWcursor*) cursor; 721 } 722 723 GLFWcursor* glfwCreateStandardCursor(int shape) { 724 _GLFWcursor* cursor; 725 726 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 727 728 if (shape != GLFW_ARROW_CURSOR && 729 shape != GLFW_IBEAM_CURSOR && 730 shape != GLFW_CROSSHAIR_CURSOR && 731 shape != GLFW_HAND_CURSOR && 732 shape != GLFW_HRESIZE_CURSOR && 733 shape != GLFW_VRESIZE_CURSOR) 734 { 735 _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); 736 return null; 737 } 738 739 cursor = cast(_GLFWcursor*) calloc(1, _GLFWcursor.sizeof); 740 cursor.next = _glfw.cursorListHead; 741 _glfw.cursorListHead = cursor; 742 743 if (!_glfwPlatformCreateStandardCursor(cursor, shape)) 744 { 745 glfwDestroyCursor(cast(GLFWcursor*) cursor); 746 return null; 747 } 748 749 return cast(GLFWcursor*) cursor; 750 } 751 752 void glfwDestroyCursor(GLFWcursor* handle) { 753 _GLFWcursor* cursor = cast(_GLFWcursor*) handle; 754 755 mixin(_GLFW_REQUIRE_INIT); 756 757 if (cursor == null) 758 return; 759 760 // Make sure the cursor is not being used by any window 761 { 762 _GLFWwindow* window; 763 764 for (window = _glfw.windowListHead; window; window = window.next) 765 { 766 if (window.cursor == cursor) 767 glfwSetCursor(cast(GLFWwindow*) window, null); 768 } 769 } 770 771 _glfwPlatformDestroyCursor(cursor); 772 773 // Unlink cursor from global linked list 774 { 775 _GLFWcursor** prev = &_glfw.cursorListHead; 776 777 while (*prev != cursor) 778 prev = &((*prev).next); 779 780 *prev = cursor.next; 781 } 782 783 free(cursor); 784 } 785 786 void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) { 787 _GLFWwindow* window = cast(_GLFWwindow*) windowHandle; 788 _GLFWcursor* cursor = cast(_GLFWcursor*) cursorHandle; 789 assert(window != null); 790 791 mixin(_GLFW_REQUIRE_INIT); 792 793 window.cursor = cursor; 794 795 _glfwPlatformSetCursor(window, cursor); 796 } 797 798 GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) { 799 _GLFWwindow* window = cast(_GLFWwindow*) handle; 800 assert(window != null); 801 802 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 803 _GLFW_SWAP_POINTERS(window.callbacks.key, cbfun); 804 return cbfun; 805 } 806 807 GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) { 808 _GLFWwindow* window = cast(_GLFWwindow*) handle; 809 assert(window != null); 810 811 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 812 _GLFW_SWAP_POINTERS(window.callbacks.character, cbfun); 813 return cbfun; 814 } 815 816 GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) { 817 _GLFWwindow* window = cast(_GLFWwindow*) handle; 818 assert(window != null); 819 820 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 821 _GLFW_SWAP_POINTERS(window.callbacks.charmods, cbfun); 822 return cbfun; 823 } 824 825 GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, GLFWmousebuttonfun cbfun) { 826 _GLFWwindow* window = cast(_GLFWwindow*) handle; 827 assert(window != null); 828 829 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 830 _GLFW_SWAP_POINTERS(window.callbacks.mouseButton, cbfun); 831 return cbfun; 832 } 833 834 GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, GLFWcursorposfun cbfun) { 835 _GLFWwindow* window = cast(_GLFWwindow*) handle; 836 assert(window != null); 837 838 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 839 _GLFW_SWAP_POINTERS(window.callbacks.cursorPos, cbfun); 840 return cbfun; 841 } 842 843 GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, GLFWcursorenterfun cbfun) { 844 _GLFWwindow* window = cast(_GLFWwindow*) handle; 845 assert(window != null); 846 847 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 848 _GLFW_SWAP_POINTERS(window.callbacks.cursorEnter, cbfun); 849 return cbfun; 850 } 851 852 GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, GLFWscrollfun cbfun) { 853 _GLFWwindow* window = cast(_GLFWwindow*) handle; 854 assert(window != null); 855 856 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 857 _GLFW_SWAP_POINTERS(window.callbacks.scroll, cbfun); 858 return cbfun; 859 } 860 861 GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) { 862 _GLFWwindow* window = cast(_GLFWwindow*) handle; 863 assert(window != null); 864 865 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 866 _GLFW_SWAP_POINTERS(window.callbacks.drop, cbfun); 867 return cbfun; 868 } 869 870 int glfwJoystickPresent(int jid) { 871 _GLFWjoystick* js; 872 873 assert(jid >= GLFW_JOYSTICK_1); 874 assert(jid <= GLFW_JOYSTICK_LAST); 875 876 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 877 878 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 879 { 880 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 881 return GLFW_FALSE; 882 } 883 884 js = _glfw.joysticks.ptr + jid; 885 if (!js.present) 886 return GLFW_FALSE; 887 888 return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); 889 } 890 891 const(float)* glfwGetJoystickAxes(int jid, int* count) { 892 _GLFWjoystick* js; 893 894 assert(jid >= GLFW_JOYSTICK_1); 895 assert(jid <= GLFW_JOYSTICK_LAST); 896 assert(count != null); 897 898 *count = 0; 899 900 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 901 902 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 903 { 904 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 905 return null; 906 } 907 908 js = _glfw.joysticks.ptr + jid; 909 if (!js.present) 910 return null; 911 912 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) 913 return null; 914 915 *count = js.axisCount; 916 return js.axes; 917 } 918 919 const(ubyte)* glfwGetJoystickButtons(int jid, int* count) { 920 _GLFWjoystick* js; 921 922 assert(jid >= GLFW_JOYSTICK_1); 923 assert(jid <= GLFW_JOYSTICK_LAST); 924 assert(count != null); 925 926 *count = 0; 927 928 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 929 930 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 931 { 932 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 933 return null; 934 } 935 936 js = _glfw.joysticks.ptr + jid; 937 if (!js.present) 938 return null; 939 940 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) 941 return null; 942 943 if (_glfw.hints.init.hatButtons) 944 *count = js.buttonCount + js.hatCount * 4; 945 else 946 *count = js.buttonCount; 947 948 return js.buttons; 949 } 950 951 const(ubyte)* glfwGetJoystickHats(int jid, int* count) { 952 _GLFWjoystick* js; 953 954 assert(jid >= GLFW_JOYSTICK_1); 955 assert(jid <= GLFW_JOYSTICK_LAST); 956 assert(count != null); 957 958 *count = 0; 959 960 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 961 962 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 963 { 964 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 965 return null; 966 } 967 968 js = _glfw.joysticks.ptr + jid; 969 if (!js.present) 970 return null; 971 972 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) 973 return null; 974 975 *count = js.hatCount; 976 return js.hats; 977 } 978 979 const(char)* glfwGetJoystickName(int jid) { 980 _GLFWjoystick* js; 981 982 assert(jid >= GLFW_JOYSTICK_1); 983 assert(jid <= GLFW_JOYSTICK_LAST); 984 985 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 986 987 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 988 { 989 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 990 return null; 991 } 992 993 js = _glfw.joysticks.ptr + jid; 994 if (!js.present) 995 return null; 996 997 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 998 return null; 999 1000 return js.name; 1001 } 1002 1003 const(char)* glfwGetJoystickGUID(int jid) { 1004 _GLFWjoystick* js; 1005 1006 assert(jid >= GLFW_JOYSTICK_1); 1007 assert(jid <= GLFW_JOYSTICK_LAST); 1008 1009 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 1010 1011 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1012 { 1013 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1014 return null; 1015 } 1016 1017 js = _glfw.joysticks.ptr + jid; 1018 if (!js.present) 1019 return null; 1020 1021 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1022 return null; 1023 1024 return js.guid.ptr; 1025 } 1026 1027 void glfwSetJoystickUserPointer(int jid, void* pointer) { 1028 _GLFWjoystick* js; 1029 1030 assert(jid >= GLFW_JOYSTICK_1); 1031 assert(jid <= GLFW_JOYSTICK_LAST); 1032 1033 mixin(_GLFW_REQUIRE_INIT); 1034 1035 js = _glfw.joysticks.ptr + jid; 1036 if (!js.present) 1037 return; 1038 1039 js.userPointer = pointer; 1040 } 1041 1042 void* glfwGetJoystickUserPointer(int jid) { 1043 _GLFWjoystick* js; 1044 1045 assert(jid >= GLFW_JOYSTICK_1); 1046 assert(jid <= GLFW_JOYSTICK_LAST); 1047 1048 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 1049 1050 js = _glfw.joysticks.ptr + jid; 1051 if (!js.present) 1052 return null; 1053 1054 return js.userPointer; 1055 } 1056 1057 GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) { 1058 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 1059 _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun); 1060 return cbfun; 1061 } 1062 1063 int glfwUpdateGamepadMappings(const(char)* string) { 1064 int jid; 1065 const(char)* c = string; 1066 1067 assert(string != null); 1068 1069 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 1070 1071 while (*c) 1072 { 1073 if ((*c >= '0' && *c <= '9') || 1074 (*c >= 'a' && *c <= 'f') || 1075 (*c >= 'A' && *c <= 'F')) 1076 { 1077 char[1024] line; 1078 1079 const(size_t) length = strcspn(c, "\r\n"); 1080 if (length < typeof(line).sizeof) 1081 { 1082 _GLFWmapping mapping = _GLFWmapping.init; 1083 1084 memcpy(line.ptr, c, length); 1085 line[length] = '\0'; 1086 1087 if (parseMapping(&mapping, line.ptr)) 1088 { 1089 _GLFWmapping* previous = findMapping(mapping.guid.ptr); 1090 if (previous) 1091 *previous = mapping; 1092 else 1093 { 1094 _glfw.mappingCount++; 1095 _glfw.mappings = 1096 cast(_GLFWmapping*) realloc(_glfw.mappings, 1097 _GLFWmapping.sizeof * _glfw.mappingCount); 1098 _glfw.mappings[_glfw.mappingCount - 1] = mapping; 1099 } 1100 } 1101 } 1102 1103 c += length; 1104 } 1105 else 1106 { 1107 c += strcspn(c, "\r\n"); 1108 c += strspn(c, "\r\n"); 1109 } 1110 } 1111 1112 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) 1113 { 1114 _GLFWjoystick* js = _glfw.joysticks.ptr + jid; 1115 if (js.present) 1116 js.mapping = findValidMapping(js); 1117 } 1118 1119 return GLFW_TRUE; 1120 } 1121 1122 int glfwJoystickIsGamepad(int jid) { 1123 _GLFWjoystick* js; 1124 1125 assert(jid >= GLFW_JOYSTICK_1); 1126 assert(jid <= GLFW_JOYSTICK_LAST); 1127 1128 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 1129 1130 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1131 { 1132 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1133 return GLFW_FALSE; 1134 } 1135 1136 js = _glfw.joysticks.ptr + jid; 1137 if (!js.present) 1138 return GLFW_FALSE; 1139 1140 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1141 return GLFW_FALSE; 1142 1143 return js.mapping != null; 1144 } 1145 1146 const(char)* glfwGetGamepadName(int jid) { 1147 _GLFWjoystick* js; 1148 1149 assert(jid >= GLFW_JOYSTICK_1); 1150 assert(jid <= GLFW_JOYSTICK_LAST); 1151 1152 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 1153 1154 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1155 { 1156 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1157 return null; 1158 } 1159 1160 js = _glfw.joysticks.ptr + jid; 1161 if (!js.present) 1162 return null; 1163 1164 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1165 return null; 1166 1167 if (!js.mapping) 1168 return null; 1169 1170 return js.mapping.name.ptr; 1171 } 1172 1173 int glfwGetGamepadState(int jid, GLFWgamepadstate* state) { 1174 int i; 1175 _GLFWjoystick* js; 1176 1177 assert(jid >= GLFW_JOYSTICK_1); 1178 assert(jid <= GLFW_JOYSTICK_LAST); 1179 assert(state != null); 1180 1181 memset(state, 0, GLFWgamepadstate.sizeof); 1182 1183 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"GLFW_FALSE"); 1184 1185 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1186 { 1187 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1188 return GLFW_FALSE; 1189 } 1190 1191 js = _glfw.joysticks.ptr + jid; 1192 if (!js.present) 1193 return GLFW_FALSE; 1194 1195 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) 1196 return GLFW_FALSE; 1197 1198 if (!js.mapping) 1199 return GLFW_FALSE; 1200 1201 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) 1202 { 1203 const(_GLFWmapelement)* e = js.mapping.buttons.ptr + i; 1204 if (e.type == _GLFW_JOYSTICK_AXIS) 1205 { 1206 const(float) value = js.axes[e.index] * e.axisScale + e.axisOffset; 1207 // HACK: This should be baked into the value transform 1208 // TODO: Bake into transform when implementing output modifiers 1209 if (e.axisOffset < 0 || (e.axisOffset == 0 && e.axisScale > 0)) 1210 { 1211 if (value >= 0.0f) 1212 state.buttons[i] = GLFW_PRESS; 1213 } 1214 else 1215 { 1216 if (value <= 0.0f) 1217 state.buttons[i] = GLFW_PRESS; 1218 } 1219 } 1220 else if (e.type == _GLFW_JOYSTICK_HATBIT) 1221 { 1222 const(uint) hat = e.index >> 4; 1223 const(uint) bit = e.index & 0xf; 1224 if (js.hats[hat] & bit) 1225 state.buttons[i] = GLFW_PRESS; 1226 } 1227 else if (e.type == _GLFW_JOYSTICK_BUTTON) 1228 state.buttons[i] = js.buttons[e.index]; 1229 } 1230 1231 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) 1232 { 1233 const(_GLFWmapelement)* e = js.mapping.axes.ptr + i; 1234 if (e.type == _GLFW_JOYSTICK_AXIS) 1235 { 1236 const(float) value = js.axes[e.index] * e.axisScale + e.axisOffset; 1237 state.axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.0f), 1.0f); 1238 } 1239 else if (e.type == _GLFW_JOYSTICK_HATBIT) 1240 { 1241 const(uint) hat = e.index >> 4; 1242 const(uint) bit = e.index & 0xf; 1243 if (js.hats[hat] & bit) 1244 state.axes[i] = 1.0f; 1245 else 1246 state.axes[i] = -1.0f; 1247 } 1248 else if (e.type == _GLFW_JOYSTICK_BUTTON) 1249 state.axes[i] = js.buttons[e.index] * 2.0f - 1.0f; 1250 } 1251 1252 return GLFW_TRUE; 1253 } 1254 1255 void glfwSetClipboardString(GLFWwindow* handle, const(char)* string) { 1256 assert(string != null); 1257 1258 mixin(_GLFW_REQUIRE_INIT); 1259 _glfwPlatformSetClipboardString(string); 1260 } 1261 1262 const(char)* glfwGetClipboardString(GLFWwindow* handle) { 1263 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"null"); 1264 return _glfwPlatformGetClipboardString(); 1265 } 1266 1267 double glfwGetTime() { 1268 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0.0"); 1269 return cast(double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / 1270 _glfwPlatformGetTimerFrequency(); 1271 } 1272 1273 void glfwSetTime(double time) { 1274 mixin(_GLFW_REQUIRE_INIT); 1275 1276 if (time != time || time < 0.0 || time > 18446744073.0) 1277 { 1278 _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); 1279 return; 1280 } 1281 1282 _glfw.timer.offset = _glfwPlatformGetTimerValue() - 1283 cast(ulong) (time * _glfwPlatformGetTimerFrequency()); 1284 } 1285 1286 ulong glfwGetTimerValue() { 1287 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); 1288 return _glfwPlatformGetTimerValue(); 1289 } 1290 1291 ulong glfwGetTimerFrequency() { 1292 mixin(_GLFW_REQUIRE_INIT_OR_RETURN!"0"); 1293 return _glfwPlatformGetTimerFrequency(); 1294 }