volviewer

Volumetric Data Toy Viewer
git clone anongit@rnpnr.xyz:volviewer.git
Log | Files | Refs | Feed | LICENSE

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