2023-11-05 15:30:11 +00:00
|
|
|
/*
|
|
|
|
* GLEQ - A basic event queue for GLFW 3
|
|
|
|
* Copyright © 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.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef GLEQ_HEADER_FILE
|
|
|
|
#define GLEQ_HEADER_FILE
|
|
|
|
|
|
|
|
// #include <GLFW/glfw3.h>
|
|
|
|
|
|
|
|
#ifdef GLEQ_STATIC
|
|
|
|
#define GLEQDEF static
|
|
|
|
#else
|
|
|
|
#define GLEQDEF extern
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
extern "C" {
|
|
|
|
#endif
|
|
|
|
|
|
|
|
typedef enum
|
|
|
|
{
|
|
|
|
GLEQ_NONE = 0,
|
|
|
|
GLEQ_WINDOW_MOVED = 1<<1,
|
|
|
|
GLEQ_WINDOW_RESIZED = 1<<2,
|
|
|
|
GLEQ_WINDOW_CLOSED = 1<<3,
|
|
|
|
GLEQ_WINDOW_REFRESH = 1<<4,
|
|
|
|
GLEQ_WINDOW_FOCUSED = 1<<5,
|
|
|
|
GLEQ_WINDOW_DEFOCUSED = 1<<6,
|
|
|
|
GLEQ_WINDOW_ICONIFIED = 1<<7,
|
|
|
|
GLEQ_WINDOW_UNICONIFIED = 1<<8,
|
|
|
|
GLEQ_FRAMEBUFFER_RESIZED = 1<<9,
|
|
|
|
GLEQ_BUTTON_PRESSED = 1<<10,
|
|
|
|
GLEQ_BUTTON_RELEASED = 1<<11,
|
|
|
|
GLEQ_CURSOR_MOVED = 1<<12,
|
|
|
|
GLEQ_CURSOR_ENTERED = 1<<13,
|
|
|
|
GLEQ_CURSOR_LEFT = 1<<14,
|
|
|
|
GLEQ_SCROLLED = 1<<15,
|
|
|
|
GLEQ_KEY_PRESSED = 1<<16,
|
|
|
|
GLEQ_KEY_REPEATED = 1<<17,
|
|
|
|
GLEQ_KEY_RELEASED = 1<<18,
|
|
|
|
GLEQ_CODEPOINT_INPUT = 1<<19,
|
|
|
|
GLEQ_MONITOR_CONNECTED = 1<<20,
|
|
|
|
GLEQ_MONITOR_DISCONNECTED = 1<<21,
|
|
|
|
#if GLFW_VERSION_MINOR >= 1
|
|
|
|
GLEQ_FILE_DROPPED = 1<<22,
|
|
|
|
#endif
|
|
|
|
#if GLFW_VERSION_MINOR >= 2
|
|
|
|
GLEQ_JOYSTICK_CONNECTED = 1<<23,
|
|
|
|
GLEQ_JOYSTICK_DISCONNECTED = 1<<24,
|
|
|
|
#endif
|
|
|
|
#if GLFW_VERSION_MINOR >= 3
|
|
|
|
GLEQ_WINDOW_MAXIMIZED = 1<<25,
|
|
|
|
GLEQ_WINDOW_UNMAXIMIZED = 1<<26,
|
|
|
|
GLEQ_WINDOW_SCALE_CHANGED = 1<<27,
|
|
|
|
#endif
|
|
|
|
} GLEQtype;
|
|
|
|
|
|
|
|
typedef struct GLEQevent
|
|
|
|
{
|
|
|
|
unsigned/*GLEQtype*/ type;
|
|
|
|
union {
|
|
|
|
GLFWwindow* window;
|
|
|
|
GLFWmonitor* monitor;
|
|
|
|
int joystick;
|
|
|
|
};
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
int x;
|
|
|
|
int y;
|
|
|
|
} pos;
|
|
|
|
struct {
|
|
|
|
int width;
|
|
|
|
int height;
|
|
|
|
} size;
|
|
|
|
struct {
|
|
|
|
double x;
|
|
|
|
double y;
|
|
|
|
} scroll;
|
|
|
|
struct {
|
|
|
|
int key;
|
|
|
|
int scancode;
|
|
|
|
int mods;
|
|
|
|
} keyboard;
|
|
|
|
struct {
|
|
|
|
int button;
|
|
|
|
int mods;
|
|
|
|
} mouse;
|
|
|
|
unsigned int codepoint;
|
|
|
|
#if GLFW_VERSION_MINOR >= 1
|
|
|
|
struct {
|
|
|
|
char** paths;
|
|
|
|
int count;
|
|
|
|
} file;
|
|
|
|
#endif
|
|
|
|
#if GLFW_VERSION_MINOR >= 3
|
|
|
|
struct {
|
|
|
|
float x;
|
|
|
|
float y;
|
|
|
|
} scale;
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
} GLEQevent;
|
|
|
|
|
|
|
|
GLEQDEF void gleqInit(void);
|
|
|
|
GLEQDEF void gleqTrackWindow(GLFWwindow* window);
|
|
|
|
|
|
|
|
GLEQDEF int gleqNextEvent(GLEQevent* event);
|
|
|
|
GLEQDEF void gleqFreeEvent(GLEQevent* event);
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef GLEQ_IMPLEMENTATION
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#ifndef GLEQ_CAPACITY
|
|
|
|
#define GLEQ_CAPACITY 1024
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static struct
|
|
|
|
{
|
|
|
|
GLEQevent events[GLEQ_CAPACITY];
|
|
|
|
size_t head;
|
|
|
|
size_t tail;
|
|
|
|
} gleq_queue = { {0}, 0, 0 };
|
|
|
|
|
|
|
|
static char* gleq_strdup(const char* string)
|
|
|
|
{
|
|
|
|
const size_t size = strlen(string) + 1;
|
|
|
|
char* result = (char*) malloc(size);
|
|
|
|
memcpy(result, string, size);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
static GLEQevent* gleq_new_event(void)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_queue.events + gleq_queue.head;
|
|
|
|
gleq_queue.head = (gleq_queue.head + 1) % GLEQ_CAPACITY;
|
|
|
|
assert(gleq_queue.head != gleq_queue.tail);
|
|
|
|
memset(event, 0, sizeof(GLEQevent));
|
|
|
|
return event;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_pos_callback(GLFWwindow* window, int x, int y)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_WINDOW_MOVED;
|
|
|
|
event->window = window;
|
|
|
|
event->pos.x = x;
|
|
|
|
event->pos.y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_size_callback(GLFWwindow* window, int width, int height)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_WINDOW_RESIZED;
|
|
|
|
event->window = window;
|
|
|
|
event->size.width = width;
|
|
|
|
event->size.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_close_callback(GLFWwindow* window)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_WINDOW_CLOSED;
|
|
|
|
event->window = window;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_refresh_callback(GLFWwindow* window)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_WINDOW_REFRESH;
|
|
|
|
event->window = window;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_focus_callback(GLFWwindow* window, int focused)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
|
|
|
|
if (focused)
|
|
|
|
event->type = GLEQ_WINDOW_FOCUSED;
|
|
|
|
else
|
|
|
|
event->type = GLEQ_WINDOW_DEFOCUSED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_iconify_callback(GLFWwindow* window, int iconified)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
|
|
|
|
if (iconified)
|
|
|
|
event->type = GLEQ_WINDOW_ICONIFIED;
|
|
|
|
else
|
|
|
|
event->type = GLEQ_WINDOW_UNICONIFIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_framebuffer_size_callback(GLFWwindow* window, int width, int height)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_FRAMEBUFFER_RESIZED;
|
|
|
|
event->window = window;
|
|
|
|
event->size.width = width;
|
|
|
|
event->size.height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
event->mouse.button = button;
|
|
|
|
event->mouse.mods = mods;
|
|
|
|
|
|
|
|
if (action == GLFW_PRESS)
|
|
|
|
event->type = GLEQ_BUTTON_PRESSED;
|
|
|
|
else if (action == GLFW_RELEASE)
|
|
|
|
event->type = GLEQ_BUTTON_RELEASED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_cursor_pos_callback(GLFWwindow* window, double x, double y)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_CURSOR_MOVED;
|
|
|
|
event->window = window;
|
|
|
|
event->pos.x = (int) x;
|
|
|
|
event->pos.y = (int) y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_cursor_enter_callback(GLFWwindow* window, int entered)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
|
|
|
|
if (entered)
|
|
|
|
event->type = GLEQ_CURSOR_ENTERED;
|
|
|
|
else
|
|
|
|
event->type = GLEQ_CURSOR_LEFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_scroll_callback(GLFWwindow* window, double x, double y)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_SCROLLED;
|
|
|
|
event->window = window;
|
|
|
|
event->scroll.x = x;
|
|
|
|
event->scroll.y = y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_key_callback(GLFWwindow* window, int key, int scancode, int action, int mods)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
event->keyboard.key = key;
|
|
|
|
event->keyboard.scancode = scancode;
|
|
|
|
event->keyboard.mods = mods;
|
|
|
|
|
|
|
|
if (action == GLFW_PRESS)
|
|
|
|
event->type = GLEQ_KEY_PRESSED;
|
|
|
|
else if (action == GLFW_RELEASE)
|
|
|
|
event->type = GLEQ_KEY_RELEASED;
|
|
|
|
else if (action == GLFW_REPEAT)
|
|
|
|
event->type = GLEQ_KEY_REPEATED;
|
|
|
|
}
|
|
|
|
|
2023-11-26 15:06:55 +00:00
|
|
|
static void (*gleq_char_callback_prev)(GLFWwindow* window, unsigned int codepoint) = 0;
|
2023-11-05 15:30:11 +00:00
|
|
|
static void gleq_char_callback(GLFWwindow* window, unsigned int codepoint)
|
|
|
|
{
|
2023-11-26 15:06:55 +00:00
|
|
|
if( gleq_char_callback_prev )
|
|
|
|
gleq_char_callback_prev(window, codepoint);
|
|
|
|
|
2023-11-05 15:30:11 +00:00
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_CODEPOINT_INPUT;
|
|
|
|
event->window = window;
|
|
|
|
event->codepoint = codepoint;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_monitor_callback(GLFWmonitor* monitor, int action)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->monitor = monitor;
|
|
|
|
|
|
|
|
if (action == GLFW_CONNECTED)
|
|
|
|
event->type = GLEQ_MONITOR_CONNECTED;
|
|
|
|
else if (action == GLFW_DISCONNECTED)
|
|
|
|
event->type = GLEQ_MONITOR_DISCONNECTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if GLFW_VERSION_MINOR >= 1
|
|
|
|
static void gleq_file_drop_callback(GLFWwindow* window, int count, const char** paths)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->type = GLEQ_FILE_DROPPED;
|
|
|
|
event->window = window;
|
|
|
|
event->file.paths = (char**) malloc(count * sizeof(char*));
|
|
|
|
event->file.count = count;
|
|
|
|
|
|
|
|
while (count--)
|
|
|
|
event->file.paths[count] = gleq_strdup(paths[count]);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if GLFW_VERSION_MINOR >= 2
|
|
|
|
static void gleq_joystick_callback(int jid, int action)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->joystick = jid;
|
|
|
|
|
|
|
|
if (action == GLFW_CONNECTED)
|
|
|
|
event->type = GLEQ_JOYSTICK_CONNECTED;
|
|
|
|
else if (action == GLFW_DISCONNECTED)
|
|
|
|
event->type = GLEQ_JOYSTICK_DISCONNECTED;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if GLFW_VERSION_MINOR >= 3
|
|
|
|
static void gleq_window_maximize_callback(GLFWwindow* window, int maximized)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
|
|
|
|
if (maximized)
|
|
|
|
event->type = GLEQ_WINDOW_MAXIMIZED;
|
|
|
|
else
|
|
|
|
event->type = GLEQ_WINDOW_UNMAXIMIZED;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void gleq_window_content_scale_callback(GLFWwindow* window, float xscale, float yscale)
|
|
|
|
{
|
|
|
|
GLEQevent* event = gleq_new_event();
|
|
|
|
event->window = window;
|
|
|
|
event->type = GLEQ_WINDOW_SCALE_CHANGED;
|
|
|
|
event->scale.x = xscale;
|
|
|
|
event->scale.y = yscale;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
GLEQDEF void gleqInit(void)
|
|
|
|
{
|
|
|
|
glfwSetMonitorCallback(gleq_monitor_callback);
|
|
|
|
#if GLFW_VERSION_MINOR >= 2
|
|
|
|
glfwSetJoystickCallback(gleq_joystick_callback);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GLEQDEF void gleqTrackWindow(GLFWwindow* window)
|
|
|
|
{
|
|
|
|
glfwSetWindowPosCallback(window, gleq_window_pos_callback);
|
|
|
|
glfwSetWindowSizeCallback(window, gleq_window_size_callback);
|
|
|
|
glfwSetWindowCloseCallback(window, gleq_window_close_callback);
|
|
|
|
glfwSetWindowRefreshCallback(window, gleq_window_refresh_callback);
|
|
|
|
glfwSetWindowFocusCallback(window, gleq_window_focus_callback);
|
|
|
|
glfwSetWindowIconifyCallback(window, gleq_window_iconify_callback);
|
|
|
|
glfwSetFramebufferSizeCallback(window, gleq_framebuffer_size_callback);
|
|
|
|
glfwSetMouseButtonCallback(window, gleq_mouse_button_callback);
|
|
|
|
glfwSetCursorPosCallback(window, gleq_cursor_pos_callback);
|
|
|
|
glfwSetCursorEnterCallback(window, gleq_cursor_enter_callback);
|
|
|
|
glfwSetScrollCallback(window, gleq_scroll_callback);
|
|
|
|
glfwSetKeyCallback(window, gleq_key_callback);
|
2023-11-26 15:06:55 +00:00
|
|
|
gleq_char_callback_prev = //< @r-lyeh
|
2023-11-05 15:30:11 +00:00
|
|
|
glfwSetCharCallback(window, gleq_char_callback);
|
|
|
|
#if GLFW_VERSION_MINOR >= 1
|
|
|
|
glfwSetDropCallback(window, gleq_file_drop_callback);
|
|
|
|
#endif
|
|
|
|
#if GLFW_VERSION_MINOR >= 3
|
|
|
|
glfwSetWindowMaximizeCallback(window, gleq_window_maximize_callback);
|
|
|
|
glfwSetWindowContentScaleCallback(window, gleq_window_content_scale_callback);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
GLEQDEF int gleqNextEvent(GLEQevent* event)
|
|
|
|
{
|
|
|
|
memset(event, 0, sizeof(GLEQevent));
|
|
|
|
|
|
|
|
if (gleq_queue.head != gleq_queue.tail)
|
|
|
|
{
|
|
|
|
*event = gleq_queue.events[gleq_queue.tail];
|
|
|
|
gleq_queue.tail = (gleq_queue.tail + 1) % GLEQ_CAPACITY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return event->type != GLEQ_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GLEQDEF void gleqFreeEvent(GLEQevent* event)
|
|
|
|
{
|
|
|
|
#if GLFW_VERSION_MINOR >= 1
|
|
|
|
if (event->type == GLEQ_FILE_DROPPED)
|
|
|
|
{
|
|
|
|
while (event->file.count--)
|
|
|
|
free(event->file.paths[event->file.count]);
|
|
|
|
|
|
|
|
free(event->file.paths);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
memset(event, 0, sizeof(GLEQevent));
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* GLEQ_IMPLEMENTATION */
|
|
|
|
|
|
|
|
#endif /* GLEQ_HEADER_FILE */
|