GCC Code Coverage Report


Directory: ./
File: submodules/raylib/src/external/glfw/src/input.c
Date: 2023-09-29 04:53:15
Exec Total Coverage
Lines: 0 559 0.0%
Branches: 0 478 0.0%

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