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