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