first commit
[joydevmap.git] / src / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <assert.h>
5 #include <errno.h>
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <unistd.h>
11
12 #include <sys/ioctl.h>
13 #include <linux/joystick.h>
14
15 #include "config.h"
16
17
18 #define MAXFN 1024
19 #define EXIT_INVARG 1
20 #define EXIT_OPEN 2
21 #define EXIT_IOCTL 3
22 #define EXIT_VERSION 4
23 #define EXIT_VALUE 5
24
25
26
27 void reportMissingArgument(const char* opt)
28 {
29 fprintf(stderr, "Missing argument for option '%s'.\n", opt);
30 exit(EXIT_INVARG);
31 }
32
33 void printHelp(FILE* out, int argc, char** argv)
34 {
35 (void) argc;
36
37 fprintf(out, "Usage:\n"
38 " %s -h\n"
39 " %s --help\n"
40 " %s {commands} --dev <device>\n"
41 "\n"
42 "Commands:\n"
43 " --list-axismap\n"
44 " --list-buttonmap\n"
45 " --set-axismap 'id, id, id...'\n"
46 " --set-buttonmap 'id, id, id...'\n",
47 argv[0], argv[0], argv[0]);
48 }
49
50
51 void listAxismap(int fd)
52 {
53 __u8 cnt=0;
54 __u8 map[ABS_CNT] = {-1};
55
56
57 if (ioctl(fd, JSIOCGAXES, &cnt) )
58 {
59 perror(PACKAGE_STRING ": error getting number of axes");
60 exit(EXIT_IOCTL);
61 }
62 printf("Got %d axes:\n", cnt);
63 assert( cnt <= ABS_CNT);
64
65
66 if( ioctl(fd, JSIOCGAXMAP, &map) < 0 )
67 {
68 perror(PACKAGE_STRING ": error getting axis map");
69 exit(1);
70 }
71
72 for(int i=0; i<cnt; i++)
73 printf(" %d => %d\n", i, map[i] );
74
75 printf("\n");
76 printf("Set this mapping with:\n");
77 printf(" " PACKAGE_STRING " --set-axismap '");
78 for(int i=0; i<cnt; i++)
79 {
80 if( i> 0)
81 printf(", ");
82 printf("%d", map[i] );
83 }
84 printf("'\n");
85 }
86
87
88 void listButtonmap(int fd)
89 {
90 __u8 cnt=0;
91 __u16 map[KEY_MAX - BTN_MISC + 1] = {-1};
92
93 if (ioctl(fd, JSIOCGBUTTONS, &cnt) )
94 {
95 perror(PACKAGE_STRING ": error getting number of buttons");
96 exit(EXIT_IOCTL);
97 }
98 printf("Got %d buttons:\n", cnt);
99
100
101 if( ioctl(fd, JSIOCGBTNMAP, &map) < 0 )
102 {
103 perror(PACKAGE_STRING ": error getting button map");
104 exit(1);
105 }
106
107 for(int i=0; i<cnt; i++)
108 printf(" %d => %d\n", i, map[i] );
109
110 printf("\n");
111 printf("Set this mapping with:\n");
112 printf(" " PACKAGE_STRING " --set-buttonmap '");
113 for(int i=0; i<cnt; i++)
114 {
115 if( i> 0)
116 printf(", ");
117 printf("%d", map[i] );
118 }
119 printf("'\n");
120 }
121
122
123 void setAxismap(int fd, char* mapstr)
124 {
125 __u8 cnt=0;
126 __u8 map[ABS_CNT] = {-1};
127
128
129 if (ioctl(fd, JSIOCGAXES, &cnt) )
130 {
131 perror(PACKAGE_STRING ": error getting number of axes");
132 exit(EXIT_IOCTL);
133 }
134 printf("Setting %d axes.\n", cnt);
135 assert( cnt <= ABS_CNT);
136
137
138 char* s = mapstr;
139 for(unsigned i=0; i<cnt; ++i)
140 {
141 if( !s )
142 {
143 fprintf(stderr, "Missing value for axis %d.\n", i);
144 exit(EXIT_VALUE);
145 }
146
147 int val=-1;
148 sscanf(s, "%d", &val);
149 if( val<0 || val>=(1<<8) )
150 {
151 fprintf(stderr, "Value out of bounds: %d\n", val);
152 exit(EXIT_VALUE);
153 }
154 map[i] = val;
155
156 s = strstr(s, ",");
157 if(s)
158 s++;
159 }
160
161 if( s )
162 fprintf(stderr, "Too many values given for the axismap. Ignoring the rest.\n");
163
164
165 printf("Setting the following map:\n");
166 for(int i=0; i<cnt; i++)
167 printf(" %d => %d\n", i, map[i] );
168
169
170 if( ioctl(fd, JSIOCSAXMAP, &map) )
171 {
172 perror( PACKAGE_STRING ": error setting axis map");
173 exit(EXIT_IOCTL);
174 }
175 }
176
177
178 void setButtonmap(int fd, char* mapstr)
179 {
180 __u8 cnt=0;
181 __u16 map[KEY_MAX - BTN_MISC + 1] = {-1};
182
183 printf("foo: %d\n", 1<<8);
184
185 if (ioctl(fd, JSIOCGBUTTONS, &cnt) )
186 {
187 perror(PACKAGE_STRING ": error getting number of buttons");
188 exit(EXIT_IOCTL);
189 }
190 printf("Setting %d buttons.\n", cnt);
191
192
193 char* s = mapstr;
194 for(unsigned i=0; i<cnt; ++i)
195 {
196 if( !s )
197 {
198 fprintf(stderr, "Missing value for axis %d.\n", i);
199 exit(EXIT_VALUE);
200 }
201
202 int val=-1;
203 sscanf(s, "%d", &val);
204 if( val<0 || val>=(1<<16) )
205 {
206 fprintf(stderr, "Value out of bounds: %d\n", val);
207 exit(EXIT_VALUE);
208 }
209 map[i] = val;
210
211 s = strstr(s, ",");
212 if(s)
213 s++;
214 }
215
216 if( s )
217 fprintf(stderr, "Too many values given for the axismap. Ignoring the rest.\n");
218
219
220 printf("Setting the following map:\n");
221 for(int i=0; i<cnt; i++)
222 printf(" %d => %d\n", i, map[i] );
223
224
225 if( ioctl(fd, JSIOCSBTNMAP, &map) )
226 {
227 perror( PACKAGE_STRING ": error setting button map");
228 exit(EXIT_IOCTL);
229 }
230 }
231
232
233 int main(int argc, char** argv)
234 {
235 int argListAxismap=0;
236 int argListButtonmap=0;
237 char* argSetAxismap=0;
238 char* argSetButtonmap=0;
239 char dev[MAXFN+1] = "";
240
241
242
243 for(int i=1; i<argc; ++i)
244 {
245 const char* opt = argv[i];
246
247 if( !strcmp(opt,"--help") || !strcmp(opt,"-h") )
248 {
249 printHelp(stdout, argc, argv);
250 return EXIT_SUCCESS;
251 }
252 else if( !strcmp(opt, "--dev") || !strcmp(opt,"-d") )
253 {
254 i++;
255 if( i >= argc )
256 reportMissingArgument(opt);
257 strncpy(dev, argv[i], MAXFN);
258 }
259 else if( !strcmp(opt, "--list-axismap") )
260 {
261 argListAxismap = 1;
262 }
263 else if( !strcmp(opt, "--list-buttonmap") )
264 {
265 argListButtonmap = 1;
266 }
267 else if( !strcmp(opt, "--set-axismap") )
268 {
269 i++;
270 if( i >= argc )
271 reportMissingArgument(opt);
272 argSetAxismap = argv[i];
273 }
274 else if( !strcmp(opt, "--set-buttonmap") )
275 {
276 i++;
277 if( i >= argc )
278 reportMissingArgument(opt);
279 argSetButtonmap = argv[i];
280 }
281 else
282 {
283 fprintf(stderr, "Invalid option '%s'.\n", opt);
284 return EXIT_INVARG;
285 }
286 }
287
288
289 if( strcmp("", dev)==0 )
290 {
291 fprintf(stderr, "You need to specify a device.\n");
292 return EXIT_INVARG;
293 }
294
295
296 int fd=-1;
297 if( (fd = open(dev, O_RDONLY)) < 0 )
298 {
299 perror("Cannot open device.");
300 return EXIT_OPEN;
301 }
302
303
304 int version;
305 if( ioctl(fd, JSIOCGVERSION, &version) )
306 {
307 perror( PACKAGE_STRING ": error getting version");
308 exit(EXIT_IOCTL);
309 }
310
311 if( version != JS_VERSION )
312 {
313 fprintf(stderr, PACKAGE_STRING ": compiled with different version %d\n", JS_VERSION);
314 exit(EXIT_VERSION);
315 }
316
317
318 if( argListAxismap )
319 listAxismap(fd);
320
321 if( argListButtonmap )
322 listButtonmap(fd);
323
324 if( argSetAxismap )
325 setAxismap(fd, argSetAxismap);
326
327 if( argSetButtonmap )
328 setButtonmap(fd, argSetButtonmap);
329
330
331 close(fd);
332 return 0;
333 }