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