--- /dev/null
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <sys/ioctl.h>
+#include <linux/joystick.h>
+
+#include "config.h"
+
+
+#define MAXFN 1024
+#define EXIT_INVARG 1
+#define EXIT_OPEN 2
+#define EXIT_IOCTL 3
+#define EXIT_VERSION 4
+#define EXIT_VALUE 5
+
+
+
+void reportMissingArgument(const char* opt)
+{
+ fprintf(stderr, "Missing argument for option '%s'.\n", opt);
+ exit(EXIT_INVARG);
+}
+
+void printHelp(FILE* out, int argc, char** argv)
+{
+ (void) argc;
+
+ fprintf(out, "Usage:\n"
+ " %s -h\n"
+ " %s --help\n"
+ " %s {commands} --dev <device>\n"
+ "\n"
+ "Commands:\n"
+ " --list-axismap\n"
+ " --list-buttonmap\n"
+ " --set-axismap 'id, id, id...'\n"
+ " --set-buttonmap 'id, id, id...'\n",
+ argv[0], argv[0], argv[0]);
+}
+
+
+void listAxismap(int fd)
+{
+ __u8 cnt=0;
+ __u8 map[ABS_CNT] = {-1};
+
+
+ if (ioctl(fd, JSIOCGAXES, &cnt) )
+ {
+ perror(PACKAGE_STRING ": error getting number of axes");
+ exit(EXIT_IOCTL);
+ }
+ printf("Got %d axes:\n", cnt);
+ assert( cnt <= ABS_CNT);
+
+
+ if( ioctl(fd, JSIOCGAXMAP, &map) < 0 )
+ {
+ perror(PACKAGE_STRING ": error getting axis map");
+ exit(1);
+ }
+
+ for(int i=0; i<cnt; i++)
+ printf(" %d => %d\n", i, map[i] );
+
+ printf("\n");
+ printf("Set this mapping with:\n");
+ printf(" " PACKAGE_STRING " --set-axismap '");
+ for(int i=0; i<cnt; i++)
+ {
+ if( i> 0)
+ printf(", ");
+ printf("%d", map[i] );
+ }
+ printf("'\n");
+}
+
+
+void listButtonmap(int fd)
+{
+ __u8 cnt=0;
+ __u16 map[KEY_MAX - BTN_MISC + 1] = {-1};
+
+ if (ioctl(fd, JSIOCGBUTTONS, &cnt) )
+ {
+ perror(PACKAGE_STRING ": error getting number of buttons");
+ exit(EXIT_IOCTL);
+ }
+ printf("Got %d buttons:\n", cnt);
+
+
+ if( ioctl(fd, JSIOCGBTNMAP, &map) < 0 )
+ {
+ perror(PACKAGE_STRING ": error getting button map");
+ exit(1);
+ }
+
+ for(int i=0; i<cnt; i++)
+ printf(" %d => %d\n", i, map[i] );
+
+ printf("\n");
+ printf("Set this mapping with:\n");
+ printf(" " PACKAGE_STRING " --set-buttonmap '");
+ for(int i=0; i<cnt; i++)
+ {
+ if( i> 0)
+ printf(", ");
+ printf("%d", map[i] );
+ }
+ printf("'\n");
+}
+
+
+void setAxismap(int fd, char* mapstr)
+{
+ __u8 cnt=0;
+ __u8 map[ABS_CNT] = {-1};
+
+
+ if (ioctl(fd, JSIOCGAXES, &cnt) )
+ {
+ perror(PACKAGE_STRING ": error getting number of axes");
+ exit(EXIT_IOCTL);
+ }
+ printf("Setting %d axes.\n", cnt);
+ assert( cnt <= ABS_CNT);
+
+
+ char* s = mapstr;
+ for(unsigned i=0; i<cnt; ++i)
+ {
+ if( !s )
+ {
+ fprintf(stderr, "Missing value for axis %d.\n", i);
+ exit(EXIT_VALUE);
+ }
+
+ int val=-1;
+ sscanf(s, "%d", &val);
+ if( val<0 || val>=(1<<8) )
+ {
+ fprintf(stderr, "Value out of bounds: %d\n", val);
+ exit(EXIT_VALUE);
+ }
+ map[i] = val;
+
+ s = strstr(s, ",");
+ if(s)
+ s++;
+ }
+
+ if( s )
+ fprintf(stderr, "Too many values given for the axismap. Ignoring the rest.\n");
+
+
+ printf("Setting the following map:\n");
+ for(int i=0; i<cnt; i++)
+ printf(" %d => %d\n", i, map[i] );
+
+
+ if( ioctl(fd, JSIOCSAXMAP, &map) )
+ {
+ perror( PACKAGE_STRING ": error setting axis map");
+ exit(EXIT_IOCTL);
+ }
+}
+
+
+void setButtonmap(int fd, char* mapstr)
+{
+ __u8 cnt=0;
+ __u16 map[KEY_MAX - BTN_MISC + 1] = {-1};
+
+ printf("foo: %d\n", 1<<8);
+
+ if (ioctl(fd, JSIOCGBUTTONS, &cnt) )
+ {
+ perror(PACKAGE_STRING ": error getting number of buttons");
+ exit(EXIT_IOCTL);
+ }
+ printf("Setting %d buttons.\n", cnt);
+
+
+ char* s = mapstr;
+ for(unsigned i=0; i<cnt; ++i)
+ {
+ if( !s )
+ {
+ fprintf(stderr, "Missing value for axis %d.\n", i);
+ exit(EXIT_VALUE);
+ }
+
+ int val=-1;
+ sscanf(s, "%d", &val);
+ if( val<0 || val>=(1<<16) )
+ {
+ fprintf(stderr, "Value out of bounds: %d\n", val);
+ exit(EXIT_VALUE);
+ }
+ map[i] = val;
+
+ s = strstr(s, ",");
+ if(s)
+ s++;
+ }
+
+ if( s )
+ fprintf(stderr, "Too many values given for the axismap. Ignoring the rest.\n");
+
+
+ printf("Setting the following map:\n");
+ for(int i=0; i<cnt; i++)
+ printf(" %d => %d\n", i, map[i] );
+
+
+ if( ioctl(fd, JSIOCSBTNMAP, &map) )
+ {
+ perror( PACKAGE_STRING ": error setting button map");
+ exit(EXIT_IOCTL);
+ }
+}
+
+
+int main(int argc, char** argv)
+{
+ int argListAxismap=0;
+ int argListButtonmap=0;
+ char* argSetAxismap=0;
+ char* argSetButtonmap=0;
+ char dev[MAXFN+1] = "";
+
+
+
+ for(int i=1; i<argc; ++i)
+ {
+ const char* opt = argv[i];
+
+ if( !strcmp(opt,"--help") || !strcmp(opt,"-h") )
+ {
+ printHelp(stdout, argc, argv);
+ return EXIT_SUCCESS;
+ }
+ else if( !strcmp(opt, "--dev") || !strcmp(opt,"-d") )
+ {
+ i++;
+ if( i >= argc )
+ reportMissingArgument(opt);
+ strncpy(dev, argv[i], MAXFN);
+ }
+ else if( !strcmp(opt, "--list-axismap") )
+ {
+ argListAxismap = 1;
+ }
+ else if( !strcmp(opt, "--list-buttonmap") )
+ {
+ argListButtonmap = 1;
+ }
+ else if( !strcmp(opt, "--set-axismap") )
+ {
+ i++;
+ if( i >= argc )
+ reportMissingArgument(opt);
+ argSetAxismap = argv[i];
+ }
+ else if( !strcmp(opt, "--set-buttonmap") )
+ {
+ i++;
+ if( i >= argc )
+ reportMissingArgument(opt);
+ argSetButtonmap = argv[i];
+ }
+ else
+ {
+ fprintf(stderr, "Invalid option '%s'.\n", opt);
+ return EXIT_INVARG;
+ }
+ }
+
+
+ if( strcmp("", dev)==0 )
+ {
+ fprintf(stderr, "You need to specify a device.\n");
+ return EXIT_INVARG;
+ }
+
+
+ int fd=-1;
+ if( (fd = open(dev, O_RDONLY)) < 0 )
+ {
+ perror("Cannot open device.");
+ return EXIT_OPEN;
+ }
+
+
+ int version;
+ if( ioctl(fd, JSIOCGVERSION, &version) )
+ {
+ perror( PACKAGE_STRING ": error getting version");
+ exit(EXIT_IOCTL);
+ }
+
+ if( version != JS_VERSION )
+ {
+ fprintf(stderr, PACKAGE_STRING ": compiled with different version %d\n", JS_VERSION);
+ exit(EXIT_VERSION);
+ }
+
+
+ if( argListAxismap )
+ listAxismap(fd);
+
+ if( argListButtonmap )
+ listButtonmap(fd);
+
+ if( argSetAxismap )
+ setAxismap(fd, argSetAxismap);
+
+ if( argSetButtonmap )
+ setButtonmap(fd, argSetButtonmap);
+
+
+ close(fd);
+ return 0;
+}