First program
Find the box, send a command, read one event, free itOne file: connect, read the firmware version, move the cursor, click the left button, wait for one physical input, then free it. C has no exceptions, so every fallible call returns a MediusStatus you check, and the detail comes from medius_last_error_message. What the commands mean lives in the Library and Native sections; this page is only the C mechanics.
Get medius.h and the library from Build & features. New to the box itself? Read the Native quickstart 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 checkscheck() 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.
#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;
}medius-capi 3.0.0 (abi 3)
firmware 3.0.0 (proto 3)
motion: dx=12 dy=-4 dz=0medius_event_stream_recv blocks until the user touches the mouse or keyboard. To poll instead, or to loop over many events, see Streams.
Run it
gcc or clang, link libmedius_capiRun from the unpacked release, with medius.h under include/ and libmedius_capi.so beside it. cc, gcc, and clang all work.
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). |
Static linking (libmedius_capi.a), Windows, and the mock / flash feature macros are on Build & features.
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) fills v. |
| Freeing | Each handle has a *_free: medius_device_free, medius_event_stream_free, medius_log_stream_free. 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, wheel, press, inject, and the lock / LED calls queue a frame and return at once. This is the fire-and-forget model. |
| Blocks | medius_device_find / _open (the handshake), every medius_device_query_*, and medius_event_stream_recv wait for a reply or an event. |
| Sharing | medius_device_clone / medius_event_stream_clone hand back another handle to the same link; each clone must be freed. See Lifecycle. |
MediusStatus medius_device_find(MediusDevice **out); uintptr_t medius_last_error_message(char *buf, uintptr_t cap); /* returns full length */
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 · the handshake |
medius_device_query_version | Requests |
medius_device_move_rel | Move · Native move |
medius_device_press / _soft_release | Inject · the injection model |
medius_device_catch_events / medius_event_stream_recv | Catch · consuming them in C on Streams |
medius_device_free | Lifecycle |
Every call and type is indexed on API index and Types & errors. These mirror the medius crate (source).