Atlas - input.c
Home / ext / glfw / src Lines: 4 | Size: 41556 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1//======================================================================== 2// GLFW 3.5 - www.glfw.org 3//------------------------------------------------------------------------ 4// Copyright (c) 2002-2006 Marcus Geelnard 5// Copyright (c) 2006-2019 Camilla Löwy <[email protected]> 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// 54static 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// 70static _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// 85static 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// 100static _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// 125static 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// 272void _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// 309void _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// 333void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) 334{ 335 assert(window != NULL); 336 assert(isfinite(xoffset)); 337 assert(isfinite(yoffset)); 338 339 if (window->callbacks.scroll) 340 window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); 341} 342 343// Notifies shared code of a mouse button click event 344// 345void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods) 346{ 347 assert(window != NULL); 348 assert(button >= 0); 349 assert(action == GLFW_PRESS || action == GLFW_RELEASE); 350 assert(mods == (mods & GLFW_MOD_MASK)); 351 352 if (button < 0 || (!window->disableMouseButtonLimit && button > GLFW_MOUSE_BUTTON_LAST)) 353 return; 354 355 if (!window->lockKeyMods) 356 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK); 357 358 if (button <= GLFW_MOUSE_BUTTON_LAST) 359 { 360 if (action == GLFW_RELEASE && window->stickyMouseButtons) 361 window->mouseButtons[button] = _GLFW_STICK; 362 else 363 window->mouseButtons[button] = (char) action; 364 } 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// 373void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos) 374{ 375 assert(window != NULL); 376 assert(isfinite(xpos)); 377 assert(isfinite(ypos)); 378 379 if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos) 380 return; 381 382 window->virtualCursorPosX = xpos; 383 window->virtualCursorPosY = ypos; 384 385 if (window->callbacks.cursorPos) 386 window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos); 387} 388 389// Notifies shared code of a cursor enter/leave event 390// 391void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) 392{ 393 assert(window != NULL); 394 assert(entered == GLFW_TRUE || entered == GLFW_FALSE); 395 396 if (window->callbacks.cursorEnter) 397 window->callbacks.cursorEnter((GLFWwindow*) window, entered); 398} 399 400// Notifies shared code of files or directories dropped on a window 401// 402void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) 403{ 404 assert(window != NULL); 405 assert(count > 0); 406 assert(paths != NULL); 407 408 if (window->callbacks.drop) 409 window->callbacks.drop((GLFWwindow*) window, count, paths); 410} 411 412// Notifies shared code of a joystick connection or disconnection 413// 414void _glfwInputJoystick(_GLFWjoystick* js, int event) 415{ 416 assert(js != NULL); 417 assert(event == GLFW_CONNECTED || event == GLFW_DISCONNECTED); 418 419 if (event == GLFW_CONNECTED) 420 js->connected = GLFW_TRUE; 421 else if (event == GLFW_DISCONNECTED) 422 js->connected = GLFW_FALSE; 423 424 if (_glfw.callbacks.joystick) 425 _glfw.callbacks.joystick((int) (js - _glfw.joysticks), event); 426} 427 428// Notifies shared code of the new value of a joystick axis 429// 430void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value) 431{ 432 assert(js != NULL); 433 assert(axis >= 0); 434 assert(axis < js->axisCount); 435 assert(isfinite(value)); 436 437 js->axes[axis] = value; 438} 439 440// Notifies shared code of the new value of a joystick button 441// 442void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value) 443{ 444 assert(js != NULL); 445 assert(button >= 0); 446 assert(button < js->buttonCount); 447 assert(value == GLFW_PRESS || value == GLFW_RELEASE); 448 449 js->buttons[button] = value; 450} 451 452// Notifies shared code of the new value of a joystick hat 453// 454void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value) 455{ 456 int base; 457 458 assert(js != NULL); 459 assert(hat >= 0); 460 assert(hat < js->hatCount); 461 462 // Valid hat values only use the least significant nibble 463 assert((value & 0xf0) == 0); 464 // Valid hat values do not have both bits of an axis set 465 assert((value & GLFW_HAT_LEFT) == 0 || (value & GLFW_HAT_RIGHT) == 0); 466 assert((value & GLFW_HAT_UP) == 0 || (value & GLFW_HAT_DOWN) == 0); 467 468 base = js->buttonCount + hat * 4; 469 470 js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE; 471 js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE; 472 js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE; 473 js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE; 474 475 js->hats[hat] = value; 476} 477 478 479////////////////////////////////////////////////////////////////////////// 480////// GLFW internal API ////// 481////////////////////////////////////////////////////////////////////////// 482 483// Adds the built-in set of gamepad mappings 484// 485void _glfwInitGamepadMappings(void) 486{ 487 size_t i; 488 const size_t count = sizeof(_glfwDefaultMappings) / sizeof(char*); 489 _glfw.mappings = _glfw_calloc(count, sizeof(_GLFWmapping)); 490 491 for (i = 0; i < count; i++) 492 { 493 if (parseMapping(&_glfw.mappings[_glfw.mappingCount], _glfwDefaultMappings[i])) 494 _glfw.mappingCount++; 495 } 496} 497 498// Returns an available joystick object with arrays and name allocated 499// 500_GLFWjoystick* _glfwAllocJoystick(const char* name, 501 const char* guid, 502 int axisCount, 503 int buttonCount, 504 int hatCount) 505{ 506 int jid; 507 _GLFWjoystick* js; 508 509 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) 510 { 511 if (!_glfw.joysticks[jid].allocated) 512 break; 513 } 514 515 if (jid > GLFW_JOYSTICK_LAST) 516 return NULL; 517 518 js = _glfw.joysticks + jid; 519 js->allocated = GLFW_TRUE; 520 js->axes = _glfw_calloc(axisCount, sizeof(float)); 521 js->buttons = _glfw_calloc(buttonCount + (size_t) hatCount * 4, 1); 522 js->hats = _glfw_calloc(hatCount, 1); 523 js->axisCount = axisCount; 524 js->buttonCount = buttonCount; 525 js->hatCount = hatCount; 526 527 strncpy(js->name, name, sizeof(js->name) - 1); 528 strncpy(js->guid, guid, sizeof(js->guid) - 1); 529 js->mapping = findValidMapping(js); 530 531 return js; 532} 533 534// Frees arrays and name and flags the joystick object as unused 535// 536void _glfwFreeJoystick(_GLFWjoystick* js) 537{ 538 _glfw_free(js->axes); 539 _glfw_free(js->buttons); 540 _glfw_free(js->hats); 541 memset(js, 0, sizeof(_GLFWjoystick)); 542} 543 544// Center the cursor in the content area of the specified window 545// 546void _glfwCenterCursorInContentArea(_GLFWwindow* window) 547{ 548 int width, height; 549 550 _glfw.platform.getWindowSize(window, &width, &height); 551 _glfw.platform.setCursorPos(window, width / 2.0, height / 2.0); 552} 553 554 555////////////////////////////////////////////////////////////////////////// 556////// GLFW public API ////// 557////////////////////////////////////////////////////////////////////////// 558 559GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode) 560{ 561 _GLFW_REQUIRE_INIT_OR_RETURN(0); 562 563 _GLFWwindow* window = (_GLFWwindow*) handle; 564 assert(window != NULL); 565 566 switch (mode) 567 { 568 case GLFW_CURSOR: 569 return window->cursorMode; 570 case GLFW_STICKY_KEYS: 571 return window->stickyKeys; 572 case GLFW_STICKY_MOUSE_BUTTONS: 573 return window->stickyMouseButtons; 574 case GLFW_LOCK_KEY_MODS: 575 return window->lockKeyMods; 576 case GLFW_RAW_MOUSE_MOTION: 577 return window->rawMouseMotion; 578 case GLFW_UNLIMITED_MOUSE_BUTTONS: 579 return window->disableMouseButtonLimit; 580 } 581 582 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); 583 return 0; 584} 585 586GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value) 587{ 588 _GLFW_REQUIRE_INIT(); 589 590 _GLFWwindow* window = (_GLFWwindow*) handle; 591 assert(window != NULL); 592 593 switch (mode) 594 { 595 case GLFW_CURSOR: 596 { 597 if (value != GLFW_CURSOR_NORMAL && 598 value != GLFW_CURSOR_HIDDEN && 599 value != GLFW_CURSOR_DISABLED && 600 value != GLFW_CURSOR_CAPTURED) 601 { 602 _glfwInputError(GLFW_INVALID_ENUM, 603 "Invalid cursor mode 0x%08X", 604 value); 605 return; 606 } 607 608 if (window->cursorMode == value) 609 return; 610 611 window->cursorMode = value; 612 613 _glfw.platform.getCursorPos(window, 614 &window->virtualCursorPosX, 615 &window->virtualCursorPosY); 616 _glfw.platform.setCursorMode(window, value); 617 return; 618 } 619 620 case GLFW_STICKY_KEYS: 621 { 622 value = value ? GLFW_TRUE : GLFW_FALSE; 623 if (window->stickyKeys == value) 624 return; 625 626 if (!value) 627 { 628 int i; 629 630 // Release all sticky keys 631 for (i = 0; i <= GLFW_KEY_LAST; i++) 632 { 633 if (window->keys[i] == _GLFW_STICK) 634 window->keys[i] = GLFW_RELEASE; 635 } 636 } 637 638 window->stickyKeys = value; 639 return; 640 } 641 642 case GLFW_STICKY_MOUSE_BUTTONS: 643 { 644 value = value ? GLFW_TRUE : GLFW_FALSE; 645 if (window->stickyMouseButtons == value) 646 return; 647 648 if (!value) 649 { 650 int i; 651 652 // Release all sticky mouse buttons 653 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++) 654 { 655 if (window->mouseButtons[i] == _GLFW_STICK) 656 window->mouseButtons[i] = GLFW_RELEASE; 657 } 658 } 659 660 window->stickyMouseButtons = value; 661 return; 662 } 663 664 case GLFW_LOCK_KEY_MODS: 665 { 666 window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE; 667 return; 668 } 669 670 case GLFW_RAW_MOUSE_MOTION: 671 { 672 if (!_glfw.platform.rawMouseMotionSupported()) 673 { 674 _glfwInputError(GLFW_PLATFORM_ERROR, 675 "Raw mouse motion is not supported on this system"); 676 return; 677 } 678 679 value = value ? GLFW_TRUE : GLFW_FALSE; 680 if (window->rawMouseMotion == value) 681 return; 682 683 window->rawMouseMotion = value; 684 _glfw.platform.setRawMouseMotion(window, value); 685 return; 686 } 687 688 case GLFW_UNLIMITED_MOUSE_BUTTONS: 689 { 690 window->disableMouseButtonLimit = value ? GLFW_TRUE : GLFW_FALSE; 691 return; 692 } 693 } 694 695 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode); 696} 697 698GLFWAPI int glfwRawMouseMotionSupported(void) 699{ 700 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 701 return _glfw.platform.rawMouseMotionSupported(); 702} 703 704GLFWAPI const char* glfwGetKeyName(int key, int scancode) 705{ 706 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 707 708 if (key != GLFW_KEY_UNKNOWN) 709 { 710 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) 711 { 712 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); 713 return NULL; 714 } 715 716 if (key != GLFW_KEY_KP_EQUAL && 717 (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) && 718 (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2)) 719 { 720 return NULL; 721 } 722 723 scancode = _glfw.platform.getKeyScancode(key); 724 } 725 726 return _glfw.platform.getScancodeName(scancode); 727} 728 729GLFWAPI int glfwGetKeyScancode(int key) 730{ 731 _GLFW_REQUIRE_INIT_OR_RETURN(0); 732 733 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) 734 { 735 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); 736 return -1; 737 } 738 739 return _glfw.platform.getKeyScancode(key); 740} 741 742GLFWAPI int glfwGetKey(GLFWwindow* handle, int key) 743{ 744 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); 745 746 _GLFWwindow* window = (_GLFWwindow*) handle; 747 assert(window != NULL); 748 749 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST) 750 { 751 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key); 752 return GLFW_RELEASE; 753 } 754 755 if (window->keys[key] == _GLFW_STICK) 756 { 757 // Sticky mode: release key now 758 window->keys[key] = GLFW_RELEASE; 759 return GLFW_PRESS; 760 } 761 762 return (int) window->keys[key]; 763} 764 765GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button) 766{ 767 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE); 768 769 _GLFWwindow* window = (_GLFWwindow*) handle; 770 assert(window != NULL); 771 772 if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST) 773 { 774 _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button); 775 return GLFW_RELEASE; 776 } 777 778 if (window->mouseButtons[button] == _GLFW_STICK) 779 { 780 // Sticky mode: release mouse button now 781 window->mouseButtons[button] = GLFW_RELEASE; 782 return GLFW_PRESS; 783 } 784 785 return (int) window->mouseButtons[button]; 786} 787 788GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos) 789{ 790 if (xpos) 791 *xpos = 0; 792 if (ypos) 793 *ypos = 0; 794 795 _GLFW_REQUIRE_INIT(); 796 797 _GLFWwindow* window = (_GLFWwindow*) handle; 798 assert(window != NULL); 799 800 if (window->cursorMode == GLFW_CURSOR_DISABLED) 801 { 802 if (xpos) 803 *xpos = window->virtualCursorPosX; 804 if (ypos) 805 *ypos = window->virtualCursorPosY; 806 } 807 else 808 _glfw.platform.getCursorPos(window, xpos, ypos); 809} 810 811GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos) 812{ 813 _GLFW_REQUIRE_INIT(); 814 815 _GLFWwindow* window = (_GLFWwindow*) handle; 816 assert(window != NULL); 817 818 if (!isfinite(xpos) || !isfinite(ypos)) 819 { 820 _glfwInputError(GLFW_INVALID_VALUE, 821 "Invalid cursor position %f %f", 822 xpos, ypos); 823 return; 824 } 825 826 if (!_glfw.platform.windowFocused(window)) 827 return; 828 829 if (window->cursorMode == GLFW_CURSOR_DISABLED) 830 { 831 // Only update the accumulated position if the cursor is disabled 832 window->virtualCursorPosX = xpos; 833 window->virtualCursorPosY = ypos; 834 } 835 else 836 { 837 // Update system cursor position 838 _glfw.platform.setCursorPos(window, xpos, ypos); 839 } 840} 841 842GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot) 843{ 844 _GLFWcursor* cursor; 845 846 assert(image != NULL); 847 assert(image->pixels != NULL); 848 849 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 850 851 if (image->width <= 0 || image->height <= 0) 852 { 853 _glfwInputError(GLFW_INVALID_VALUE, "Invalid image dimensions for cursor"); 854 return NULL; 855 } 856 857 cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); 858 cursor->next = _glfw.cursorListHead; 859 _glfw.cursorListHead = cursor; 860 861 if (!_glfw.platform.createCursor(cursor, image, xhot, yhot)) 862 { 863 glfwDestroyCursor((GLFWcursor*) cursor); 864 return NULL; 865 } 866 867 return (GLFWcursor*) cursor; 868} 869 870GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape) 871{ 872 _GLFWcursor* cursor; 873 874 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 875 876 if (shape != GLFW_ARROW_CURSOR && 877 shape != GLFW_IBEAM_CURSOR && 878 shape != GLFW_CROSSHAIR_CURSOR && 879 shape != GLFW_POINTING_HAND_CURSOR && 880 shape != GLFW_RESIZE_EW_CURSOR && 881 shape != GLFW_RESIZE_NS_CURSOR && 882 shape != GLFW_RESIZE_NWSE_CURSOR && 883 shape != GLFW_RESIZE_NESW_CURSOR && 884 shape != GLFW_RESIZE_ALL_CURSOR && 885 shape != GLFW_NOT_ALLOWED_CURSOR) 886 { 887 _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape); 888 return NULL; 889 } 890 891 cursor = _glfw_calloc(1, sizeof(_GLFWcursor)); 892 cursor->next = _glfw.cursorListHead; 893 _glfw.cursorListHead = cursor; 894 895 if (!_glfw.platform.createStandardCursor(cursor, shape)) 896 { 897 glfwDestroyCursor((GLFWcursor*) cursor); 898 return NULL; 899 } 900 901 return (GLFWcursor*) cursor; 902} 903 904GLFWAPI void glfwDestroyCursor(GLFWcursor* handle) 905{ 906 _GLFW_REQUIRE_INIT(); 907 908 _GLFWcursor* cursor = (_GLFWcursor*) handle; 909 910 if (cursor == NULL) 911 return; 912 913 // Make sure the cursor is not being used by any window 914 { 915 _GLFWwindow* window; 916 917 for (window = _glfw.windowListHead; window; window = window->next) 918 { 919 if (window->cursor == cursor) 920 glfwSetCursor((GLFWwindow*) window, NULL); 921 } 922 } 923 924 _glfw.platform.destroyCursor(cursor); 925 926 // Unlink cursor from global linked list 927 { 928 _GLFWcursor** prev = &_glfw.cursorListHead; 929 930 while (*prev != cursor) 931 prev = &((*prev)->next); 932 933 *prev = cursor->next; 934 } 935 936 _glfw_free(cursor); 937} 938 939GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle) 940{ 941 _GLFW_REQUIRE_INIT(); 942 943 _GLFWwindow* window = (_GLFWwindow*) windowHandle; 944 _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle; 945 assert(window != NULL); 946 947 window->cursor = cursor; 948 949 _glfw.platform.setCursor(window, cursor); 950} 951 952GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun) 953{ 954 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 955 956 _GLFWwindow* window = (_GLFWwindow*) handle; 957 assert(window != NULL); 958 959 _GLFW_SWAP(GLFWkeyfun, window->callbacks.key, cbfun); 960 return cbfun; 961} 962 963GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun) 964{ 965 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 966 967 _GLFWwindow* window = (_GLFWwindow*) handle; 968 assert(window != NULL); 969 970 _GLFW_SWAP(GLFWcharfun, window->callbacks.character, cbfun); 971 return cbfun; 972} 973 974GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun) 975{ 976 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 977 978 _GLFWwindow* window = (_GLFWwindow*) handle; 979 assert(window != NULL); 980 981 _GLFW_SWAP(GLFWcharmodsfun, window->callbacks.charmods, cbfun); 982 return cbfun; 983} 984 985GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle, 986 GLFWmousebuttonfun cbfun) 987{ 988 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 989 990 _GLFWwindow* window = (_GLFWwindow*) handle; 991 assert(window != NULL); 992 993 _GLFW_SWAP(GLFWmousebuttonfun, window->callbacks.mouseButton, cbfun); 994 return cbfun; 995} 996 997GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle, 998 GLFWcursorposfun cbfun) 999{ 1000 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1001 1002 _GLFWwindow* window = (_GLFWwindow*) handle; 1003 assert(window != NULL); 1004 1005 _GLFW_SWAP(GLFWcursorposfun, window->callbacks.cursorPos, cbfun); 1006 return cbfun; 1007} 1008 1009GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle, 1010 GLFWcursorenterfun cbfun) 1011{ 1012 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1013 1014 _GLFWwindow* window = (_GLFWwindow*) handle; 1015 assert(window != NULL); 1016 1017 _GLFW_SWAP(GLFWcursorenterfun, window->callbacks.cursorEnter, cbfun); 1018 return cbfun; 1019} 1020 1021GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle, 1022 GLFWscrollfun cbfun) 1023{ 1024 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1025 1026 _GLFWwindow* window = (_GLFWwindow*) handle; 1027 assert(window != NULL); 1028 1029 _GLFW_SWAP(GLFWscrollfun, window->callbacks.scroll, cbfun); 1030 return cbfun; 1031} 1032 1033GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun) 1034{ 1035 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1036 1037 _GLFWwindow* window = (_GLFWwindow*) handle; 1038 assert(window != NULL); 1039 1040 _GLFW_SWAP(GLFWdropfun, window->callbacks.drop, cbfun); 1041 return cbfun; 1042} 1043 1044GLFWAPI int glfwJoystickPresent(int jid) 1045{ 1046 _GLFWjoystick* js; 1047 1048 assert(jid >= GLFW_JOYSTICK_1); 1049 assert(jid <= GLFW_JOYSTICK_LAST); 1050 1051 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1052 1053 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1054 { 1055 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1056 return GLFW_FALSE; 1057 } 1058 1059 if (!initJoysticks()) 1060 return GLFW_FALSE; 1061 1062 js = _glfw.joysticks + jid; 1063 if (!js->connected) 1064 return GLFW_FALSE; 1065 1066 return _glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE); 1067} 1068 1069GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count) 1070{ 1071 _GLFWjoystick* js; 1072 1073 assert(jid >= GLFW_JOYSTICK_1); 1074 assert(jid <= GLFW_JOYSTICK_LAST); 1075 assert(count != NULL); 1076 1077 *count = 0; 1078 1079 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1080 1081 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1082 { 1083 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1084 return NULL; 1085 } 1086 1087 if (!initJoysticks()) 1088 return NULL; 1089 1090 js = _glfw.joysticks + jid; 1091 if (!js->connected) 1092 return NULL; 1093 1094 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_AXES)) 1095 return NULL; 1096 1097 *count = js->axisCount; 1098 return js->axes; 1099} 1100 1101GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count) 1102{ 1103 _GLFWjoystick* js; 1104 1105 assert(jid >= GLFW_JOYSTICK_1); 1106 assert(jid <= GLFW_JOYSTICK_LAST); 1107 assert(count != NULL); 1108 1109 *count = 0; 1110 1111 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1112 1113 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1114 { 1115 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1116 return NULL; 1117 } 1118 1119 if (!initJoysticks()) 1120 return NULL; 1121 1122 js = _glfw.joysticks + jid; 1123 if (!js->connected) 1124 return NULL; 1125 1126 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) 1127 return NULL; 1128 1129 if (_glfw.hints.init.hatButtons) 1130 *count = js->buttonCount + js->hatCount * 4; 1131 else 1132 *count = js->buttonCount; 1133 1134 return js->buttons; 1135} 1136 1137GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count) 1138{ 1139 _GLFWjoystick* js; 1140 1141 assert(jid >= GLFW_JOYSTICK_1); 1142 assert(jid <= GLFW_JOYSTICK_LAST); 1143 assert(count != NULL); 1144 1145 *count = 0; 1146 1147 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1148 1149 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1150 { 1151 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1152 return NULL; 1153 } 1154 1155 if (!initJoysticks()) 1156 return NULL; 1157 1158 js = _glfw.joysticks + jid; 1159 if (!js->connected) 1160 return NULL; 1161 1162 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_BUTTONS)) 1163 return NULL; 1164 1165 *count = js->hatCount; 1166 return js->hats; 1167} 1168 1169GLFWAPI const char* glfwGetJoystickName(int jid) 1170{ 1171 _GLFWjoystick* js; 1172 1173 assert(jid >= GLFW_JOYSTICK_1); 1174 assert(jid <= GLFW_JOYSTICK_LAST); 1175 1176 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1177 1178 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1179 { 1180 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1181 return NULL; 1182 } 1183 1184 if (!initJoysticks()) 1185 return NULL; 1186 1187 js = _glfw.joysticks + jid; 1188 if (!js->connected) 1189 return NULL; 1190 1191 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) 1192 return NULL; 1193 1194 return js->name; 1195} 1196 1197GLFWAPI const char* glfwGetJoystickGUID(int jid) 1198{ 1199 _GLFWjoystick* js; 1200 1201 assert(jid >= GLFW_JOYSTICK_1); 1202 assert(jid <= GLFW_JOYSTICK_LAST); 1203 1204 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1205 1206 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1207 { 1208 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1209 return NULL; 1210 } 1211 1212 if (!initJoysticks()) 1213 return NULL; 1214 1215 js = _glfw.joysticks + jid; 1216 if (!js->connected) 1217 return NULL; 1218 1219 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) 1220 return NULL; 1221 1222 return js->guid; 1223} 1224 1225GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer) 1226{ 1227 _GLFWjoystick* js; 1228 1229 assert(jid >= GLFW_JOYSTICK_1); 1230 assert(jid <= GLFW_JOYSTICK_LAST); 1231 1232 _GLFW_REQUIRE_INIT(); 1233 1234 js = _glfw.joysticks + jid; 1235 if (!js->allocated) 1236 return; 1237 1238 js->userPointer = pointer; 1239} 1240 1241GLFWAPI void* glfwGetJoystickUserPointer(int jid) 1242{ 1243 _GLFWjoystick* js; 1244 1245 assert(jid >= GLFW_JOYSTICK_1); 1246 assert(jid <= GLFW_JOYSTICK_LAST); 1247 1248 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1249 1250 js = _glfw.joysticks + jid; 1251 if (!js->allocated) 1252 return NULL; 1253 1254 return js->userPointer; 1255} 1256 1257GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun) 1258{ 1259 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1260 1261 if (!initJoysticks()) 1262 return NULL; 1263 1264 _GLFW_SWAP(GLFWjoystickfun, _glfw.callbacks.joystick, cbfun); 1265 return cbfun; 1266} 1267 1268GLFWAPI int glfwUpdateGamepadMappings(const char* string) 1269{ 1270 int jid; 1271 const char* c = string; 1272 1273 assert(string != NULL); 1274 1275 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1276 1277 while (*c) 1278 { 1279 if ((*c >= '0' && *c <= '9') || 1280 (*c >= 'a' && *c <= 'f') || 1281 (*c >= 'A' && *c <= 'F')) 1282 { 1283 char line[1024]; 1284 1285 const size_t length = strcspn(c, "\r\n"); 1286 if (length < sizeof(line)) 1287 { 1288 _GLFWmapping mapping = {{0}}; 1289 1290 memcpy(line, c, length); 1291 line[length] = '\0'; 1292 1293 if (parseMapping(&mapping, line)) 1294 { 1295 _GLFWmapping* previous = findMapping(mapping.guid); 1296 if (previous) 1297 *previous = mapping; 1298 else 1299 { 1300 _glfw.mappingCount++; 1301 _glfw.mappings = 1302 _glfw_realloc(_glfw.mappings, 1303 sizeof(_GLFWmapping) * _glfw.mappingCount); 1304 _glfw.mappings[_glfw.mappingCount - 1] = mapping; 1305 } 1306 } 1307 } 1308 1309 c += length; 1310 } 1311 else 1312 { 1313 c += strcspn(c, "\r\n"); 1314 c += strspn(c, "\r\n"); 1315 } 1316 } 1317 1318 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++) 1319 { 1320 _GLFWjoystick* js = _glfw.joysticks + jid; 1321 if (js->connected) 1322 js->mapping = findValidMapping(js); 1323 } 1324 1325 return GLFW_TRUE; 1326} 1327 1328GLFWAPI int glfwJoystickIsGamepad(int jid) 1329{ 1330 _GLFWjoystick* js; 1331 1332 assert(jid >= GLFW_JOYSTICK_1); 1333 assert(jid <= GLFW_JOYSTICK_LAST); 1334 1335 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1336 1337 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1338 { 1339 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1340 return GLFW_FALSE; 1341 } 1342 1343 if (!initJoysticks()) 1344 return GLFW_FALSE; 1345 1346 js = _glfw.joysticks + jid; 1347 if (!js->connected) 1348 return GLFW_FALSE; 1349 1350 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) 1351 return GLFW_FALSE; 1352 1353 return js->mapping != NULL; 1354} 1355 1356GLFWAPI const char* glfwGetGamepadName(int jid) 1357{ 1358 _GLFWjoystick* js; 1359 1360 assert(jid >= GLFW_JOYSTICK_1); 1361 assert(jid <= GLFW_JOYSTICK_LAST); 1362 1363 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1364 1365 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1366 { 1367 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1368 return NULL; 1369 } 1370 1371 if (!initJoysticks()) 1372 return NULL; 1373 1374 js = _glfw.joysticks + jid; 1375 if (!js->connected) 1376 return NULL; 1377 1378 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_PRESENCE)) 1379 return NULL; 1380 1381 if (!js->mapping) 1382 return NULL; 1383 1384 return js->mapping->name; 1385} 1386 1387GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state) 1388{ 1389 int i; 1390 _GLFWjoystick* js; 1391 1392 assert(jid >= GLFW_JOYSTICK_1); 1393 assert(jid <= GLFW_JOYSTICK_LAST); 1394 assert(state != NULL); 1395 1396 memset(state, 0, sizeof(GLFWgamepadstate)); 1397 1398 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE); 1399 1400 if (jid < 0 || jid > GLFW_JOYSTICK_LAST) 1401 { 1402 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid); 1403 return GLFW_FALSE; 1404 } 1405 1406 if (!initJoysticks()) 1407 return GLFW_FALSE; 1408 1409 js = _glfw.joysticks + jid; 1410 if (!js->connected) 1411 return GLFW_FALSE; 1412 1413 if (!_glfw.platform.pollJoystick(js, _GLFW_POLL_ALL)) 1414 return GLFW_FALSE; 1415 1416 if (!js->mapping) 1417 return GLFW_FALSE; 1418 1419 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++) 1420 { 1421 const _GLFWmapelement* e = js->mapping->buttons + i; 1422 if (e->type == _GLFW_JOYSTICK_AXIS) 1423 { 1424 const float value = js->axes[e->index] * e->axisScale + e->axisOffset; 1425 // HACK: This should be baked into the value transform 1426 // TODO: Bake into transform when implementing output modifiers 1427 if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0)) 1428 { 1429 if (value >= 0.f) 1430 state->buttons[i] = GLFW_PRESS; 1431 } 1432 else 1433 { 1434 if (value <= 0.f) 1435 state->buttons[i] = GLFW_PRESS; 1436 } 1437 } 1438 else if (e->type == _GLFW_JOYSTICK_HATBIT) 1439 { 1440 const unsigned int hat = e->index >> 4; 1441 const unsigned int bit = e->index & 0xf; 1442 if (js->hats[hat] & bit) 1443 state->buttons[i] = GLFW_PRESS; 1444 } 1445 else if (e->type == _GLFW_JOYSTICK_BUTTON) 1446 state->buttons[i] = js->buttons[e->index]; 1447 } 1448 1449 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++) 1450 { 1451 const _GLFWmapelement* e = js->mapping->axes + i; 1452 if (e->type == _GLFW_JOYSTICK_AXIS) 1453 { 1454 const float value = js->axes[e->index] * e->axisScale + e->axisOffset; 1455 state->axes[i] = fminf(fmaxf(value, -1.f), 1.f); 1456 } 1457 else if (e->type == _GLFW_JOYSTICK_HATBIT) 1458 { 1459 const unsigned int hat = e->index >> 4; 1460 const unsigned int bit = e->index & 0xf; 1461 if (js->hats[hat] & bit) 1462 state->axes[i] = 1.f; 1463 else 1464 state->axes[i] = -1.f; 1465 } 1466 else if (e->type == _GLFW_JOYSTICK_BUTTON) 1467 state->axes[i] = js->buttons[e->index] * 2.f - 1.f; 1468 } 1469 1470 return GLFW_TRUE; 1471} 1472 1473GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string) 1474{ 1475 assert(string != NULL); 1476 1477 _GLFW_REQUIRE_INIT(); 1478 _glfw.platform.setClipboardString(string); 1479} 1480 1481GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle) 1482{ 1483 _GLFW_REQUIRE_INIT_OR_RETURN(NULL); 1484 return _glfw.platform.getClipboardString(); 1485} 1486 1487GLFWAPI double glfwGetTime(void) 1488{ 1489 _GLFW_REQUIRE_INIT_OR_RETURN(0.0); 1490 return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) / 1491 _glfwPlatformGetTimerFrequency(); 1492} 1493 1494GLFWAPI void glfwSetTime(double time) 1495{ 1496 _GLFW_REQUIRE_INIT(); 1497 1498 if (!isfinite(time) || time < 0.0 || time > 18446744073.0) 1499 { 1500 _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time); 1501 return; 1502 } 1503 1504 _glfw.timer.offset = _glfwPlatformGetTimerValue() - 1505 (uint64_t) (time * _glfwPlatformGetTimerFrequency()); 1506} 1507 1508GLFWAPI uint64_t glfwGetTimerValue(void) 1509{ 1510 _GLFW_REQUIRE_INIT_OR_RETURN(0); 1511 return _glfwPlatformGetTimerValue(); 1512} 1513 1514GLFWAPI uint64_t glfwGetTimerFrequency(void) 1515{ 1516 _GLFW_REQUIRE_INIT_OR_RETURN(0); 1517 return _glfwPlatformGetTimerFrequency(); 1518} 1519 1520[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.