--- /dev/null
+/*
+ * usage:
+ * .../hidrawconv-<controller> -d
+ * .../hidrawconv-<controller> -e </dev/hidrawN
+ * where -a means all, and the other letters are:
+ * -d print expected descriptor (as for hidraw-ioctl -d)
+ * -e pretend to be evdev-manip
+ * exit status:
+ * 0 all ok
+ * other some other problem
+ */
+
+#include "hidrawconv.h"
+
+void die_vprintf_hook(const char *fmt, va_list al) { }
+void die_hook(void) { }
+
+typedef struct { int len; uint8_t *msg; } Last;
+static Last lasts[MAXREPORTS];
+
+void reportbits(const uint8_t msg[], const uint8_t last[],
+ int len, const KeyBit *bit) {
+ for (; bit->str; bit++) {
+ if (bit->pos >= len) continue;
+ uint8_t m= msg[bit->pos] & bit->mask;
+ uint8_t l= last[bit->pos] & bit->mask;
+ if (m==l) continue;
+ printf("%s %d\n", bit->str, !!m);
+ }
+}
+
+void reportlocs(const uint8_t msg[], const uint8_t last[],
+ int len, const ValLoc *loc) {
+ for (; loc->str; loc++) {
+ if (loc->pos >= len) continue;
+ uint8_t mb= msg[loc->pos] & loc->mask;
+ uint8_t lb= last[loc->pos] & loc->mask;
+ if (mb==lb) continue;
+ mb >>= loc->rshift;
+ mb -= loc->zero;
+ printf("%s %d\n", loc->str, loc->sign * (int8_t)mb);
+ }
+}
+
+static void events(void) {
+ uint8_t msg[MAXREPORTLEN];
+ for (;;) {
+ int l= read(0, msg, sizeof(msg));
+ if (!l) break;
+ if (l<0) { perror("hidrawconv: read"); exit(-1); }
+ ProcessReport *pr= report_processors[msg[0]];
+ Last *last= &lasts[msg[0]];
+ if (!pr) {
+ if (!last->len)
+ fprintf(stderr,"%s: unexpected report 0x%02x", progname, msg[0]);
+ last->len= l;
+ continue;
+ }
+ if (last->len < l) {
+ last->msg= mrealloc(last->msg, l);
+ memset(last->msg + last->len, 0, l - last->len);
+ last->len= l;
+ }
+ pr(msg, l, last->msg);
+ if (ferror(stdout) || fflush(stdout))
+ diee("failed flushing event to stdout");
+ memcpy(last->msg, msg, l);
+ }
+}
+
+int main(int argc, char **argv) {
+ const char *how;
+
+ if (!*argv || !(how=*++argv) || *how++!='-' || !*how || how[1] || *++argv)
+ badusage("need exactly one argument, -d or -e");
+
+ switch (how[0]) {
+ case 'd':
+ puts(descriptor);
+ break;
+
+ case 'e':
+ events();
+ break;
+
+ default:
+ badusage("unknown option/mode");
+ }
+
+ if (ferror(stdout) || fflush(stdout))
+ diee("write/flush stdout");
+
+ return 0;
+}