1
0
Fork 0
mirror of https://github.com/gwm17/glfw.git synced 2025-08-23 19:58:51 -04:00
glfw/src/input.c
Camilla Löwy d5de48ab53 Report invalid constants in the appropriate base
If the expected constants are defined in hexadecimal in the header then
the error string should also use hexadecimal.

Idea by IntellectualKitty.

Related to #970.
2017-06-28 12:07:06 +02:00

803 lines
21 KiB
C

//========================================================================
// GLFW 3.3 - www.glfw.org
//------------------------------------------------------------------------
// Copyright (c) 2002-2006 Marcus Geelnard
// Copyright (c) 2006-2016 Camilla Löwy <elmindreda@glfw.org>
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would
// be appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not
// be misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source
// distribution.
//
//========================================================================
#include "internal.h"
#include <assert.h>
#include <float.h>
#include <stdlib.h>
#include <string.h>
// Internal key state used for sticky keys
#define _GLFW_STICK 3
//////////////////////////////////////////////////////////////////////////
////// GLFW event API //////
//////////////////////////////////////////////////////////////////////////
void _glfwInputKey(_GLFWwindow* window, int key, int scancode, int action, int mods)
{
if (key >= 0 && key <= GLFW_KEY_LAST)
{
GLFWbool repeated = GLFW_FALSE;
if (action == GLFW_RELEASE && window->keys[key] == GLFW_RELEASE)
return;
if (action == GLFW_PRESS && window->keys[key] == GLFW_PRESS)
repeated = GLFW_TRUE;
if (action == GLFW_RELEASE && window->stickyKeys)
window->keys[key] = _GLFW_STICK;
else
window->keys[key] = (char) action;
if (repeated)
action = GLFW_REPEAT;
}
if (window->callbacks.key)
window->callbacks.key((GLFWwindow*) window, key, scancode, action, mods);
}
void _glfwInputChar(_GLFWwindow* window, unsigned int codepoint, int mods, GLFWbool plain)
{
if (codepoint < 32 || (codepoint > 126 && codepoint < 160))
return;
if (window->callbacks.charmods)
window->callbacks.charmods((GLFWwindow*) window, codepoint, mods);
if (plain)
{
if (window->callbacks.character)
window->callbacks.character((GLFWwindow*) window, codepoint);
}
}
void _glfwInputScroll(_GLFWwindow* window, double xoffset, double yoffset)
{
if (window->callbacks.scroll)
window->callbacks.scroll((GLFWwindow*) window, xoffset, yoffset);
}
void _glfwInputMouseClick(_GLFWwindow* window, int button, int action, int mods)
{
if (button < 0 || button > GLFW_MOUSE_BUTTON_LAST)
return;
if (action == GLFW_RELEASE && window->stickyMouseButtons)
window->mouseButtons[button] = _GLFW_STICK;
else
window->mouseButtons[button] = (char) action;
if (window->callbacks.mouseButton)
window->callbacks.mouseButton((GLFWwindow*) window, button, action, mods);
}
void _glfwInputCursorPos(_GLFWwindow* window, double xpos, double ypos)
{
if (window->virtualCursorPosX == xpos && window->virtualCursorPosY == ypos)
return;
window->virtualCursorPosX = xpos;
window->virtualCursorPosY = ypos;
if (window->callbacks.cursorPos)
window->callbacks.cursorPos((GLFWwindow*) window, xpos, ypos);
}
void _glfwInputCursorEnter(_GLFWwindow* window, GLFWbool entered)
{
if (window->callbacks.cursorEnter)
window->callbacks.cursorEnter((GLFWwindow*) window, entered);
}
void _glfwInputDrop(_GLFWwindow* window, int count, const char** paths)
{
if (window->callbacks.drop)
window->callbacks.drop((GLFWwindow*) window, count, paths);
}
void _glfwInputJoystick(int jid, int event)
{
if (_glfw.callbacks.joystick)
_glfw.callbacks.joystick(jid, event);
}
void _glfwInputJoystickAxis(int jid, int axis, float value)
{
_glfw.joysticks[jid].axes[axis] = value;
}
void _glfwInputJoystickButton(int jid, int button, char value)
{
_glfw.joysticks[jid].buttons[button] = value;
}
void _glfwInputJoystickHat(int jid, int hat, char value)
{
_GLFWjoystick* js = _glfw.joysticks + jid;
const int base = js->buttonCount + hat * 4;
js->buttons[base + 0] = (value & 0x01) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 1] = (value & 0x02) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 2] = (value & 0x04) ? GLFW_PRESS : GLFW_RELEASE;
js->buttons[base + 3] = (value & 0x08) ? GLFW_PRESS : GLFW_RELEASE;
js->hats[hat] = value;
}
//////////////////////////////////////////////////////////////////////////
////// GLFW internal API //////
//////////////////////////////////////////////////////////////////////////
GLFWbool _glfwIsPrintable(int key)
{
return (key >= GLFW_KEY_APOSTROPHE && key <= GLFW_KEY_WORLD_2) ||
(key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) ||
key == GLFW_KEY_KP_EQUAL;
}
_GLFWjoystick* _glfwAllocJoystick(const char* name,
int axisCount,
int buttonCount,
int hatCount)
{
int jid;
_GLFWjoystick* js;
for (jid = 0; jid <= GLFW_JOYSTICK_LAST; jid++)
{
if (!_glfw.joysticks[jid].present)
break;
}
if (jid > GLFW_JOYSTICK_LAST)
return NULL;
js = _glfw.joysticks + jid;
js->present = GLFW_TRUE;
js->name = strdup(name);
js->axes = calloc(axisCount, sizeof(float));
js->buttons = calloc(buttonCount + hatCount * 4, 1);
js->hats = calloc(hatCount, 1);
js->axisCount = axisCount;
js->buttonCount = buttonCount;
js->hatCount = hatCount;
return js;
}
void _glfwFreeJoystick(_GLFWjoystick* js)
{
free(js->name);
free(js->axes);
free(js->buttons);
free(js->hats);
memset(js, 0, sizeof(_GLFWjoystick));
}
//////////////////////////////////////////////////////////////////////////
////// GLFW public API //////
//////////////////////////////////////////////////////////////////////////
GLFWAPI int glfwGetInputMode(GLFWwindow* handle, int mode)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(0);
switch (mode)
{
case GLFW_CURSOR:
return window->cursorMode;
case GLFW_STICKY_KEYS:
return window->stickyKeys;
case GLFW_STICKY_MOUSE_BUTTONS:
return window->stickyMouseButtons;
default:
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
return 0;
}
}
GLFWAPI void glfwSetInputMode(GLFWwindow* handle, int mode, int value)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT();
switch (mode)
{
case GLFW_CURSOR:
{
if (value != GLFW_CURSOR_NORMAL &&
value != GLFW_CURSOR_HIDDEN &&
value != GLFW_CURSOR_DISABLED)
{
_glfwInputError(GLFW_INVALID_ENUM,
"Invalid cursor mode 0x%08X",
value);
return;
}
if (window->cursorMode == value)
return;
window->cursorMode = value;
_glfwPlatformGetCursorPos(window,
&window->virtualCursorPosX,
&window->virtualCursorPosY);
if (_glfwPlatformWindowFocused(window))
_glfwPlatformSetCursorMode(window, value);
return;
}
case GLFW_STICKY_KEYS:
{
if (window->stickyKeys == value)
return;
if (!value)
{
int i;
// Release all sticky keys
for (i = 0; i <= GLFW_KEY_LAST; i++)
{
if (window->keys[i] == _GLFW_STICK)
window->keys[i] = GLFW_RELEASE;
}
}
window->stickyKeys = value ? GLFW_TRUE : GLFW_FALSE;
return;
}
case GLFW_STICKY_MOUSE_BUTTONS:
{
if (window->stickyMouseButtons == value)
return;
if (!value)
{
int i;
// Release all sticky mouse buttons
for (i = 0; i <= GLFW_MOUSE_BUTTON_LAST; i++)
{
if (window->mouseButtons[i] == _GLFW_STICK)
window->mouseButtons[i] = GLFW_RELEASE;
}
}
window->stickyMouseButtons = value ? GLFW_TRUE : GLFW_FALSE;
return;
}
}
_glfwInputError(GLFW_INVALID_ENUM, "Invalid input mode 0x%08X", mode);
}
GLFWAPI const char* glfwGetKeyName(int key, int scancode)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetKeyName(key, scancode);
}
GLFWAPI int glfwGetKeyScancode(int key)
{
_GLFW_REQUIRE_INIT_OR_RETURN(-1);
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
return GLFW_RELEASE;
}
return _glfwPlatformGetKeyScancode(key);
}
GLFWAPI int glfwGetKey(GLFWwindow* handle, int key)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
if (key < GLFW_KEY_SPACE || key > GLFW_KEY_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid key %i", key);
return GLFW_RELEASE;
}
if (window->keys[key] == _GLFW_STICK)
{
// Sticky mode: release key now
window->keys[key] = GLFW_RELEASE;
return GLFW_PRESS;
}
return (int) window->keys[key];
}
GLFWAPI int glfwGetMouseButton(GLFWwindow* handle, int button)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_RELEASE);
if (button < GLFW_MOUSE_BUTTON_1 || button > GLFW_MOUSE_BUTTON_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid mouse button %i", button);
return GLFW_RELEASE;
}
if (window->mouseButtons[button] == _GLFW_STICK)
{
// Sticky mode: release mouse button now
window->mouseButtons[button] = GLFW_RELEASE;
return GLFW_PRESS;
}
return (int) window->mouseButtons[button];
}
GLFWAPI void glfwGetCursorPos(GLFWwindow* handle, double* xpos, double* ypos)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
if (xpos)
*xpos = 0;
if (ypos)
*ypos = 0;
_GLFW_REQUIRE_INIT();
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
if (xpos)
*xpos = window->virtualCursorPosX;
if (ypos)
*ypos = window->virtualCursorPosY;
}
else
_glfwPlatformGetCursorPos(window, xpos, ypos);
}
GLFWAPI void glfwSetCursorPos(GLFWwindow* handle, double xpos, double ypos)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT();
if (xpos != xpos || xpos < -DBL_MAX || xpos > DBL_MAX ||
ypos != ypos || ypos < -DBL_MAX || ypos > DBL_MAX)
{
_glfwInputError(GLFW_INVALID_VALUE,
"Invalid cursor position %f %f",
xpos, ypos);
return;
}
if (!_glfwPlatformWindowFocused(window))
return;
if (window->cursorMode == GLFW_CURSOR_DISABLED)
{
// Only update the accumulated position if the cursor is disabled
window->virtualCursorPosX = xpos;
window->virtualCursorPosY = ypos;
}
else
{
// Update system cursor position
_glfwPlatformSetCursorPos(window, xpos, ypos);
}
}
GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot)
{
_GLFWcursor* cursor;
assert(image != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
cursor = calloc(1, sizeof(_GLFWcursor));
cursor->next = _glfw.cursorListHead;
_glfw.cursorListHead = cursor;
if (!_glfwPlatformCreateCursor(cursor, image, xhot, yhot))
{
glfwDestroyCursor((GLFWcursor*) cursor);
return NULL;
}
return (GLFWcursor*) cursor;
}
GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape)
{
_GLFWcursor* cursor;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (shape != GLFW_ARROW_CURSOR &&
shape != GLFW_IBEAM_CURSOR &&
shape != GLFW_CROSSHAIR_CURSOR &&
shape != GLFW_HAND_CURSOR &&
shape != GLFW_HRESIZE_CURSOR &&
shape != GLFW_VRESIZE_CURSOR)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid standard cursor 0x%08X", shape);
return NULL;
}
cursor = calloc(1, sizeof(_GLFWcursor));
cursor->next = _glfw.cursorListHead;
_glfw.cursorListHead = cursor;
if (!_glfwPlatformCreateStandardCursor(cursor, shape))
{
glfwDestroyCursor((GLFWcursor*) cursor);
return NULL;
}
return (GLFWcursor*) cursor;
}
GLFWAPI void glfwDestroyCursor(GLFWcursor* handle)
{
_GLFWcursor* cursor = (_GLFWcursor*) handle;
_GLFW_REQUIRE_INIT();
if (cursor == NULL)
return;
// Make sure the cursor is not being used by any window
{
_GLFWwindow* window;
for (window = _glfw.windowListHead; window; window = window->next)
{
if (window->cursor == cursor)
glfwSetCursor((GLFWwindow*) window, NULL);
}
}
_glfwPlatformDestroyCursor(cursor);
// Unlink cursor from global linked list
{
_GLFWcursor** prev = &_glfw.cursorListHead;
while (*prev != cursor)
prev = &((*prev)->next);
*prev = cursor->next;
}
free(cursor);
}
GLFWAPI void glfwSetCursor(GLFWwindow* windowHandle, GLFWcursor* cursorHandle)
{
_GLFWwindow* window = (_GLFWwindow*) windowHandle;
_GLFWcursor* cursor = (_GLFWcursor*) cursorHandle;
assert(window != NULL);
_GLFW_REQUIRE_INIT();
window->cursor = cursor;
_glfwPlatformSetCursor(window, cursor);
}
GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* handle, GLFWkeyfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.key, cbfun);
return cbfun;
}
GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* handle, GLFWcharfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.character, cbfun);
return cbfun;
}
GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* handle, GLFWcharmodsfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.charmods, cbfun);
return cbfun;
}
GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* handle,
GLFWmousebuttonfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.mouseButton, cbfun);
return cbfun;
}
GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* handle,
GLFWcursorposfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.cursorPos, cbfun);
return cbfun;
}
GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* handle,
GLFWcursorenterfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.cursorEnter, cbfun);
return cbfun;
}
GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* handle,
GLFWscrollfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.scroll, cbfun);
return cbfun;
}
GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* handle, GLFWdropfun cbfun)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(window->callbacks.drop, cbfun);
return cbfun;
}
GLFWAPI int glfwJoystickPresent(int jid)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
_GLFW_REQUIRE_INIT_OR_RETURN(GLFW_FALSE);
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
return GLFW_FALSE;
}
if (!_glfw.joysticks[jid].present)
return GLFW_FALSE;
return _glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE);
}
GLFWAPI const float* glfwGetJoystickAxes(int jid, int* count)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
return NULL;
}
if (!_glfw.joysticks[jid].present)
return NULL;
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_AXES))
return NULL;
*count = _glfw.joysticks[jid].axisCount;
return _glfw.joysticks[jid].axes;
}
GLFWAPI const unsigned char* glfwGetJoystickButtons(int jid, int* count)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
return NULL;
}
if (!_glfw.joysticks[jid].present)
return NULL;
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS))
return NULL;
if (_glfw.hints.init.hatButtons)
{
*count = _glfw.joysticks[jid].buttonCount +
_glfw.joysticks[jid].hatCount * 4;
}
else
*count = _glfw.joysticks[jid].buttonCount;
return _glfw.joysticks[jid].buttons;
}
GLFWAPI const unsigned char* glfwGetJoystickHats(int jid, int* count)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
assert(count != NULL);
*count = 0;
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
return NULL;
}
if (!_glfw.joysticks[jid].present)
return NULL;
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_BUTTONS))
return NULL;
*count = _glfw.joysticks[jid].hatCount;
return _glfw.joysticks[jid].hats;
}
GLFWAPI const char* glfwGetJoystickName(int jid)
{
assert(jid >= GLFW_JOYSTICK_1);
assert(jid <= GLFW_JOYSTICK_LAST);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
if (jid < 0 || jid > GLFW_JOYSTICK_LAST)
{
_glfwInputError(GLFW_INVALID_ENUM, "Invalid joystick ID %i", jid);
return NULL;
}
if (!_glfw.joysticks[jid].present)
return NULL;
if (!_glfwPlatformPollJoystick(jid, _GLFW_POLL_PRESENCE))
return NULL;
return _glfw.joysticks[jid].name;
}
GLFWAPI GLFWjoystickfun glfwSetJoystickCallback(GLFWjoystickfun cbfun)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
_GLFW_SWAP_POINTERS(_glfw.callbacks.joystick, cbfun);
return cbfun;
}
GLFWAPI void glfwSetClipboardString(GLFWwindow* handle, const char* string)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
assert(string != NULL);
_GLFW_REQUIRE_INIT();
_glfwPlatformSetClipboardString(window, string);
}
GLFWAPI const char* glfwGetClipboardString(GLFWwindow* handle)
{
_GLFWwindow* window = (_GLFWwindow*) handle;
assert(window != NULL);
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetClipboardString(window);
}
GLFWAPI double glfwGetTime(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0.0);
return (double) (_glfwPlatformGetTimerValue() - _glfw.timer.offset) /
_glfwPlatformGetTimerFrequency();
}
GLFWAPI void glfwSetTime(double time)
{
_GLFW_REQUIRE_INIT();
if (time != time || time < 0.0 || time > 18446744073.0)
{
_glfwInputError(GLFW_INVALID_VALUE, "Invalid time %f", time);
return;
}
_glfw.timer.offset = _glfwPlatformGetTimerValue() -
(uint64_t) (time * _glfwPlatformGetTimerFrequency());
}
GLFWAPI uint64_t glfwGetTimerValue(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerValue();
}
GLFWAPI uint64_t glfwGetTimerFrequency(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(0);
return _glfwPlatformGetTimerFrequency();
}