update and expand api
This commit is contained in:
parent
221c258514
commit
b07a437fe7
2 changed files with 263 additions and 149 deletions
|
@ -9,11 +9,6 @@ pub fn build(b: *std.Build) void {
|
||||||
.root_source_file = .{ .path = "src/hidapi.zig" },
|
.root_source_file = .{ .path = "src/hidapi.zig" },
|
||||||
});
|
});
|
||||||
|
|
||||||
// hidapi.linkLibC();
|
|
||||||
// hidapi.linkSystemLibrary("hidapi-libusb");
|
|
||||||
|
|
||||||
// b.installArtifact(hidapi);
|
|
||||||
|
|
||||||
const unit_tests = b.addTest(.{
|
const unit_tests = b.addTest(.{
|
||||||
.root_source_file = .{ .path = "src/hidapi.zig" },
|
.root_source_file = .{ .path = "src/hidapi.zig" },
|
||||||
.target = target,
|
.target = target,
|
||||||
|
|
407
src/hidapi.zig
407
src/hidapi.zig
|
@ -15,118 +15,25 @@ const HidBusType = enum(hidapi.hid_bus_type) {
|
||||||
_,
|
_,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn from_wchar(alloc: std.mem.Allocator, wide_string: [*c]const hidapi.wchar_t) !?[]u8 {
|
pub fn init() !void {
|
||||||
if (wide_string == null) return null;
|
const ret = hidapi.hid_init();
|
||||||
var output = std.ArrayList(u8).init(alloc);
|
if (ret != 0) return error.HidApiInitError;
|
||||||
var writer = output.writer();
|
|
||||||
var index: usize = 0;
|
|
||||||
while (wide_string[index] != 0) : (index += 1) {
|
|
||||||
var buf: [4]u8 = undefined;
|
|
||||||
const len = try std.unicode.utf8Encode(@intCast(wide_string[index]), &buf);
|
|
||||||
try writer.writeAll(buf[0..len]);
|
|
||||||
}
|
|
||||||
return try output.toOwnedSlice();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_wchar(alloc: std.mem.Allocator, string: []const u8) ![*c]hidapi.wchar_t {
|
pub fn exit() !void {
|
||||||
var list = std.ArrayList(hidapi.wchar_t).init(alloc);
|
const ret = hidapi.hid_exit();
|
||||||
errdefer list.deinit();
|
if (ret != 0) return error.HidApiExitError;
|
||||||
var iter = std.unicode.Utf8View.init(string);
|
|
||||||
while (iter.next()) |codepoint| {
|
|
||||||
try list.append(@intCast(codepoint));
|
|
||||||
}
|
|
||||||
return list.toOwnedSliceSentinel(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn err(alloc: std.mem.Allocator) ![]const u8 {
|
pub fn getError(alloc: std.mem.Allocator) ![]const u8 {
|
||||||
return try from_wchar(alloc, hidapi.hid_error(null));
|
const err = try from_wchar_alloc(alloc, hidapi.hid_error(null));
|
||||||
}
|
if (err) |e| return e;
|
||||||
|
return "";
|
||||||
const Device = struct {
|
|
||||||
device: ?*hidapi.hid_device,
|
|
||||||
|
|
||||||
const Self = @This();
|
|
||||||
|
|
||||||
pub fn err(self: @This(), alloc: std.mem.Allocator) ![]const u8 {
|
|
||||||
return try from_wchar(alloc, hidapi.hid_error(self.device));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a HID feature report to an open HID device.
|
|
||||||
pub fn send_feature_report(self: Self, data: []const u8) !c_int {
|
|
||||||
return hidapi.hid_send_feature_report(self.device, data.ptr, data.len);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_feature_report(self: Self, report_id: u8, buffer: []u8) ![]const u8 {
|
|
||||||
buffer[0] = report_id;
|
|
||||||
const length = hidapi.hid_get_feature_report(self.device, buffer.ptr, buffer.len);
|
|
||||||
if (length < 0) return error.HIDAPiError;
|
|
||||||
return buffer[0..length];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_input_report(self: @This(), report_id: u8, buffer: []u8) ![]const u8 {
|
|
||||||
buffer[0] = report_id;
|
|
||||||
const result = hidapi.hid_get_input_report(self.device, buffer.ptr, buffer.len);
|
|
||||||
if (result < 1) return error.HIDApiError;
|
|
||||||
return buffer[0..result];
|
|
||||||
}
|
|
||||||
pub fn set_nonblocking(self: @This(), nonblocking: bool) !void {
|
|
||||||
const result = hidapi.hid_set_nonblocking(self.device, if (nonblocking) 1 else 0);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn write(self: @This(), data: []const u8) !c_int {
|
|
||||||
const result = hidapi.hid_write(self.device, data.ptr, data.len);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read_timeout(self: @This(), buffer: []u8, milliseconds: c_int) !?[]const u8 {
|
|
||||||
const result = hidapi.hid_read_timeout(self.device, buffer.ptr, buffer.len, milliseconds);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
if (result == 0) return null;
|
|
||||||
return buffer[0..result];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn read(self: @This(), buffer: []u8) !?[]const u8 {
|
|
||||||
const result = hidapi.hid_read(self.device, buffer.ptr, buffer.len);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
if (result == 0) return null;
|
|
||||||
return buffer[0..result];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_indexed_string(self: @This(), string_index: c_int, buffer: []hidapi.wchar_t) !void {
|
|
||||||
const result = hidapi.hid_get_indexed_string(self.device, string_index, buffer.ptr, buffer.len);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_report_descriptor(self: @This(), buffer: []u8) ![]const u8 {
|
|
||||||
const result = hidapi.hid_get_report_descriptor(self.device, buffer.ptr, buffer.len);
|
|
||||||
if (result < 0) return error.HIDApiError;
|
|
||||||
return buffer[0..result];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn close(self: *Self) void {
|
|
||||||
hidapi.hid_close(self.device);
|
|
||||||
self.device = null;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn open(alloc: std.mem.Allocator, vendor_id: c_ushort, product_id: c_ushort, serial_number: ?[]const u8) !Device {
|
|
||||||
const s = if (serial_number) |s| try to_wchar(alloc, s) else null;
|
|
||||||
const device = hidapi.hid_open(vendor_id, product_id, s);
|
|
||||||
if (device) |_| return .{ .device = device };
|
|
||||||
return error.HIDApiError;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn open_path(path: [:0]const u8) !Device {
|
|
||||||
const d = Device{ .device = hidapi.hid_open_path(path.ptr) };
|
|
||||||
if (d.device != null) return d;
|
|
||||||
return error.HIDApiError;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeviceInfo = struct {
|
const DeviceInfo = struct {
|
||||||
vendor_id: u16,
|
vendor_id: c_ushort,
|
||||||
product_id: u16,
|
product_id: c_ushort,
|
||||||
path: []u8,
|
path: []u8,
|
||||||
serial_number: ?[]u8,
|
serial_number: ?[]u8,
|
||||||
release_number: c_ushort,
|
release_number: c_ushort,
|
||||||
|
@ -139,16 +46,32 @@ const DeviceInfo = struct {
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
|
|
||||||
pub fn open(self: Self) !Device {
|
pub fn init(alloc: std.mem.Allocator, hid_device_info: [*c]hidapi.hid_device_info) !DeviceInfo {
|
||||||
const d = Device{
|
return .{
|
||||||
.device = hidapi.hid_open_path(self.path),
|
.vendor_id = hid_device_info.vendor_id,
|
||||||
|
.product_id = hid_device_info.product_id,
|
||||||
|
.release_number = hid_device_info.release_number,
|
||||||
|
.path = try alloc.dupe(u8, std.mem.span(hid_device_info.path)),
|
||||||
|
.serial_number = try from_wchar_alloc(alloc, hid_device_info.serial_number),
|
||||||
|
.manufacturer = try from_wchar_alloc(alloc, hid_device_info.manufacturer_string),
|
||||||
|
.product = try from_wchar_alloc(alloc, hid_device_info.product_string),
|
||||||
|
.usage_page = hid_device_info.usage_page,
|
||||||
|
.usage = hid_device_info.usage,
|
||||||
|
.interface_number = hid_device_info.interface_number,
|
||||||
|
.bus_type = @enumFromInt(hid_device_info.bus_type),
|
||||||
};
|
};
|
||||||
if (d.device) return d;
|
|
||||||
const err = hidapi.hid_error(null);
|
|
||||||
d.err = try from_wchar(err, &d.err);
|
|
||||||
return d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn open(self: Self) !Device {
|
||||||
|
// const d = Device{
|
||||||
|
// .device = hidapi.hid_open_path(self.path),
|
||||||
|
// };
|
||||||
|
// if (d.device) return d;
|
||||||
|
// const err = hidapi.hid_error(null);
|
||||||
|
// d.err = try from_wchar_alloc(err, &d.err);
|
||||||
|
// return d;
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
pub fn format(self: @This(), comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
|
||||||
try writer.print("{x:0>4} {x:0>4} {s} '{?s}'\n", .{ self.vendor_id, self.product_id, self.path, self.serial_number });
|
try writer.print("{x:0>4} {x:0>4} {s} '{?s}'\n", .{ self.vendor_id, self.product_id, self.path, self.serial_number });
|
||||||
try writer.print("Manufacturer: {?s}\n", .{self.manufacturer});
|
try writer.print("Manufacturer: {?s}\n", .{self.manufacturer});
|
||||||
|
@ -161,6 +84,13 @@ const DeviceInfo = struct {
|
||||||
@intFromEnum(self.bus_type),
|
@intFromEnum(self.bus_type),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: @This(), alloc: std.mem.Allocator) void {
|
||||||
|
alloc.free(self.path);
|
||||||
|
alloc.free(self.serial_number);
|
||||||
|
alloc.free(self.manufacturer);
|
||||||
|
alloc.free(self.product);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const DeviceInfos = struct {
|
const DeviceInfos = struct {
|
||||||
|
@ -168,6 +98,7 @@ const DeviceInfos = struct {
|
||||||
devices: []DeviceInfo,
|
devices: []DeviceInfo,
|
||||||
|
|
||||||
pub fn deinit(self: @This()) void {
|
pub fn deinit(self: @This()) void {
|
||||||
|
for (self.devices) |device| device.deinit();
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -183,21 +114,8 @@ pub fn enumerate(allocator: std.mem.Allocator, vendor_id: c_ushort, product_id:
|
||||||
var current: ?*hidapi.hid_device_info = hidapi.hid_enumerate(vendor_id, product_id);
|
var current: ?*hidapi.hid_device_info = hidapi.hid_enumerate(vendor_id, product_id);
|
||||||
defer hidapi.hid_free_enumeration(current);
|
defer hidapi.hid_free_enumeration(current);
|
||||||
|
|
||||||
while (current) |hid_device_info| {
|
while (current) |hid_device_info| : (current = hid_device_info.next) {
|
||||||
try dl.append(.{
|
try dl.append(DeviceInfo.init(alloc, hid_device_info));
|
||||||
.vendor_id = hid_device_info.vendor_id,
|
|
||||||
.product_id = hid_device_info.product_id,
|
|
||||||
.release_number = hid_device_info.release_number,
|
|
||||||
.path = try alloc.dupe(u8, std.mem.span(hid_device_info.path)),
|
|
||||||
.serial_number = try from_wchar(alloc, hid_device_info.serial_number),
|
|
||||||
.manufacturer = try from_wchar(alloc, hid_device_info.manufacturer_string),
|
|
||||||
.product = try from_wchar(alloc, hid_device_info.product_string),
|
|
||||||
.usage_page = hid_device_info.usage_page,
|
|
||||||
.usage = hid_device_info.usage,
|
|
||||||
.interface_number = hid_device_info.interface_number,
|
|
||||||
.bus_type = @enumFromInt(hid_device_info.bus_type),
|
|
||||||
});
|
|
||||||
current = hid_device_info.next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
@ -206,16 +124,6 @@ pub fn enumerate(allocator: std.mem.Allocator, vendor_id: c_ushort, product_id:
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init() !void {
|
|
||||||
const ret = hidapi.hid_init();
|
|
||||||
if (ret != 0) return error.HidApiInitError;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exit() !void {
|
|
||||||
const ret = hidapi.hid_exit();
|
|
||||||
if (ret != 0) return error.HidApiExitError;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn version() struct { major: c_int, minor: c_int, patch: c_int } {
|
pub fn version() struct { major: c_int, minor: c_int, patch: c_int } {
|
||||||
if (hidapi.hid_version()) |v| {
|
if (hidapi.hid_version()) |v| {
|
||||||
return .{
|
return .{
|
||||||
|
@ -245,12 +153,223 @@ test "version-2" {
|
||||||
try std.testing.expectEqualStrings("0.14.0", v);
|
try std.testing.expectEqualStrings("0.14.0", v);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "enumerate" {
|
pub const Device = struct {
|
||||||
try init();
|
device: *hidapi.hid_device,
|
||||||
defer exit() catch unreachable;
|
|
||||||
const device_infos = try enumerate(std.testing.allocator);
|
const Self = @This();
|
||||||
defer device_infos.deinit();
|
|
||||||
for (device_infos.devices) |device_info| {
|
pub fn open(vendor_id: c_ushort, product_id: c_ushort, serial_number: ?[]const u8) !Device {
|
||||||
std.debug.print("{}\n\n", .{device_info});
|
var buffer: [128]hidapi.wchar_t = undefined;
|
||||||
|
const device = hidapi.hid_open(
|
||||||
|
vendor_id,
|
||||||
|
product_id,
|
||||||
|
if (serial_number) |s| try to_wchar(s, &buffer) else null,
|
||||||
|
);
|
||||||
|
if (device) |d| return .{ .device = d };
|
||||||
|
return error.HIDApiError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn openPath(path: [:0]const u8) !Device {
|
||||||
|
const device = hidapi.hid_open_path(path.ptr);
|
||||||
|
if (device) |d| return .{ .device = d };
|
||||||
|
return error.HIDApiError;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn close(self: Self) void {
|
||||||
|
hidapi.hid_close(self.device);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getVendorID(self: Self) !c_ushort {
|
||||||
|
const di = hidapi.hid_get_device_info(self.device);
|
||||||
|
return di.*.vendor_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getProductID(self: Self) !c_ushort {
|
||||||
|
const di = hidapi.hid_get_device_info(self.device);
|
||||||
|
return di.*.product_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getError(self: Self, alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
const err = try from_wchar_alloc(alloc, hidapi.hid_error(self.device));
|
||||||
|
if (err) |e| return e;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Send a Feature report to the device.
|
||||||
|
///
|
||||||
|
/// Feature reports are sent over the Control endpoint as a Set_Report
|
||||||
|
/// transfer. The first byte of `data` must contain the Report ID. For
|
||||||
|
/// devices which only support a single report, this must be set to 0x0.
|
||||||
|
/// The remaining bytes contain the report data. Since the Report ID is
|
||||||
|
/// mandatory, calls to sendFeatureReport() will always contain one more
|
||||||
|
/// byte than the report contains. For example, if a hid report is 16 bytes
|
||||||
|
/// long, 17 bytes must be passed to hid_send_feature_report(): the Report
|
||||||
|
/// ID (or 0x0, for devices which do not use numbered reports), followed by
|
||||||
|
/// the report data (16 bytes). In this example, the length passed in would
|
||||||
|
/// be 17.
|
||||||
|
pub fn sendFeatureReport(self: Self, data: []const u8) !usize {
|
||||||
|
const result = hidapi.hid_send_feature_report(self.device, data.ptr, data.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return @intCast(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a feature report from a HID device.
|
||||||
|
///
|
||||||
|
/// Set the first byte of `data` to the Report ID of the report to be read.
|
||||||
|
/// Make sure to allow space for this extra byte in `data`. Upon return, the
|
||||||
|
/// first byte will still contain the Report ID, and the report data will
|
||||||
|
/// start in data[1].
|
||||||
|
pub fn getFeatureReport(self: Self, buffer: []u8) ![]const u8 {
|
||||||
|
const result = hidapi.hid_get_feature_report(self.device, buffer.ptr, buffer.len);
|
||||||
|
if (result < 0) return error.HIDAPiError;
|
||||||
|
return buffer[0..@intCast(result)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a input report from a HID device.
|
||||||
|
///
|
||||||
|
/// Set the first byte of `data` to the Report ID of the report to be read.
|
||||||
|
/// Make sure to allow space for this extra byte in `data`. Upon return, the
|
||||||
|
/// first byte will still contain the Report ID, and the report data will
|
||||||
|
/// start in `data[1]`.
|
||||||
|
pub fn getInputReport(self: @This(), buffer: []u8) ![]const u8 {
|
||||||
|
const result = hidapi.hid_get_input_report(self.device, buffer.ptr, buffer.len);
|
||||||
|
if (result < 1) return error.HIDApiError;
|
||||||
|
return buffer[0..@intCast(result)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set the device handle to be non-blocking.
|
||||||
|
///
|
||||||
|
/// In non-blocking mode calls to read() will return immediately with a
|
||||||
|
/// null if there is no data to be read. In blocking mode, read() will
|
||||||
|
/// wait (block) until there is data to read before returning.
|
||||||
|
///
|
||||||
|
/// Nonblocking can be turned on and off at any time.
|
||||||
|
pub fn setNonblocking(self: @This(), nonblocking: bool) !void {
|
||||||
|
const result = hidapi.hid_set_nonblocking(self.device, if (nonblocking) 1 else 0);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Write an Output report to a HID device.
|
||||||
|
///
|
||||||
|
/// The first byte of `data` must contain the Report ID. For
|
||||||
|
/// devices which only support a single report, this must be set
|
||||||
|
/// to 0x0. The remaining bytes contain the report data. Since
|
||||||
|
/// the Report ID is mandatory, calls to `write()` will always
|
||||||
|
/// contain one more byte than the report contains. For example,
|
||||||
|
/// if a HID report is 16 bytes long, 17 bytes must be passed to
|
||||||
|
/// `write()`, the Report ID (or 0x0, for devices with a
|
||||||
|
/// single report), followed by the report data (16 bytes).
|
||||||
|
///
|
||||||
|
/// write() will send the data on the first OUT endpoint, if
|
||||||
|
/// one exists. If it does not, it will send the data through
|
||||||
|
/// the Control Endpoint (Endpoint 0).
|
||||||
|
pub fn write(self: @This(), data: []const u8) !usize {
|
||||||
|
const result = hidapi.hid_write(self.device, data.ptr, data.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return @intCast(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read an Input report from a HID device with timeout.
|
||||||
|
///
|
||||||
|
/// Input reports are returned to the host through the INTERRUPT IN endpoint.
|
||||||
|
/// The first byte will contain the Report number if the device uses numbered
|
||||||
|
/// reports.
|
||||||
|
pub fn readTimeout(self: @This(), buffer: []u8, milliseconds: c_int) !?[]const u8 {
|
||||||
|
const result = hidapi.hid_read_timeout(self.device, buffer.ptr, buffer.len, milliseconds);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
if (result == 0) return null;
|
||||||
|
return buffer[0..result];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read an Input report from a HID device.
|
||||||
|
///
|
||||||
|
/// Input reports are returned to the host through the INTERRUPT IN endpoint.
|
||||||
|
/// The first byte will contain the Report number if the device uses numbered
|
||||||
|
/// reports.
|
||||||
|
pub fn read(self: @This(), buffer: []u8) !?[]const u8 {
|
||||||
|
const result = hidapi.hid_read(self.device, buffer.ptr, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
if (result == 0) return null;
|
||||||
|
return buffer[0..@intCast(result)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get The Manufacturer String from a HID device.
|
||||||
|
pub fn getManufacturerString(self: @This(), alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
var buffer: [128]hidapi.wchar_t = undefined;
|
||||||
|
const result = hidapi.hid_get_manufacturer_string(self.device, &buffer, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return try from_wchar_alloc(alloc, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get The Product String from a HID device.
|
||||||
|
pub fn getProductString(self: @This(), alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
var buffer: [128]hidapi.wchar_t = undefined;
|
||||||
|
const result = hidapi.hid_get_product_string(self.device, &buffer, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return try from_wchar_alloc(alloc, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get The Serial Number String from a HID device.
|
||||||
|
pub fn getSerialNumberString(self: @This(), alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
var buffer: [128]hidapi.wchar_t = undefined;
|
||||||
|
const result = hidapi.hid_get_serial_number_string(self.device, &buffer, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return try from_wchar_alloc(alloc, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a string from a HID device, based on its string index.
|
||||||
|
pub fn getIndexedString(self: @This(), alloc: std.mem.Allocator, string_index: c_int) ![]const u8 {
|
||||||
|
var buffer: [128]hidapi.wchar_t = undefined;
|
||||||
|
const result = hidapi.hid_get_indexed_string(self.device, string_index, &buffer, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return try from_wchar_alloc(alloc, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a report descriptor from a HID device.
|
||||||
|
pub fn getReportDescriptor(self: @This(), alloc: std.mem.Allocator) ![]const u8 {
|
||||||
|
var buffer: [MAX_REPORT_DESCRIPTOR_SIZE]u8 = undefined;
|
||||||
|
const result = hidapi.hid_get_report_descriptor(self.device, &buffer, buffer.len);
|
||||||
|
if (result < 0) return error.HIDApiError;
|
||||||
|
return try alloc.dupe(u8, buffer[0..@intCast(result)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getDeviceInfo(self: @This(), alloc: std.mem.Allocator) !DeviceInfo {
|
||||||
|
if (hidapi.hid_get_device_info(self.device)) |hid_device_info| {
|
||||||
|
return DeviceInfo.init(alloc, hid_device_info);
|
||||||
|
}
|
||||||
|
return error.HIDApiError;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fn from_wchar_alloc(alloc: std.mem.Allocator, wide_string: [*c]const hidapi.wchar_t) !?[]u8 {
|
||||||
|
if (wide_string == null) return null;
|
||||||
|
var output = std.ArrayList(u8).init(alloc);
|
||||||
|
var writer = output.writer();
|
||||||
|
var index: usize = 0;
|
||||||
|
while (wide_string[index] != 0) : (index += 1) {
|
||||||
|
var buf: [4]u8 = undefined;
|
||||||
|
const len = try std.unicode.utf8Encode(@intCast(wide_string[index]), &buf);
|
||||||
|
try writer.writeAll(buf[0..len]);
|
||||||
|
}
|
||||||
|
return try output.toOwnedSlice();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_wchar_alloc(alloc: std.mem.Allocator, string: []const u8) ![*c]hidapi.wchar_t {
|
||||||
|
var list = std.ArrayList(hidapi.wchar_t).init(alloc);
|
||||||
|
errdefer list.deinit();
|
||||||
|
var iter = (try std.unicode.Utf8View.init(string)).iterator();
|
||||||
|
while (iter.nextCodepoint()) |codepoint| {
|
||||||
|
try list.append(@intCast(codepoint));
|
||||||
|
}
|
||||||
|
return try list.toOwnedSliceSentinel(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn to_wchar(string: []const u8, buffer: []hidapi.wchar_t) ![*c]hidapi.wchar_t {
|
||||||
|
var iter = (try std.unicode.Utf8View.init(string)).iterator();
|
||||||
|
var index: usize = 0;
|
||||||
|
while (iter.nextCodepoint()) |codepoint| : (index += 1) {
|
||||||
|
buffer[index] = @intCast(codepoint);
|
||||||
|
}
|
||||||
|
buffer[index] = 0;
|
||||||
|
return buffer.ptr;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue