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 provides two models for handling user input:
  • Event callbacks — functions you register that are called once per individual key press or mouse click.
  • Polled state — functions you call yourself (typically inside the per-frame callback) to read which keys or mouse buttons are currently held down.
Use callbacks for one-shot reactions (submit a form, fire a weapon) and polling for continuous movement or held-button logic.

Keyboard Callback

void GEventAttachKey(void (*Key)(int key));
Registers a function that is called once each time a key-press event is received. The key argument is the ASCII character code for printable keys, or one of the LWXGL key constants for special keys:
ConstantValueKey
LWXGL_KEY_LEFT170Left arrow
LWXGL_KEY_RIGHT171Right arrow
LWXGL_KEY_UP172Up arrow
LWXGL_KEY_DOWN173Down arrow
LWXGL_KEY_FN + 1151F1
LWXGL_KEY_FN + 2152F2
LWXGL_KEY_FN + 12162F12
LWXGL_KEY_FN (150) is the base offset; Fn = LWXGL_KEY_FN + n. The callback is not invoked when:
  • A modal dialog is currently open (GQueryModalOpen() returns 1).
  • The cursor is hovering over a focused input field or console widget — those widgets capture the keystroke directly.
void on_key(int key) {
    if (key == LWXGL_KEY_LEFT)  printf("Left arrow\n");
    if (key == LWXGL_KEY_RIGHT) printf("Right arrow\n");
    if (key == 'q' || key == 'Q') GDeleteWindow();

    // F1–F12
    if (key >= LWXGL_KEY_FN + 1 && key <= LWXGL_KEY_FN + 12) {
        printf("F%d pressed\n", key - LWXGL_KEY_FN);
    }
}

// Register before starting the loop
GEventAttachKey(on_key);

Mouse-Click Callback

void GEventAttachClick(void (*Click)(int x, int y, int btn));
Registers a function called on every button release event. x and y are the cursor coordinates at the time of release. btn is the X11 button number:
btnButton
1Left
2Middle
3Right
4Scroll up
5Scroll down
The callback is not invoked when:
  • The release falls inside a button or checkbox widget (those widgets handle the click themselves).
  • A modal dialog is currently open.
void on_click(int x, int y, int btn) {
    if (btn == 1) {
        printf("Left click at (%d, %d)\n", x, y);
    } else if (btn == 3) {
        printf("Right click at (%d, %d)\n", x, y);
    }
}

GEventAttachClick(on_click);

Window-Close Callback

void GEventAttachDelete(int (*on_exit)());
Registers a function called when the user clicks the window’s close button (the X button in the title bar). Return 1 to allow the window to close, or 0 to cancel the close and keep the window open. If no callback is attached, clicking the close button always sets closing = 1 and the loop exits.
int on_close(void) {
    // Spawn a confirmation modal before allowing close
    GSpawnModal(1, "Quit the application?\nUnsaved changes will be lost.", NULL);
    return 0; // cancel the close for now; modal handles it
}

GEventAttachDelete(on_close);
A simpler example that always allows closing:
int on_close(void) {
    printf("Goodbye!\n");
    return 1; // allow close
}

Polled Keyboard State

unsigned char* GQueryKeyboard(void);
int            GQueryKeyDown(int ch);
GQueryKeyboard() returns a pointer to an internal unsigned char[8] array containing the character codes of up to eight currently held keys (0 = empty slot). GQueryKeyDown(ch) scans that array and returns 1 if ch is currently held, 0 otherwise. Use these inside the per-frame callback passed to GSimpleWindowLoop to implement smooth continuous movement.
void on_frame(int tick) {
    if (GQueryKeyDown(LWXGL_KEY_LEFT))  player_x -= 2;
    if (GQueryKeyDown(LWXGL_KEY_RIGHT)) player_x += 2;
    if (GQueryKeyDown(LWXGL_KEY_UP))    player_y -= 2;
    if (GQueryKeyDown(LWXGL_KEY_DOWN))  player_y += 2;

    // You can also iterate the full array directly:
    unsigned char* keys = GQueryKeyboard();
    for (int i = 0; i < 8; i++) {
        if (keys[i] != 0)
            printf("Held key: %d\n", keys[i]);
    }
}

Polled Mouse State

void GQueryMouse(int* x, int* y, int* btn);
Fills in the current cursor position and the currently pressed mouse button. x and y are set to -1 when the cursor is outside the window. btn is the X11 button number of the button currently held (1/2/3), or 0 if no button is pressed.
void on_frame(int tick) {
    int mx, my, mbtn;
    GQueryMouse(&mx, &my, &mbtn);

    if (mx == -1) {
        // cursor is outside the window
        return;
    }

    if (mbtn == 1) {
        // left button is held — paint a pixel on the canvas
        unsigned char* pixels = GGetImageData(0);
        if (mx < 200 && my < 150)
            pixels[my * 200 + mx] = 15; // white
        GUpdateImage(0);
    }
}
Combine both models for the best experience: use callbacks (GEventAttachKey, GEventAttachClick) to react to discrete events such as opening menus or confirming actions, and use polling (GQueryKeyDown, GQueryMouse) inside your per-frame callback for anything that needs to respond every frame, like moving a character or drawing with the mouse.

Build docs developers (and LLMs) love