zorldo

Goofing around with Ebiten
git clone git://bsandro.tech/zorldo
Log | Files | Refs | README

input.c (37496B)


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