Medius - BindingsStreams

Streams

Read live input and logs in C

Two live channels from the box: physical input (Catch) and device log lines (Logs & counters). Subscribe, then pull fixed-size POD events off the handle.

  medius_device_catch_events(dev, mask, &stream)    ──  subscribe to live input
  medius_device_logs(dev, &stream)                  ──  subscribe to log lines
          │
          ▼   a background reader thread fills a host-side queue
  medius_event_stream_recv(stream, &event)          ──  pull one (blocks)
  medius_log_stream_recv(stream, &line)             ──  the same, for logs
          │
          ▼   loop until MEDIUS_STATUS_ERR_DISCONNECTED
  medius_event_stream_free(stream)                  ──  unsubscribe
  medius_log_stream_free(stream)                    ──  the same, for logs

Subscribe

Open an event or log stream

Both return a MediusStatus and write an opaque handle through an out-param. Pick the input classes with a MediusCatchMask.

MediusStatus medius_device_catch_events(struct MediusDevice *dev, MediusCatchMask mask, struct MediusEventStream **out); MediusStatus medius_device_logs(struct MediusDevice *dev, struct MediusLogStream **out);
CallDoes
medius_device_catch_events(dev, mask, &out)Subscribe to physical input for the class mask. See Catch.
medius_device_logs(dev, &out)Open the device LOG channel. See Logs.
medius_event_stream_clone(stream) / medius_log_stream_clone(stream)Another handle to the same subscription. Null in → null out.
medius_event_stream_free(stream) / medius_log_stream_free(stream)Release a handle (unsubscribes when the last clone drops). Null is a no-op.
CATCH MASK BITS
ConstantValueClass
MEDIUS_CATCH_MASK_MOTION1cursor motion (dx / dy)
MEDIUS_CATCH_MASK_WHEEL2wheel
MEDIUS_CATCH_MASK_BUTTONS4mouse buttons
MEDIUS_CATCH_MASK_KEYS8keyboard keys
MEDIUS_CATCH_MASK_MEDIA16media keys
MEDIUS_CATCH_MASK_ALL31everything (1 | 2 | 4 | 8 | 16)

Receive

Pull one event off the queue

There's no iterator. Loop a receive call until it returns MEDIUS_STATUS_ERR_DISCONNECTED (the stream closes after a reset or link loss). Each writes one event through *out.

FunctionReturnsBlocks?
medius_event_stream_recv(stream, &out)MediusStatus (MEDIUS_STATUS_ERR_DISCONNECTED on close)Yes, until the next event
medius_event_stream_try_recv(stream, &out)bool (false if the queue is empty)No, returns at once
medius_event_stream_recv_timeout(stream, timeout_ms, &out)bool (false on timeout or close)Up to timeout_ms
LOGS MIRROR THIS
FunctionReturns
medius_log_stream_recv(stream, &out)MediusStatus (MEDIUS_STATUS_ERR_DISCONNECTED on close)
medius_log_stream_try_recv(stream, &out)bool (false if none queued)
medius_log_stream_recv_timeout(stream, timeout_ms, &out)bool (false on timeout or close)

Event objects

Fixed-size PODs, nothing to free per event

medius_event_stream_recv fills a MediusCatchEvent: a kind tag plus a union. Read the union arm that matches kind. The usage list is length-prefixed by an inline n count; the backing array is fixed at MEDIUS_MAX_USAGES (256), so nothing truncates. It holds class-tagged MediusUsage usages (a button, key, or media HID usage).

typedef struct MediusCatchEvent {
    MediusCatchEventKind kind;          // MOTION=0, USAGES=1
    union MediusCatchEventData data;    // read the arm for kind
} MediusCatchEvent;

struct MediusMotionEvent { int16_t dx, dy, dz; };                     // cursor + wheel deltas
struct MediusUsageEvent  { uint16_t n; MediusUsage usages[256]; };    // class-tagged held usages

typedef struct MediusLogLine {          // from medius_log_stream_recv
    MediusLogLevel level;               // ERROR=0, WARN=1, INFO=2, DEBUG=3, VERBOSE=4
    char text[512];                     // NUL-terminated
} MediusLogLine;
When kind isReadFields
MEDIUS_CATCH_EVENT_KIND_MOTIONdata.motiondx, dy, dz (cursor and wheel deltas)
MEDIUS_CATCH_EVENT_KIND_USAGESdata.usagesusages[0..n], each a class-tagged MediusUsage
INSPECTORS
HelperDoes
medius_usage_event_is_held(&ev.data.usages, usage)bool: true if that MediusUsage usage (button, key, or media) is held.
medius_event_stream_dropped(stream)uint64_t: events dropped because the consumer fell behind (host-side back-pressure).

Consume loop

Subscribe, drain until disconnect, free
#include <medius.h>
#include <stdio.h>

MediusEventStream *events = NULL;
if (medius_device_catch_events(dev, MEDIUS_CATCH_MASK_ALL, &events) != MEDIUS_STATUS_OK) {
    char msg[256];
    medius_last_error_message(msg, sizeof msg);
    fprintf(stderr, "subscribe failed: %s\n", msg);
    return 1;
}

MediusCatchEvent ev;
while (medius_event_stream_recv(events, &ev) == MEDIUS_STATUS_OK) {
    switch (ev.kind) {
    case 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);
        break;
    case MEDIUS_CATCH_EVENT_KIND_USAGES:
        printf("held usages=%u  LMB=%d  W=%d\n", ev.data.usages.n,
               medius_usage_event_is_held(&ev.data.usages, medius_usage_button(MEDIUS_BUTTON_LEFT)),
               medius_usage_event_is_held(&ev.data.usages, medius_usage_key(MEDIUS_KEY_W)));
        break;
    }
}
/* recv returned MEDIUS_STATUS_ERR_DISCONNECTED: the box reset or the link dropped */
printf("dropped while behind: %llu\n",
       (unsigned long long)medius_event_stream_dropped(events));
medius_event_stream_free(events);

No async

Build it on the non-blocking receives

The C ABI is synchronous; there's no async API. For a single-threaded event loop, poll with medius_event_stream_try_recv or block with a budget using medius_event_stream_recv_timeout; or run the blocking recv loop on its own thread. A stream handle is clonable, so each thread can hold its own.