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