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 | |
42 | void _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 | |
67 | void _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 | |
82 | void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset) |
83 | { |
84 | if (window->callbacks.scroll) |
85 | window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset); |
86 | } |
87 | |
88 | void _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 | |
103 | void _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 | |
115 | void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered) |
116 | { |
117 | if (window->callbacks.cursorEnter) |
118 | window->callbacks.cursorEnter((GLFWwindow*) window, entered); |
119 | } |
120 | |
121 | void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths) |
122 | { |
123 | if (window->callbacks.drop) |
124 | window->callbacks.drop((GLFWwindow*) window, count, paths); |
125 | } |
126 | |
127 | void _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 | |
138 | GLFWbool _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 | |
150 | GLFWAPI 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 | |
171 | GLFWAPI 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 | |
253 | GLFWAPI const char* glfwGetKeyName(int key, int scancode) |
254 | { |
255 | _GLFW_REQUIRE_INIT_OR_RETURN(NULL); |
256 | return _glfwPlatformGetKeyName(key, scancode); |
257 | } |
258 | |
259 | GLFWAPI 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 | |
282 | GLFWAPI 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 | |
305 | GLFWAPI 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 | |
328 | GLFWAPI 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 | |
360 | GLFWAPI 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 | |
381 | GLFWAPI 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 | |
411 | GLFWAPI 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 | |
446 | GLFWAPI 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 | |
459 | GLFWAPI 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 | |
469 | GLFWAPI 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 | |
479 | GLFWAPI 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 | |
489 | GLFWAPI 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 | |
500 | GLFWAPI 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 | |
511 | GLFWAPI 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 | |
522 | GLFWAPI 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 | |
533 | GLFWAPI 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 | |
543 | GLFWAPI 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 | |
556 | GLFWAPI 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 | |
572 | GLFWAPI 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 | |
588 | GLFWAPI 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 | |
601 | GLFWAPI 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 | |
608 | GLFWAPI 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 | |
618 | GLFWAPI 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 | |
627 | GLFWAPI double glfwGetTime(void) |
628 | { |
629 | _GLFW_REQUIRE_INIT_OR_RETURN(0.0); |
630 | return (double) (_glfwPlatformGetTimerValue() - _glfw.timerOffset) / |
631 | _glfwPlatformGetTimerFrequency(); |
632 | } |
633 | |
634 | GLFWAPI 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 | |
648 | GLFWAPI uint64_t glfwGetTimerValue(void) |
649 | { |
650 | _GLFW_REQUIRE_INIT_OR_RETURN(0); |
651 | return _glfwPlatformGetTimerValue(); |
652 | } |
653 | |
654 | GLFWAPI uint64_t glfwGetTimerFrequency(void) |
655 | { |
656 | _GLFW_REQUIRE_INIT_OR_RETURN(0); |
657 | return _glfwPlatformGetTimerFrequency(); |
658 | } |
659 | |
660 | |