medfall

A super great game engine
Log | Files | Refs

input.cc (31756B)


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