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