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