<!-- Source: https://medius.k4tech.net/bindings/c/quickstart -->
# First program

_Find the box, send a command, read one event, free it_

One file: [connect](/library/connection.md), read the firmware version, move the cursor, click the left button, wait for one physical input, then free it. C has no [exceptions](https://en.cppreference.com/w/cpp/language/exceptions), so every fallible call returns a [`MediusStatus`](/bindings/c/types.md#errors) you check, and the detail comes from [`medius_last_error_message`](/bindings/c/api.md#module). What the commands _mean_ lives in the [Library](/library.md) and [Native](/native.md) sections; this page is only the C mechanics.

> **Note**
>
> Get [`medius.h`](/bindings/c.md) and the library from [Build & features](/bindings/c/build.md). New to the [box](/native/hardware.md) itself? Read the [Native quickstart](/native/quickstart.md) first.

```
  find()            ──▶  open + handshake      blocks
  query_version()   ──▶  read the version      blocks
  move() / press()  ──▶  inject input          fire-and-forget
  catch_events()    ──▶  subscribe to input    fire-and-forget
  recv()            ──▶  next physical event   blocks
  free()            ──▶  close, NULL-safe      local
```

## The program

_Every call, with error checks_

`check()` is the whole error story: compare against `MEDIUS_STATUS_OK` (which is `0`), and on anything else pull the text with `medius_last_error_message`. Results land through an out-pointer (`&dev`, `&v`, `&events`), never the return value.

```c
#include <stdio.h>
#include <medius.h>

/* Returns 0 on success, 1 on failure (after printing the last error). */
static int check(MediusStatus s, const char *what) {
    if (s == MEDIUS_STATUS_OK) return 0;
    char msg[256];
    medius_last_error_message(msg, sizeof msg);   /* detail for the last failure */
    fprintf(stderr, "%s failed (status %d): %s\n", what, (int)s, msg);
    return 1;
}

int main(void) {
    MediusDevice *dev = NULL;
    if (check(medius_device_find(&dev), "find"))            /* open first box + handshake */
        return 1;

    printf("medius-capi %s (abi %u)\n", medius_version_string(), medius_abi_version());

    MediusVersion v;
    if (!check(medius_device_query_version(dev, &v), "query_version"))
        printf("firmware %u.%u.%u (proto %u)\n", v.fw_major, v.fw_minor, v.fw_patch, v.proto_ver);

    check(medius_device_move_rel(dev, 100, -50), "move_rel");   /* fire-and-forget */
    check(medius_device_press(dev, medius_usage_button(MEDIUS_BUTTON_LEFT)), "press");
    check(medius_device_soft_release(dev, medius_usage_button(MEDIUS_BUTTON_LEFT)), "release");

    MediusEventStream *events = NULL;
    if (!check(medius_device_catch_events(dev, MEDIUS_CATCH_MASK_ALL, &events), "catch_events")) {
        MediusCatchEvent ev;                                   /* blocks for one physical event */
        if (medius_event_stream_recv(events, &ev) == MEDIUS_STATUS_OK &&
            ev.kind == MEDIUS_CATCH_EVENT_KIND_MOTION)
            printf("motion: dx=%d dy=%d dz=%d\n",
                   ev.data.motion.dx, ev.data.motion.dy, ev.data.motion.dz);
        medius_event_stream_free(events);                      /* unsubscribe */
    }

    medius_device_free(dev);                                   /* close link, join threads */
    return 0;
}
```

#### PRINTS (numbers depend on your box)

```c
medius-capi 3.0.0 (abi 3)
firmware 3.0.0 (proto 3)
motion: dx=12 dy=-4 dz=0
```

> **Note**
>
> [`medius_event_stream_recv`](/bindings/c/api.md#streams) blocks until the user touches the mouse or keyboard. To poll instead, or to loop over many events, see [Streams](/bindings/c/streams.md).

## Run it

_gcc or clang, link libmedius_capi_

Run from the unpacked release, with `medius.h` under `include/` and [`libmedius_capi.so`](/bindings/c.md) beside it. `cc`, [`gcc`](https://gcc.gnu.org/), and [`clang`](https://clang.llvm.org/) all work.

```bash
cc first.c -Iinclude -L. -lmedius_capi -o first
LD_LIBRARY_PATH=. ./first      # so the loader finds libmedius_capi.so
```

| Flag | What it does |
| --- | --- |
| `-Iinclude` | Where `medius.h` lives. |
| `-L.` | Where `libmedius_capi` lives (here, the current dir). |
| `-lmedius_capi` | Link the library (file name is `libmedius_capi`). |

> **Note**
>
> Static linking (`libmedius_capi.a`), Windows, and the [mock](/library/features/mock.md) / [flash](/library/features/flash.md) feature macros are on [Build & features](/bindings/c/build.md).

## Walkthrough

_Errors, out-params, freeing, blocking_

| Mechanic | How it works in C |
| --- | --- |
| Errors | Every fallible call returns a `MediusStatus`; `MEDIUS_STATUS_OK` is `0`, everything else is a failure. Read the human text with `medius_last_error_message(buf, cap)` right after the failing call. |
| Results | Return values are status codes, so data comes back through an out-pointer: [`medius_device_query_version(dev, &v)`](/bindings/c/api.md#queries) fills `v`. |
| Freeing | Each handle has a `*_free`: [`medius_device_free`](/bindings/c/api.md#connect), [`medius_event_stream_free`](/bindings/c/api.md#streams), [`medius_log_stream_free`](/bindings/c/api.md#streams). All are NULL-safe no-ops. Catch events are fixed-size structs, so there's nothing to free per event. |
| _Fire-and-forget_ | [`move_rel`](/bindings/c/api.md#move), [`wheel`](/bindings/c/api.md#move), [`press`](/bindings/c/api.md#inject), [`inject`](/bindings/c/api.md#inject), and the [lock](/bindings/c/api.md#lock) / [LED](/bindings/c/api.md#led-admin-options) calls queue a [frame](/native/frame.md) and return at once. This is the [fire-and-forget](/native/injection.md#fire-and-forget) model. |
| _Blocks_ | [`medius_device_find`](/bindings/c/api.md#connect) / `_open` (the [handshake](/native/connection.md#handshake)), every `medius_device_query_*`, and `medius_event_stream_recv` wait for a [reply](/native/commands/requests.md) or an event. |
| Sharing | [`medius_device_clone`](/bindings/c/api.md#connect) / [`medius_event_stream_clone`](/bindings/c/api.md#streams) hand back another handle to the same link; each clone must be freed. See [Lifecycle](/library/lifecycle.md). |

```text
MediusStatus medius_device_find(MediusDevice **out);
uintptr_t    medius_last_error_message(char *buf, uintptr_t cap);  /* returns full length */
```

> **Warning**
>
> `medius_last_error_message` is per-thread and reflects only the most recent failure on that thread, so read it before the next call overwrites it. It returns the full message length (excluding the NUL), so size your buffer and retry if it was truncated.

## Call reference

_Each call's Library and Native page_

| In the program | What it means |
| --- | --- |
| `medius_device_find` | [Connection](/library/connection.md) · the [handshake](/native/connection.md#handshake) |
| `medius_device_query_version` | [Requests](/library/requests.md) |
| `medius_device_move_rel` | [Move](/library/move.md) · [Native move](/native/commands/move.md#move) |
| `medius_device_press` / `_soft_release` | [Inject](/library/inject.md) · the [injection model](/native/injection.md) |
| `medius_device_catch_events` / `medius_event_stream_recv` | [Catch](/library/catch.md) · consuming them in C on [Streams](/bindings/c/streams.md) |
| `medius_device_free` | [Lifecycle](/library/lifecycle.md) |

Every call and type is indexed on [API index](/bindings/c/api.md) and [Types & errors](/bindings/c/types.md). These mirror the [medius](https://crates.io/crates/medius) crate ([source](https://github.com/K4HVH/medius)).
