Skip to content

Instantly share code, notes, and snippets.

@MCMrARM
Created November 14, 2018 13:24
Show Gist options
  • Save MCMrARM/9eaaf8a395ed31c59aaafbbe33f2b771 to your computer and use it in GitHub Desktop.
Save MCMrARM/9eaaf8a395ed31c59aaafbbe33f2b771 to your computer and use it in GitHub Desktop.
#include <cstdlib>
#include <cstring>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <unistd.h>
#include <fcntl.h>
#include <libudev.h>
#include <libevdev-1.0/libevdev/libevdev.h>
#define LBITS (sizeof(long) * 8)
#define NLONGS(x) (((x) - 1) / LBITS + 1)
#define TEST_BIT(v, i) !!((v)[(i) / LBITS] & (1L << ((i) % LBITS)))
static void writeLEShort(std::ostream& s, unsigned short v) {
s << std::setw(2) << (v & 0xff) << std::setw(2) << ((v >> 8) & 0xff);
}
std::string getGUID(struct libevdev* edev) {
std::stringstream ss;
ss << std::hex << std::setfill('0');
writeLEShort(ss, (unsigned short) libevdev_get_id_bustype(edev));
writeLEShort(ss, 0);
writeLEShort(ss, (unsigned short) libevdev_get_id_vendor(edev));
writeLEShort(ss, 0);
writeLEShort(ss, (unsigned short) libevdev_get_id_product(edev));
writeLEShort(ss, 0);
writeLEShort(ss, (unsigned short) libevdev_get_id_version(edev));
writeLEShort(ss, 0);
return ss.str();
}
inline bool isHat(int index) {
return (index >= ABS_HAT0X && index <= ABS_HAT3Y);
}
void handleDev(struct udev_device* dev) {
const char* val = udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
if (val != nullptr && strcmp(val, "1") == 0) {
const char* devPath = udev_device_get_devnode(dev);
if (devPath == nullptr)
return;
int fd = open(devPath, O_RDONLY | O_NONBLOCK);
struct libevdev* edev = nullptr;
int err = libevdev_new_from_fd(fd, &edev);
if (err) {
printf("libevdev_new_from_fd error %i (%s)\n", err, devPath);
close(fd);
return;
}
printf("%s\n", getGUID(edev).c_str());
unsigned long abs[NLONGS(ABS_CNT)];
int len = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs)), abs);
if (len < 0)
throw std::runtime_error("Failed to get joystick abs");
len *= 8;
int nextId = 0;
for (size_t i = 0; i < len; i++) {
if (!TEST_BIT(abs, i)) {
continue;
}
const input_absinfo* absinfo = libevdev_get_abs_info(edev, i);
if (absinfo == nullptr)
continue;
int id = isHat(i) ? 0 : (nextId++);
if (!isHat(i))
printf("id=%i min=%i max=%i flat=%i fuzz=%i\n", id, absinfo->minimum, absinfo->maximum, absinfo->flat, absinfo->fuzz);
}
libevdev_free(edev);
}
}
int main() {
struct udev* udev = udev_new();
struct udev_enumerate* enumerate = udev_enumerate_new(udev);
udev_enumerate_add_match_subsystem(enumerate, "input");
udev_enumerate_scan_devices(enumerate);
struct udev_list_entry* devices = udev_enumerate_get_list_entry(enumerate);
struct udev_list_entry* dev_list_entry;
udev_list_entry_foreach(dev_list_entry, devices) {
const char* path = udev_list_entry_get_name(dev_list_entry);
struct udev_device* dev = udev_device_new_from_syspath(udev, path);
if (dev == nullptr)
continue;
handleDev(dev);
udev_device_unref(dev);
}
udev_enumerate_unref(enumerate);
return 0;
}
@arduent
Copy link

arduent commented Aug 1, 2020

ln 59: for (size_t i = 0; i < len; i++) {

should probably be "i <= len", id=0 doesn't print a value in the loop.
on my usb joystick
id=0 min=-32768 max=32767 flat=128 fuzz=16

@MCMrARM
Copy link
Author

MCMrARM commented Aug 6, 2020

I don't think the suggested patch matches much sense, albeit this doesn't mean there's no bug in the code -- I'm not confident whether the result of ioctl is even supposed to be used now that I am reviewing the code; maybe it should be replaced with a generic loop to NLONGS(ABS_CNT) * 8.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment