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>
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.
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:
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.
20 // 2. Altered source versions must be plainly marked as such, and must not
21 // be misrepresented as being the original software.
23 // 3. This notice may not be removed or altered from any source
26 //========================================================================
27 // Please use C89 style variable declarations in this file because VS 2010
28 //========================================================================
38 // Internal key state used for sticky keys
41 // Internal constants for gamepad mapping source types
42 #define _GLFW_JOYSTICK_AXIS 1
43 #define _GLFW_JOYSTICK_BUTTON 2
44 #define _GLFW_JOYSTICK_HATBIT 3
46 // Initializes the platform joystick API if it has not been already
48 static GLFWbool initJoysticks(void)
50 if (!_glfw.joysticksInitialized)
52 if (!_glfwPlatformInitJoysticks())
54 _glfwPlatformTerminateJoysticks();
59 return _glfw.joysticksInitialized = GLFW_TRUE;
62 // Finds a mapping based on joystick GUID
64 static _GLFWmapping* findMapping(const char* guid)
68 for (i = 0; i < _glfw.mappingCount; i++)
70 if (strcmp(_glfw.mappings[i].guid, guid) == 0)
71 return _glfw.mappings + i;
77 // Checks whether a gamepad mapping element is present in the hardware
79 static GLFWbool isValidElementForJoystick(const _GLFWmapelement* e,
80 const _GLFWjoystick* js)
82 if (e->type == _GLFW_JOYSTICK_HATBIT && (e->index >> 4) >= js->hatCount)
84 else if (e->type == _GLFW_JOYSTICK_BUTTON && e->index >= js->buttonCount)
86 else if (e->type == _GLFW_JOYSTICK_AXIS && e->index >= js->axisCount)
92 // Finds a mapping based on joystick GUID and verifies element indices
94 static _GLFWmapping* findValidMapping(const _GLFWjoystick* js)
96 _GLFWmapping* mapping = findMapping(js->guid);
101 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
103 if (!isValidElementForJoystick(mapping->buttons + i, js))
105 _glfwInputError(GLFW_INVALID_VALUE,
106 "Invalid button in gamepad mapping %s (%s)",
113 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
115 if (!isValidElementForJoystick(mapping->axes + i, js))
117 _glfwInputError(GLFW_INVALID_VALUE,
118 "Invalid axis in gamepad mapping %s (%s)",
129 // Parses an SDL_GameControllerDB line and adds it to the mapping list
131 static GLFWbool parseMapping(_GLFWmapping* mapping, const char* string)
133 const char* c = string;
138 _GLFWmapelement* element;
141 { "platform", NULL },
142 { "a", mapping->buttons + GLFW_GAMEPAD_BUTTON_A },
143 { "b", mapping->buttons + GLFW_GAMEPAD_BUTTON_B },
144 { "x", mapping->buttons + GLFW_GAMEPAD_BUTTON_X },
145 { "y", mapping->buttons + GLFW_GAMEPAD_BUTTON_Y },
146 { "back", mapping->buttons + GLFW_GAMEPAD_BUTTON_BACK },
147 { "start", mapping->buttons + GLFW_GAMEPAD_BUTTON_START },
148 { "guide", mapping->buttons + GLFW_GAMEPAD_BUTTON_GUIDE },
149 { "leftshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_BUMPER },
150 { "rightshoulder", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER },
151 { "leftstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_LEFT_THUMB },
152 { "rightstick", mapping->buttons + GLFW_GAMEPAD_BUTTON_RIGHT_THUMB },
153 { "dpup", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_UP },
154 { "dpright", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_RIGHT },
155 { "dpdown", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_DOWN },
156 { "dpleft", mapping->buttons + GLFW_GAMEPAD_BUTTON_DPAD_LEFT },
157 { "lefttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_TRIGGER },
158 { "righttrigger", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER },
159 { "leftx", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_X },
160 { "lefty", mapping->axes + GLFW_GAMEPAD_AXIS_LEFT_Y },
161 { "rightx", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_X },
162 { "righty", mapping->axes + GLFW_GAMEPAD_AXIS_RIGHT_Y }
165 length = strcspn(c, ",");
166 if (length != 32 || c[length] != ',')
168 _glfwInputError(GLFW_INVALID_VALUE, NULL);
172 memcpy(mapping->guid, c, length);
175 length = strcspn(c, ",");
176 if (length >= sizeof(mapping->name) || c[length] != ',')
178 _glfwInputError(GLFW_INVALID_VALUE, NULL);
182 memcpy(mapping->name, c, length);
187 // TODO: Implement output modifiers
188 if (*c == '+' || *c == '-')
191 for (i = 0; i < sizeof(fields) / sizeof(fields[0]); i++)
193 length = strlen(fields[i].name);
194 if (strncmp(c, fields[i].name, length) != 0 || c[length] != ':')
199 if (fields[i].element)
201 _GLFWmapelement* e = fields[i].element;
217 e->type = _GLFW_JOYSTICK_AXIS;
219 e->type = _GLFW_JOYSTICK_BUTTON;
221 e->type = _GLFW_JOYSTICK_HATBIT;
225 if (e->type == _GLFW_JOYSTICK_HATBIT)
227 const unsigned long hat = strtoul(c + 1, (char**) &c, 10);
228 const unsigned long bit = strtoul(c + 1, (char**) &c, 10);
229 e->index = (uint8_t) ((hat << 4) | bit);
232 e->index = (uint8_t) strtoul(c + 1, (char**) &c, 10);
234 if (e->type == _GLFW_JOYSTICK_AXIS)
236 e->axisScale = 2 / (maximum - minimum);
237 e->axisOffset = -(maximum + minimum);
241 e->axisScale = -e->axisScale;
242 e->axisOffset = -e->axisOffset;
248 length = strlen(_GLFW_PLATFORM_MAPPING_NAME);
249 if (strncmp(c, _GLFW_PLATFORM_MAPPING_NAME, length) != 0)
256 c += strcspn(c, ",");
260 for (i = 0; i < 32; i++)
262 if (mapping->guid[i] >= 'A' && mapping->guid[i] <= 'F')
263 mapping->guid[i] += 'a' - 'A';
266 _glfwPlatformUpdateGamepadGUID(mapping->guid);
271 //////////////////////////////////////////////////////////////////////////
272 ////// GLFW event API //////
273 //////////////////////////////////////////////////////////////////////////
275 // Notifies shared code of a physical key event
277 void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
279 if (key >= 0 && key <= GLFW_KEY_LAST)
281 GLFWbool repeated = GLFW_FALSE;
283 if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
286 if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
287 repeated = GLFW_TRUE;
289 if (action == GLFW_RELEASE && window->stickyKeys)
290 window->keys[key] = _GLFW_STICK;
292 window->keys[key] = (char) action;
295 action = GLFW_REPEAT;
298 if (!window->lockKeyMods)
299 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
301 if (window->callbacks.key)
302 window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
305 // Notifies shared code of a Unicode codepoint input event
306 // The 'plain' parameter determines whether to emit a regular character event
308 void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
310 if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
313 if (!window->lockKeyMods)
314 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
316 if (window->callbacks.charmods)
317 window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
321 if (window->callbacks.character)
322 window->callbacks.character((GLFWwindow*) window, codepoint);
326 // Notifies shared code of a scroll event
328 void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
330 if (window->callbacks.scroll)
331 window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
334 // Notifies shared code of a mouse button click event
336 void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
338 if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
341 if (!window->lockKeyMods)
342 mods &= ~(GLFW_MOD_CAPS_LOCK | GLFW_MOD_NUM_LOCK);
344 if (action == GLFW_RELEASE && window->stickyMouseButtons)
345 window->mouseButtons[button] = _GLFW_STICK;
347 window->mouseButtons[button] = (char) action;
349 if (window->callbacks.mouseButton)
350 window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
353 // Notifies shared code of a cursor motion event
354 // The position is specified in content area relative screen coordinates
356 void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
358 if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
361 window->virtualCursorPosX = xpos;
362 window->virtualCursorPosY = ypos;
364 if (window->callbacks.cursorPos)
365 window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
368 // Notifies shared code of a cursor enter/leave event
370 void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
372 if (window->callbacks.cursorEnter)
373 window->callbacks.cursorEnter((GLFWwindow*) window, entered);
376 // Notifies shared code of files or directories dropped on a window
378 void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
380 if (window->callbacks.drop)
381 window->callbacks.drop((GLFWwindow*) window, count, paths);
384 // Notifies shared code of a joystick connection or disconnection
386 void _glfwInputJoystick(_GLFWjoystick* js, int event)
388 const int jid = (int) (js - _glfw.joysticks);
390 if (_glfw.callbacks.joystick)
391 _glfw.callbacks.joystick(jid, event);
394 // Notifies shared code of the new value of a joystick axis
396 void _glfwInputJoystickAxis(_GLFWjoystick* js, int axis, float value)
398 js->axes[axis] = value;
401 // Notifies shared code of the new value of a joystick button
403 void _glfwInputJoystickButton(_GLFWjoystick* js, int button, char value)
405 js->buttons[button] = value;
408 // Notifies shared code of the new value of a joystick hat
410 void _glfwInputJoystickHat(_GLFWjoystick* js, int hat, char value)
412 const int base = js->buttonCount + hat * 4;
414 js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
415 js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
416 js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE;
417 js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
419 js->hats[hat] = value;
423 //////////////////////////////////////////////////////////////////////////
424 ////// GLFW internal API //////
425 //////////////////////////////////////////////////////////////////////////
427 // Returns an available joystick object with arrays and name allocated
429 _GLFWjoystick* _glfwAllocJoystick(const char* name,
438 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
440 if (!_glfw.joysticks[jid].present)
444 if (jid > GLFW_JOYSTICK_LAST)
447 js = _glfw.joysticks + jid;
448 js->present = GLFW_TRUE;
449 js->name = _glfw_strdup(name);
450 js->axes = calloc(axisCount, sizeof(float));
451 js->buttons = calloc(buttonCount + (size_t) hatCount * 4, 1);
452 js->hats = calloc(hatCount, 1);
453 js->axisCount = axisCount;
454 js->buttonCount = buttonCount;
455 js->hatCount = hatCount;
457 strncpy(js->guid, guid, sizeof(js->guid) - 1);
458 js->mapping = findValidMapping(js);
463 // Frees arrays and name and flags the joystick object as unused
465 void _glfwFreeJoystick(_GLFWjoystick* js)
471 memset(js, 0, sizeof(_GLFWjoystick));
474 // Center the cursor in the content area of the specified window
476 void _glfwCenterCursorInContentArea(_GLFWwindow* window)
480 _glfwPlatformGetWindowSize(window, &width, &height);
481 _glfwPlatformSetCursorPos(window, width / 2.0, height / 2.0);
485 //////////////////////////////////////////////////////////////////////////
486 ////// GLFW public API //////
487 //////////////////////////////////////////////////////////////////////////
489 GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
491 _GLFWwindow* window = (_GLFWwindow*) handle;
492 assert(window != NULL);
494 _GLFW_REQUIRE_INIT_OR_RETURN(0);
499 return window->cursorMode;
500 case GLFW_STICKY_KEYS:
501 return window->stickyKeys;
502 case GLFW_STICKY_MOUSE_BUTTONS:
503 return window->stickyMouseButtons;
504 case GLFW_LOCK_KEY_MODS:
505 return window->lockKeyMods;
506 case GLFW_RAW_MOUSE_MOTION:
507 return window->rawMouseMotion;
510 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
514 GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
516 _GLFWwindow* window = (_GLFWwindow*) handle;
517 assert(window != NULL);
519 _GLFW_REQUIRE_INIT();
521 if (mode == GLFW_CURSOR)
523 if (value != GLFW_CURSOR_NORMAL &&
524 value != GLFW_CURSOR_HIDDEN &&
525 value != GLFW_CURSOR_DISABLED)
527 _glfwInputError(GLFW_INVALID_ENUM,
528 "Invalid cursor mode 0x%08X",
533 if (window->cursorMode == value)
536 window->cursorMode = value;
538 _glfwPlatformGetCursorPos(window,
539 &window->virtualCursorPosX,
540 &window->virtualCursorPosY);
541 _glfwPlatformSetCursorMode(window, value);
543 else if (mode == GLFW_STICKY_KEYS)
545 value = value ? GLFW_TRUE : GLFW_FALSE;
546 if (window->stickyKeys == value)
553 // Release all sticky keys
554 for (i = 0; i <= GLFW_KEY_LAST; i++)
556 if (window->keys[i] == _GLFW_STICK)
557 window->keys[i] = GLFW_RELEASE;
561 window->stickyKeys = value;
563 else if (mode == GLFW_STICKY_MOUSE_BUTTONS)
565 value = value ? GLFW_TRUE : GLFW_FALSE;
566 if (window->stickyMouseButtons == value)
573 // Release all sticky mouse buttons
574 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
576 if (window->mouseButtons[i] == _GLFW_STICK)
577 window->mouseButtons[i] = GLFW_RELEASE;
581 window->stickyMouseButtons = value;
583 else if (mode == GLFW_LOCK_KEY_MODS)
585 window->lockKeyMods = value ? GLFW_TRUE : GLFW_FALSE;
587 else if (mode == GLFW_RAW_MOUSE_MOTION)
589 if (!_glfwPlatformRawMouseMotionSupported())
591 _glfwInputError(GLFW_PLATFORM_ERROR,
592 "Raw mouse motion is not supported on this system");
596 value = value ? GLFW_TRUE : GLFW_FALSE;
597 if (window->rawMouseMotion == value)
600 window->rawMouseMotion = value;
601 _glfwPlatformSetRawMouseMotion(window, value);
604 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
607 GLFWAPI int glfwRawMouseMotionSupported(void)
609 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
610 return _glfwPlatformRawMouseMotionSupported();
613 GLFWAPI const char* glfwGetKeyName(int key, int scancode)
615 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
617 if (key != GLFW_KEY_UNKNOWN)
619 if (key != GLFW_KEY_KP_EQUAL &&
620 (key < GLFW_KEY_KP_0 || key > GLFW_KEY_KP_ADD) &&
621 (key < GLFW_KEY_APOSTROPHE || key > GLFW_KEY_WORLD_2))
626 scancode = _glfwPlatformGetKeyScancode(key);
629 return _glfwPlatformGetScancodeName(scancode);
632 GLFWAPI int glfwGetKeyScancode(int key)
634 _GLFW_REQUIRE_INIT_OR_RETURN(-1);
636 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
638 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
642 return _glfwPlatformGetKeyScancode(key);
645 GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
647 _GLFWwindow* window = (_GLFWwindow*) handle;
648 assert(window != NULL);
650 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
652 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
654 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
658 if (window->keys[key] == _GLFW_STICK)
660 // Sticky mode: release key now
661 window->keys[key] = GLFW_RELEASE;
665 return (int) window->keys[key];
668 GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
670 _GLFWwindow* window = (_GLFWwindow*) handle;
671 assert(window != NULL);
673 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
675 if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
677 _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
681 if (window->mouseButtons[button] == _GLFW_STICK)
683 // Sticky mode: release mouse button now
684 window->mouseButtons[button] = GLFW_RELEASE;
688 return (int) window->mouseButtons[button];
691 GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
693 _GLFWwindow* window = (_GLFWwindow*) handle;
694 assert(window != NULL);
701 _GLFW_REQUIRE_INIT();
703 if (window->cursorMode == GLFW_CURSOR_DISABLED)
706 *xpos = window->virtualCursorPosX;
708 *ypos = window->virtualCursorPosY;
711 _glfwPlatformGetCursorPos(window, xpos, ypos);
714 GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
716 _GLFWwindow* window = (_GLFWwindow*) handle;
717 assert(window != NULL);
719 _GLFW_REQUIRE_INIT();
721 if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
722 ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
724 _glfwInputError(GLFW_INVALID_VALUE,
725 "Invalid cursor position %f %f",
730 if (!_glfwPlatformWindowFocused(window))
733 if (window->cursorMode == GLFW_CURSOR_DISABLED)
735 // Only update the accumulated position if the cursor is disabled
736 window->virtualCursorPosX = xpos;
737 window->virtualCursorPosY = ypos;
741 // Update system cursor position
742 _glfwPlatformSetCursorPos(window, xpos, ypos);
746 GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
750 assert(image != NULL);
752 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
754 cursor = calloc(1, sizeof(_GLFWcursor));
755 cursor->next = _glfw.cursorListHead;
756 _glfw.cursorListHead = cursor;
758 if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot))
760 glfwDestroyCursor((GLFWcursor*) cursor);
764 return (GLFWcursor*) cursor;
767 GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
771 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
773 if (shape != GLFW_ARROW_CURSOR &&
774 shape != GLFW_IBEAM_CURSOR &&
775 shape != GLFW_CROSSHAIR_CURSOR &&
776 shape != GLFW_POINTING_HAND_CURSOR &&
777 shape != GLFW_RESIZE_EW_CURSOR &&
778 shape != GLFW_RESIZE_NS_CURSOR &&
779 shape != GLFW_RESIZE_NWSE_CURSOR &&
780 shape != GLFW_RESIZE_NESW_CURSOR &&
781 shape != GLFW_RESIZE_ALL_CURSOR &&
782 shape != GLFW_NOT_ALLOWED_CURSOR)
784 _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
788 cursor = calloc(1, sizeof(_GLFWcursor));
789 cursor->next = _glfw.cursorListHead;
790 _glfw.cursorListHead = cursor;
792 if (!_glfwPlatformCreateStandardCursor(cursor, shape))
794 glfwDestroyCursor((GLFWcursor*) cursor);
798 return (GLFWcursor*) cursor;
801 GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
803 _GLFWcursor* cursor = (_GLFWcursor*) handle;
805 _GLFW_REQUIRE_INIT();
810 // Make sure the cursor is not being used by any window
814 for (window = _glfw.windowListHead; window; window = window->next)
816 if (window->cursor == cursor)
817 glfwSetCursor((GLFWwindow*) window, NULL);
821 _glfwPlatformDestroyCursor(cursor);
823 // Unlink cursor from global linked list
825 _GLFWcursor** prev = &_glfw.cursorListHead;
827 while (*prev != cursor)
828 prev = &((*prev)->next);
830 *prev = cursor->next;
836 GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
838 _GLFWwindow* window = (_GLFWwindow*) windowHandle;
839 _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
840 assert(window != NULL);
842 _GLFW_REQUIRE_INIT();
844 window->cursor = cursor;
846 _glfwPlatformSetCursor(window, cursor);
849 GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
851 _GLFWwindow* window = (_GLFWwindow*) handle;
852 assert(window != NULL);
854 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
855 _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
859 GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
861 _GLFWwindow* window = (_GLFWwindow*) handle;
862 assert(window != NULL);
864 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
865 _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
869 GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
871 _GLFWwindow* window = (_GLFWwindow*) handle;
872 assert(window != NULL);
874 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
875 _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
879 GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
880 GLFWmousebuttonfun cbfun)
882 _GLFWwindow* window = (_GLFWwindow*) handle;
883 assert(window != NULL);
885 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
886 _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
890 GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
891 GLFWcursorposfun cbfun)
893 _GLFWwindow* window = (_GLFWwindow*) handle;
894 assert(window != NULL);
896 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
897 _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
901 GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
902 GLFWcursorenterfun cbfun)
904 _GLFWwindow* window = (_GLFWwindow*) handle;
905 assert(window != NULL);
907 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
908 _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
912 GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
915 _GLFWwindow* window = (_GLFWwindow*) handle;
916 assert(window != NULL);
918 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
919 _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
923 GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
925 _GLFWwindow* window = (_GLFWwindow*) handle;
926 assert(window != NULL);
928 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
929 _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
933 GLFWAPI int glfwJoystickPresent(int jid)
937 assert(jid >= GLFW_JOYSTICK_1);
938 assert(jid <= GLFW_JOYSTICK_LAST);
940 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
942 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
944 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
948 if (!initJoysticks())
951 js = _glfw.joysticks + jid;
955 return _glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE);
958 GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
962 assert(jid >= GLFW_JOYSTICK_1);
963 assert(jid <= GLFW_JOYSTICK_LAST);
964 assert(count != NULL);
968 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
970 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
972 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
976 if (!initJoysticks())
979 js = _glfw.joysticks + jid;
983 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_AXES))
986 *count = js->axisCount;
990 GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
994 assert(jid >= GLFW_JOYSTICK_1);
995 assert(jid <= GLFW_JOYSTICK_LAST);
996 assert(count != NULL);
1000 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1002 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1004 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1008 if (!initJoysticks())
1011 js = _glfw.joysticks + jid;
1015 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
1018 if (_glfw.hints.init.hatButtons)
1019 *count = js->buttonCount + js->hatCount * 4;
1021 *count = js->buttonCount;
1026 GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
1030 assert(jid >= GLFW_JOYSTICK_1);
1031 assert(jid <= GLFW_JOYSTICK_LAST);
1032 assert(count != NULL);
1036 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1038 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1040 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1044 if (!initJoysticks())
1047 js = _glfw.joysticks + jid;
1051 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_BUTTONS))
1054 *count = js->hatCount;
1058 GLFWAPI const char* glfwGetJoystickName(int jid)
1062 assert(jid >= GLFW_JOYSTICK_1);
1063 assert(jid <= GLFW_JOYSTICK_LAST);
1065 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1067 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1069 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1073 if (!initJoysticks())
1076 js = _glfw.joysticks + jid;
1080 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1086 GLFWAPI const char* glfwGetJoystickGUID(int jid)
1090 assert(jid >= GLFW_JOYSTICK_1);
1091 assert(jid <= GLFW_JOYSTICK_LAST);
1093 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1095 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1097 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1101 if (!initJoysticks())
1104 js = _glfw.joysticks + jid;
1108 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1114 GLFWAPI void glfwSetJoystickUserPointer(int jid, void* pointer)
1118 assert(jid >= GLFW_JOYSTICK_1);
1119 assert(jid <= GLFW_JOYSTICK_LAST);
1121 _GLFW_REQUIRE_INIT();
1123 js = _glfw.joysticks + jid;
1127 js->userPointer = pointer;
1130 GLFWAPI void* glfwGetJoystickUserPointer(int jid)
1134 assert(jid >= GLFW_JOYSTICK_1);
1135 assert(jid <= GLFW_JOYSTICK_LAST);
1137 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1139 js = _glfw.joysticks + jid;
1143 return js->userPointer;
1146 GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
1148 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1150 if (!initJoysticks())
1153 _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
1157 GLFWAPI int glfwUpdateGamepadMappings(const char* string)
1160 const char* c = string;
1162 assert(string != NULL);
1164 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1168 if ((*c >= '0' && *c <= '9') ||
1169 (*c >= 'a' && *c <= 'f') ||
1170 (*c >= 'A' && *c <= 'F'))
1174 const size_t length = strcspn(c, "\r\n");
1175 if (length < sizeof(line))
1177 _GLFWmapping mapping = {{0}};
1179 memcpy(line, c, length);
1180 line[length] = '\0';
1182 if (parseMapping(&mapping, line))
1184 _GLFWmapping* previous = findMapping(mapping.guid);
1186 *previous = mapping;
1189 _glfw.mappingCount++;
1191 realloc(_glfw.mappings,
1192 sizeof(_GLFWmapping) * _glfw.mappingCount);
1193 _glfw.mappings[_glfw.mappingCount - 1] = mapping;
1202 c += strcspn(c, "\r\n");
1203 c += strspn(c, "\r\n");
1207 for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
1209 _GLFWjoystick* js = _glfw.joysticks + jid;
1211 js->mapping = findValidMapping(js);
1217 GLFWAPI int glfwJoystickIsGamepad(int jid)
1221 assert(jid >= GLFW_JOYSTICK_1);
1222 assert(jid <= GLFW_JOYSTICK_LAST);
1224 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1226 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1228 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1232 if (!initJoysticks())
1235 js = _glfw.joysticks + jid;
1239 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1242 return js->mapping != NULL;
1245 GLFWAPI const char* glfwGetGamepadName(int jid)
1249 assert(jid >= GLFW_JOYSTICK_1);
1250 assert(jid <= GLFW_JOYSTICK_LAST);
1252 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1254 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1256 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1260 if (!initJoysticks())
1263 js = _glfw.joysticks + jid;
1267 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_PRESENCE))
1273 return js->mapping->name;
1276 GLFWAPI int glfwGetGamepadState(int jid, GLFWgamepadstate* state)
1281 assert(jid >= GLFW_JOYSTICK_1);
1282 assert(jid <= GLFW_JOYSTICK_LAST);
1283 assert(state != NULL);
1285 memset(state, 0, sizeof(GLFWgamepadstate));
1287 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
1289 if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
1291 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
1295 if (!initJoysticks())
1298 js = _glfw.joysticks + jid;
1302 if (!_glfwPlatformPollJoystick(js, _GLFW_POLL_ALL))
1308 for (i = 0; i <= GLFW_GAMEPAD_BUTTON_LAST; i++)
1310 const _GLFWmapelement* e = js->mapping->buttons + i;
1311 if (e->type == _GLFW_JOYSTICK_AXIS)
1313 const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
1314 // HACK: This should be baked into the value transform
1315 // TODO: Bake into transform when implementing output modifiers
1316 if (e->axisOffset < 0 || (e->axisOffset == 0 && e->axisScale > 0))
1319 state->buttons[i] = GLFW_PRESS;
1324 state->buttons[i] = GLFW_PRESS;
1327 else if (e->type == _GLFW_JOYSTICK_HATBIT)
1329 const unsigned int hat = e->index >> 4;
1330 const unsigned int bit = e->index & 0xf;
1331 if (js->hats[hat] & bit)
1332 state->buttons[i] = GLFW_PRESS;
1334 else if (e->type == _GLFW_JOYSTICK_BUTTON)
1335 state->buttons[i] = js->buttons[e->index];
1338 for (i = 0; i <= GLFW_GAMEPAD_AXIS_LAST; i++)
1340 const _GLFWmapelement* e = js->mapping->axes + i;
1341 if (e->type == _GLFW_JOYSTICK_AXIS)
1343 const float value = js->axes[e->index] * e->axisScale + e->axisOffset;
1344 state->axes[i] = _glfw_fminf(_glfw_fmaxf(value, -1.f), 1.f);
1346 else if (e->type == _GLFW_JOYSTICK_HATBIT)
1348 const unsigned int hat = e->index >> 4;
1349 const unsigned int bit = e->index & 0xf;
1350 if (js->hats[hat] & bit)
1351 state->axes[i] = 1.f;
1353 state->axes[i] = -1.f;
1355 else if (e->type == _GLFW_JOYSTICK_BUTTON)
1356 state->axes[i] = js->buttons[e->index] * 2.f - 1.f;
1362 GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
1364 assert(string != NULL);
1366 _GLFW_REQUIRE_INIT();
1367 _glfwPlatformSetClipboardString(string);
1370 GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
1372 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
1373 return _glfwPlatformGetClipboardString();
1376 GLFWAPI double glfwGetTime(void)
1378 _GLFW_REQUIRE_INIT_OR_RETURN(0.0);
1379 return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
1380 _glfwPlatformGetTimerFrequency();
1383 GLFWAPI void glfwSetTime(double time)
1385 _GLFW_REQUIRE_INIT();
1387 if (time != time || time < 0.0 || time > 18446744073.0)
1389 _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
1393 _glfw.timer.offset = _glfwPlatformGetTimerValue() -
1394 (uint64_t) (time * _glfwPlatformGetTimerFrequency());
1397 GLFWAPI uint64_t glfwGetTimerValue(void)
1399 _GLFW_REQUIRE_INIT_OR_RETURN(0);
1400 return _glfwPlatformGetTimerValue();
1403 GLFWAPI uint64_t glfwGetTimerFrequency(void)
1405 _GLFW_REQUIRE_INIT_OR_RETURN(0);
1406 return _glfwPlatformGetTimerFrequency();