12 #include <sys/ioctl.h>
13 #include <linux/joystick.h>
18 #define BTN_CNT (KEY_MAX - BTN_MISC + 1)
23 #define EXIT_VERSION 4
28 void reportMissingArgument(const char* opt
)
30 fprintf(stderr
, "Missing argument for option '%s'.\n", opt
);
35 void printHelp(FILE* out
, int argc
, char** argv
)
39 fprintf(out
, "Usage:\n"
42 " %s {commands} --dev <device>\n"
47 " --set-axismap 'id, id, id...'\n"
48 " --set-buttonmap 'id, id, id...'\n",
49 argv
[0], argv
[0], argv
[0]);
53 __u8
getNumberOfAxes(int fd
)
56 if (ioctl(fd
, JSIOCGAXES
, &cnt
) )
58 perror(PACKAGE_STRING
": error getting number of axes");
65 __u8
getNumberOfButtons(int fd
)
68 if (ioctl(fd
, JSIOCGBUTTONS
, &cnt
) )
70 perror(PACKAGE_STRING
": error getting number of buttons");
77 void listAxismap(int fd
)
79 __u8 map
[ABS_CNT
] = {-1};
80 const __u8 cnt
= getNumberOfAxes(fd
);
81 printf("Got %d axes:\n", cnt
);
82 assert( cnt
<= ABS_CNT
);
84 if( ioctl(fd
, JSIOCGAXMAP
, &map
) < 0 )
86 perror(PACKAGE_STRING
": error getting axis map");
90 for(int i
=0; i
<cnt
; i
++)
91 printf(" %d => %d\n", i
, map
[i
] );
94 printf("Set this mapping with:\n");
95 printf(" " PACKAGE_STRING
" --set-axismap '");
96 for(int i
=0; i
<cnt
; i
++)
100 printf("%d", map
[i
] );
106 void listButtonmap(int fd
)
108 __u16 map
[BTN_CNT
] = {-1};
109 const __u8 cnt
= getNumberOfButtons(fd
);
110 printf("Got %d buttons:\n", cnt
);
112 if( ioctl(fd
, JSIOCGBTNMAP
, &map
) < 0 )
114 perror(PACKAGE_STRING
": error getting button map");
118 for(int i
=0; i
<cnt
; i
++)
119 printf(" %d => %d\n", i
, map
[i
] );
122 printf("Set this mapping with:\n");
123 printf(" " PACKAGE_STRING
" --set-buttonmap '");
124 for(int i
=0; i
<cnt
; i
++)
128 printf("%d", map
[i
] );
134 /** Fill an integer array of given size by comma-separated values in str.
135 * Return the number of values contained in str. */
136 unsigned parseIntArray(int* array
, unsigned size
, char* str
)
139 for(i
=0; i
<size
; ++i
)
141 sscanf(str
, "%d", &array
[i
]);
143 // Move up to next comma, and one step further
144 str
= strstr(str
, ",");
150 // Skip further commas
154 str
= strstr(str
, ",");
164 /** Take an array of size that contains cnt values and fill the rest of array
165 * such that a permutation on {0, ..., size-1} results.
166 * Returns 1 if resulting array is a permutation */
167 int fillPermutation(int* array
, unsigned cnt
, unsigned size
)
169 assert( cnt
<= size
);
171 int* contains
= malloc(sizeof(int)*size
);
172 memset(contains
, 0, sizeof(int)*size
);
175 // Check which value is already there
176 for(unsigned i
=0; i
<cnt
; ++i
)
178 const unsigned v
= array
[i
];
179 if( v
>=size
|| contains
[v
] )
184 // Do it the hard way on array[cnt, max]
186 for(unsigned i
=cnt
; i
<size
; ++i
)
188 // Get minimum free value
189 while( contains
[min
] )
203 void setAxismap(int fd
, char* mapstr
)
205 __u8 map
[ABS_CNT
] = {-1};
206 int imap
[ABS_CNT
] = {-1};
209 const __u8 cnt
= getNumberOfAxes(fd
);
210 printf("Setting %d axes.\n", cnt
);
211 assert( cnt
<= ABS_CNT
);
214 const unsigned readcnt
= parseIntArray(imap
, cnt
, mapstr
);
217 fprintf(stderr
, "Invalid number of values given: %d\n", readcnt
);
225 // Fill the remaining array such that we obtain a permutation
226 if( !fillPermutation(imap
, cnt
, ABS_CNT
) )
228 fprintf(stderr
, "Mapping needs to be a permutation.\n");
232 // Copy array and check bounds
233 for(unsigned i
=0; i
<ABS_CNT
; ++i
)
235 if( imap
[i
]<0 || imap
[i
]>=ABS_CNT
)
237 fprintf(stderr
, "Value out of bounds: %d\n", imap
[i
]);
245 printf("Setting the following map:\n");
246 for(int i
=0; i
<cnt
; i
++)
247 printf(" %d => %d\n", i
, map
[i
] );
250 if( ioctl(fd
, JSIOCSAXMAP
, &map
) )
252 perror( PACKAGE_STRING
": error setting axis map");
258 void setButtonmap(int fd
, char* mapstr
)
260 __u16 map
[BTN_CNT
] = {-1};
261 int imap
[BTN_CNT
] = {-1};
263 const __u8 cnt
= getNumberOfButtons(fd
);
264 printf("Setting %d buttons.\n", cnt
);
265 assert( cnt
<= ABS_CNT
);
268 const unsigned readcnt
= parseIntArray(imap
, cnt
, mapstr
);
271 fprintf(stderr
, "Invalid number of values given: %d\n", readcnt
);
279 // Fill the remaining array such that we obtain a permutation
280 if( !fillPermutation(imap
, cnt
, BTN_CNT
) )
282 fprintf(stderr
, "Mapping needs to be a permutation.\n");
286 // Copy array and check bounds
287 for(unsigned i
=0; i
<ABS_CNT
; ++i
)
289 if( imap
[i
]<0 || imap
[i
]>=BTN_CNT
)
291 fprintf(stderr
, "Value out of bounds: %d\n", imap
[i
]);
299 printf("Setting the following map:\n");
300 for(int i
=0; i
<cnt
; i
++)
301 printf(" %d => %d\n", i
, map
[i
] );
304 if( ioctl(fd
, JSIOCSBTNMAP
, &map
) )
306 perror( PACKAGE_STRING
": error setting axis map");
312 int main(int argc
, char** argv
)
314 int argListAxismap
=0;
315 int argListButtonmap
=0;
316 char* argSetAxismap
=0;
317 char* argSetButtonmap
=0;
321 for(int i
=1; i
<argc
; ++i
)
323 const char* opt
= argv
[i
];
325 if( !strcmp(opt
,"--help") || !strcmp(opt
,"-h") )
327 printHelp(stdout
, argc
, argv
);
330 else if( !strcmp(opt
, "--dev") || !strcmp(opt
,"-d") )
334 reportMissingArgument(opt
);
337 else if( !strcmp(opt
, "--list-axismap") )
341 else if( !strcmp(opt
, "--list-buttonmap") )
343 argListButtonmap
= 1;
345 else if( !strcmp(opt
, "--set-axismap") )
349 reportMissingArgument(opt
);
350 argSetAxismap
= argv
[i
];
352 else if( !strcmp(opt
, "--set-buttonmap") )
356 reportMissingArgument(opt
);
357 argSetButtonmap
= argv
[i
];
361 fprintf(stderr
, "Invalid option '%s'.\n", opt
);
369 fprintf(stderr
, "You need to specify a device.\n");
375 if( (fd
= open(dev
, O_RDONLY
)) < 0 )
377 perror("Cannot open device.");
383 if( ioctl(fd
, JSIOCGVERSION
, &version
) )
385 perror( PACKAGE_STRING
": error getting version");
389 if( version
!= JS_VERSION
)
391 fprintf(stderr
, PACKAGE_STRING
": compiled with different version %d\n", JS_VERSION
);
399 if( argListButtonmap
)
403 setAxismap(fd
, argSetAxismap
);
405 if( argSetButtonmap
)
406 setButtonmap(fd
, argSetButtonmap
);