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