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