4 * Copyright (C) 2013-2017 Giuseppe Bilotta
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 #include <linux/input.h>
24 #include <linux/uinput.h>
26 #include <sys/select.h>
40 /* These definitions might be missing from older linux/input.h headers */
42 #define BTN_DPAD_UP 0x220
45 #define BTN_DPAD_DOWN 0x221
48 #define BTN_DPAD_LEFT 0x222
50 #ifndef BTN_DPAD_RIGHT
51 #define BTN_DPAD_RIGHT 0x223
54 #define WIIMOTE_PADMODE_VENDOR_ID 0x6181 /* GIuseppe BIlotta */
55 #define WIIMOTE_PADMODE_DEVICE_ID 0x3169 /* WIimote GamePad */
57 /* Check if an error \code is negative during \str action */
58 void err_check(int code, char const *str) {
61 fprintf(stderr, "could not %s (%d): %s\n",
62 str, err, strerror(err));
67 #define DPAD_PORTRAIT \
68 _BUTTON(XWII_KEY_UP, BTN_DPAD_UP); \
69 _BUTTON(XWII_KEY_DOWN, BTN_DPAD_DOWN); \
70 _BUTTON(XWII_KEY_LEFT, BTN_DPAD_LEFT); \
71 _BUTTON(XWII_KEY_RIGHT, BTN_DPAD_RIGHT); \
74 #define DPAD_LANDSCAPE \
75 _BUTTON(XWII_KEY_UP, BTN_DPAD_LEFT); \
76 _BUTTON(XWII_KEY_DOWN, BTN_DPAD_RIGHT); \
77 _BUTTON(XWII_KEY_LEFT, BTN_DPAD_DOWN); \
78 _BUTTON(XWII_KEY_RIGHT, BTN_DPAD_UP); \
80 #define OTHER_BUTTONS \
81 _BUTTON(XWII_KEY_A, BTN_A); \
82 _BUTTON(XWII_KEY_B, BTN_B); \
83 _BUTTON(XWII_KEY_PLUS, BTN_TL); \
84 _BUTTON(XWII_KEY_MINUS, BTN_TR); \
85 _BUTTON(XWII_KEY_HOME, BTN_MODE); \
86 _BUTTON(XWII_KEY_ONE, BTN_1); \
87 _BUTTON(XWII_KEY_TWO, BTN_2); \
89 #define BUTTONS_LANDSCAPE do { \
94 #define BUTTONS_PORTRAIT do { \
100 struct uinput_user_dev padmode;
102 /* macros to set evbits and keybits */
103 #define set_ev(key) do { \
104 ret = ioctl(fd, UI_SET_EVBIT, key); \
105 err_check(ret, "set " #key); \
108 #define set_key(key) do { \
109 ret = ioctl(fd, UI_SET_KEYBIT, key); \
110 err_check(ret, "set " #key); \
113 #define set_abs(key, min, max, fuzz, flat) do { \
114 ret = ioctl(fd, UI_SET_ABSBIT, key); \
115 err_check(ret, "set " #key); \
116 padmode.absmin[key] = min; \
117 padmode.absmax[key] = max; \
118 padmode.absfuzz[key] = fuzz; \
119 padmode.absflat[key] = flat; \
134 struct xwii_iface *iface;
136 /* Room for controller keys and two axes, plus SYN */
137 struct input_event iev[XWII_KEY_TWO+2+1+1];
143 #define MAX_WIIMOTES FD_SETSIZE
144 struct wiimote_dev dev[MAX_WIIMOTES];
145 int motes; /* Connected Wiimotes */
147 int cli_dpad_portrait; /* D-pad in portrait mode selected on the command-line */
149 void dev_init(struct wiimote_dev const *dev, struct input_event *iev) {
151 int fd = dev->uinput;
153 #define _BUTTON(n, bt) do { \
155 iev[n].type = EV_KEY; \
160 if (dev->dpad_portrait)
169 set_abs(ABS_X, -AXIS_MAX, AXIS_MAX, 2, 4);
170 iev[11].type = EV_ABS;
171 iev[11].code = ABS_X;
172 set_abs(ABS_Y, -AXIS_MAX, AXIS_MAX, 2, 4);
173 iev[12].type = EV_ABS;
174 iev[12].code = ABS_Y;
176 iev[13].type = EV_SYN;
177 iev[13].code = iev[13].value = 0;
179 snprintf(padmode.name, UINPUT_MAX_NAME_SIZE, XWII_NAME_CORE " in gamepad mode");
180 padmode.id.bustype = BUS_VIRTUAL;
182 padmode.id.vendor = 0;
183 padmode.id.product = 0;
184 padmode.id.version = 0;
187 ret = write(fd, &padmode, sizeof(padmode));
188 err_check(ret, "set dev properties");
189 ret = ioctl(fd, UI_DEV_CREATE);
190 err_check(ret, "create device");
194 static int wiimote_refresh(struct wiimote_dev *dev)
196 puts("Refreshing\n");
197 return xwii_iface_open(dev->iface, dev->ifs);
200 static void wiimote_key(struct wiimote_dev *dev, struct xwii_event const *ev)
202 unsigned int code = ev->v.key.code;
203 unsigned int state = ev->v.key.state;
204 struct input_event *iev = dev->iev;
206 if (code > XWII_KEY_TWO)
210 iev[code].value = state;
212 if (dev->uinput > 0) {
213 int ret = write(dev->uinput, iev + code, sizeof(*iev));
214 err_check(ret, "report button");
215 ret = write(dev->uinput, iev + 13, sizeof(*iev));
216 err_check(ret, "report btn SYN");
218 fputs("nowhere to report button presses to\n", stderr);
222 #define CLIP_AXIS(val) do { \
223 if (val < -AXIS_MAX) \
225 if (val > AXIS_MAX) \
230 static void wiimote_accel(struct wiimote_dev *dev, struct xwii_event const *ev)
232 struct input_event *iev = dev->iev;
234 iev[11].value = -(ev->v.abs[0].y);
235 iev[12].value = -(ev->v.abs[0].x);
237 CLIP_AXIS(iev[11].value);
238 CLIP_AXIS(iev[12].value);
240 if (dev->uinput > 0) {
241 int ret = write(dev->uinput, iev + 11, sizeof(*iev));
242 err_check(ret, "report accel X");
243 ret = write(dev->uinput, iev + 12, sizeof(*iev));
244 err_check(ret, "report accel Y");
245 ret = write(dev->uinput, iev + 13, sizeof(*iev));
246 err_check(ret, "report accel SYN");
248 printf("reported J (%d, %d) from ev (%d, %d)\n",
249 iev[11].value, iev[12].value,
250 -(ev->v.abs[0].y), ev->v.abs[0].x);
253 fputs("nowhere to report accel to\n", stderr);
257 static int wiimote_poll(struct wiimote_dev *dev)
259 struct xwii_event ev;
263 memset(&ev, 0, sizeof(ev));
264 ret = xwii_iface_dispatch(dev->iface, &ev, sizeof(ev));
270 case XWII_EVENT_WATCH:
271 ret = wiimote_refresh(dev);
274 wiimote_key(dev, &ev);
276 case XWII_EVENT_ACCEL:
277 wiimote_accel(dev, &ev);
280 printf("Unhandled Wiimote event type %d\n", ev.type);
284 if (ret == -EAGAIN) {
291 int dev_create(struct wiimote_dev *dev) {
294 struct udev_device *d, *p;
296 const char *root, *snum, *driver, *subs;
299 dev->dpad_portrait = cli_dpad_portrait;
306 if (stat(dev->device, &st)) {
313 fputs("could not connect to udev\n", stderr);
318 d = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
320 fputs("could not find udev device\n", stderr);
325 p = udev_device_get_parent_with_subsystem_devtype(d, "hid", NULL);
327 fputs("could not find parent HID device\n", stderr);
332 driver = udev_device_get_driver(p);
333 subs = udev_device_get_subsystem(p);
334 if (!driver || strcmp(driver, "wiimote") || !subs || strcmp(subs, "hid")) {
335 fputs("parent is not a HID Wiimote\n", stderr);
340 root = udev_device_get_syspath(p);
341 snum = udev_device_get_sysname(p);
342 snum = snum ? strchr(snum, '.') : NULL;
343 if (!root || !snum) {
344 fputs("Could not get root path\n", stderr);
349 num = strtol(&snum[1], NULL, 16);
351 fputs("Negative device number!\n", stderr);
357 dev->root = strdup(root);
359 fputs("Could not set device root\n", stderr);
364 printf("using device %d from root %s for %s\n",
365 dev->dev_id, dev->root, dev->device);
367 dev->ifs = XWII_IFACE_CORE | XWII_IFACE_ACCEL;
368 ret = xwii_iface_new(&dev->iface, dev->root);
370 fputs("Could not create xwiimote interface\n", stderr);
375 ret = xwii_iface_open(dev->iface, dev->ifs);
377 fputs("Could not open xwiimote interface\n", stderr);
381 if (xwii_iface_opened(dev->iface) != dev->ifs) {
382 fputs("Some interfaces failed to open\n", stderr);
387 dev->fd = xwii_iface_get_fd(dev->iface);
396 udev_device_unref(d);
401 printf("\twith D-pad in %s mode\n",
402 dev->dpad_portrait ? "portrait" : "landscape");
407 static void dev_destroy(struct wiimote_dev *dev) {
409 xwii_iface_unref(dev->iface);
413 if (dev->uinput > 0) {
414 ioctl(dev->uinput, UI_DEV_DESTROY);
417 printf("deassociated from device %s\n", dev->device);
422 static void destroy_all_devs(void) {
424 dev_destroy(dev + motes);
428 static int last_signal;
430 static void sig_exit(int _signal) {
431 last_signal = _signal;
432 printf("Interrupted by signal %d\n", last_signal);
435 struct timeval no_wait;
437 const char uinput_path[] = "/dev/uinput";
439 const char js_glob[] = "/dev/input/js*";
441 int check_dpad(int argc, char **argv[])
443 printf("%d %p\n", argc, *argv);
444 if (argc > 1 && !strcmp((*argv)[1], "--dpad")) {
447 fputs("missing --dpad spec\n", stderr);
450 if (!strcmp((*argv)[1], "land") || !strcmp((*argv)[1], "landscape")) {
451 cli_dpad_portrait = 0;
452 } else if (!strcmp((*argv)[1], "port") || !strcmp((*argv)[1], "portrait")) {
453 cli_dpad_portrait = 1;
455 fprintf(stderr, "unknown --dpad spec %s\n", (*argv)[1]);
459 printf("The next wiimote(s) will be configured with the D-pad in %s mode\n",
460 cli_dpad_portrait ? "portrait" : "landscape");
465 int main(int argc, char *argv[]) {
467 fd_set input_fds, backup_fds;
470 cli_dpad_portrait = 0;
472 atexit(destroy_all_devs);
473 signal(SIGINT, sig_exit);
476 /* Check if there is a dpad specification */
479 printf("%d %d\n", ret, argc);
480 ret = check_dpad(ret, &argv);
486 /* If there are still arguments, assume it's a device specification */
488 dev[motes].device = argv[motes+1];
489 ret = dev_create(dev + motes);
492 fprintf(stderr, "could not %s (%d): %s\n",
493 "associate", ret, strerror(ret));
501 /* No device specified. Since the Linux kernel exposes the
502 * controller also as a joystick (without axes), we peek at
503 * all available joysticks looking for one which is a Wiimote
506 switch (glob(js_glob, GLOB_NOSORT, NULL, &js_devs)) {
510 fputs("no joysticks found\n", stderr);
514 for (size_t j = 0; j < js_devs.gl_pathc; ++j) {
515 dev[motes].device = js_devs.gl_pathv[j];
516 ret = dev_create(dev + motes);
521 printf("skipping %s (%d): %s\n",
522 dev[motes].device, ret, strerror(ret));
528 fputs("no wiimote found\n", stderr);
532 FD_ZERO(&backup_fds);
534 for (int j = 0; j < motes; ++j) {
535 dev[j].uinput = open(uinput_path, O_WRONLY | O_NONBLOCK);
536 err_check(dev[j].uinput, "open uinput");
537 dev_init(dev + j, dev[j].iev);
540 FD_SET(fd, &backup_fds);
546 memset(&no_wait, 0, sizeof(no_wait));
547 input_fds = backup_fds;
551 ret = select(max_fd + 1, &input_fds, NULL, NULL, NULL);
552 err_check(ret, "poll wiimote fd");
554 for (int j = 0; j < motes; ++j) {
555 struct wiimote_dev *cur = dev + j;
556 if (FD_ISSET(cur->fd, &input_fds)) {
557 ret = wiimote_poll(cur);
558 err_check(ret, "process wiimote data");