input.c (37912B)
1 //======================================================================== 2 // GLFW 3.4 - 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 = (float*)calloc(axisCount, sizeof(float)); 435 js->buttons = (unsigned char*)calloc(buttonCount + (size_t) hatCount * 4, 1); 436 js->hats = (unsigned char*)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 = (_GLFWcursor*)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_POINTING_HAND_CURSOR && 761 shape != GLFW_RESIZE_EW_CURSOR && 762 shape != GLFW_RESIZE_NS_CURSOR && 763 shape != GLFW_RESIZE_NWSE_CURSOR && 764 shape != GLFW_RESIZE_NESW_CURSOR && 765 shape != GLFW_RESIZE_ALL_CURSOR && 766 shape != GLFW_NOT_ALLOWED_CURSOR) 767 { 768 _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); 769 return NULL; 770 } 771 772 cursor = (_GLFWcursor*)calloc(1, sizeof(_GLFWcursor)); 773 cursor->next = _glfw.cursorListHead; 774 _glfw.cursorListHead = cursor; 775 776 if (!_glfwPlatformCreateStandardCursor(cursor, shape)) 777 { 778 glfwDestroyCursor((GLFWcursor*) cursor); 779 return NULL; 780 } 781 782 return (GLFWcursor*) cursor; 783 } 784 785 GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) 786 { 787 _GLFWcursor* cursor = (_GLFWcursor*) handle; 788 789 _GLFW_REQUIRE_INIT(); 790 791 if (cursor == NULL) 792 return; 793 794 // Make sure the cursor is not being used by any window 795 { 796 _GLFWwindow* window; 797 798 for (window = _glfw.windowListHead; window; window = window->next) 799 { 800 if (window->cursor == cursor) 801 glfwSetCursor((GLFWwindow*) window, NULL); 802 } 803 } 804 805 _glfwPlatformDestroyCursor(cursor); 806 807 // Unlink cursor from global linked list 808 { 809 _GLFWcursor** prev = &_glfw.cursorListHead; 810 811 while (*prev != cursor) 812 prev = &((*prev)->next); 813 814 *prev = cursor->next; 815 } 816 817 free(cursor); 818 } 819 820 GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) 821 { 822 _GLFWwindow* window = (_GLFWwindow*) windowHandle; 823 _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; 824 assert(window != NULL); 825 826 _GLFW_REQUIRE_INIT(); 827 828 window->cursor = cursor; 829 830 _glfwPlatformSetCursor(window, cursor); 831 } 832 833 GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) 834 { 835 _GLFWwindow* window = (_GLFWwindow*) handle; 836 assert(window != NULL); 837 838 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 839 _GLFW_SWAP_POINTERS(GLFWkeyfun, window->callbacks.key, cbfun); 840 return cbfun; 841 } 842 843 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) 844 { 845 _GLFWwindow* window = (_GLFWwindow*) handle; 846 assert(window != NULL); 847 848 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 849 _GLFW_SWAP_POINTERS(GLFWcharfun, window->callbacks.character, cbfun); 850 return cbfun; 851 } 852 853 GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) 854 { 855 _GLFWwindow* window = (_GLFWwindow*) handle; 856 assert(window != NULL); 857 858 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 859 _GLFW_SWAP_POINTERS(GLFWcharmodsfun, window->callbacks.charmods, cbfun); 860 return cbfun; 861 } 862 863 GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, 864 GLFWmousebuttonfun cbfun) 865 { 866 _GLFWwindow* window = (_GLFWwindow*) handle; 867 assert(window != NULL); 868 869 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 870 _GLFW_SWAP_POINTERS(GLFWmousebuttonfun, window->callbacks.mouseButton, cbfun); 871 return cbfun; 872 } 873 874 GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, 875 GLFWcursorposfun cbfun) 876 { 877 _GLFWwindow* window = (_GLFWwindow*) handle; 878 assert(window != NULL); 879 880 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 881 _GLFW_SWAP_POINTERS(GLFWcursorposfun, window->callbacks.cursorPos, cbfun); 882 return cbfun; 883 } 884 885 GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, 886 GLFWcursorenterfun cbfun) 887 { 888 _GLFWwindow* window = (_GLFWwindow*) handle; 889 assert(window != NULL); 890 891 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 892 _GLFW_SWAP_POINTERS(GLFWcursorenterfun, window->callbacks.cursorEnter, cbfun); 893 return cbfun; 894 } 895 896 GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, 897 GLFWscrollfun cbfun) 898 { 899 _GLFWwindow* window = (_GLFWwindow*) handle; 900 assert(window != NULL); 901 902 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 903 _GLFW_SWAP_POINTERS(GLFWscrollfun, window->callbacks.scroll, cbfun); 904 return cbfun; 905 } 906 907 GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) 908 { 909 _GLFWwindow* window = (_GLFWwindow*) handle; 910 assert(window != NULL); 911 912 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 913 _GLFW_SWAP_POINTERS(GLFWdropfun, window->callbacks.drop, cbfun); 914 return cbfun; 915 } 916 917 GLFWAPI int glfwJoystickPresent(int jid) 918 { 919 _GLFWjoystick* js; 920 921 assert(jid >= GLFW_JOYSTICK_1); 922 assert(jid <= GLFW_JOYSTICK_LAST); 923 924 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 925 926 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 927 { 928 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 929 return GLFW_FALSE; 930 } 931 932 js = _glfw.joysticks + jid; 933 if (!js->present) 934 return GLFW_FALSE; 935 936 return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE); 937 } 938 939 GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) 940 { 941 _GLFWjoystick* js; 942 943 assert(jid >= GLFW_JOYSTICK_1); 944 assert(jid <= GLFW_JOYSTICK_LAST); 945 assert(count != NULL); 946 947 *count = 0; 948 949 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 950 951 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 952 { 953 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 954 return NULL; 955 } 956 957 js = _glfw.joysticks + jid; 958 if (!js->present) 959 return NULL; 960 961 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES)) 962 return NULL; 963 964 *count = js->axisCount; 965 return js->axes; 966 } 967 968 GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) 969 { 970 _GLFWjoystick* js; 971 972 assert(jid >= GLFW_JOYSTICK_1); 973 assert(jid <= GLFW_JOYSTICK_LAST); 974 assert(count != NULL); 975 976 *count = 0; 977 978 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 979 980 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 981 { 982 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 983 return NULL; 984 } 985 986 js = _glfw.joysticks + jid; 987 if (!js->present) 988 return NULL; 989 990 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) 991 return NULL; 992 993 if (_glfw.hints.init.hatButtons) 994 *count = js->buttonCount + js->hatCount * 4; 995 else 996 *count = js->buttonCount; 997 998 return js->buttons; 999 } 1000 1001 GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) 1002 { 1003 _GLFWjoystick* js; 1004 1005 assert(jid >= GLFW_JOYSTICK_1); 1006 assert(jid <= GLFW_JOYSTICK_LAST); 1007 assert(count != NULL); 1008 1009 *count = 0; 1010 1011 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1012 1013 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1014 { 1015 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1016 return NULL; 1017 } 1018 1019 js = _glfw.joysticks + jid; 1020 if (!js->present) 1021 return NULL; 1022 1023 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS)) 1024 return NULL; 1025 1026 *count = js->hatCount; 1027 return js->hats; 1028 } 1029 1030 GLFWAPI const char* glfwGetJoystickName(int jid) 1031 { 1032 _GLFWjoystick* js; 1033 1034 assert(jid >= GLFW_JOYSTICK_1); 1035 assert(jid <= GLFW_JOYSTICK_LAST); 1036 1037 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1038 1039 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1040 { 1041 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1042 return NULL; 1043 } 1044 1045 js = _glfw.joysticks + jid; 1046 if (!js->present) 1047 return NULL; 1048 1049 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1050 return NULL; 1051 1052 return js->name; 1053 } 1054 1055 GLFWAPI const char* glfwGetJoystickGUID(int jid) 1056 { 1057 _GLFWjoystick* js; 1058 1059 assert(jid >= GLFW_JOYSTICK_1); 1060 assert(jid <= GLFW_JOYSTICK_LAST); 1061 1062 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1063 1064 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1065 { 1066 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1067 return NULL; 1068 } 1069 1070 js = _glfw.joysticks + jid; 1071 if (!js->present) 1072 return NULL; 1073 1074 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1075 return NULL; 1076 1077 return js->guid; 1078 } 1079 1080 GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) 1081 { 1082 _GLFWjoystick* js; 1083 1084 assert(jid >= GLFW_JOYSTICK_1); 1085 assert(jid <= GLFW_JOYSTICK_LAST); 1086 1087 _GLFW_REQUIRE_INIT(); 1088 1089 js = _glfw.joysticks + jid; 1090 if (!js->present) 1091 return; 1092 1093 js->userPointer = pointer; 1094 } 1095 1096 GLFWAPI void* glfwGetJoystickUserPointer(int jid) 1097 { 1098 _GLFWjoystick* js; 1099 1100 assert(jid >= GLFW_JOYSTICK_1); 1101 assert(jid <= GLFW_JOYSTICK_LAST); 1102 1103 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1104 1105 js = _glfw.joysticks + jid; 1106 if (!js->present) 1107 return NULL; 1108 1109 return js->userPointer; 1110 } 1111 1112 GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) 1113 { 1114 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1115 _GLFW_SWAP_POINTERS(GLFWjoystickfun, _glfw.callbacks.joystick, cbfun); 1116 return cbfun; 1117 } 1118 1119 GLFWAPI int glfwUpdateGamepadMappings(const char* string) 1120 { 1121 int jid; 1122 const char* c = string; 1123 1124 assert(string != NULL); 1125 1126 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1127 1128 while (*c) 1129 { 1130 if ((*c >= '0' && *c <= '9') || 1131 (*c >= 'a' && *c <= 'f') || 1132 (*c >= 'A' && *c <= 'F')) 1133 { 1134 char line[1024]; 1135 1136 const size_t length = strcspn(c, "\r\n"); 1137 if (length < sizeof(line)) 1138 { 1139 _GLFWmapping mapping = {{0}}; 1140 1141 memcpy(line, c, length); 1142 line[length] = '\0'; 1143 1144 if (parseMapping(&mapping, line)) 1145 { 1146 _GLFWmapping* previous = findMapping(mapping.guid); 1147 if (previous) 1148 *previous = mapping; 1149 else 1150 { 1151 _glfw.mappingCount++; 1152 _glfw.mappings = 1153 (_GLFWmapping*)realloc(_glfw.mappings, 1154 sizeof(_GLFWmapping) * _glfw.mappingCount); 1155 _glfw.mappings[_glfw.mappingCount - 1] = mapping; 1156 } 1157 } 1158 } 1159 1160 c += length; 1161 } 1162 else 1163 { 1164 c += strcspn(c, "\r\n"); 1165 c += strspn(c, "\r\n"); 1166 } 1167 } 1168 1169 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) 1170 { 1171 _GLFWjoystick* js = _glfw.joysticks + jid; 1172 if (js->present) 1173 js->mapping = findValidMapping(js); 1174 } 1175 1176 return GLFW_TRUE; 1177 } 1178 1179 GLFWAPI int glfwJoystickIsGamepad(int jid) 1180 { 1181 _GLFWjoystick* js; 1182 1183 assert(jid >= GLFW_JOYSTICK_1); 1184 assert(jid <= GLFW_JOYSTICK_LAST); 1185 1186 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1187 1188 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1189 { 1190 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1191 return GLFW_FALSE; 1192 } 1193 1194 js = _glfw.joysticks + jid; 1195 if (!js->present) 1196 return GLFW_FALSE; 1197 1198 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1199 return GLFW_FALSE; 1200 1201 return js->mapping != NULL; 1202 } 1203 1204 GLFWAPI const char* glfwGetGamepadName(int jid) 1205 { 1206 _GLFWjoystick* js; 1207 1208 assert(jid >= GLFW_JOYSTICK_1); 1209 assert(jid <= GLFW_JOYSTICK_LAST); 1210 1211 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1212 1213 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1214 { 1215 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1216 return NULL; 1217 } 1218 1219 js = _glfw.joysticks + jid; 1220 if (!js->present) 1221 return NULL; 1222 1223 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE)) 1224 return NULL; 1225 1226 if (!js->mapping) 1227 return NULL; 1228 1229 return js->mapping->name; 1230 } 1231 1232 GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) 1233 { 1234 int i; 1235 _GLFWjoystick* js; 1236 1237 assert(jid >= GLFW_JOYSTICK_1); 1238 assert(jid <= GLFW_JOYSTICK_LAST); 1239 assert(state != NULL); 1240 1241 memset(state, 0, sizeof(GLFWgamepadstate)); 1242 1243 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1244 1245 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1246 { 1247 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1248 return GLFW_FALSE; 1249 } 1250 1251 js = _glfw.joysticks + jid; 1252 if (!js->present) 1253 return GLFW_FALSE; 1254 1255 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL)) 1256 return GLFW_FALSE; 1257 1258 if (!js->mapping) 1259 return GLFW_FALSE; 1260 1261 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) 1262 { 1263 const _GLFWmapelement* e = js->mapping->buttons + i; 1264 if (e->type == _GLFW_JOYSTICK_AXIS) 1265 { 1266 const float value = js->axes[e->index] * e->axisScale + e->axisOffset; 1267 // HACK: This should be baked into the value transform 1268 // TODO: Bake into transform when implementing output modifiers 1269 if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0)) 1270 { 1271 if (value >= 0.f) 1272 state->buttons[i] = GLFW_PRESS; 1273 } 1274 else 1275 { 1276 if (value <= 0.f) 1277 state->buttons[i] = GLFW_PRESS; 1278 } 1279 } 1280 else if (e->type == _GLFW_JOYSTICK_HATBIT) 1281 { 1282 const unsigned int hat = e->index >> 4; 1283 const unsigned int bit = e->index & 0xf; 1284 if (js->hats[hat] & bit) 1285 state->buttons[i] = GLFW_PRESS; 1286 } 1287 else if (e->type == _GLFW_JOYSTICK_BUTTON) 1288 state->buttons[i] = js->buttons[e->index]; 1289 } 1290 1291 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) 1292 { 1293 const _GLFWmapelement* e = js->mapping->axes + i; 1294 if (e->type == _GLFW_JOYSTICK_AXIS) 1295 { 1296 const float value = js->axes[e->index] * e->axisScale + e->axisOffset; 1297 state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f); 1298 } 1299 else if (e->type == _GLFW_JOYSTICK_HATBIT) 1300 { 1301 const unsigned int hat = e->index >> 4; 1302 const unsigned int bit = e->index & 0xf; 1303 if (js->hats[hat] & bit) 1304 state->axes[i] = 1.f; 1305 else 1306 state->axes[i] = -1.f; 1307 } 1308 else if (e->type == _GLFW_JOYSTICK_BUTTON) 1309 state->axes[i] = js->buttons[e->index] * 2.f - 1.f; 1310 } 1311 1312 return GLFW_TRUE; 1313 } 1314 1315 GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) 1316 { 1317 assert(string != NULL); 1318 1319 _GLFW_REQUIRE_INIT(); 1320 _glfwPlatformSetClipboardString(string); 1321 } 1322 1323 GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) 1324 { 1325 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1326 return _glfwPlatformGetClipboardString(); 1327 } 1328 1329 GLFWAPI double glfwGetTime(void) 1330 { 1331 _GLFW_REQUIRE_INIT_OR_RETURN(0.0); 1332 return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / 1333 _glfwPlatformGetTimerFrequency(); 1334 } 1335 1336 GLFWAPI void glfwSetTime(double time) 1337 { 1338 _GLFW_REQUIRE_INIT(); 1339 1340 if (time != time || time < 0.0 || time > 18446744073.0) 1341 { 1342 _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); 1343 return; 1344 } 1345 1346 _glfw.timer.offset = _glfwPlatformGetTimerValue() - 1347 (uint64_t) (time * _glfwPlatformGetTimerFrequency()); 1348 } 1349 1350 GLFWAPI uint64_t glfwGetTimerValue(void) 1351 { 1352 _GLFW_REQUIRE_INIT_OR_RETURN(0); 1353 return _glfwPlatformGetTimerValue(); 1354 } 1355 1356 GLFWAPI uint64_t glfwGetTimerFrequency(void) 1357 { 1358 _GLFW_REQUIRE_INIT_OR_RETURN(0); 1359 return _glfwPlatformGetTimerFrequency(); 1360 }