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