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