Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/DRessedAlarm184/LWXGL/llms.txt

Use this file to discover all available pages before exploring further.

LWXGL gives you two ways to respond to input. Attach callbacks (GEventAttach*) let the library push events to your code as they occur. Query functions (GQuery*) let you poll the current input state at any point in your frame — useful for smooth continuous movement or when you need input state outside of a callback. All callbacks are invoked from within GHandleWindowEvents.

Key Constants

LWXGL maps X11 keys that have no printable ASCII value to constants in the range 150–173. These constants are used wherever a key value is expected — in attach callbacks, query results, and GQueryKeyDown.
ConstantValueKey
LWXGL_KEY_FN150Base offset for function keys
LWXGL_KEY_LEFT170Left arrow
LWXGL_KEY_RIGHT171Right arrow
LWXGL_KEY_UP172Up arrow
LWXGL_KEY_DOWN173Down arrow
Function keys F1–F12 are encoded as LWXGL_KEY_FN + N, where N is the function key number (1–12):
#define LWXGL_KEY_FN    150   /* base */
/* F1  = 151, F2 = 152, ..., F12 = 162 */
Example — checking for F5
void on_key(int key) {
    if (key == LWXGL_KEY_FN + 5) {
        /* F5 pressed */
    }
}
All other keys that have a printable ASCII representation (letters, digits, punctuation, Space, Backspace, etc.) are delivered as their standard ASCII value (e.g. 'a' = 97, Backspace = 8).

GEventAttachKey

void GEventAttachKey(void (*Key)(int key));
Registers a callback that fires once for each key press event. The callback receives the translated key value: the ASCII code for printable keys, or one of the LWXGL_KEY_* constants for arrows and function keys.
Key
void (*)(int key)
required
Callback function. key is:
  • The ASCII code for printable characters (e.g. 'a', '1', ' ').
  • LWXGL_KEY_LEFT / LWXGL_KEY_RIGHT / LWXGL_KEY_UP / LWXGL_KEY_DOWN for arrow keys.
  • LWXGL_KEY_FN + N for function keys F1–F12.
Suppression rules — the callback is NOT invoked when:
  • A modal dialog is currently open (GQueryModalOpen() returns 1).
  • A focused Input element is in the window and the cursor is inside it (the element consumes the key).
  • A Console element is focused and under the cursor (Space scrolls the console).
  • The key combination is Ctrl + Escape (this closes the window before the callback would fire).
F12 is reserved by LWXGL to toggle the debug overlay and is never forwarded to the key callback.
Example
void on_key(int key) {
    if (key == LWXGL_KEY_UP)    player_y -= 4;
    if (key == LWXGL_KEY_DOWN)  player_y += 4;
    if (key == LWXGL_KEY_LEFT)  player_x -= 4;
    if (key == LWXGL_KEY_RIGHT) player_x += 4;
    if (key == 'q')             GDeleteWindow();
}

int main(void) {
    GCreateWindow(800, 600, "Input Demo", 0);
    GEventAttachKey(on_key);
    GSimpleWindowLoop(60, NULL);
    GTerminateWindow();
    return 0;
}

GEventAttachClick

void GEventAttachClick(void (*Click)(int x, int y, int btn));
Registers a callback that fires on mouse button release, delivering the cursor position and which button was released.
Click
void (*)(int x, int y, int btn)
required
Callback function:
  • x, y — cursor coordinates relative to the top-left corner of the window at the time of release.
  • btn — X11 button number: 1 = left, 2 = middle, 3 = right. Scroll wheel events (4 = up, 5 = down) are handled internally by Console elements and are never forwarded to this callback.
Suppression rules — the callback is NOT invoked when:
  • A modal dialog is open. The modal’s own click regions handle the event and return early.
  • The release lands inside a Button, Checkbox, or Console element — those elements consume the event.
Example
void on_click(int x, int y, int btn) {
    if (btn == 1) {
        printf("Left click at (%d, %d)\n", x, y);
    }
}

int main(void) {
    GCreateWindow(800, 600, "Click Demo", 0);
    GEventAttachClick(on_click);
    GSimpleWindowLoop(60, NULL);
    GTerminateWindow();
    return 0;
}

GEventAttachDelete

void GEventAttachDelete(int (*on_exit)());
Registers a callback that is invoked whenever a close is requested — either from the WM’s close button (WM_DELETE_WINDOW protocol), a call to GDeleteWindow, or Ctrl + Escape. The callback’s return value determines whether the close is allowed.
on_exit
int (*)()
required
Callback function. Return 1 to allow the window to close, 0 to block it.
If GEventAttachDelete is never called, all close events are allowed without restriction.
If on_exit always returns 0, the user will be unable to close the window through any normal mechanism, including the OS task manager’s close button.
Example — prompt before closing
int unsaved_changes = 0;

