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