github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/glfw/src/input.c (about)

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