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