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