Combos

The short control snippets below belong inside main and refer to the OutputTest combo defined in the first example.

Combos are timed output sequences that execute alongside the main loop. They are useful for accessibility sequences, controller diagnostics, and repeatable device tests.

Combo Definition

gpc
combo OutputTest {
    set_val(BUTTON_15, 100);
    wait(100);
    set_val(BUTTON_15, 0);
}

A combo stops when it reaches the end. Start it from main in response to an input event.


Combo Control Functions

Starting a Combo

gpc
combo_run(OutputTest);

Starts the combo if it is not already running.

Stopping a Combo

gpc
combo_stop(OutputTest);

Stops the combo immediately.

Restarting a Combo

gpc
combo_restart(OutputTest);

Restarts the combo from the beginning. This is useful when each input event should produce a fresh test sequence.

Pausing a Combo

gpc
combo_pause(OutputTest);

Pauses execution at its current position.

Checking Status

gpc
if (combo_running(OutputTest)) {
    printf("Output test is active");
}

// A combo name also evaluates to its running state.
if (OutputTest) {
    printf("Sequence is still running");
}

wait

wait() pauses combo execution for the specified number of milliseconds:

gpc
combo TimedSequence {
    set_val(BUTTON_16, 100);
    wait(100);
    set_val(BUTTON_16, 0);
    wait(200);
}

wait() is available inside combos, not in main or init blocks.


Calling Other Combos

Use call() to run another combo and wait for it to complete:

gpc
combo TestLeftButton {
    set_val(BUTTON_16, 100);
    wait(100);
    set_val(BUTTON_16, 0);
    wait(50);
}

combo TestTopButton {
    set_val(BUTTON_13, 100);
    wait(100);
    set_val(BUTTON_13, 0);
    wait(50);
}

combo FaceButtonTest {
    call(TestLeftButton);
    call(TestTopButton);
}

Practical Examples

One-Shot Output Test

gpc
main {
    if (event_active(BUTTON_5)) {
        combo_restart(OutputTest);
    }
}

combo OutputTest {
    set_val(BUTTON_15, 100);
    wait(120);
    set_val(BUTTON_15, 0);
}

Multi-Step Device Test

gpc
main {
    if (event_active(BUTTON_11)) {
        combo_restart(DeviceTest);
    }
}

combo DeviceTest {
    set_val(BUTTON_16, 100);
    wait(100);
    set_val(BUTTON_16, 0);
    wait(100);

    set_val(BUTTON_13, 100);
    wait(100);
    set_val(BUTTON_13, 0);
    wait(100);

    set_val(BUTTON_14, 100);
    wait(100);
    set_val(BUTTON_14, 0);
    wait(100);

    set_val(BUTTON_15, 100);
    wait(100);
    set_val(BUTTON_15, 0);
}

Adjustable Test Duration

gpc
int test_hold_ms = 100;

main {
    if (event_active(BUTTON_5)) {
        test_hold_ms = max(test_hold_ms - 10, 20);
        printf("Test duration: %d ms", test_hold_ms);
    }

    if (event_active(BUTTON_7)) {
        test_hold_ms = min(test_hold_ms + 10, 500);
        printf("Test duration: %d ms", test_hold_ms);
    }

    if (event_active(BUTTON_11)) {
        combo_restart(OutputTest);
    }
}

combo OutputTest {
    set_val(BUTTON_15, 100);
    wait(test_hold_ms);
    set_val(BUTTON_15, 0);
}

Best Practices

Keep each combo focused and give it a descriptive name such as FaceButtonTest. Use input edges such as event_active() for one-shot sequences, stop a sequence when its cancellation condition occurs, and start with longer waits while checking device timing. Keep user-adjustable timing values near the top of the script.