1 //========================================================================
2 // GLFW 3.3 - www.glfw.org
3 //------------------------------------------------------------------------
4 // Copyright (c) 2002-2006 Marcus Geelnard
5 // Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
6 //
7 // This software is provided 'as-is', without any express or implied
8 // warranty. In no event will the authors be held liable for any damages
9 // arising from the use of this software.
10 //
11 // Permission is granted to anyone to use this software for any purpose,
12 // including commercial applications, and to alter it and redistribute it
13 // freely, subject to the following restrictions:
14 //
15 // 1. The origin of this software must not be misrepresented; you must not
16 //    claim that you wrote the original software. If you use this software
17 //    in a product, an acknowledgment in the product documentation would
18 //    be appreciated but is not required.
19 //
20 // 2. Altered source versions must be plainly marked as such, and must not
21 //    be misrepresented as being the original software.
22 //
23 // 3. This notice may not be removed or altered from any source
24 //    distribution.
25 //
26 //========================================================================
27 
28 #include "internal.h"
29 
30 #include <assert.h>
31 #include <float.h>
32 #include <math.h>
33 #include <stdlib.h>
34 #include <string.h>
35 
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 client-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 + hatCount * 4, 1);
434     js->hats        = calloc(hatCount, 1);
435     js->axisCount   = axisCount;
436     js->buttonCount = buttonCount;
437     js->hatCount    = hatCount;
438 
439     strcpy(js->guid, guid);
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 
457 //////////////////////////////////////////////////////////////////////////
458 //////                        GLFW public API                       //////
459 //////////////////////////////////////////////////////////////////////////
460 
glfwGetInputMode(GLFWwindow * handle,int mode)461 GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
462 {
463     _GLFWwindow* window = (_GLFWwindow*) handle;
464     assert(window != NULL);
465 
466     _GLFW_REQUIRE_INIT_OR_RETURN(0);
467 
468     switch (mode)
469     {
470         case GLFW_CURSOR:
471             return window->cursorMode;
472         case GLFW_STICKY_KEYS:
473             return window->stickyKeys;
474         case GLFW_STICKY_MOUSE_BUTTONS:
475             return window->stickyMouseButtons;
476         case GLFW_LOCK_KEY_MODS:
477             return window->lockKeyMods;
478     }
479 
480     _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
481     return 0;
482 }
483 
glfwSetInputMode(GLFWwindow * handle,int mode,int value)484 GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
485 {
486     _GLFWwindow* window = (_GLFWwindow*) handle;
487     assert(window != NULL);
488 
489     _GLFW_REQUIRE_INIT();
490 
491     if (mode == GLFW_CURSOR)
492     {
493         if (value != GLFW_CURSOR_NORMAL &&
494             value != GLFW_CURSOR_HIDDEN &&
495             value != GLFW_CURSOR_DISABLED)
496         {
497             _glfwInputError(GLFW_INVALID_ENUM,
498                             "Invalid cursor mode 0x%08X",
499                             value);
500             return;
501         }
502 
503         if (window->cursorMode == value)
504             return;
505 
506         window->cursorMode = value;
507 
508         _glfwPlatformGetCursorPos(window,
509                                   &window->virtualCursorPosX,
510                                   &window->virtualCursorPosY);
511         _glfwPlatformSetCursorMode(window, value);
512     }
513     else if (mode == GLFW_STICKY_KEYS)
514     {
515         value = value ? GLFW_TRUE : GLFW_FALSE;
516         if (window->stickyKeys == value)
517             return;
518 
519         if (!value)
520         {
521             int i;
522 
523             // Release all sticky keys
524             for (i = 0;  i <= GLFW_KEY_LAST;  i++)
525             {
526                 if (window->keys[i] == _GLFW_STICK)
527                     window->keys[i] = GLFW_RELEASE;
528             }
529         }
530 
531         window->stickyKeys = value;
532     }
533     else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
534     {
535         value = value ? GLFW_TRUE : GLFW_FALSE;
536         if (window->stickyMouseButtons == value)
537             return;
538 
539         if (!value)
540         {
541             int i;
542 
543             // Release all sticky mouse buttons
544             for (i = 0;  i <= GLFW_MOUSE_BUTTON_LAST;  i++)
545             {
546                 if (window->mouseButtons[i] == _GLFW_STICK)
547                     window->mouseButtons[i] = GLFW_RELEASE;
548             }
549         }
550 
551         window->stickyMouseButtons = value;
552     }
553     else if (mode == GLFW_LOCK_KEY_MODS)
554         window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE;
555     else
556         _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
557 }
558 
glfwGetKeyName(int key,int scancode)559 GLFWAPI const char* glfwGetKeyName(int key, int scancode)
560 {
561     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
562 
563     if (key != GLFW_KEY_UNKNOWN)
564     {
565         if (key != GLFW_KEY_KP_EQUAL &&
566             (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
567             (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
568         {
569             return NULL;
570         }
571 
572         scancode = _glfwPlatformGetKeyScancode(key);
573     }
574 
575     return _glfwPlatformGetScancodeName(scancode);
576 }
577 
glfwGetKeyScancode(int key)578 GLFWAPI int glfwGetKeyScancode(int key)
579 {
580     _GLFW_REQUIRE_INIT_OR_RETURN(-1);
581 
582     if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
583     {
584         _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
585         return GLFW_RELEASE;
586     }
587 
588     return _glfwPlatformGetKeyScancode(key);
589 }
590 
glfwGetKey(GLFWwindow * handle,int key)591 GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
592 {
593     _GLFWwindow* window = (_GLFWwindow*) handle;
594     assert(window != NULL);
595 
596     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
597 
598     if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
599     {
600         _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
601         return GLFW_RELEASE;
602     }
603 
604     if (window->keys[key] == _GLFW_STICK)
605     {
606         // Sticky mode: release key now
607         window->keys[key] = GLFW_RELEASE;
608         return GLFW_PRESS;
609     }
610 
611     return (int) window->keys[key];
612 }
613 
glfwGetMouseButton(GLFWwindow * handle,int button)614 GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
615 {
616     _GLFWwindow* window = (_GLFWwindow*) handle;
617     assert(window != NULL);
618 
619     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
620 
621     if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
622     {
623         _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
624         return GLFW_RELEASE;
625     }
626 
627     if (window->mouseButtons[button] == _GLFW_STICK)
628     {
629         // Sticky mode: release mouse button now
630         window->mouseButtons[button] = GLFW_RELEASE;
631         return GLFW_PRESS;
632     }
633 
634     return (int) window->mouseButtons[button];
635 }
636 
glfwGetCursorPos(GLFWwindow * handle,double * xpos,double * ypos)637 GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
638 {
639     _GLFWwindow* window = (_GLFWwindow*) handle;
640     assert(window != NULL);
641 
642     if (xpos)
643         *xpos = 0;
644     if (ypos)
645         *ypos = 0;
646 
647     _GLFW_REQUIRE_INIT();
648 
649     if (window->cursorMode == GLFW_CURSOR_DISABLED)
650     {
651         if (xpos)
652             *xpos = window->virtualCursorPosX;
653         if (ypos)
654             *ypos = window->virtualCursorPosY;
655     }
656     else
657         _glfwPlatformGetCursorPos(window, xpos, ypos);
658 }
659 
glfwSetCursorPos(GLFWwindow * handle,double xpos,double ypos)660 GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
661 {
662     _GLFWwindow* window = (_GLFWwindow*) handle;
663     assert(window != NULL);
664 
665     _GLFW_REQUIRE_INIT();
666 
667     if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
668         ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
669     {
670         _glfwInputError(GLFW_INVALID_VALUE,
671                         "Invalid cursor position %f %f",
672                         xpos, ypos);
673         return;
674     }
675 
676     if (!_glfwPlatformWindowFocused(window))
677         return;
678 
679     if (window->cursorMode == GLFW_CURSOR_DISABLED)
680     {
681         // Only update the accumulated position if the cursor is disabled
682         window->virtualCursorPosX = xpos;
683         window->virtualCursorPosY = ypos;
684     }
685     else
686     {
687         // Update system cursor position
688         _glfwPlatformSetCursorPos(window, xpos, ypos);
689     }
690 }
691 
glfwCreateCursor(const GLFWimage * image,int xhot,int yhot)692 GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
693 {
694     _GLFWcursor* cursor;
695 
696     assert(image != NULL);
697 
698     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
699 
700     cursor = calloc(1, sizeof(_GLFWcursor));
701     cursor->next = _glfw.cursorListHead;
702     _glfw.cursorListHead = cursor;
703 
704     if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot))
705     {
706         glfwDestroyCursor((GLFWcursor*) cursor);
707         return NULL;
708     }
709 
710     return (GLFWcursor*) cursor;
711 }
712 
glfwCreateStandardCursor(int shape)713 GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
714 {
715     _GLFWcursor* cursor;
716 
717     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
718 
719     if (shape != GLFW_ARROW_CURSOR &&
720         shape != GLFW_IBEAM_CURSOR &&
721         shape != GLFW_CROSSHAIR_CURSOR &&
722         shape != GLFW_HAND_CURSOR &&
723         shape != GLFW_HRESIZE_CURSOR &&
724         shape != GLFW_VRESIZE_CURSOR)
725     {
726         _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
727         return NULL;
728     }
729 
730     cursor = calloc(1, sizeof(_GLFWcursor));
731     cursor->next = _glfw.cursorListHead;
732     _glfw.cursorListHead = cursor;
733 
734     if (!_glfwPlatformCreateStandardCursor(cursor, shape))
735     {
736         glfwDestroyCursor((GLFWcursor*) cursor);
737         return NULL;
738     }
739 
740     return (GLFWcursor*) cursor;
741 }
742 
glfwDestroyCursor(GLFWcursor * handle)743 GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
744 {
745     _GLFWcursor* cursor = (_GLFWcursor*) handle;
746 
747     _GLFW_REQUIRE_INIT();
748 
749     if (cursor == NULL)
750         return;
751 
752     // Make sure the cursor is not being used by any window
753     {
754         _GLFWwindow* window;
755 
756         for (window = _glfw.windowListHead;  window;  window = window->next)
757         {
758             if (window->cursor == cursor)
759                 glfwSetCursor((GLFWwindow*) window, NULL);
760         }
761     }
762 
763     _glfwPlatformDestroyCursor(cursor);
764 
765     // Unlink cursor from global linked list
766     {
767         _GLFWcursor** prev = &_glfw.cursorListHead;
768 
769         while (*prev != cursor)
770             prev = &((*prev)->next);
771 
772         *prev = cursor->next;
773     }
774 
775     free(cursor);
776 }
777 
glfwSetCursor(GLFWwindow * windowHandle,GLFWcursor * cursorHandle)778 GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
779 {
780     _GLFWwindow* window = (_GLFWwindow*) windowHandle;
781     _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
782     assert(window != NULL);
783 
784     _GLFW_REQUIRE_INIT();
785 
786     window->cursor = cursor;
787 
788     _glfwPlatformSetCursor(window, cursor);
789 }
790 
glfwSetKeyCallback(GLFWwindow * handle,GLFWkeyfun cbfun)791 GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
792 {
793     _GLFWwindow* window = (_GLFWwindow*) handle;
794     assert(window != NULL);
795 
796     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
797     _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
798     return cbfun;
799 }
800 
glfwSetCharCallback(GLFWwindow * handle,GLFWcharfun cbfun)801 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
802 {
803     _GLFWwindow* window = (_GLFWwindow*) handle;
804     assert(window != NULL);
805 
806     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
807     _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
808     return cbfun;
809 }
810 
glfwSetCharModsCallback(GLFWwindow * handle,GLFWcharmodsfun cbfun)811 GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
812 {
813     _GLFWwindow* window = (_GLFWwindow*) handle;
814     assert(window != NULL);
815 
816     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
817     _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
818     return cbfun;
819 }
820 
glfwSetMouseButtonCallback(GLFWwindow * handle,GLFWmousebuttonfun cbfun)821 GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
822                                                       GLFWmousebuttonfun cbfun)
823 {
824     _GLFWwindow* window = (_GLFWwindow*) handle;
825     assert(window != NULL);
826 
827     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
828     _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
829     return cbfun;
830 }
831 
glfwSetCursorPosCallback(GLFWwindow * handle,GLFWcursorposfun cbfun)832 GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
833                                                   GLFWcursorposfun cbfun)
834 {
835     _GLFWwindow* window = (_GLFWwindow*) handle;
836     assert(window != NULL);
837 
838     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
839     _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
840     return cbfun;
841 }
842 
glfwSetCursorEnterCallback(GLFWwindow * handle,GLFWcursorenterfun cbfun)843 GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
844                                                       GLFWcursorenterfun cbfun)
845 {
846     _GLFWwindow* window = (_GLFWwindow*) handle;
847     assert(window != NULL);
848 
849     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
850     _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
851     return cbfun;
852 }
853 
glfwSetScrollCallback(GLFWwindow * handle,GLFWscrollfun cbfun)854 GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
855                                             GLFWscrollfun cbfun)
856 {
857     _GLFWwindow* window = (_GLFWwindow*) handle;
858     assert(window != NULL);
859 
860     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
861     _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
862     return cbfun;
863 }
864 
glfwSetDropCallback(GLFWwindow * handle,GLFWdropfun cbfun)865 GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
866 {
867     _GLFWwindow* window = (_GLFWwindow*) handle;
868     assert(window != NULL);
869 
870     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
871     _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
872     return cbfun;
873 }
874 
glfwJoystickPresent(int jid)875 GLFWAPI int glfwJoystickPresent(int jid)
876 {
877     _GLFWjoystick* js;
878 
879     assert(jid >= GLFW_JOYSTICK_1);
880     assert(jid <= GLFW_JOYSTICK_LAST);
881 
882     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
883 
884     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
885     {
886         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
887         return GLFW_FALSE;
888     }
889 
890     js = _glfw.joysticks + jid;
891     if (!js->present)
892         return GLFW_FALSE;
893 
894     return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
895 }
896 
glfwGetJoystickAxes(int jid,int * count)897 GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
898 {
899     _GLFWjoystick* js;
900 
901     assert(jid >= GLFW_JOYSTICK_1);
902     assert(jid <= GLFW_JOYSTICK_LAST);
903     assert(count != NULL);
904 
905     *count = 0;
906 
907     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
908 
909     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
910     {
911         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
912         return NULL;
913     }
914 
915     js = _glfw.joysticks + jid;
916     if (!js->present)
917         return NULL;
918 
919     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES))
920         return NULL;
921 
922     *count = js->axisCount;
923     return js->axes;
924 }
925 
glfwGetJoystickButtons(int jid,int * count)926 GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
927 {
928     _GLFWjoystick* js;
929 
930     assert(jid >= GLFW_JOYSTICK_1);
931     assert(jid <= GLFW_JOYSTICK_LAST);
932     assert(count != NULL);
933 
934     *count = 0;
935 
936     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
937 
938     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
939     {
940         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
941         return NULL;
942     }
943 
944     js = _glfw.joysticks + jid;
945     if (!js->present)
946         return NULL;
947 
948     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
949         return NULL;
950 
951     if (_glfw.hints.init.hatButtons)
952         *count = js->buttonCount + js->hatCount * 4;
953     else
954         *count = js->buttonCount;
955 
956     return js->buttons;
957 }
958 
glfwGetJoystickHats(int jid,int * count)959 GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
960 {
961     _GLFWjoystick* js;
962 
963     assert(jid >= GLFW_JOYSTICK_1);
964     assert(jid <= GLFW_JOYSTICK_LAST);
965     assert(count != NULL);
966 
967     *count = 0;
968 
969     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
970 
971     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
972     {
973         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
974         return NULL;
975     }
976 
977     js = _glfw.joysticks + jid;
978     if (!js->present)
979         return NULL;
980 
981     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
982         return NULL;
983 
984     *count = js->hatCount;
985     return js->hats;
986 }
987 
glfwGetJoystickName(int jid)988 GLFWAPI const char* glfwGetJoystickName(int jid)
989 {
990     _GLFWjoystick* js;
991 
992     assert(jid >= GLFW_JOYSTICK_1);
993     assert(jid <= GLFW_JOYSTICK_LAST);
994 
995     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
996 
997     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
998     {
999         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1000         return NULL;
1001     }
1002 
1003     js = _glfw.joysticks + jid;
1004     if (!js->present)
1005         return NULL;
1006 
1007     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1008         return NULL;
1009 
1010     return js->name;
1011 }
1012 
glfwGetJoystickGUID(int jid)1013 GLFWAPI const char* glfwGetJoystickGUID(int jid)
1014 {
1015     _GLFWjoystick* js;
1016 
1017     assert(jid >= GLFW_JOYSTICK_1);
1018     assert(jid <= GLFW_JOYSTICK_LAST);
1019 
1020     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1021 
1022     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1023     {
1024         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1025         return NULL;
1026     }
1027 
1028     js = _glfw.joysticks + jid;
1029     if (!js->present)
1030         return NULL;
1031 
1032     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1033         return NULL;
1034 
1035     return js->guid;
1036 }
1037 
glfwSetJoystickUserPointer(int jid,void * pointer)1038 GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
1039 {
1040     _GLFWjoystick* js;
1041 
1042     assert(jid >= GLFW_JOYSTICK_1);
1043     assert(jid <= GLFW_JOYSTICK_LAST);
1044 
1045     _GLFW_REQUIRE_INIT();
1046 
1047     js = _glfw.joysticks + jid;
1048     if (!js->present)
1049         return;
1050 
1051     js->userPointer = pointer;
1052 }
1053 
glfwGetJoystickUserPointer(int jid)1054 GLFWAPI void* glfwGetJoystickUserPointer(int jid)
1055 {
1056     _GLFWjoystick* js;
1057 
1058     assert(jid >= GLFW_JOYSTICK_1);
1059     assert(jid <= GLFW_JOYSTICK_LAST);
1060 
1061     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1062 
1063     js = _glfw.joysticks + jid;
1064     if (!js->present)
1065         return NULL;
1066 
1067     return js->userPointer;
1068 }
1069 
glfwSetJoystickCallback(GLFWjoystickfun cbfun)1070 GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
1071 {
1072     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1073     _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
1074     return cbfun;
1075 }
1076 
glfwUpdateGamepadMappings(const char * string)1077 GLFWAPI int glfwUpdateGamepadMappings(const char* string)
1078 {
1079     int jid;
1080     const char* c = string;
1081 
1082     assert(string != NULL);
1083 
1084     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1085 
1086     while (*c)
1087     {
1088         if ((*c >= '0' && *c <= '9') ||
1089             (*c >= 'a' && *c <= 'f') ||
1090             (*c >= 'A' && *c <= 'F'))
1091         {
1092             char line[1024];
1093 
1094             const size_t length = strcspn(c, "\r\n");
1095             if (length < sizeof(line))
1096             {
1097                 _GLFWmapping mapping = {{0}};
1098 
1099                 memcpy(line, c, length);
1100                 line[length] = '\0';
1101 
1102                 if (parseMapping(&mapping, line))
1103                 {
1104                     _GLFWmapping* previous = findMapping(mapping.guid);
1105                     if (previous)
1106                         *previous = mapping;
1107                     else
1108                     {
1109                         _glfw.mappingCount++;
1110                         _glfw.mappings =
1111                             realloc(_glfw.mappings,
1112                                     sizeof(_GLFWmapping) * _glfw.mappingCount);
1113                         _glfw.mappings[_glfw.mappingCount - 1] = mapping;
1114                     }
1115                 }
1116             }
1117 
1118             c += length;
1119         }
1120         else
1121         {
1122             c += strcspn(c, "\r\n");
1123             c += strspn(c, "\r\n");
1124         }
1125     }
1126 
1127     for (jid = 0;  jid <= GLFW_JOYSTICK_LAST;  jid++)
1128     {
1129         _GLFWjoystick* js = _glfw.joysticks + jid;
1130         if (js->present)
1131             js->mapping = findValidMapping(js);
1132     }
1133 
1134     return GLFW_TRUE;
1135 }
1136 
glfwJoystickIsGamepad(int jid)1137 GLFWAPI int glfwJoystickIsGamepad(int jid)
1138 {
1139     _GLFWjoystick* js;
1140 
1141     assert(jid >= GLFW_JOYSTICK_1);
1142     assert(jid <= GLFW_JOYSTICK_LAST);
1143 
1144     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1145 
1146     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1147     {
1148         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1149         return GLFW_FALSE;
1150     }
1151 
1152     js = _glfw.joysticks + jid;
1153     if (!js->present)
1154         return GLFW_FALSE;
1155 
1156     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1157         return GLFW_FALSE;
1158 
1159     return js->mapping != NULL;
1160 }
1161 
glfwGetGamepadName(int jid)1162 GLFWAPI const char* glfwGetGamepadName(int jid)
1163 {
1164     _GLFWjoystick* js;
1165 
1166     assert(jid >= GLFW_JOYSTICK_1);
1167     assert(jid <= GLFW_JOYSTICK_LAST);
1168 
1169     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1170 
1171     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1172     {
1173         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1174         return NULL;
1175     }
1176 
1177     js = _glfw.joysticks + jid;
1178     if (!js->present)
1179         return NULL;
1180 
1181     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1182         return NULL;
1183 
1184     if (!js->mapping)
1185         return NULL;
1186 
1187     return js->mapping->name;
1188 }
1189 
glfwGetGamepadState(int jid,GLFWgamepadstate * state)1190 GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
1191 {
1192     int i;
1193     _GLFWjoystick* js;
1194 
1195     assert(jid >= GLFW_JOYSTICK_1);
1196     assert(jid <= GLFW_JOYSTICK_LAST);
1197     assert(state != NULL);
1198 
1199     memset(state, 0, sizeof(GLFWgamepadstate));
1200 
1201     _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1202 
1203     if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1204     {
1205         _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1206         return GLFW_FALSE;
1207     }
1208 
1209     js = _glfw.joysticks + jid;
1210     if (!js->present)
1211         return GLFW_FALSE;
1212 
1213     if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL))
1214         return GLFW_FALSE;
1215 
1216     if (!js->mapping)
1217         return GLFW_FALSE;
1218 
1219     for (i = 0;  i <= GLFW_GAMEPAD_BUTTON_LAST;  i++)
1220     {
1221         const _GLFWmapelement* e = js->mapping->buttons + i;
1222         if (e->type == _GLFW_JOYSTICK_AXIS)
1223         {
1224             const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
1225             if (value > 0.f)
1226                 state->buttons[i] = GLFW_PRESS;
1227         }
1228         else if (e->type == _GLFW_JOYSTICK_HATBIT)
1229         {
1230             const unsigned int hat = e->index >> 4;
1231             const unsigned int bit = e->index & 0xf;
1232             if (js->hats[hat] & bit)
1233                 state->buttons[i] = GLFW_PRESS;
1234         }
1235         else if (e->type == _GLFW_JOYSTICK_BUTTON)
1236             state->buttons[i] = js->buttons[e->index];
1237     }
1238 
1239     for (i = 0;  i <= GLFW_GAMEPAD_AXIS_LAST;  i++)
1240     {
1241         const _GLFWmapelement* e = js->mapping->axes + i;
1242         if (e->type == _GLFW_JOYSTICK_AXIS)
1243         {
1244             const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
1245             state->axes[i] = fminf(fmaxf(value, -1.f), 1.f);
1246         }
1247         else if (e->type == _GLFW_JOYSTICK_HATBIT)
1248         {
1249             const unsigned int hat = e->index >> 4;
1250             const unsigned int bit = e->index & 0xf;
1251             if (js->hats[hat] & bit)
1252                 state->axes[i] = 1.f;
1253         }
1254         else if (e->type == _GLFW_JOYSTICK_BUTTON)
1255             state->axes[i] = (float) js->buttons[e->index];
1256     }
1257 
1258     return GLFW_TRUE;
1259 }
1260 
glfwSetClipboardString(GLFWwindow * handle,const char * string)1261 GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
1262 {
1263     assert(string != NULL);
1264 
1265     _GLFW_REQUIRE_INIT();
1266     _glfwPlatformSetClipboardString(string);
1267 }
1268 
glfwGetClipboardString(GLFWwindow * handle)1269 GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
1270 {
1271     _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1272     return _glfwPlatformGetClipboardString();
1273 }
1274 
glfwGetTime(void)1275 GLFWAPI double glfwGetTime(void)
1276 {
1277     _GLFW_REQUIRE_INIT_OR_RETURN(0.0);
1278     return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
1279         _glfwPlatformGetTimerFrequency();
1280 }
1281 
glfwSetTime(double time)1282 GLFWAPI void glfwSetTime(double time)
1283 {
1284     _GLFW_REQUIRE_INIT();
1285 
1286     if (time != time || time < 0.0 || time > 18446744073.0)
1287     {
1288         _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
1289         return;
1290     }
1291 
1292     _glfw.timer.offset = _glfwPlatformGetTimerValue() -
1293         (uint64_t) (time * _glfwPlatformGetTimerFrequency());
1294 }
1295 
glfwGetTimerValue(void)1296 GLFWAPI uint64_t glfwGetTimerValue(void)
1297 {
1298     _GLFW_REQUIRE_INIT_OR_RETURN(0);
1299     return _glfwPlatformGetTimerValue();
1300 }
1301 
glfwGetTimerFrequency(void)1302 GLFWAPI uint64_t glfwGetTimerFrequency(void)
1303 {
1304     _GLFW_REQUIRE_INIT_OR_RETURN(0);
1305     return _glfwPlatformGetTimerFrequency();
1306 }
1307 
1308