libhs is a C library to enumerate HID and serial devices and interact with them.


Just download libhs.h from the GitHub repository. This file provides both the interface and the implementation. To instantiate the implementation, #define HS_IMPLEMENTATION in ONE source file, before including libhs.h.

libhs depends on a few OS-provided libraries that you need to link:

OS Dependencies
Windows (MSVC) Nothing to do, libhs uses #pragma comment(lib)
Windows (MinGW-w64) Link user32, advapi32, setupapi and hid -luser32 -ladvapi32 -lsetupapi -lhid
OSX (Clang) Link CoreFoundation and IOKit
Linux (GCC) Link libudev -ludev

This library is developed as part of the TyTools project where you can find the original libhs source code. The amalgamated header file is automatically produced by CMake scripts.

Look at Sean Barrett's excellent stb libraries for the reasoning behind this mode of distribution.


libhs is in the public domain, or the equivalent where that is not possible. You can and should do anything you want with it. You have no legal obligation to do anything else, although I appreciate attribution.


You can clone the code and report bugs on the TyTools GitHub repository.


You can find a few complete working examples in the GitHub repository.

The following code uses libhs to enumerate serial and HID devices:

/* libhs - public domain
   Niels Martignène <niels.martignene@protonmail.com>

   This software is in the public domain. Where that dedication is not
   recognized, you are granted a perpetual, irrevocable license to copy,
   distribute, and modify this file as you see fit.

   See the LICENSE file for more details. */

#include <inttypes.h>
#include <stdio.h>

#include "libhs.h"

static int device_callback(hs_device *dev, void *udata)

    printf("+ %s@%"PRIu8" %04"PRIx16":%04"PRIx16" (%s)\n",
           dev->location, dev->iface_number, dev->vid, dev->pid,
    printf("  - device node:   %s\n", dev->path);
    if (dev->manufacturer_string)
        printf("  - manufacturer:  %s\n", dev->manufacturer_string);
    if (dev->product_string)
        printf("  - product:       %s\n", dev->product_string);
    if (dev->serial_number_string)
        printf("  - serial number: %s\n", dev->serial_number_string);

    /* If you return a non-zero value, the enumeration is aborted and this value is returned
       from the calling function. */
    return 0;

int main(void)
    int r;

    /* Go through the device tree and call our callback for each device. The callback can abort
       the enumeration by returning a non-zero value. */
    r = hs_enumerate(NULL, 0, device_callback, NULL);
    if (r < 0)
        return -r;

    return 0;