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