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 processes X11 events inside GHandleWindowEvents, which is called automatically by GSimpleWindowLoop each frame (or manually in a custom loop). You can respond to input in two complementary ways: attach callbacks that fire when a specific event occurs, or poll state directly to check what is currently pressed or where the mouse is.

Keyboard Callbacks

void GEventAttachKey(void (*Key)(int key));
The attached callback fires once for each keypress, as long as:
  • No input widget (GCreateInput) has the cursor inside its bounds, and
  • No modal dialog is currently open.
The key parameter is the ASCII value for printable keys, or one of the following special constants for non-printable keys:
ConstantValueKey
GKeyLeft170Left arrow
GKeyRight171Right arrow
GKeyUp172Up arrow
GKeyDown173Down arrow
GKeyFnBase + 1151F1
GKeyFnBase + 2152F2
GKeyFnBase + 12162F12
GKeyFnBase is 150; function keys are GKeyFnBase + N for FN. Two key combinations are always handled by LWXGL before your callback is reached:
  • Ctrl+Escape — calls GDeleteWindow() directly, bypassing your key callback. The GEventAttachDelete callback is still consulted; return 0 from it to cancel the close.
  • F12 — toggles the debug overlay (when GSimpleWindowLoop is active).
void handle_key(int key) {
    if (key == GKeyLeft)  { /* move player left */ }
    if (key == GKeyRight) { /* move player right */ }
    if (key == GKeyUp)    { /* jump */ }
    if (key == 'q')       { GDeleteWindow(); }
}

/* Attach before entering the loop */
GEventAttachKey(handle_key);

Keyboard Polling

For smooth, frame-by-frame input (such as continuous movement while a key is held), poll the keyboard state directly instead of using the event callback.
unsigned char *GQueryKeyboard(void);
int            GQueryKeyDown(int ch);
  • GQueryKeyboard() returns a pointer to an 8-byte array of currently held key codes (up to 8 simultaneous keys). A value of 0 in a slot means no key is held there.
  • GQueryKeyDown(ch) returns 1 if the given character or key constant is currently pressed, 0 otherwise.
void on_frame(int tick) {
    if (GQueryKeyDown(GKeyLeft))  { /* move left */ }
    if (GQueryKeyDown(GKeyRight)) { /* move right */ }
    if (GQueryKeyDown(GKeyUp))    { /* move up */ }
    if (GQueryKeyDown(GKeyDown))  { /* move down */ }
}

Mouse Callbacks

void GEventAttachClick(void (*Click)(int x, int y, int btn));
The attached callback fires on mouse button release, provided:
  • No button widget (GCreateButton) was the click target, and
  • No modal dialog is currently open.
btn valueButton
1Left
2Middle
3Right
x and y are the cursor position at the time of release.
void handle_click(int x, int y, int btn) {
    if (btn == 1) {
        /* left click at (x, y) */
    }
}

GEventAttachClick(handle_click);

Mouse Polling

void GQueryMouse(int *x, int *y, int *btn);
Fills all three output pointers with the current mouse state:
OutputDescription
*x, *yCurrent cursor position in window coordinates. Both are -1 when the cursor is outside the window.
*btnCurrently held button: 0 = none, 1 = left, 2 = middle, 3 = right
void on_frame(int tick) {
    int mx, my, mb;
    GQueryMouse(&mx, &my, &mb);
    if (mx != -1 && mb == 1) {
        /* left button held at (mx, my) */
    }
}

Window Close Callback

void GEventAttachDelete(int (*on_exit)(void));
Register a callback that is invoked when the window is asked to close (either by GDeleteWindow() or by the WM close button). The return value controls what happens:
Return valueEffect
Non-zeroClose proceeds (closing flag is set to 1)
0Close is cancelled
If no callback is registered, closing is always allowed. The following pattern shows how to use a modal confirmation dialog to intercept the close event:
void confirm_quit(void) {
    GDeleteWindow(); /* user clicked OK — now actually close */
}

int on_close(void) {
    GSpawnModal(1, "Quit the application?", confirm_quit);
    return 0; /* block close until modal resolves */
}

/* ... */
GEventAttachDelete(on_close);
Event priority rules:
  • A button onclick fires before the global GEventAttachClick callback. If a button was clicked, the global Click callback is not called for that release event.
  • Input widgets consume keypresses before the GEventAttachKey callback, as long as the cursor is inside the input’s bounds. If no input widget has the cursor, the key callback fires normally.
  • While a modal is open, button onclick callbacks and the key callback are suppressed entirely. Mouse clicks are only processed by the modal’s own OK/Cancel buttons.

Build docs developers (and LLMs) love