1//========================================================================
2// GLFW 3.2 - www.glfw.org
3//------------------------------------------------------------------------
4// Copyright (c) 2002-2006 Marcus Geelnard
5// Copyright (c) 2006-2016 Camilla Berglund <elmindreda@glfw.org>
6//
7// This software is provided 'as-is', without any express or implied
8// warranty. In no event will the authors be held liable for any damages
9// arising from the use of this software.
10//
11// Permission is granted to anyone to use this software for any purpose,
12// including commercial applications, and to alter it and redistribute it
13// freely, subject to the following restrictions:
14//
15// 1. The origin of this software must not be misrepresented; you must not
16// claim that you wrote the original software. If you use this software
17// in a product, an acknowledgment in the product documentation would
18// be appreciated but is not required.
19//
20// 2. Altered source versions must be plainly marked as such, and must not
21// be misrepresented as being the original software.
22//
23// 3. This notice may not be removed or altered from any source
24// distribution.
25//
26//========================================================================
27
28#include "internal.h"
29
30#include <assert.h>
31#include <float.h>
32#include <stdlib.h>
33
34// Internal key state used for sticky keys
35#define _GLFW_STICK 3
36
37
38//////////////////////////////////////////////////////////////////////////
39////// GLFW event API //////
40//////////////////////////////////////////////////////////////////////////
41
42void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
43{
44 if (key >= 0 && key <= GLFW_KEY_LAST)
45 {
46 GLFWbool repeated = GLFW_FALSE;
47
48 if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
49 return;
50
51 if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
52 repeated = GLFW_TRUE;
53
54 if (action == GLFW_RELEASE && window->stickyKeys)
55 window->keys[key] = _GLFW_STICK;
56 else
57 window->keys[key] = (char) action;
58
59 if (repeated)
60 action = GLFW_REPEAT;
61 }
62
63 if (window->callbacks.key)
64 window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
65}
66
67void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
68{
69 if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
70 return;
71
72 if (window->callbacks.charmods)
73 window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
74
75 if (plain)
76 {
77 if (window->callbacks.character)
78 window->callbacks.character((GLFWwindow*) window, codepoint);
79 }
80}
81
82void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
83{
84 if (window->callbacks.scroll)
85 window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
86}
87
88void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
89{
90 if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
91 return;
92
93 // Register mouse button action
94 if (action == GLFW_RELEASE && window->stickyMouseButtons)
95 window->mouseButtons[button] = _GLFW_STICK;
96 else
97 window->mouseButtons[button] = (char) action;
98
99 if (window->callbacks.mouseButton)
100 window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
101}
102
103void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
104{
105 if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
106 return;
107
108 window->virtualCursorPosX = xpos;
109 window->virtualCursorPosY = ypos;
110
111 if (window->callbacks.cursorPos)
112 window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
113}
114
115void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
116{
117 if (window->callbacks.cursorEnter)
118 window->callbacks.cursorEnter((GLFWwindow*) window, entered);
119}
120
121void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
122{
123 if (window->callbacks.drop)
124 window->callbacks.drop((GLFWwindow*) window, count, paths);
125}
126
127void _glfwInputJoystickChange(int joy, int event)
128{
129 if (_glfw.callbacks.joystick)
130 _glfw.callbacks.joystick(joy, event);
131}
132
133
134//////////////////////////////////////////////////////////////////////////
135////// GLFW internal API //////
136//////////////////////////////////////////////////////////////////////////
137
138GLFWbool _glfwIsPrintable(int key)
139{
140 return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) ||
141 (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) ||
142 key == GLFW_KEY_KP_EQUAL;
143}
144
145
146//////////////////////////////////////////////////////////////////////////
147////// GLFW public API //////
148//////////////////////////////////////////////////////////////////////////
149
150GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
151{
152 _GLFWwindow* window = (_GLFWwindow*) handle;
153 assert(window != NULL);
154
155 _GLFW_REQUIRE_INIT_OR_RETURN(0);
156
157 switch (mode)
158 {
159 case GLFW_CURSOR:
160 return window->cursorMode;
161 case GLFW_STICKY_KEYS:
162 return window->stickyKeys;
163 case GLFW_STICKY_MOUSE_BUTTONS:
164 return window->stickyMouseButtons;
165 default:
166 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
167 return 0;
168 }
169}
170
171GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
172{
173 _GLFWwindow* window = (_GLFWwindow*) handle;
174 assert(window != NULL);
175
176 _GLFW_REQUIRE_INIT();
177
178 switch (mode)
179 {
180 case GLFW_CURSOR:
181 {
182 if (value != GLFW_CURSOR_NORMAL &&
183 value != GLFW_CURSOR_HIDDEN &&
184 value != GLFW_CURSOR_DISABLED)
185 {
186 _glfwInputError(GLFW_INVALID_ENUM,
187 "Invalid cursor mode %i",
188 value);
189 return;
190 }
191
192 if (window->cursorMode == value)
193 return;
194
195 window->cursorMode = value;
196
197 _glfwPlatformGetCursorPos(window,
198 &window->virtualCursorPosX,
199 &window->virtualCursorPosY);
200
201 if (_glfwPlatformWindowFocused(window))
202 _glfwPlatformSetCursorMode(window, value);
203
204 return;
205 }
206
207 case GLFW_STICKY_KEYS:
208 {
209 if (window->stickyKeys == value)
210 return;
211
212 if (!value)
213 {
214 int i;
215
216 // Release all sticky keys
217 for (i = 0; i <= GLFW_KEY_LAST; i++)
218 {
219 if (window->keys[i] == _GLFW_STICK)
220 window->keys[i] = GLFW_RELEASE;
221 }
222 }
223
224 window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
225 return;
226 }
227
228 case GLFW_STICKY_MOUSE_BUTTONS:
229 {
230 if (window->stickyMouseButtons == value)
231 return;
232
233 if (!value)
234 {
235 int i;
236
237 // Release all sticky mouse buttons
238 for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
239 {
240 if (window->mouseButtons[i] == _GLFW_STICK)
241 window->mouseButtons[i] = GLFW_RELEASE;
242 }
243 }
244
245 window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
246 return;
247 }
248 }
249
250 _glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode %i", mode);
251}
252
253GLFWAPI const char* glfwGetKeyName(int key, int scancode)
254{
255 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
256 return _glfwPlatformGetKeyName(key, scancode);
257}
258
259GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
260{
261 _GLFWwindow* window = (_GLFWwindow*) handle;
262 assert(window != NULL);
263
264 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
265
266 if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
267 {
268 _glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
269 return GLFW_RELEASE;
270 }
271
272 if (window->keys[key] == _GLFW_STICK)
273 {
274 // Sticky mode: release key now
275 window->keys[key] = GLFW_RELEASE;
276 return GLFW_PRESS;
277 }
278
279 return (int) window->keys[key];
280}
281
282GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
283{
284 _GLFWwindow* window = (_GLFWwindow*) handle;
285 assert(window != NULL);
286
287 _GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
288
289 if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
290 {
291 _glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
292 return GLFW_RELEASE;
293 }
294
295 if (window->mouseButtons[button] == _GLFW_STICK)
296 {
297 // Sticky mode: release mouse button now
298 window->mouseButtons[button] = GLFW_RELEASE;
299 return GLFW_PRESS;
300 }
301
302 return (int) window->mouseButtons[button];
303}
304
305GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
306{
307 _GLFWwindow* window = (_GLFWwindow*) handle;
308 assert(window != NULL);
309
310 if (xpos)
311 *xpos = 0;
312 if (ypos)
313 *ypos = 0;
314
315 _GLFW_REQUIRE_INIT();
316
317 if (window->cursorMode == GLFW_CURSOR_DISABLED)
318 {
319 if (xpos)
320 *xpos = window->virtualCursorPosX;
321 if (ypos)
322 *ypos = window->virtualCursorPosY;
323 }
324 else
325 _glfwPlatformGetCursorPos(window, xpos, ypos);
326}
327
328GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
329{
330 _GLFWwindow* window = (_GLFWwindow*) handle;
331 assert(window != NULL);
332
333 _GLFW_REQUIRE_INIT();
334
335 if (xpos != xpos || xpos < DBL_MIN || xpos > DBL_MAX ||
336 ypos != ypos || ypos < DBL_MIN || ypos > DBL_MAX)
337 {
338 _glfwInputError(GLFW_INVALID_VALUE,
339 "Invalid cursor position %fx%f",
340 xpos, ypos);
341 return;
342 }
343
344 if (!_glfwPlatformWindowFocused(window))
345 return;
346
347 if (window->cursorMode == GLFW_CURSOR_DISABLED)
348 {
349 // Only update the accumulated position if the cursor is disabled
350 window->virtualCursorPosX = xpos;
351 window->virtualCursorPosY = ypos;
352 }
353 else
354 {
355 // Update system cursor position
356 _glfwPlatformSetCursorPos(window, xpos, ypos);
357 }
358}
359
360GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
361{
362 _GLFWcursor* cursor;
363
364 assert(image != NULL);
365
366 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
367
368 cursor = calloc(1, sizeof(_GLFWcursor));
369 cursor->next = _glfw.cursorListHead;
370 _glfw.cursorListHead = cursor;
371
372 if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot))
373 {
374 glfwDestroyCursor((GLFWcursor*) cursor);
375 return NULL;
376 }
377
378 return (GLFWcursor*) cursor;
379}
380
381GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
382{
383 _GLFWcursor* cursor;
384
385 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
386
387 if (shape != GLFW_ARROW_CURSOR &&
388 shape != GLFW_IBEAM_CURSOR &&
389 shape != GLFW_CROSSHAIR_CURSOR &&
390 shape != GLFW_HAND_CURSOR &&
391 shape != GLFW_HRESIZE_CURSOR &&
392 shape != GLFW_VRESIZE_CURSOR)
393 {
394 _glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor %i", shape);
395 return NULL;
396 }
397
398 cursor = calloc(1, sizeof(_GLFWcursor));
399 cursor->next = _glfw.cursorListHead;
400 _glfw.cursorListHead = cursor;
401
402 if (!_glfwPlatformCreateStandardCursor(cursor, shape))
403 {
404 glfwDestroyCursor((GLFWcursor*) cursor);
405 return NULL;
406 }
407
408 return (GLFWcursor*) cursor;
409}
410
411GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
412{
413 _GLFWcursor* cursor = (_GLFWcursor*) handle;
414
415 _GLFW_REQUIRE_INIT();
416
417 if (cursor == NULL)
418 return;
419
420 // Make sure the cursor is not being used by any window
421 {
422 _GLFWwindow* window;
423
424 for (window = _glfw.windowListHead; window; window = window->next)
425 {
426 if (window->cursor == cursor)
427 glfwSetCursor((GLFWwindow*) window, NULL);
428 }
429 }
430
431 _glfwPlatformDestroyCursor(cursor);
432
433 // Unlink cursor from global linked list
434 {
435 _GLFWcursor** prev = &_glfw.cursorListHead;
436
437 while (*prev != cursor)
438 prev = &((*prev)->next);
439
440 *prev = cursor->next;
441 }
442
443 free(cursor);
444}
445
446GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
447{
448 _GLFWwindow* window = (_GLFWwindow*) windowHandle;
449 _GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
450 assert(window != NULL);
451
452 _GLFW_REQUIRE_INIT();
453
454 window->cursor = cursor;
455
456 _glfwPlatformSetCursor(window, cursor);
457}
458
459GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
460{
461 _GLFWwindow* window = (_GLFWwindow*) handle;
462 assert(window != NULL);
463
464 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
465 _GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
466 return cbfun;
467}
468
469GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
470{
471 _GLFWwindow* window = (_GLFWwindow*) handle;
472 assert(window != NULL);
473
474 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
475 _GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
476 return cbfun;
477}
478
479GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
480{
481 _GLFWwindow* window = (_GLFWwindow*) handle;
482 assert(window != NULL);
483
484 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
485 _GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
486 return cbfun;
487}
488
489GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
490 GLFWmousebuttonfun cbfun)
491{
492 _GLFWwindow* window = (_GLFWwindow*) handle;
493 assert(window != NULL);
494
495 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
496 _GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
497 return cbfun;
498}
499
500GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
501 GLFWcursorposfun cbfun)
502{
503 _GLFWwindow* window = (_GLFWwindow*) handle;
504 assert(window != NULL);
505
506 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
507 _GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
508 return cbfun;
509}
510
511GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
512 GLFWcursorenterfun cbfun)
513{
514 _GLFWwindow* window = (_GLFWwindow*) handle;
515 assert(window != NULL);
516
517 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
518 _GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
519 return cbfun;
520}
521
522GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
523 GLFWscrollfun cbfun)
524{
525 _GLFWwindow* window = (_GLFWwindow*) handle;
526 assert(window != NULL);
527
528 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
529 _GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
530 return cbfun;
531}
532
533GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
534{
535 _GLFWwindow* window = (_GLFWwindow*) handle;
536 assert(window != NULL);
537
538 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
539 _GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
540 return cbfun;
541}
542
543GLFWAPI int glfwJoystickPresent(int joy)
544{
545 _GLFW_REQUIRE_INIT_OR_RETURN(0);
546
547 if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
548 {
549 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
550 return 0;
551 }
552
553 return _glfwPlatformJoystickPresent(joy);
554}
555
556GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count)
557{
558 assert(count != NULL);
559 *count = 0;
560
561 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
562
563 if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
564 {
565 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
566 return NULL;
567 }
568
569 return _glfwPlatformGetJoystickAxes(joy, count);
570}
571
572GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count)
573{
574 assert(count != NULL);
575 *count = 0;
576
577 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
578
579 if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
580 {
581 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
582 return NULL;
583 }
584
585 return _glfwPlatformGetJoystickButtons(joy, count);
586}
587
588GLFWAPI const char* glfwGetJoystickName(int joy)
589{
590 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
591
592 if (joy < 0 || joy > GLFW_JOYSTICK_LAST)
593 {
594 _glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick %i", joy);
595 return NULL;
596 }
597
598 return _glfwPlatformGetJoystickName(joy);
599}
600
601GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
602{
603 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
604 _GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
605 return cbfun;
606}
607
608GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
609{
610 _GLFWwindow* window = (_GLFWwindow*) handle;
611 assert(window != NULL);
612 assert(string != NULL);
613
614 _GLFW_REQUIRE_INIT();
615 _glfwPlatformSetClipboardString(window, string);
616}
617
618GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
619{
620 _GLFWwindow* window = (_GLFWwindow*) handle;
621 assert(window != NULL);
622
623 _GLFW_REQUIRE_INIT_OR_RETURN(NULL);
624 return _glfwPlatformGetClipboardString(window);
625}
626
627GLFWAPI double glfwGetTime(void)
628{
629 _GLFW_REQUIRE_INIT_OR_RETURN(0.0);
630 return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) /
631 _glfwPlatformGetTimerFrequency();
632}
633
634GLFWAPI void glfwSetTime(double time)
635{
636 _GLFW_REQUIRE_INIT();
637
638 if (time != time || time < 0.0 || time > 18446744073.0)
639 {
640 _glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
641 return;
642 }
643
644 _glfw.timerOffset = _glfwPlatformGetTimerValue() -
645 (uint64_t) (time * _glfwPlatformGetTimerFrequency());
646}
647
648GLFWAPI uint64_t glfwGetTimerValue(void)
649{
650 _GLFW_REQUIRE_INIT_OR_RETURN(0);
651 return _glfwPlatformGetTimerValue();
652}
653
654GLFWAPI uint64_t glfwGetTimerFrequency(void)
655{
656 _GLFW_REQUIRE_INIT_OR_RETURN(0);
657 return _glfwPlatformGetTimerFrequency();
658}
659
660