int on_exit(void) {
    if (unsaved_changes) {
        GSpawnModal(1, "Unsaved changes.\nClose anyway?", GDeleteWindow);
        return 0; /* block this close attempt; modal will re-trigger */
    }
    return 1; /* allow */
}

int main(void) {
    GCreateWindow(800, 600, "Editor", 0);
    GEventAttachDelete(on_exit);
    GSimpleWindowLoop(60, NULL);
    GTerminateWindow();
    return 0;
}

GQueryMouse

void GQueryMouse(int* x, int* y, int* btn);
Fills the provided pointers with the current mouse state. The values are updated continuously by GHandleWindowEvents as motion and button events arrive — poll this function anywhere in your frame logic to read the latest state.
x
int*
required
Receives the cursor’s X coordinate relative to the window origin. Set to -1 when the cursor is outside the window.
y
int*
required
Receives the cursor’s Y coordinate relative to the window origin. Set to -1 when the cursor is outside the window.
btn
int*
required
Receives the currently held button number (1 = left, 2 = middle, 3 = right). Set to 0 when no button is pressed.
GQueryMouse reports the pressed button (i.e. held down), not the most recently released button. For release events, use GEventAttachClick.
Example
void on_frame(int tick, float dt) {
    int x, y, btn;
    GQueryMouse(&x, &y, &btn);

    if (x != -1 && btn == 1) {
        /* left button held; drag logic */
    }
}

GQueryKeyboard

unsigned char* GQueryKeyboard();
Returns a pointer to the internal 8-element array of currently pressed key values. Each slot contains an ASCII value or a LWXGL_KEY_* constant for a key that is currently held down. Slots not occupied by an active key hold 0. Returns unsigned char* pointing to an array of 8 unsigned char values. This pointer is valid for the lifetime of the window; do not free it.
Do not write to the returned array. It is an internal buffer managed by the event system.
Example
void on_frame(int tick, float dt) {
    unsigned char *keys = GQueryKeyboard();
    for (int i = 0; i < 8; i++) {
        if (keys[i] == LWXGL_KEY_UP)    player_y -= 2;
        if (keys[i] == LWXGL_KEY_DOWN)  player_y += 2;
        if (keys[i] == LWXGL_KEY_LEFT)  player_x -= 2;
        if (keys[i] == LWXGL_KEY_RIGHT) player_x += 2;
    }
}

GQueryKeyDown

int GQueryKeyDown(int ch);
Returns whether a specific key is currently held down. Internally searches the same 8-element pressed-keys array that GQueryKeyboard exposes.
ch
int
required
The key value to test: an ASCII code or a LWXGL_KEY_* constant.
Returns 1 if the key is currently held, 0 otherwise.
GQueryKeyDown is the most ergonomic way to test a single key. Use GQueryKeyboard only when you need to inspect all held keys simultaneously.
Example
void on_frame(int tick, float dt) {
    if (GQueryKeyDown(LWXGL_KEY_LEFT))  player_x -= 3;
    if (GQueryKeyDown(LWXGL_KEY_RIGHT)) player_x += 3;
    if (GQueryKeyDown(LWXGL_KEY_UP))    player_y -= 3;
    if (GQueryKeyDown(LWXGL_KEY_DOWN))  player_y += 3;

    if (GQueryKeyDown('z')) fire_weapon();
}

Putting it all together

The following example combines attach callbacks for discrete events with polling for continuous movement:
#include "libLWXGL.h"
#include <stdio.h>

static int player_x = 400, player_y = 300;

/* Discrete key events (e.g. menu navigation, firing) */
void on_key(int key) {
    if (key == ' ') printf("Fire!\n");
    if (key == LWXGL_KEY_FN + 1) printf("F1: help\n"); /* F1 */
}

/* Discrete click events */
void on_click(int x, int y, int btn) {
    if (btn == 1) printf("Placed marker at (%d, %d)\n", x, y);
}

/* Per-frame: smooth movement via polling */
void on_frame(int tick, float dt) {
    float speed = 200.0f * dt; /* pixels per second */
    if (GQueryKeyDown(LWXGL_KEY_LEFT))  player_x -= (int)speed;
    if (GQueryKeyDown(LWXGL_KEY_RIGHT)) player_x += (int)speed;
    if (GQueryKeyDown(LWXGL_KEY_UP))    player_y -= (int)speed;
    if (GQueryKeyDown(LWXGL_KEY_DOWN))  player_y += (int)speed;
}

int main(void) {
    GCreateWindow(800, 600, "Combined Input Demo", 0);
    GEventAttachKey(on_key);
    GEventAttachClick(on_click);
    GSimpleWindowLoop(60, on_frame);
    GTerminateWindow();
    return 0;
}

Build docs developers (and LLMs) love