aa794619044128c35ba7cfffaff824d53e774c0d
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
);
34 void printHelp(FILE* out
, int argc
, char** argv
)
38 fprintf(out
, "Usage:\n"
41 " %s {commands} --dev <device>\n"
46 " --set-axismap 'id, id, id...'\n"
47 " --set-buttonmap 'id, id, id...'\n",
48 argv
[0], argv
[0], argv
[0]);
52 __u8
getNumberOfAxes(int fd
)
55 if (ioctl(fd
, JSIOCGAXES
, &cnt
) )
57 perror(PACKAGE_STRING
": error getting number of axes");
64 __u8
getNumberOfButtons(int fd
)
67 if (ioctl(fd
, JSIOCGBUTTONS
, &cnt
) )
69 perror(PACKAGE_STRING
": error getting number of buttons");
76 void listAxismap(int fd
)
78 __u8 map
[ABS_CNT
] = {-1};
79 const __u8 cnt
= getNumberOfAxes(fd
);
80 printf("Got %d axes:\n", cnt
);
81 assert( cnt
<= ABS_CNT
);
83 if( ioctl(fd
, JSIOCGAXMAP
, &map
) < 0 )
85 perror(PACKAGE_STRING
": error getting axis map");
89 for(int i
=0; i
<cnt
; i
++)
90 printf(" %d => %d\n", i
, map
[i
] );
93 printf("Set this mapping with:\n");
94 printf(" " PACKAGE_STRING
" --set-axismap '");
95 for(int i
=0; i
<cnt
; i
++)
99 printf("%d", map
[i
] );
105 void listButtonmap(int fd
)
107 __u16 map
[BTN_CNT
] = {-1};
108 const __u8 cnt
= getNumberOfButtons(fd
);
109 printf("Got %d buttons:\n", cnt
);
111 if( ioctl(fd
, JSIOCGBTNMAP
, &map
) < 0 )
113 perror(PACKAGE_STRING
": error getting button map");
117 for(int i
=0; i
<cnt
; i
++)
118 printf(" %d => %d\n", i
, map
[i
] );
121 printf("Set this mapping with:\n");
122 printf(" " PACKAGE_STRING
" --set-buttonmap '");
123 for(int i
=0; i
<cnt
; i
++)
127 printf("%d", map
[i
] );
133 /** Fill an integer array of given size by comma-separated values in str.
134 * Return the number of values contained in str. */
135 unsigned parseIntArray(int* array
, unsigned size
, char* str
)
138 for(i
=0; i
<size
; ++i
)
140 sscanf(str
, "%d", &array
[i
]);
142 // Move up to next comma, and one step further
143 str
= strstr(str
, ",");
149 // Skip further commas
153 str
= strstr(str
, ",");
163 /** Take an array of size that contains cnt values and fill the rest of array
164 * such that a permutation on {0, ..., size-1} results.
165 * Returns 1 if resulting array is a permutation */
166 int fillPermutation(int* array
, unsigned cnt
, unsigned size
)
168 assert( cnt
<= size
);
170 int* contains
= malloc(sizeof(int)*size
);
171 memset(contains
, 0, sizeof(int)*size
);
174 // Check which value is already there
175 for(unsigned i
=0; i
<cnt
; ++i
)
177 const unsigned v
= array
[i
];
178 if( v
>=size
|| contains
[v
] )
183 // Do it the hard way on array[cnt, max]
185 for(unsigned i
=cnt
; i
<size
; ++i
)
187 // Get minimum free value
188 while( contains
[min
] )
202 void setAxismap(int fd
, char* mapstr
)
204 __u8 map
[ABS_CNT
] = {-1};
205 int imap
[ABS_CNT
] = {-1};
208 const __u8 cnt
= getNumberOfAxes(fd
);
209 printf("Setting %d axes.\n", cnt
);
210 assert( cnt
<= ABS_CNT
);
213 const unsigned readcnt
= parseIntArray(imap
, cnt
, mapstr
);
216 fprintf(stderr
, "Invalid number of values given: %d\n", readcnt
);
224 // Fill the remaining array such that we obtain a permutation
225 if( !fillPermutation(imap
, cnt
, ABS_CNT
) )
227 fprintf(stderr
, "Mapping needs to be a permutation.\n");
231 // Copy array and check bounds
232 for(unsigned i
=0; i
<ABS_CNT
; ++i
)
234 if( imap
[i
]<0 || imap
[i
]>=ABS_CNT
)
236 fprintf(stderr
, "Value out of bounds: %d\n", imap
[i
]);
244 printf("Setting the following map:\n");
245 for(int i
=0; i
<cnt
; i
++)
246 printf(" %d => %d\n", i
, map
[i
] );
249 if( ioctl(fd
, JSIOCSAXMAP
, &map
) )
251 perror( PACKAGE_STRING
": error setting axis map");
257 void setButtonmap(int fd
, char* mapstr
)
259 __u16 map
[BTN_CNT
] = {-1};
260 int imap
[BTN_CNT
] = {-1};
262 const __u8 cnt
= getNumberOfButtons(fd
);
263 printf("Setting %d buttons.\n", cnt
);
264 assert( cnt
<= ABS_CNT
);
267 const unsigned readcnt
= parseIntArray(imap
, cnt
, mapstr
);
270 fprintf(stderr
, "Invalid number of values given: %d\n", readcnt
);
278 // Fill the remaining array such that we obtain a permutation
279 if( !fillPermutation(imap
, cnt
, BTN_CNT
) )
281 fprintf(stderr
, "Mapping needs to be a permutation.\n");
285 // Copy array and check bounds
286 for(unsigned i
=0; i
<ABS_CNT
; ++i
)
288 if( imap
[i
]<0 || imap
[i
]>=BTN_CNT
)
290 fprintf(stderr
, "Value out of bounds: %d\n", imap
[i
]);
298 printf("Setting the following map:\n");
299 for(int i
=0; i
<cnt
; i
++)
300 printf(" %d => %d\n", i
, map
[i
] );
303 if( ioctl(fd
, JSIOCSBTNMAP
, &map
) )
305 perror( PACKAGE_STRING
": error setting axis map");
311 int main(int argc
, char** argv
)
313 int argListAxismap
=0;
314 int argListButtonmap
=0;
315 char* argSetAxismap
=0;
316 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
);