├── Makefile ├── maps ├── horz_wiimote ├── vert_wiimote ├── media_control └── demo_readme ├── LICENSE ├── src ├── epoll.c ├── udev.c ├── uinput.c ├── slot_management.c ├── wiimoteglue.h ├── device_management.c ├── main.c ├── process_xwiimote_events.c ├── control_mappings.c ├── commandline.c └── key_codes.c └── README.md /Makefile: -------------------------------------------------------------------------------- 1 | LINK_LIBS += -ludev 2 | LINK_LIBS += -lxwiimote 3 | EXTRA_CFLAGS += $(CONFIG_FLAGS) 4 | 5 | wiimoteglue: src/*.c 6 | $(CC) -o wiimoteglue $(EXTRA_CFLAGS) $(LINK_LIBS) src/*.c 7 | 8 | keycodefix: 9 | if ! [ -e key_codes.c.old ] ; \ 10 | then cp src/key_codes.c ./key_codes.c.old ; \ 11 | fi 12 | 13 | @echo "" 14 | 15 | ./build_util/generate_key_codes $(INPUT_HEADER_PATH) 16 | mv key_codes.c src/key_codes.c 17 | 18 | @echo "" 19 | @echo "key_codes.c has been updated. Try building again?" 20 | 21 | basickeys: 22 | $(MAKE) wiimoteglue CONFIG_FLAGS=-DNO_EXTRA_KEYBOARD_KEYS 23 | 24 | clean: 25 | rm wiimoteglue 26 | 27 | 28 | -------------------------------------------------------------------------------- /maps/horz_wiimote: -------------------------------------------------------------------------------- 1 | #a simple mapping for holding the wiimote horizontally 2 | #Great for classic games using a dpad and two action buttons. 3 | 4 | 5 | map wiimote up left 6 | map wiimote left down 7 | map wiimote right up 8 | map wiimote down right 9 | map wiimote a north 10 | map wiimote b west 11 | map wiimote 1 south 12 | map wiimote 2 east 13 | map wiimote plus start 14 | map wiimote home mode 15 | map wiimote minus select 16 | 17 | 18 | #Tilt controls are mapped to a virtual left-stick, 19 | #but the accelerometers are off by default. 20 | 21 | disable wiimote accel 22 | map wiimote accelx left_y invert 23 | map wiimote accely left_x invert 24 | 25 | #The IR sensor is just going to be pointing at a hand. 26 | #No need to enable it. 27 | disable wiimote ir 28 | -------------------------------------------------------------------------------- /maps/vert_wiimote: -------------------------------------------------------------------------------- 1 | #a simple mapping for holding the wiimote vertically 2 | #With only one hand on the wiimote, the uses here are 3 | #a bit limited. 4 | 5 | 6 | map wiimote up up 7 | map wiimote left left 8 | map wiimote right right 9 | map wiimote down down 10 | map wiimote a south 11 | map wiimote b east 12 | map wiimote 1 north 13 | map wiimote 2 west 14 | map wiimote plus start 15 | map wiimote home mode 16 | map wiimote minus select 17 | 18 | 19 | #Tilt controls are mapped to a virtual left-stick, 20 | 21 | enable wiimote accel 22 | map wiimote accelx left_x invert 23 | map wiimote accely left_y invert 24 | 25 | #The IR sensor is mapped to a virtual right-stick. 26 | #You'll probably want either tilt or IR, not both. 27 | 28 | disable wiimote ir 29 | map wiimote ir_x right_x 30 | map wiimote ir_y right_y 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Joseph Geumlek 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/epoll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "wiimoteglue.h" 6 | 7 | /* We use epoll to wait for the next input to handle. 8 | * This should prevent using unecessary CPU time. 9 | */ 10 | 11 | #define EPOLL_MAX_EVENTS 10 12 | struct epoll_event event; 13 | struct epoll_event events[EPOLL_MAX_EVENTS]; 14 | 15 | int wiimoteglue_epoll_init(int *epfd) { 16 | *epfd = epoll_create(EPOLL_MAX_EVENTS); 17 | 18 | memset(events,0, sizeof(events)); 19 | 20 | return 0; 21 | } 22 | 23 | 24 | int wiimoteglue_epoll_watch_monitor(int epfd, int mon_fd, void *monitor) { 25 | memset(&event, 0, sizeof(event)); 26 | 27 | event.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; 28 | event.data.ptr = monitor; 29 | 30 | return epoll_ctl(epfd, EPOLL_CTL_ADD, mon_fd, &event); 31 | 32 | } 33 | 34 | int wiimoteglue_epoll_watch_stdin(struct wiimoteglue_state* state, int epfd) { 35 | memset(&event, 0, sizeof(event)); 36 | 37 | event.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; 38 | event.data.ptr = state; 39 | 40 | return epoll_ctl(epfd, EPOLL_CTL_ADD, 0, &event); //HACK magic constant 41 | } 42 | 43 | int wiimoteglue_epoll_watch_wiimote(int epfd, struct wii_device *device) { 44 | if (device == NULL) return 0; //TODO: ERROR HANDLING. 45 | memset(&event, 0, sizeof(event)); 46 | 47 | event.events = EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP; 48 | event.data.ptr = device; 49 | return epoll_ctl(epfd, EPOLL_CTL_ADD, device->fd, &event); 50 | } 51 | 52 | void wiimoteglue_epoll_loop(int epfd, struct wiimoteglue_state *state) { 53 | int n; 54 | int i; 55 | 56 | while (state->keep_looping > 0) { 57 | n = epoll_wait(epfd, events, EPOLL_MAX_EVENTS, -1); 58 | for (i = 0; i < n; i++) { 59 | if (events[i].data.ptr == state->monitor) { 60 | //HANDLE UDEV STUFF 61 | wiimoteglue_udev_handle_event(state); 62 | printf("\n>>"); 63 | fflush(stdout); 64 | } else if (events[i].data.ptr == state) { 65 | //HANDLE USER INPUT 66 | state->load_lines = 0; 67 | int ret = wiimoteglue_handle_input(state,0); 68 | if (ret < 0) 69 | close(0); 70 | printf("\n>>"); 71 | fflush(stdout); 72 | } else { 73 | //HANDLE WII STUFF 74 | wiimoteglue_handle_wii_event(state,events[i].data.ptr); 75 | } 76 | } 77 | } 78 | 79 | } 80 | 81 | -------------------------------------------------------------------------------- /maps/media_control: -------------------------------------------------------------------------------- 1 | #This file shows how one might like 2 | #to set a wiimote to control one's media 3 | 4 | #first, lets change player 1 to simulate a keyboard 5 | #One can also do "assign keyboardmouse" 6 | 7 | slot 1 keyboardmouse 8 | 9 | #Keyboard and mouse events only work if one 10 | #these two cases are true: 11 | # -The device's slot is set to keyboardmouse mode 12 | # -The device is directly assigned to the keyboardmouse slot 13 | 14 | #These buttons are sensible in all the modes: 15 | map keyboardmouse all plus key_volumeup 16 | map keyboardmouse all minus key_volumedown 17 | 18 | #Note that we must specify the name of the mapping 19 | #"keyboardmouse", otherwise it will default to 20 | #the "gamepad" mapping. 21 | 22 | 23 | #lets hold the wiimote vertically, like a remote. 24 | 25 | map keyboardmouse wiimote a key_playpause 26 | map keyboardmouse wiimote b key_mute 27 | map keyboardmouse wiimote left key_previoussong 28 | map keyboardmouse wiimote right key_nextsong 29 | map keyboardmouse wiimote home key_stop 30 | map keyboardmouse wiimote 1 key_shuffle 31 | map keyboardmouse wiimote up key_brightnessup 32 | map keyboardmouse wiimote down key_brightnessdown 33 | 34 | #add a nunchuk, and we'll add some mouse controls as well. 35 | 36 | enable keyboardmouse nunchuk ir 37 | map keyboardmouse nunchuk ir_x mouse_x 38 | map keyboardmouse nunchuk ir_y mouse_y 39 | map keyboardmouse nunchuk a left_click 40 | map keyboardmouse nunchuk b right_click 41 | 42 | map keyboardmouse nunchuk c key_playpause 43 | map keyboardmouse nunchuk z key_mute 44 | map keyboardmouse nunchuk left key_previoussong 45 | map keyboardmouse nunchuk right key_nextsong 46 | map keyboardmouse nunchuk home key_stop 47 | map keyboardmouse nunchuk 1 key_shuffle 48 | map keyboardmouse nunchuk up key_brightnessup 49 | map keyboardmouse nunchuk down key_brightnessdown 50 | 51 | #What should we do with a classic controller? 52 | #This file is more of a demo than an 53 | #actually useful setup. 54 | 55 | map keyboardmouse classic a key_playpause 56 | map keyboardmouse classic home key_stop 57 | map keyboardmouse classic b key_mute 58 | map keyboardmouse classic x key_shuffle 59 | 60 | map keyboardmouse classic zr key_nextsong 61 | map keyboardmouse classic zl key_previoussong 62 | map keyboardmouse classic l left_click 63 | map keyboardmouse classic r right_click 64 | map keyboardmouse classic left_x mouse_x 65 | map keyboardmouse classic left_y mouse_y 66 | -------------------------------------------------------------------------------- /src/udev.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "wiimoteglue.h" 6 | 7 | /* 8 | * Udev functionality. Handles finding and adding wiimotes. 9 | * 10 | */ 11 | 12 | struct wii_device * lookup_syspath(struct wii_device_list *devlist, char *syspath); 13 | 14 | int wiimoteglue_udev_monitor_init(struct udev **udev, struct udev_monitor **monitor, int *mon_fd) { 15 | 16 | if (*udev == NULL) { 17 | *udev = udev_new(); 18 | if (*udev == NULL) { 19 | printf("error opening udev"); 20 | return -1; 21 | } 22 | } 23 | 24 | 25 | 26 | *monitor = udev_monitor_new_from_netlink(*udev,"udev"); 27 | udev_monitor_filter_add_match_subsystem_devtype(*monitor,"hid",NULL); 28 | udev_monitor_filter_add_match_subsystem_devtype(*monitor,"input",NULL); 29 | 30 | udev_monitor_enable_receiving(*monitor); 31 | 32 | *mon_fd = udev_monitor_get_fd(*monitor); 33 | 34 | return 0; 35 | } 36 | 37 | int wiimoteglue_udev_enumerate(struct wiimoteglue_state *state, struct udev **udev) { 38 | if (*udev == NULL) { 39 | *udev = udev_new(); 40 | if (*udev == NULL) { 41 | printf("error opening udev"); 42 | return -1; 43 | } 44 | } 45 | 46 | 47 | struct udev_enumerate *enumerate; 48 | struct udev_list_entry *devices, *dev_list_entry; 49 | struct udev_device *dev; 50 | 51 | enumerate = udev_enumerate_new(*udev); 52 | udev_enumerate_add_match_subsystem(enumerate,"hid"); 53 | 54 | udev_enumerate_scan_devices(enumerate); 55 | devices = udev_enumerate_get_list_entry(enumerate); 56 | 57 | udev_list_entry_foreach(dev_list_entry, devices) { 58 | const char* driver; 59 | const char* subsystem; 60 | const char* path; 61 | path = udev_list_entry_get_name(dev_list_entry); 62 | dev = udev_device_new_from_syspath(*udev, path); 63 | driver = udev_device_get_driver(dev); 64 | subsystem = udev_device_get_subsystem(dev); 65 | 66 | 67 | 68 | if (subsystem != NULL && strcmp(subsystem, "hid") == 0) { 69 | if (driver != NULL && strcmp(driver,"wiimote") == 0) { 70 | add_wii_device(state,udev_device_ref(dev)); 71 | } 72 | } 73 | 74 | udev_device_unref(dev); 75 | 76 | } 77 | 78 | udev_enumerate_unref(enumerate); 79 | 80 | return 0; 81 | } 82 | 83 | 84 | int wiimoteglue_udev_handle_event(struct wiimoteglue_state *state) { 85 | struct udev_device *dev; 86 | dev = udev_monitor_receive_device(state->monitor); 87 | if (dev) { 88 | const char* action; 89 | const char* driver; 90 | const char* subsystem; 91 | action = udev_device_get_action(dev); 92 | driver = udev_device_get_driver(dev); 93 | subsystem = udev_device_get_subsystem(dev); 94 | 95 | 96 | if (strcmp(action,"change") == 0) { 97 | //It seems "change" happens once the wiimote is ready, 98 | //"add" happens too early. 99 | if (subsystem != NULL && strcmp(subsystem, "hid") == 0) { 100 | if (driver != NULL && strcmp(driver,"wiimote") == 0) { 101 | 102 | add_wii_device(state,udev_device_ref(dev)); 103 | } 104 | } 105 | } 106 | 107 | if (strcmp(action,"add") == 0) { 108 | struct udev_device *parentdev = udev_device_get_parent_with_subsystem_devtype(dev,"hid",NULL); 109 | char* syspath = udev_device_get_syspath(parentdev); 110 | struct wii_device *wiidev = lookup_syspath(&state->dev_list,syspath); 111 | if (wiidev != NULL) 112 | wiimoteglue_update_extensions(state,wiidev); 113 | } 114 | 115 | if (strcmp(action,"remove") == 0) { 116 | 117 | if (subsystem != NULL && strcmp(subsystem, "input")) { 118 | struct udev_device *parentdev = udev_device_get_parent_with_subsystem_devtype(dev,"hid",NULL); 119 | char* syspath = udev_device_get_syspath(parentdev); 120 | struct wii_device *wiidev = lookup_syspath(&state->dev_list,syspath); 121 | if (wiidev != NULL) 122 | wiimoteglue_update_extensions(state,wiidev); 123 | } 124 | 125 | if (subsystem != NULL && strcmp(subsystem, "hid") == 0) { 126 | 127 | char* syspath = udev_device_get_syspath(dev); 128 | struct wii_device *wiidev = lookup_syspath(&state->dev_list,syspath); 129 | if (wiidev != NULL) { 130 | remove_device_from_slot(wiidev); 131 | udev_device_unref(wiidev->udev); 132 | wiidev->udev = NULL; 133 | printf("Device %s disconnected from system.\n",wiidev->id); 134 | close_wii_device(state,wiidev); 135 | } 136 | 137 | } 138 | } 139 | 140 | //The controller interface will detect its removal. 141 | //Trying to use the udev remove event would require 142 | //searching the device list to find the matching entry. 143 | //xwiimote says not to do this, but I had trouble 144 | //handling the extension insertions/removals. 145 | //Seemed like one couldn't add multiple parent-match filters? 146 | 147 | //With most use cases having only a handful of controllers, 148 | //this might be okay? 149 | } 150 | 151 | udev_device_unref(dev); 152 | 153 | return 0; 154 | } 155 | 156 | 157 | struct wii_device * lookup_syspath(struct wii_device_list *devlist, char *syspath) { 158 | 159 | if (devlist == NULL) { 160 | return NULL; 161 | } 162 | if (syspath == NULL) { 163 | return NULL; 164 | } 165 | 166 | struct wii_device_list* list_node = devlist->next; 167 | 168 | while (*KEEP_LOOPING && list_node != devlist && list_node != NULL) { 169 | 170 | 171 | if (list_node->dev != NULL) { 172 | if (list_node->dev->udev != NULL) { 173 | char* devpath = udev_device_get_syspath(list_node->dev->udev); 174 | 175 | if (strncmp(syspath,devpath,2048) == 0) 176 | return list_node->dev; 177 | 178 | } 179 | 180 | list_node = list_node->next; 181 | } 182 | } 183 | 184 | 185 | return NULL; 186 | } -------------------------------------------------------------------------------- /src/uinput.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "wiimoteglue.h" 9 | 10 | /*Handles opening uinput and creating virtual gamepads. 11 | *Change the location /dev/uinput below if you need to. 12 | */ 13 | 14 | char* try_to_find_uinput() { 15 | static char* paths[] = { 16 | "/dev/uinput", 17 | "/dev/input/uinput", 18 | "/dev/misc/uinput" 19 | }; 20 | const int num_paths = 3; 21 | int i; 22 | 23 | for (i = 0; i < num_paths; i++) { 24 | if (access(paths[i],F_OK) == 0) { 25 | return paths[i]; 26 | } 27 | } 28 | 29 | return NULL; 30 | 31 | } 32 | 33 | 34 | int wiimoteglue_uinput_init(int num_slots, struct virtual_controller slots[], char* uinput_path) { 35 | int uinput_fd = 0; 36 | int i; 37 | int keyboardmouse_fd = open_uinput_keyboardmouse_fd(uinput_path); 38 | if (keyboardmouse_fd < 0) { 39 | return -1; 40 | } 41 | 42 | 43 | 44 | slots[0].uinput_fd = keyboardmouse_fd; 45 | slots[0].keyboardmouse_fd = slots[0].uinput_fd; 46 | slots[0].gamepad_fd = slots[0].uinput_fd; 47 | slots[0].has_wiimote = 0; 48 | slots[0].has_board = 0; 49 | slots[0].slot_number = 0; 50 | slots[0].dev_list.next = &slots[0].dev_list; 51 | slots[0].dev_list.prev = &slots[0].dev_list; 52 | slots[0].slot_name = calloc(WG_MAX_NAME_SIZE,sizeof(char)); 53 | strncpy(slots[0].slot_name,"keyboardmouse",WG_MAX_NAME_SIZE); 54 | 55 | 56 | 57 | for (i = 1; i <= num_slots; i++) { 58 | uinput_fd = open_uinput_gamepad_fd(uinput_path); 59 | if (uinput_fd < 0) { 60 | return -1; 61 | } 62 | slots[i].uinput_fd = uinput_fd; 63 | slots[i].keyboardmouse_fd = keyboardmouse_fd; 64 | slots[i].gamepad_fd = uinput_fd; 65 | slots[i].slot_number = i; 66 | slots[i].has_wiimote = 0; 67 | slots[i].has_board = 0; 68 | slots[i].dev_list.next = &slots[i].dev_list; 69 | slots[i].dev_list.prev = &slots[i].dev_list; 70 | slots[i].slot_name = calloc(WG_MAX_NAME_SIZE,sizeof(char)); 71 | snprintf(slots[i].slot_name,WG_MAX_NAME_SIZE,"%d",i); 72 | } 73 | 74 | 75 | return 0; 76 | 77 | } 78 | 79 | int wiimoteglue_uinput_close(int num_slots, struct virtual_controller slots[]) { 80 | int i; 81 | /*Remember, there are num_slots+1 devices, because of the fake keyboard/mouse */ 82 | for (i = 0; i <= num_slots; i++) { 83 | if (ioctl(slots[i].uinput_fd, UI_DEV_DESTROY) < 0) { 84 | printf("Error destroying uinput device.\n"); 85 | perror("uinput destroy"); 86 | } 87 | 88 | free(slots[i].slot_name); 89 | 90 | close(slots[i].uinput_fd); 91 | } 92 | 93 | return 0; 94 | } 95 | 96 | 97 | int open_uinput_gamepad_fd(char* uinput_path) { 98 | /* as far as I know, you can't change the reported event types 99 | * after creating the virtual device. 100 | * So we just create a gamepad with all of them, even if unmapped. 101 | */ 102 | static int abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY}; 103 | static int key[] = { BTN_SOUTH, BTN_EAST, BTN_NORTH, BTN_WEST, BTN_SELECT, BTN_MODE, BTN_START, BTN_TL, BTN_TL2, BTN_TR, BTN_TR2, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, BTN_DPAD_UP,BTN_THUMBL, BTN_THUMBR}; 104 | struct uinput_user_dev uidev; 105 | int fd; 106 | int i; 107 | //TODO: Read from uinput for rumble events? 108 | fd = open(uinput_path, O_WRONLY | O_NONBLOCK); 109 | if (fd < 0) { 110 | perror("open uinput"); 111 | return -1; 112 | } 113 | memset(&uidev, 0, sizeof(uidev)); 114 | snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "WiimoteGlue Virtual Gamepad"); 115 | uidev.id.bustype = BUS_USB; 116 | uidev.id.vendor = 0x1; 117 | uidev.id.product = 0x1; 118 | uidev.id.version = 1; 119 | 120 | ioctl(fd, UI_SET_EVBIT, EV_ABS); 121 | for (i = 0; i < 4; i++) { 122 | ioctl(fd, UI_SET_ABSBIT, abs[i]); 123 | uidev.absmin[abs[i]] = -32768; 124 | uidev.absmax[abs[i]] = 32768; 125 | uidev.absflat[abs[i]] = 4096; 126 | } 127 | 128 | ioctl(fd, UI_SET_EVBIT, EV_KEY); 129 | for (i = 0; i < 17; i++) { 130 | ioctl(fd, UI_SET_KEYBIT, key[i]); 131 | } 132 | 133 | write(fd, &uidev, sizeof(uidev)); 134 | if (ioctl(fd, UI_DEV_CREATE) < 0) 135 | perror("uinput device creation"); 136 | return fd; 137 | } 138 | 139 | int open_uinput_keyboardmouse_fd(char* uinput_path) { 140 | 141 | static int abs[] = { ABS_X, ABS_Y}; 142 | static int key[] = { BTN_LEFT, BTN_MIDDLE, BTN_RIGHT,BTN_TOUCH,BTN_TOOL_PEN}; 143 | /* BTN_TOOL_PEN seems to successfully hint to evdev that 144 | * we are going to be outputting absolute positions, 145 | * not relative motions. 146 | */ 147 | struct uinput_user_dev uidev; 148 | int fd; 149 | int i; 150 | 151 | //TODO: Read from uinput for rumble events? 152 | fd = open(uinput_path, O_WRONLY | O_NONBLOCK); 153 | if (fd < 0) { 154 | perror("\nopen uinput"); 155 | return -1; 156 | } 157 | memset(&uidev, 0, sizeof(uidev)); 158 | snprintf(uidev.name, UINPUT_MAX_NAME_SIZE, "WiimoteGlue Virtual Keyboard and Mouse"); 159 | uidev.id.bustype = BUS_USB; 160 | uidev.id.vendor = 0x1; 161 | uidev.id.product = 0x1; 162 | uidev.id.version = 1; 163 | 164 | ioctl(fd, UI_SET_EVBIT, EV_ABS); 165 | for (i = 0; i < 2; i++) { 166 | ioctl(fd, UI_SET_ABSBIT, abs[i]); 167 | uidev.absmin[abs[i]] = -32768; 168 | uidev.absmax[abs[i]] = 32768; 169 | uidev.absflat[abs[i]] = 4096; 170 | } 171 | 172 | 173 | 174 | /*Just set all possible keys that come before BTN_MISC 175 | * This should cover all reasonable keyboard keys.*/ 176 | ioctl(fd, UI_SET_EVBIT, EV_KEY); 177 | for (i = KEY_ESC; i < BTN_MISC; i++) { 178 | ioctl(fd, UI_SET_KEYBIT, i); 179 | } 180 | for (i = KEY_OK; i < KEY_MAX; i++) { 181 | ioctl(fd, UI_SET_KEYBIT, i); 182 | } 183 | 184 | 185 | /*Set standard mouse buttons*/ 186 | for (i = 0; i < 5; i++) { 187 | ioctl(fd, UI_SET_KEYBIT, key[i]); 188 | } 189 | 190 | write(fd, &uidev, sizeof(uidev)); 191 | if (ioctl(fd, UI_DEV_CREATE) < 0) 192 | perror("uinput device creation"); 193 | return fd; 194 | } 195 | -------------------------------------------------------------------------------- /src/slot_management.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "wiimoteglue.h" 4 | 5 | /*This file has helper functions for dealing with 6 | *the virtual controller slots. 7 | */ 8 | 9 | #define NUM_SLOT_PATTERNS 9 10 | bool slot_leds[NUM_SLOT_PATTERNS+1][4] = { 11 | {0,1,1,0}, /*keyboardmouse slot*/ 12 | {1,0,0,0}, /*slot 1... etc. */ 13 | {0,1,0,0}, 14 | {0,0,1,0}, 15 | {0,0,0,1}, 16 | {1,0,0,1}, 17 | {0,1,0,1}, 18 | {0,0,1,1}, 19 | {1,0,1,1}, 20 | {0,1,1,1} 21 | }; 22 | 23 | 24 | bool no_slot_leds[4] = {1,0,1,0}; 25 | bool slot_overflow_leds[4] = {1,1,1,1}; 26 | 27 | struct virtual_controller* find_open_wiimote_slot(struct wiimoteglue_state *state) { 28 | int i; 29 | for (i = 1; i <= state->num_slots; i++) { 30 | if (state->slots[i].has_wiimote == 0) { 31 | return &state->slots[i]; 32 | } 33 | } 34 | return NULL; 35 | } 36 | 37 | struct virtual_controller* find_open_board_slot(struct wiimoteglue_state *state) { 38 | int i; 39 | for (i = 1; i <= state->num_slots; i++) { 40 | if (state->slots[i].has_board == 0) { 41 | return &state->slots[i]; 42 | } 43 | } 44 | return NULL; 45 | } 46 | 47 | struct virtual_controller* find_open_slot(struct wiimoteglue_state *state, int dev_type) { 48 | if (dev_type == BALANCE) 49 | return find_open_board_slot(state); 50 | 51 | return find_open_wiimote_slot(state); 52 | } 53 | 54 | int add_device_to_slot(struct wiimoteglue_state* state, struct wii_device *dev, struct virtual_controller *slot) { 55 | int ret = 0; 56 | /*We don't support a device being in two slots at once.*/ 57 | if (dev == NULL || dev->slot != NULL || dev->slot_list == NULL) 58 | return -1; 59 | 60 | if (slot == NULL) { 61 | ret = set_led_state(state,dev,no_slot_leds); 62 | if (ret < 0 && ret != -2) 63 | printf("There were errors on setting the LEDs. Permissions?\n"); 64 | 65 | return 0; /*This is actually okay!*/ 66 | } 67 | 68 | 69 | 70 | 71 | 72 | dev->slot_list->next = slot->dev_list.next; 73 | dev->slot_list->prev = &slot->dev_list; 74 | 75 | if (slot->dev_list.next != NULL) { 76 | slot->dev_list.next->prev = dev->slot_list; 77 | } 78 | 79 | slot->dev_list.next = dev->slot_list; 80 | 81 | dev->slot = slot; 82 | 83 | 84 | 85 | if (dev->type == BALANCE) { 86 | slot->has_board++; 87 | } else { 88 | slot->has_wiimote++; 89 | } 90 | 91 | 92 | 93 | int num = slot->slot_number; 94 | 95 | 96 | if (num <= 0) { 97 | /*Keyboard/mouse slot. Let's just set a distinctive pattern.*/ 98 | ret = set_led_state(state,dev,slot_leds[0]); 99 | 100 | } else if (num > NUM_SLOT_PATTERNS) { 101 | /*Future work: add some reasonable patterns here for higher nums?*/ 102 | ret = set_led_state(state,dev,slot_overflow_leds); 103 | } else { 104 | ret = set_led_state(state,dev,&slot_leds[num]); 105 | } 106 | 107 | if (ret < 0 && ret != -2) 108 | printf("There were errors on setting the LEDs. Permissions?\n"); 109 | 110 | compute_device_map(state,dev); 111 | 112 | 113 | 114 | return 0; 115 | } 116 | 117 | int remove_device_from_slot(struct wii_device *dev) { 118 | if (dev == NULL) { 119 | return -1; 120 | } 121 | 122 | 123 | if (dev->slot == NULL) 124 | return 0; /*This is okay!*/ 125 | 126 | if (dev->slot_list == NULL) { 127 | return -1; /*Something has gone wrong...*/ 128 | } 129 | 130 | if (dev->slot_list->next != NULL) 131 | dev->slot_list->next->prev = dev->slot_list->prev; 132 | 133 | if (dev->slot_list->prev != NULL) 134 | dev->slot_list->prev->next = dev->slot_list->next; 135 | 136 | 137 | 138 | if (dev->type == BALANCE) { 139 | dev->slot->has_board--; 140 | } else { 141 | dev->slot->has_wiimote--; 142 | } 143 | 144 | 145 | dev->slot = NULL; 146 | 147 | 148 | 149 | return 0; 150 | } 151 | 152 | int change_slot_type(struct wiimoteglue_state* state, struct virtual_controller *slot,int type) { 153 | if (slot == NULL) 154 | return -1; 155 | if (slot->slot_number == 0) { 156 | return -1; 157 | /*We do not support switching slot 0's type. 158 | *It is assumed to always be a keyboard/mouse. 159 | */ 160 | } 161 | 162 | if (type == SLOT_GAMEPAD) { 163 | slot->uinput_fd = slot->gamepad_fd; 164 | slot->type = SLOT_GAMEPAD; 165 | 166 | /*Try to do the right thing: 167 | *If it was the keyboardmouse map, unset it. 168 | *otherwise, maintain the specific mapping. 169 | */ 170 | if (slot->slot_specific_mappings == state->slots[0].slot_specific_mappings) { 171 | printf("Switched slot's mapping to the gamepad mapping.\n"); 172 | slot->slot_specific_mappings = NULL; 173 | } 174 | return 0; 175 | } 176 | 177 | if (type == SLOT_KEYBOARDMOUSE) { 178 | slot->uinput_fd = slot->keyboardmouse_fd; 179 | slot->type = SLOT_KEYBOARDMOUSE; 180 | /*If no specific map set, go ahead and use the keyboardmouse one.*/ 181 | if (slot->slot_specific_mappings == NULL) { 182 | printf("Switched slot's mapping to the keyboardmouse mapping.\n"); 183 | slot->slot_specific_mappings = state->slots[0].slot_specific_mappings; 184 | } 185 | return 0; 186 | } 187 | 188 | return -2; 189 | 190 | } 191 | 192 | int set_slot_specific_mappings(struct virtual_controller *slot, struct mode_mappings *maps) { 193 | if (slot == NULL) 194 | return -1; 195 | 196 | /*The keyboardmouse slot has its mapping set exactly once*/ 197 | if (slot->slot_number == 0 && slot->slot_specific_mappings != NULL) 198 | return -2; 199 | 200 | 201 | if (slot->slot_specific_mappings != NULL) 202 | mappings_unref(slot->slot_specific_mappings); 203 | 204 | slot->slot_specific_mappings = maps; 205 | 206 | if (maps != NULL) 207 | mappings_ref(maps); 208 | 209 | return 0; 210 | 211 | } 212 | 213 | struct virtual_controller* lookup_slot(struct wiimoteglue_state* state, char* name) { 214 | if (name == NULL) 215 | return NULL; 216 | 217 | int i; 218 | for (i = 0; i <= state->num_slots; i++) { 219 | if (strncmp(name,state->slots[i].slot_name,WG_MAX_NAME_SIZE) == 0) 220 | return &state->slots[i]; 221 | } 222 | 223 | return NULL; 224 | 225 | } 226 | 227 | -------------------------------------------------------------------------------- /src/wiimoteglue.h: -------------------------------------------------------------------------------- 1 | #ifndef WIIMOTEGLUE_H 2 | #define WIIMOTEGLUE_H 3 | 4 | #include 5 | #include 6 | 7 | #define WIIMOTEGLUE_VERSION "1.02.00" 8 | 9 | 10 | #define ABS_LIMIT 32767 11 | #define TILT_LIMIT 80 12 | #define TILT_SCALE (ABS_LIMIT/TILT_LIMIT) 13 | #define NUNCHUK_LIMIT 90 14 | #define NUNCHUK_SCALE (ABS_LIMIT/NUNCHUK_LIMIT) 15 | #define CLASSIC_LIMIT 22 16 | #define CLASSIC_SCALE (ABS_LIMIT/CLASSIC_LIMIT) 17 | #define NO_MAP -1 18 | 19 | /* Set a limit on file loading to avoid an endless loop. 20 | * With only so many settings to change, plus a modest 21 | * amount of comments, this should be sufficient. 22 | */ 23 | #define MAX_LOAD_LINES 500 24 | 25 | /* Used throughout as a max length for various identifiers, 26 | * like device IDs or mapping names 27 | */ 28 | #define WG_MAX_NAME_SIZE 32 29 | 30 | 31 | 32 | 33 | struct event_map { 34 | int button_map[XWII_KEY_NUM]; 35 | //int waggle_button; 36 | //int nunchuk_waggle_button; 37 | //int waggle_cooldown; 38 | int accel_active; 39 | int accel_map[6][2]; 40 | int stick_map[6][2]; 41 | int balance_map[6][2]; 42 | //int balance_cog; 43 | int IR_count; 44 | //int IR_deadzone; 45 | int IR_map[2][2]; 46 | }; 47 | 48 | struct mode_mappings { 49 | char* name; 50 | int reference_count; 51 | /*I want devices to be able to share 52 | *mappings, but I also want to be 53 | *able to free up unused ones. 54 | */ 55 | struct event_map mode_no_ext; 56 | struct event_map mode_nunchuk; 57 | struct event_map mode_classic; 58 | }; 59 | 60 | struct virtual_controller; 61 | struct wii_device_list; 62 | 63 | struct wii_device { 64 | 65 | struct xwii_iface *xwii; 66 | struct virtual_controller *slot; 67 | int fd; 68 | 69 | int ifaces; 70 | struct event_map *map; 71 | struct mode_mappings* dev_specific_mappings; 72 | 73 | char* id; 74 | char* bluetooth_addr; 75 | 76 | struct udev_device* udev; 77 | 78 | enum DEVICE_TYPE { REMOTE, BALANCE, PRO, UNKNOWN} type; 79 | 80 | enum MODE_TYPE { NO_EXT, NUNCHUK, CLASSIC} mode; 81 | 82 | /*At any time, a device should be in at most 83 | *two lists: the main list of all devices, 84 | *and the list of devices for a certain slot. 85 | */ 86 | struct wii_device_list *main_list, *slot_list; 87 | 88 | bool original_leds[4]; 89 | /*Let's be nice and leave the LEDs 90 | *how we found them. 91 | */ 92 | }; 93 | 94 | /*Mmm... Linked lists. 95 | *Ease of insertion and deletion is nice. 96 | *Users are unlikely to use more than a handful 97 | *of controllers at once, and all lookups/iterations 98 | *over this list are done in non-time-critical 99 | *situations. 100 | */ 101 | struct wii_device_list { 102 | struct wii_device_list *prev, *next; 103 | 104 | struct wii_device *dev; 105 | }; 106 | 107 | struct map_list { 108 | struct map_list *prev, *next; 109 | 110 | struct mode_mappings maps; 111 | }; 112 | 113 | struct virtual_controller { 114 | int uinput_fd; 115 | int keyboardmouse_fd; 116 | int gamepad_fd; 117 | int slot_number; 118 | char* slot_name; 119 | int has_wiimote; 120 | int has_board; 121 | enum SLOT_TYPE {SLOT_KEYBOARDMOUSE,SLOT_GAMEPAD} type; 122 | struct mode_mappings* slot_specific_mappings; 123 | 124 | struct wii_device_list dev_list; 125 | }; 126 | 127 | 128 | struct wiimoteglue_state { 129 | struct udev_monitor *monitor; 130 | struct virtual_controller* slots; 131 | int num_slots; 132 | 133 | int virtual_keyboardmouse_fd; /*Handy enough to keep around*/ 134 | 135 | int epfd; 136 | int keep_looping; 137 | int load_lines; /*how many lines of loaded files have we processed? */ 138 | int dev_count; /*simple counter for making identifiers*/ 139 | int ignore_pro; /*ignore Wii U Pro Controllers?*/ 140 | int set_leds; /*Should we try changing controlle LEDs?*/ 141 | 142 | struct wii_device_list dev_list; 143 | struct map_list head_map; 144 | }; 145 | 146 | int * KEEP_LOOPING; //Sprinkle around some checks to let signals interrupt. 147 | 148 | enum axis_entries { 149 | AXIS_CODE, 150 | AXIS_SCALE, 151 | }; 152 | 153 | enum accel_axis { 154 | WG_ACCELX = 0, 155 | WG_ACCELY, 156 | WG_ACCELZ, 157 | WG_N_ACCELX, 158 | WG_N_ACCELY, 159 | WG_N_ACCELZ, 160 | }; 161 | 162 | enum stick_axis { 163 | WG_LEFT_X, 164 | WG_LEFT_Y, 165 | WG_RIGHT_X, 166 | WG_RIGHT_Y, 167 | WG_N_X, 168 | WG_N_Y, 169 | }; 170 | 171 | enum IR_axis { 172 | WG_IR_X, 173 | WG_IR_Y, 174 | }; 175 | 176 | enum bal_axis { 177 | WG_BAL_FL, 178 | WG_BAL_FR, 179 | WG_BAL_BL, 180 | WG_BAL_BR, 181 | WG_BAL_X, 182 | WG_BAL_Y 183 | }; 184 | 185 | char* try_to_find_uinput(); 186 | int wiimoteglue_uinput_close(int num_slots, struct virtual_controller slots[]); 187 | int wiimoteglue_uinput_init(int num_slots, struct virtual_controller slots[], char* uinput_path); 188 | 189 | int wiimoteglue_udev_monitor_init(struct udev **udev, struct udev_monitor **monitor, int *mon_fd); 190 | int wiimoteglue_udev_handle_event(struct wiimoteglue_state* state); 191 | 192 | int wiimoteglue_epoll_init(int *epfd); 193 | int wiimoteglue_epoll_watch_monitor(int epfd, int mon_fd, void *monitor); 194 | int wiimoteglue_epoll_watch_wiimote(int epfd, struct wii_device *device); 195 | int wiimoteglue_epoll_watch_stdin(struct wiimoteglue_state* state, int epfd); 196 | void wiimoteglue_epoll_loop(int epfd, struct wiimoteglue_state *state); 197 | 198 | int wiimoteglue_load_command_file(struct wiimoteglue_state *state, char *filename); 199 | int wiimoteglue_handle_input(struct wiimoteglue_state *state, int file); 200 | 201 | int wiimoteglue_update_wiimote_ifaces(struct wii_device *dev); 202 | int wiimoteglue_handle_wii_event(struct wiimoteglue_state *state, struct wii_device *dev); 203 | 204 | struct virtual_controller* find_open_slot(struct wiimoteglue_state *state, int dev_type); 205 | struct virtual_controller* lookup_slot(struct wiimoteglue_state* state, char* name); 206 | 207 | int wiimoteglue_compute_all_device_maps(struct wiimoteglue_state* state, struct wii_device_list *devlist); 208 | int compute_device_map(struct wiimoteglue_state* state, struct wii_device *devlist); 209 | struct mode_mappings* lookup_mappings(struct wiimoteglue_state* state, char* map_name); 210 | struct map_list* create_mappings(struct wiimoteglue_state *state, char *name); 211 | 212 | int * get_input_key(char *key_name, int button_map[]); 213 | int * get_input_axis(char *axis_name, struct event_map *map); 214 | int get_output_key(char *key_name); 215 | int get_output_axis(char *axis_name); 216 | 217 | #endif 218 | -------------------------------------------------------------------------------- /src/device_management.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "wiimoteglue.h" 8 | 9 | /*This logic was a bit too ugly 10 | *to place in the other files, 11 | *so here it is. 12 | */ 13 | 14 | struct wii_device_list* new_wii_device(struct wiimoteglue_state *state, char* uniq) { 15 | struct wii_device_list *list_node = calloc(1,sizeof(struct wii_device_list)); 16 | struct wii_device *dev = calloc(1,sizeof(struct wii_device)); 17 | list_node->dev = dev; 18 | dev->main_list = list_node; 19 | dev->slot_list = calloc(1,sizeof(struct wii_device_list)); 20 | dev->slot_list->dev = dev; 21 | 22 | dev->bluetooth_addr = malloc(18*sizeof(char)); 23 | strncpy(dev->bluetooth_addr, uniq, 17); 24 | dev->bluetooth_addr[17] = '\0'; 25 | 26 | dev->id = calloc(WG_MAX_NAME_SIZE,sizeof(char)); 27 | snprintf(dev->id,WG_MAX_NAME_SIZE,"dev%d",++(state->dev_count)); 28 | 29 | dev->original_leds[0] = -2; 30 | dev->type = UNKNOWN; 31 | 32 | printf("\tid: %s\n\taddress %s\n",dev->id, dev->bluetooth_addr); 33 | 34 | list_node->next = &state->dev_list; 35 | list_node->prev = state->dev_list.prev; 36 | 37 | if (list_node->next != NULL) 38 | list_node->next->prev = list_node; 39 | 40 | if (list_node->prev != NULL) 41 | list_node->prev->next = list_node; 42 | 43 | return list_node; 44 | } 45 | 46 | int add_wii_device(struct wiimoteglue_state *state, struct udev_device* udev) { 47 | 48 | 49 | char* uniq = udev_device_get_property_value(udev, "HID_UNIQ"); 50 | 51 | struct wii_device *dev = lookup_device(&state->dev_list,uniq); 52 | 53 | if (dev == NULL) { 54 | 55 | struct wii_device_list* node = new_wii_device(state,uniq); 56 | node->dev->udev = udev; 57 | dev = node->dev; 58 | 59 | 60 | } else { 61 | 62 | udev_device_unref(dev->udev); 63 | dev->udev = udev; 64 | printf("\tid: %s\n\taddress %s\n",dev->id, dev->bluetooth_addr); 65 | } 66 | 67 | open_wii_device(state, dev); 68 | remove_device_from_slot(dev); 69 | 70 | if (dev->slot == NULL) { 71 | auto_assign_slot(state, dev); 72 | } 73 | 74 | if (dev->slot == NULL) { 75 | close_wii_device(state,dev); 76 | } 77 | 78 | return 0; 79 | } 80 | 81 | 82 | 83 | int open_wii_device(struct wiimoteglue_state *state, struct wii_device* dev) { 84 | if (dev->xwii != NULL) { 85 | return 0; //Already open. 86 | } 87 | 88 | if (dev->udev == NULL) { 89 | return -1; //Not even connected. 90 | } 91 | 92 | int i; 93 | struct xwii_iface *wiidev; 94 | char* syspath = udev_device_get_syspath(dev->udev); 95 | if (syspath == NULL) 96 | return -1; 97 | xwii_iface_new(&wiidev,syspath); 98 | xwii_iface_watch(wiidev,true); 99 | xwii_iface_open(wiidev, XWII_IFACE_WRITABLE | (XWII_IFACE_ALL ^ XWII_IFACE_ACCEL ^ XWII_IFACE_IR ^ XWII_IFACE_MOTION_PLUS)); 100 | if (!(xwii_iface_available(wiidev) & (XWII_IFACE_CORE | XWII_IFACE_PRO_CONTROLLER | XWII_IFACE_BALANCE_BOARD))) { 101 | printf("Tried to open a non-wiimote device...\n"); 102 | printf("Or we didn't have permission on the event devices?\n"); 103 | printf("You might need to add a udev rule to give permission.\n"); 104 | xwii_iface_unref(wiidev); 105 | return -1; 106 | } 107 | 108 | dev->xwii = wiidev; 109 | dev->ifaces = xwii_iface_opened(wiidev); 110 | 111 | if (state->ignore_pro && (dev->ifaces & XWII_IFACE_PRO_CONTROLLER)) { 112 | xwii_iface_unref(wiidev); 113 | dev->xwii = NULL; 114 | return 0; 115 | } 116 | 117 | 118 | 119 | dev->type = REMOTE; 120 | if (dev->ifaces & XWII_IFACE_BALANCE_BOARD) { 121 | dev->type = BALANCE; 122 | } 123 | if (dev->ifaces & XWII_IFACE_PRO_CONTROLLER) { 124 | dev->type = PRO; 125 | } 126 | 127 | dev->fd = xwii_iface_get_fd(wiidev); 128 | wiimoteglue_epoll_watch_wiimote(state->epfd, dev); 129 | 130 | 131 | 132 | compute_device_map(state,dev); 133 | 134 | if (dev->map->accel_active) { 135 | xwii_iface_open(wiidev,XWII_IFACE_ACCEL); 136 | } else { 137 | xwii_iface_close(wiidev,XWII_IFACE_ACCEL); 138 | } 139 | 140 | if (dev->map->IR_count) { 141 | xwii_iface_open(wiidev,XWII_IFACE_IR); 142 | } else { 143 | xwii_iface_close(wiidev,XWII_IFACE_IR); 144 | } 145 | 146 | /*LEDs only checked after opening, 147 | *and we want to store the state 148 | *only on the very initial opening.*/ 149 | if (dev->original_leds[0] == -2) 150 | store_led_state(state,dev); 151 | 152 | return 0; 153 | 154 | } 155 | 156 | int auto_assign_slot(struct wiimoteglue_state* state, struct wii_device *dev) { 157 | 158 | 159 | 160 | if (state->num_slots > 0) { 161 | struct virtual_controller *slot = find_open_slot(state,dev->type); 162 | add_device_to_slot(state,dev,slot); 163 | } else { 164 | add_device_to_slot(state,dev,&state->slots[0]); 165 | /*If the user has no virtual gamepads, 166 | *they likely want devices to automatically 167 | *go to the keyboardmouse 168 | */ 169 | } 170 | 171 | 172 | 173 | if (dev->slot == NULL) { 174 | if (dev->type == BALANCE) { 175 | printf("Balance board detected, but there are no open slots\n"); 176 | } else { 177 | printf("Controller detected, but there are no open slots\n"); 178 | } 179 | close_wii_device(state,dev); 180 | return 0; 181 | } 182 | 183 | 184 | if (dev->type == BALANCE) { 185 | printf("Balance Board added to slot %s\n",dev->slot->slot_name); 186 | } else { 187 | printf("Controller added to slot %s\n",dev->slot->slot_name); 188 | } 189 | 190 | return 0; 191 | } 192 | 193 | int forget_wii_device(struct wiimoteglue_state* state, struct wii_device *dev) { 194 | 195 | if (dev == NULL) return -1; 196 | if (state->set_leds) { 197 | open_wii_device(state,dev); 198 | set_led_state(state,dev,dev->original_leds); 199 | } 200 | if (dev->xwii != NULL) close_wii_device(state,dev); 201 | 202 | struct wii_device_list *list = dev->main_list; 203 | if (list->prev) { 204 | list->prev->next = list->next; 205 | } 206 | if (list->next) { 207 | list->next->prev = list->prev; 208 | } 209 | 210 | if (dev->id != NULL) { 211 | free(dev->id); 212 | } 213 | if (dev->bluetooth_addr != NULL) { 214 | free(dev->bluetooth_addr); 215 | } 216 | 217 | udev_device_unref(dev->udev); 218 | free(dev->slot_list); 219 | free(dev); 220 | free(list); 221 | return 0; 222 | } 223 | 224 | int close_wii_device(struct wiimoteglue_state* state, struct wii_device *dev) { 225 | if (dev->xwii == NULL) { 226 | return 0; //Already closed. 227 | } 228 | printf("Controller %s (%s) has been closed.\n",dev->id,dev->bluetooth_addr); 229 | 230 | 231 | close(dev->fd); 232 | 233 | xwii_iface_unref(dev->xwii); 234 | dev->xwii = NULL; 235 | if (dev->slot != NULL) { 236 | printf("(It was assigned slot %s)\n",dev->slot->slot_name); 237 | remove_device_from_slot(dev); 238 | } 239 | 240 | return 0; 241 | } 242 | 243 | int set_device_specific_mappings(struct wii_device *dev, struct mode_mappings *maps) { 244 | if (dev == NULL) 245 | return -1; 246 | 247 | if (dev->dev_specific_mappings != NULL) 248 | mappings_unref(dev->dev_specific_mappings); 249 | 250 | dev->dev_specific_mappings = maps; 251 | 252 | if (maps != NULL) 253 | mappings_ref(maps); 254 | 255 | return 0; 256 | 257 | } 258 | 259 | int store_led_state(struct wiimoteglue_state* state, struct wii_device *dev) { 260 | if (dev == NULL || dev->xwii == NULL) 261 | return -1; 262 | if (state->set_leds == 0 || dev->type == BALANCE) 263 | return 0; /*do nothing*/ 264 | /*This code will have to change 265 | *if there is ever a wiimote with 266 | *more than 4 LEDs. 267 | */ 268 | int i; 269 | int ret; 270 | int okay = 0; 271 | for (i = 1; i <= 4; i++) { 272 | ret = xwii_iface_get_led(dev->xwii,XWII_LED(i),&dev->original_leds[i-1]); 273 | if (ret < 0) { 274 | dev->original_leds[i-1] = -1; 275 | okay = -1; 276 | } 277 | } 278 | return okay; 279 | } 280 | 281 | int set_led_state(struct wiimoteglue_state* state, struct wii_device *dev, bool leds[]) { 282 | /*This code will have to change 283 | *if there is ever a wiimote with 284 | *more than 4 LEDs. 285 | */ 286 | 287 | if (dev == NULL || leds == NULL) 288 | return -1; 289 | if (dev->xwii == NULL) 290 | return -2; /*this controller is closed, but otherwise okay.*/ 291 | if (state->set_leds == 0 || dev->type == BALANCE) 292 | return 0; /*do nothing*/ 293 | int i; 294 | int ret; 295 | int okay = 0; 296 | 297 | for (i = 1; i <= 4; i++) { 298 | if (leds[i-1] < 0) 299 | return -1; 300 | /*if anything seems fishy, bail out. 301 | *We really don't want to end up with 302 | *a device connected but with all 4 303 | *leds off. 304 | */ 305 | } 306 | 307 | for (i = 1; i <= 4; i++) { 308 | ret = xwii_iface_set_led(dev->xwii,XWII_LED(i),leds[i-1]); 309 | if (ret < 0) { 310 | okay = -1; 311 | } 312 | } 313 | return okay; 314 | } -------------------------------------------------------------------------------- /maps/demo_readme: -------------------------------------------------------------------------------- 1 | #This is a sample file to help demonstrate WiimoteGlue 2 | #Any of these commands can be entered on STDIN, 3 | #or loaded from a file. 4 | #Clearly the "#" lets you make comments. 5 | 6 | #This demonstration is still a bit confusing... 7 | #It needs some work! 8 | 9 | ################################################ 10 | # Basics of mapping buttons in different modes # 11 | ################################################ 12 | 13 | #WiimoteGlue works under a system of modes. 14 | #Each mode has its own control mapping. 15 | 16 | #The map command sets control mappings, it has this format: 17 | # map 18 | 19 | 20 | map wiimote up left 21 | map wiimote left down 22 | map wiimote right up 23 | map wiimote down right 24 | 25 | #The above commands have mapped the wiimote dpad to the virtual dpad 26 | #when no extension is present. However, it is mapped "sideways". 27 | #This is desirable for holding the wiimote like an NES controller. 28 | 29 | map nunchuk up up 30 | map nunchuk down down 31 | map nunchuk left left 32 | map nunchuk right right 33 | 34 | #the above commands map the dpad to a virtual dpad when 35 | #a nunchuk is plugged in. 36 | #The word nunchuk above refers to 37 | #"do this when the nunchuk is plugged in" 38 | #Note that "up" still refers to the dpad, which is 39 | #not on the nunchuk, it is on the wiimote. 40 | 41 | #Now when a nunchuk is plugged in, the dpad will be mapped 42 | #"normally", but as soon as you remove the nunchuk, 43 | #the dpad will switch to the sideways mapping, without 44 | #any extra effort. Pretty handy, eh? 45 | 46 | #Let's add some other buttons: 47 | 48 | map wiimote a south 49 | map wiimote b east 50 | map nunchuk b tr2 51 | map nunchuk a south 52 | 53 | #Now when the wiimote is alone, the B button acts like 54 | #a face button (east). Once the nunchuk is plugged in, 55 | #the B button becomes the right trigger. 56 | #[Reminder: Many games view "east", the rightmost button, 57 | # as a "cancel" or "go back" button"] 58 | 59 | 60 | #in both modes, the "A" button on the wiimote was 61 | #maped to "south", the primary action button 62 | #on the virtual gamepad. 63 | 64 | #Hopefully the usefulness is becoming clear. 65 | #There is one other mode, "classic". It used when either 66 | #a classic controller is plugged in, or for the Wii U pro 67 | #controller. 68 | 69 | 70 | #you can also map the accelerometers based on mode 71 | 72 | map wiimote accely left_x invert 73 | 74 | #The wiimotes y-accelerometer is now mapped 75 | #to the x-axis of the left thumbstick on a 76 | #virtual gamepad. 77 | # 78 | #This particular setup is for tilting a horizontal wiimote 79 | #left and right. Notice the optional "invert" at the end 80 | #to reverse the direction. 81 | # 82 | #However, even when mapped, the accelerometers are off 83 | #by default 84 | 85 | enable wiimote accel 86 | 87 | #"disable wiimote accel" to turn them off 88 | 89 | #Note that wiimote here refers to the mode, not the device. 90 | #"enable nunchuk accel" would activate the wiimote (and nunchuk) 91 | #accelerometers when a nunchuk is plugged in. 92 | 93 | #"ir" is another feature that is off by default. 94 | 95 | enable wiimote ir 96 | disable wiimote ir 97 | 98 | #Why would we want these disabled? They use up batteries! 99 | #When WiimoteGlue switches to mode with one of these 100 | #features disabled, the appropriate interfaces are closed 101 | #and the wiimote batteries are saved. 102 | 103 | #Instead of specifying each mode, you can use "all" 104 | #(later map commands can change this for a specific mapping) 105 | 106 | map all home mode 107 | 108 | #now all three modes (wiimote,nunchuk,classic) 109 | #have home set to mode. 110 | #[Reminder: "mode" is the generic name for those special 111 | # buttons found often in the center of a controller, 112 | # such as the Xbox guide button.] 113 | 114 | 115 | 116 | #use "help" for all commands. 117 | 118 | #use "events" to see all recongized event names 119 | # for use with the "map" command. 120 | 121 | #similarly, "features" reminds you about the recognized 122 | # features to enable/disable. 123 | 124 | #use "modes" to see the different mode names. 125 | 126 | ################# 127 | # Saving Setups # 128 | ################# 129 | 130 | #At the moment, you'll need to create a text file 131 | #with all the various commands used, each on 132 | #their own line, much like this file. 133 | 134 | #load 135 | 136 | #That "load" command will read the file line by line and 137 | #run the commands inside. 138 | 139 | #Commands are handled identically, whether loaded 140 | #from a file, or submitted to WiimoteGlue directly. 141 | 142 | ############################## 143 | # Changing Controller Slots # 144 | ############################## 145 | 146 | #Want to move a device to a different slot? 147 | 148 | assign 2 149 | 150 | #This will assign the device with ID "" to slot #2. 151 | #Use "list devices" to see the device IDs. 152 | 153 | #You can also use the lowercase bluetooth address in place 154 | #of the device id 155 | 156 | ############################## 157 | # Keyboard and Mouse Mapping # 158 | ############################## 159 | 160 | #WiimoteGlue also lets you map wiimote inputs to a fake 161 | #keyboard and mouse. However, it takes a little extra work. 162 | # 163 | #In order to have the fake devices be detected correctly, 164 | #we need to separate our fake keyboard from our fake gamepads. 165 | # 166 | #There are two ways to tell WiimoteGlue you'd like to use 167 | #the fake keyboard/mouse. 168 | 169 | #Option 1: Assign a device straight to the fake keyboard. 170 | #-------------------------------------------------------- 171 | 172 | assign keyboardmouse 173 | 174 | #Where is a device ID or address, like in the 175 | #previous section 176 | 177 | #Option 2: Change a slot to be a keyboard instead of a gamepad. 178 | #-------------------------------------------------------------- 179 | 180 | slot 1 keyboardmouse 181 | 182 | #Now slot #1 is a fake keyboard instead of a fake gamepad. 183 | #Any devices assigned to this slot will automatically 184 | #be able to send keyboard or mouse events. 185 | 186 | #The keyboard/mouse mapping 187 | #-------------------------- 188 | 189 | #The fake keyboard maintains its own mapping, and the mapping 190 | #has all three modes (wiimote/nunchuk/classic) too. 191 | # 192 | #This is nice, since keyboard events are useless for fake 193 | #gamepads, and vice versa. 194 | # 195 | #but how do we change these mappings? 196 | #The "map" command has an optional second parameter 197 | #specifying the mapping as well as the mode we'd like 198 | #to change. When not present, it defaults to "gamepad" 199 | 200 | map nunchuk b tr2 201 | map gamepad nunchuk b tr2 202 | 203 | #The two above commands are identical, and they change 204 | #the mapping of the B button on the wiimote to TR2 205 | #when the nunchuk is plugged in. 206 | 207 | 208 | map keyboardmouse all b right_click 209 | map keyboardmouse wiimote a key_leftshift 210 | 211 | #these change the keyboardmouse mapping, which is used 212 | #if a device is assigned to the keyboardmouse slot, or 213 | #a slot that has been changed to a fake keyboard/mouse. 214 | 215 | #Note that although the mapping name is optional, 216 | #(defaulting to "gamepad") 217 | #The mode name is not optional. You must specify 218 | #wiimote, nunchuk, classic, or all 219 | 220 | #WiimoteGlue starts with two named mappings: 221 | #keyboardmouse and gamepad 222 | 223 | list mappings 224 | 225 | #This will list all the mappings. 226 | 227 | ####################### 228 | ####################### 229 | ## ADVANCED FEATURES ## 230 | ####################### 231 | ####################### 232 | 233 | 234 | ######################### 235 | # Creating new mappings # 236 | ######################### 237 | 238 | new mapping MyMap 239 | 240 | #This creates a new named mapping, with the 241 | #name "MyMap". It starts out with no buttons 242 | #mapped at all. 243 | 244 | #Why might you want a new mapping? 245 | #Perhaps player 2 wants a different mapping. 246 | #Maybe you want to create a control panel 247 | #of several wiimotes, with each button 248 | #sending a unique event. 249 | # 250 | #You could even create a new named mapping 251 | #for each game/application you use, and 252 | #set WiimoteGlue to read them all in when 253 | #starting up. 254 | 255 | #For now, you'll have to assign the new mappings 256 | #to use them. 257 | 258 | slot 1 mapping MyMap 259 | 260 | #Now slot 1 will use the MyMap mapping. 261 | 262 | new mapping OtherMap 263 | 264 | device dev1 mapping OtherMap 265 | 266 | #Now dev1 will use the MyMap mapping. 267 | #(Replace dev1 with for other devices...) 268 | 269 | #Note that device-specific mappings take 270 | #priority. If dev1 was assigned to 271 | #slot 1, OtherMap will be used for dev1 272 | #despite slot 1 using MyMap. 273 | 274 | #################### 275 | # Balance Board # 276 | #################### 277 | 278 | #A Wii balance board will be assigned to the first 279 | #slot that doesn't have a board already. 280 | 281 | #This means a slot can have both controller inputs 282 | #and board inputs combined. 283 | 284 | #A balance board is considered to ALWAYS be in the 285 | #"wiimote" mode. 286 | 287 | #################### 288 | # Device renaming # 289 | #################### 290 | 291 | #Don't like the look of "dev1"? 292 | 293 | device dev1 rename NewName 294 | 295 | #Note that bluetooth addresses can always be 296 | #used to specify a device, no matter what 297 | #its name changed to. 298 | 299 | #As a special case, the following command 300 | #works even before a device is connected: 301 | 302 | device rename 303 | 304 | #This will create a listing for that address 305 | #with the given name. 306 | 307 | #Now you can set up all sorts of settings for 308 | #that device just like it was connected, and 309 | #when it shows up, it will be matched up. 310 | 311 | #For example, you might want have a file at 312 | #startup for WiimoteGlue that renames all your 313 | #known controller addresses to more friendly 314 | #distinctive names. 315 | 316 | 317 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | 14 | #include "wiimoteglue.h" 15 | 16 | 17 | 18 | 19 | void signal_handler(int signum) { 20 | printf("Signal received, attempting to clean up.\n"); 21 | *KEEP_LOOPING = 0; 22 | /*Technically could segfault if we receive a signal 23 | *before the first line of main() where this 24 | *pointer is set. But in that case, 25 | *is segfaulting really such a crime? 26 | */ 27 | } 28 | 29 | struct commandline_options { 30 | /*Many of these are wishful thinking at the moment*/ 31 | char* file_to_load; 32 | int number_of_slots; 33 | int no_keyboardmouse; 34 | int check_for_existing_wiimotes; 35 | int monitor_for_new_wiimotes; 36 | int ignore_pro; 37 | int no_set_leds; 38 | char* virt_gamepad_name; 39 | char* virt_keyboardmouse_name; 40 | char* uinput_path; 41 | } options; 42 | 43 | 44 | int init_mappings(struct mode_mappings *maps, char* name); 45 | int handle_arguments(struct commandline_options *options, int argc, char *argv[]); 46 | 47 | int main(int argc, char *argv[]) { 48 | struct udev *udev = NULL; 49 | struct wiimoteglue_state state; 50 | KEEP_LOOPING = &state.keep_looping; 51 | memset(&state, 0, sizeof(state)); 52 | memset(&options, 0, sizeof(options)); 53 | int monitor_fd; 54 | int epfd; 55 | int ret; 56 | options.number_of_slots = -1; /*initialize so we know it has been set*/ 57 | options.monitor_for_new_wiimotes = 1; /*sensible default values*/ 58 | options.check_for_existing_wiimotes = 1; 59 | ret = handle_arguments(&options, argc, argv); 60 | if (ret == 1) { 61 | return 0; /*arguments just said to print out help or version info.*/ 62 | } 63 | if (ret < 0) { 64 | return ret; 65 | } 66 | printf("WiimoteGlue Version %s\n\n",WIIMOTEGLUE_VERSION); 67 | 68 | if (!options.no_set_leds) 69 | state.set_leds = 1; 70 | 71 | if (options.ignore_pro) { 72 | printf("Wii U Pro controllers will be ignored.\n"); 73 | state.ignore_pro = 1; 74 | } 75 | 76 | 77 | if (options.uinput_path == NULL) { 78 | printf("Trying to find uinput... "); 79 | options.uinput_path = try_to_find_uinput(); 80 | if (options.uinput_path == NULL) { 81 | printf("not found.\n"); 82 | printf("Use --uinput-path to specify its location.\n"); 83 | return -1; 84 | } else { 85 | printf("%s\n",options.uinput_path); 86 | } 87 | } 88 | 89 | 90 | state.num_slots = 4; 91 | if (options.number_of_slots != -1) { 92 | state.num_slots = options.number_of_slots; 93 | } 94 | 95 | /*add one for the keyboardmouse spot*/ 96 | state.slots = calloc((1+state.num_slots),sizeof(struct virtual_controller)); 97 | 98 | printf("Creating %d gamepad(s) and a keyboard/mouse...",state.num_slots); 99 | fflush(stdout); 100 | int i; 101 | 102 | 103 | 104 | ret = wiimoteglue_uinput_init(state.num_slots, state.slots,options.uinput_path); 105 | 106 | if (ret) { 107 | printf("\nError in creating uinput devices, aborting.\nCheck the permissions.\n"); 108 | wiimoteglue_uinput_close(state.num_slots,state.slots); 109 | return -1; 110 | } else { 111 | printf(" okay.\n"); 112 | } 113 | 114 | state.virtual_keyboardmouse_fd = state.slots[0].uinput_fd; 115 | 116 | state.head_map.next = &state.head_map; 117 | state.head_map.prev = &state.head_map; 118 | init_gamepad_mappings(&state.head_map.maps,"gamepad"); 119 | 120 | struct map_list *keymouse = create_mappings(&state,"keyboardmouse"); 121 | init_keyboardmouse_mappings(&keymouse->maps); 122 | set_slot_specific_mappings(&state.slots[0],&keymouse->maps); 123 | 124 | 125 | /*The device list is cyclic*/ 126 | state.dev_list.next = &state.dev_list; 127 | state.dev_list.prev = &state.dev_list; 128 | 129 | 130 | if (options.monitor_for_new_wiimotes) { 131 | printf("Starting udev monitor..."); 132 | ret = wiimoteglue_udev_monitor_init(&udev, &state.monitor, &monitor_fd); 133 | if (ret) { 134 | printf("\nError in creating udev monitor. No additional controllers will be detected."); 135 | } else { 136 | printf(" okay.\n"); 137 | } 138 | } else { 139 | printf("No monitor started; no new devices will be found.\n"); 140 | } 141 | 142 | 143 | printf("KB name: %s\n",keymouse->maps.name); 144 | 145 | 146 | wiimoteglue_epoll_init(&epfd); 147 | if (options.monitor_for_new_wiimotes) 148 | wiimoteglue_epoll_watch_monitor(epfd, monitor_fd, state.monitor); 149 | 150 | wiimoteglue_epoll_watch_stdin(&state, epfd); 151 | 152 | state.epfd = epfd; 153 | 154 | 155 | //Start forwarding input events. 156 | 157 | //Process user input. 158 | state.keep_looping = 1; 159 | 160 | state.dev_count = 0; 161 | 162 | signal(SIGINT, signal_handler); 163 | signal(SIGTERM, signal_handler); 164 | signal(SIGHUP, signal_handler); 165 | if (options.file_to_load != NULL) { 166 | printf("\n"); 167 | wiimoteglue_load_command_file(&state,options.file_to_load); 168 | printf("\n"); 169 | } 170 | 171 | if (options.check_for_existing_wiimotes) { 172 | printf("Looking for already connected devices...\n"); 173 | ret = wiimoteglue_udev_enumerate(&state, &udev); 174 | if (ret) { 175 | printf("\nError in udev enumeration. No existing controllers will be found.\n"); 176 | } 177 | } else { 178 | printf("Any currently connected wiimotes will be ignored.\n"); 179 | } 180 | 181 | if (options.monitor_for_new_wiimotes) 182 | printf("\nWiimoteGlue is now running and waiting for Wiimotes.\n"); 183 | printf("Enter \"help\" for available commands.\n>>"); 184 | fflush(stdout); 185 | wiimoteglue_epoll_loop(epfd, &state); 186 | 187 | 188 | 189 | printf("Shutting down...\n"); 190 | 191 | 192 | for (i = 0; i <= state.num_slots; i++) 193 | change_slot_type(&state,&state.slots[i],SLOT_GAMEPAD); 194 | 195 | struct wii_device_list *list_node = state.dev_list.next; 196 | while (list_node != &state.dev_list && list_node != NULL) { 197 | 198 | struct wii_device_list *next = list_node->next; 199 | 200 | close_wii_device(&state,list_node->dev); 201 | forget_wii_device(&state,list_node->dev); 202 | 203 | list_node = next; 204 | } 205 | 206 | struct map_list *mlist_node; 207 | mlist_node = state.head_map.next; 208 | while (mlist_node != NULL && mlist_node != &state.head_map) { 209 | struct map_list *next = mlist_node->next; 210 | free(mlist_node->maps.name); 211 | free(mlist_node); 212 | mlist_node = next; 213 | } 214 | 215 | 216 | 217 | wiimoteglue_uinput_close(state.num_slots, state.slots); 218 | 219 | free(state.slots); 220 | 221 | 222 | if (options.monitor_for_new_wiimotes) 223 | udev_monitor_unref(state.monitor); 224 | 225 | if (udev != NULL) 226 | udev_unref(udev); 227 | 228 | return 0; 229 | } 230 | 231 | int handle_arguments(struct commandline_options *options, int argc, char *argv[]) { 232 | char* invoke = argv[0]; 233 | argc--; 234 | argv++; 235 | /*skip the program name*/ 236 | while (argc > 0) { 237 | if (strcmp("--help",argv[0]) == 0 || strcmp("-h",argv[0]) == 0) { 238 | printf("WiimoteGlue Version %s\n",WIIMOTEGLUE_VERSION); 239 | printf("\t%s [arguments]\n\n",invoke); 240 | printf("Recognized Arguments:\n"); 241 | printf(" -h, --help\t\t\tShow help text\n"); 242 | printf(" -v, --version\t\t\tShow version string\n"); 243 | printf(" -d, --dir \t\tSet the directory for command files\n"); 244 | printf(" -l, --load-file \tLoad the file at start-up\n"); 245 | printf(" -n, --num-pads \tNumber of fake gamepad slots to create\n"); 246 | printf(" --uinput-path\t\tSpecify path to uinput\n"); 247 | printf(" --no-enumerate\t\tDon't enumerate connected devices\n"); 248 | printf(" --no-monitor\t\tDon't listen for new devices.\n"); 249 | printf(" --ignore-pro\t\tIgnore Wii U Pro controllers\n"); 250 | printf(" --no-set-leds\t\tDon't change controller LEDS\n"); 251 | return 1; 252 | } 253 | if (strcmp("--version",argv[0]) == 0 || strcmp("-v",argv[0]) == 0) { 254 | printf("WiimoteGlue Version %s\n",WIIMOTEGLUE_VERSION); 255 | return 1; 256 | } 257 | if (strcmp("--load-file",argv[0]) == 0 || strcmp("-l",argv[0]) == 0) { 258 | if (argc < 2) { 259 | printf("Argument \"%s\" requires a filename to load.\n",argv[0]); 260 | return -1; 261 | } 262 | options->file_to_load = argv[1]; 263 | argc--; 264 | argv++; 265 | } else if (strcmp("--dir",argv[0]) == 0 || strcmp("-d",argv[0]) == 0) { 266 | if (argc < 2) { 267 | printf("Argument \"%s\" requires a directory.\n",argv[0]); 268 | return -1; 269 | } 270 | 271 | if (chdir(argv[1]) < 0) { 272 | printf("Could not switch to directory \"%s\"\n",argv[1]); 273 | perror("chdir"); 274 | return -1; 275 | } 276 | 277 | argc--; 278 | argv++; 279 | } else if (strcmp("--uinput-path",argv[0]) == 0) { 280 | if (argc < 2) { 281 | printf("Argument \"%s\" requires a path.\n",argv[0]); 282 | return -1; 283 | } 284 | 285 | options->uinput_path = argv[1]; 286 | 287 | argc--; 288 | argv++; 289 | } else if (strcmp("--num-pads",argv[0]) == 0 || strcmp("-n",argv[0]) == 0) { 290 | if (argc < 2) { 291 | printf("Argument \"%s\" requires a number.\n",argv[0]); 292 | return -1; 293 | } 294 | 295 | int num = argv[1][0] - '0'; /*HACK bad atoi*/ 296 | 297 | 298 | if (num < 0 || num > 9 || argv[1][0] == '\0' || argv[1][1] != '\0') { 299 | printf("Number of gamepad slots %d must be in range 0 to 9\n",num); 300 | return -1; 301 | } 302 | 303 | options->number_of_slots = num; 304 | 305 | argc--; 306 | argv++; 307 | } else if (strcmp("--ignore-pro",argv[0]) == 0) { 308 | options->ignore_pro = 1; 309 | } else if (strcmp("--no-set-leds",argv[0]) == 0) { 310 | options->no_set_leds = 1; 311 | } else if (strcmp("--no-enumerate",argv[0]) == 0) { 312 | options->check_for_existing_wiimotes = 0; 313 | } else if (strcmp("--no-monitor",argv[0]) == 0) { 314 | options->monitor_for_new_wiimotes = 0; 315 | } else { 316 | printf("Argument \"%s\" not recognized.\n",argv[0]); 317 | return -1; 318 | } 319 | 320 | argc--; 321 | argv++; 322 | } 323 | return 0; 324 | } 325 | 326 | 327 | 328 | -------------------------------------------------------------------------------- /src/process_xwiimote_events.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "wiimoteglue.h" 8 | 9 | /* This file uses the xwiimote library 10 | * for interacting with wiimotes. 11 | * It handles opening and closing interfaces 12 | * and translating wiimote events to gamepad events. 13 | * 14 | */ 15 | 16 | 17 | 18 | void handle_key(int uinput_fd, int button_map[], struct xwii_event_key *ev); 19 | void handle_nunchuk(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 20 | void handle_classic(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 21 | void handle_pro(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 22 | void handle_accel(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 23 | void handle_IR(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 24 | void handle_balance(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]); 25 | 26 | int wiimoteglue_update_all_wiimote_ifaces(struct wii_device_list *devlist) { 27 | if (devlist == NULL) 28 | return -1; 29 | 30 | struct wii_device_list* list_node = devlist->next; 31 | 32 | while (*KEEP_LOOPING && list_node != devlist && list_node != NULL) { 33 | 34 | struct wii_device* dev = list_node->dev; 35 | 36 | 37 | wiimoteglue_update_wiimote_ifaces(dev); 38 | 39 | list_node = list_node->next; 40 | 41 | } 42 | return 0; 43 | } 44 | 45 | int wiimoteglue_update_wiimote_ifaces(struct wii_device *dev) { 46 | if (dev != NULL && dev->xwii != NULL) { 47 | if (dev->map == NULL) { 48 | return -1; 49 | } 50 | 51 | if (dev->map->accel_active) { 52 | xwii_iface_open(dev->xwii,XWII_IFACE_ACCEL); 53 | } else { 54 | xwii_iface_close(dev->xwii,XWII_IFACE_ACCEL); 55 | } 56 | 57 | if (dev->map->IR_count) { 58 | xwii_iface_open(dev->xwii,XWII_IFACE_IR); 59 | } else { 60 | xwii_iface_close(dev->xwii,XWII_IFACE_IR); 61 | } 62 | } 63 | } 64 | 65 | int wiimoteglue_update_extensions(struct wiimoteglue_state *state, struct wii_device *dev) { 66 | xwii_iface_open(dev->xwii,XWII_IFACE_CLASSIC_CONTROLLER | XWII_IFACE_NUNCHUK | XWII_IFACE_PRO_CONTROLLER | XWII_IFACE_BALANCE_BOARD); 67 | dev->ifaces = xwii_iface_opened(dev->xwii); 68 | 69 | compute_device_map(state,dev); 70 | 71 | if (dev->map->accel_active) { 72 | xwii_iface_open(dev->xwii,XWII_IFACE_ACCEL); 73 | } else { 74 | xwii_iface_close(dev->xwii,XWII_IFACE_ACCEL); 75 | } 76 | 77 | if (dev->map->IR_count) { 78 | xwii_iface_open(dev->xwii,XWII_IFACE_IR); 79 | } else { 80 | xwii_iface_close(dev->xwii,XWII_IFACE_IR); 81 | } 82 | 83 | if (xwii_iface_available(dev->xwii) == 0 || dev->ifaces == 0) { 84 | //Controller removed. 85 | close_wii_device(state, dev); 86 | } 87 | 88 | return 0; 89 | } 90 | 91 | 92 | int wiimoteglue_handle_wii_event(struct wiimoteglue_state *state, struct wii_device *dev) { 93 | struct xwii_event ev; 94 | if (dev == NULL) { 95 | return -1; 96 | } 97 | 98 | int ret = xwii_iface_dispatch(dev->xwii,&ev,sizeof(ev)); 99 | if (dev->slot == NULL && ev.type != XWII_EVENT_GONE) { 100 | /*Just ignore this event, but be sure to read it to clear it*/ 101 | return -1; 102 | } 103 | 104 | if (ret < 0 && ret != -EAGAIN) { 105 | printf("Error reading controller. "); 106 | close_wii_device(dev); 107 | 108 | } else if (ret != -EAGAIN) { 109 | 110 | struct event_map* mapping; 111 | 112 | 113 | mapping = dev->map; 114 | 115 | switch(ev.type) { 116 | case XWII_EVENT_KEY: 117 | case XWII_EVENT_CLASSIC_CONTROLLER_KEY: 118 | case XWII_EVENT_PRO_CONTROLLER_KEY: 119 | case XWII_EVENT_NUNCHUK_KEY: 120 | handle_key(dev->slot->uinput_fd, mapping->button_map, &ev.v.key); 121 | break; 122 | case XWII_EVENT_CLASSIC_CONTROLLER_MOVE: 123 | handle_classic(dev->slot->uinput_fd, mapping, ev.v.abs); 124 | break; 125 | case XWII_EVENT_NUNCHUK_MOVE: 126 | handle_nunchuk(dev->slot->uinput_fd, mapping, ev.v.abs); 127 | break; 128 | case XWII_EVENT_PRO_CONTROLLER_MOVE: 129 | handle_pro(dev->slot->uinput_fd, mapping, ev.v.abs); 130 | break; 131 | case XWII_EVENT_ACCEL: 132 | handle_accel(dev->slot->uinput_fd, mapping, ev.v.abs); 133 | break; 134 | case XWII_EVENT_IR: 135 | handle_IR(dev->slot->uinput_fd, mapping, ev.v.abs); 136 | break; 137 | case XWII_EVENT_BALANCE_BOARD: 138 | handle_balance(dev->slot->uinput_fd, mapping, ev.v.abs); 139 | break; 140 | case XWII_EVENT_WATCH: 141 | case XWII_EVENT_GONE: 142 | wiimoteglue_update_extensions(state,dev); 143 | break; 144 | 145 | } 146 | } 147 | 148 | return 0; 149 | } 150 | 151 | void handle_key(int uinput_fd, int button_map[], struct xwii_event_key *ev) { 152 | struct input_event out; 153 | memset(&out,0,sizeof(out)); 154 | out.type = EV_KEY; 155 | out.code = button_map[ev->code]; 156 | out.value = ev->state; 157 | write(uinput_fd, &out, sizeof(out)); 158 | 159 | out.type = EV_SYN; 160 | out.code = SYN_REPORT; 161 | out.value = 0; 162 | write(uinput_fd, &out, sizeof(out)); 163 | } 164 | 165 | void handle_nunchuk(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 166 | struct input_event out; 167 | memset(&out,0,sizeof(out)); 168 | out.type = EV_ABS; 169 | out.code = map->stick_map[WG_N_X][AXIS_CODE]; 170 | out.value = ev[0].x * map->stick_map[WG_N_X][AXIS_SCALE]; 171 | write(uinput_fd, &out, sizeof(out)); 172 | out.code = map->stick_map[WG_N_Y][AXIS_CODE]; 173 | out.value = ev[0].y * map->stick_map[WG_N_Y][AXIS_SCALE]; 174 | write(uinput_fd, &out, sizeof(out)); 175 | 176 | out.type = EV_SYN; 177 | out.code = SYN_REPORT; 178 | out.value = 0; 179 | write(uinput_fd, &out, sizeof(out)); 180 | 181 | if (!map->accel_active) return; /*skip the accel values.*/ 182 | 183 | out.type = EV_ABS; 184 | out.code = map->accel_map[WG_N_ACCELX][AXIS_CODE]; 185 | out.value = ev[1].x * map->accel_map[WG_N_ACCELX][AXIS_SCALE]; 186 | write(uinput_fd, &out, sizeof(out)); 187 | out.code = map->accel_map[WG_N_ACCELY][AXIS_CODE]; 188 | out.value = ev[1].y * map->accel_map[WG_N_ACCELY][AXIS_SCALE]; 189 | write(uinput_fd, &out, sizeof(out)); 190 | out.code = map->accel_map[WG_N_ACCELZ][AXIS_CODE]; 191 | out.value = ev[1].z * map->accel_map[WG_N_ACCELZ][AXIS_SCALE]; 192 | write(uinput_fd, &out, sizeof(out)); 193 | 194 | out.type = EV_SYN; 195 | out.code = SYN_REPORT; 196 | out.value = 0; 197 | write(uinput_fd, &out, sizeof(out)); 198 | 199 | } 200 | void handle_classic(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 201 | struct input_event out; 202 | memset(&out,0,sizeof(out)); 203 | out.type = EV_ABS; 204 | out.code = map->stick_map[WG_LEFT_X][AXIS_CODE]; 205 | out.value = ev[0].x * map->stick_map[WG_LEFT_X][AXIS_SCALE]; 206 | write(uinput_fd, &out, sizeof(out)); 207 | out.code = map->stick_map[WG_LEFT_Y][AXIS_CODE]; 208 | out.value = ev[0].y * map->stick_map[WG_LEFT_Y][AXIS_SCALE]; 209 | write(uinput_fd, &out, sizeof(out)); 210 | out.code = map->stick_map[WG_RIGHT_X][AXIS_CODE]; 211 | out.value = ev[1].x * map->stick_map[WG_RIGHT_X][AXIS_SCALE]; 212 | write(uinput_fd, &out, sizeof(out)); 213 | out.code = map->stick_map[WG_RIGHT_Y][AXIS_CODE]; 214 | out.value = ev[1].y * map->stick_map[WG_RIGHT_Y][AXIS_SCALE]; 215 | write(uinput_fd, &out, sizeof(out)); 216 | 217 | out.type = EV_SYN; 218 | out.code = SYN_REPORT; 219 | out.value = 0; 220 | write(uinput_fd, &out, sizeof(out)); 221 | /*analog trigger values are ignored. 222 | *only the original classic controllers have them. 223 | */ 224 | } 225 | void handle_pro(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 226 | struct input_event out; 227 | memset(&out,0,sizeof(out)); 228 | out.type = EV_ABS; 229 | out.code = map->stick_map[WG_LEFT_X][AXIS_CODE]; 230 | out.value = ev[0].x * 32; 231 | write(uinput_fd, &out, sizeof(out)); 232 | out.code = map->stick_map[WG_LEFT_Y][AXIS_CODE]; 233 | out.value = ev[0].y * 32; 234 | write(uinput_fd, &out, sizeof(out)); 235 | out.code = map->stick_map[WG_RIGHT_X][AXIS_CODE]; 236 | out.value = ev[1].x * 32; 237 | write(uinput_fd, &out, sizeof(out)); 238 | out.code = map->stick_map[WG_RIGHT_Y][AXIS_CODE]; 239 | out.value = ev[1].y * 32; 240 | write(uinput_fd, &out, sizeof(out)); 241 | 242 | /*Wii U Pro has different axis limits, hardcoded above to 243 | * scale from ~1024 to 32,768, the reported scale of 244 | * the virtual gamepads. 245 | * This means the Wii U Pro does not support inverting 246 | * the axes! 247 | */ 248 | 249 | out.type = EV_SYN; 250 | out.code = SYN_REPORT; 251 | out.value = 0; 252 | write(uinput_fd, &out, sizeof(out)); 253 | 254 | } 255 | void handle_accel(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 256 | struct input_event out; 257 | memset(&out,0,sizeof(out)); 258 | out.type = EV_ABS; 259 | out.code = map->accel_map[WG_ACCELX][AXIS_CODE]; 260 | out.value = ev[0].x * map->accel_map[WG_ACCELX][AXIS_SCALE]; 261 | write(uinput_fd, &out, sizeof(out)); 262 | out.code = map->accel_map[WG_ACCELY][AXIS_CODE]; 263 | out.value = ev[0].y * map->accel_map[WG_ACCELY][AXIS_SCALE]; 264 | write(uinput_fd, &out, sizeof(out)); 265 | out.code = map->accel_map[WG_ACCELZ][AXIS_CODE]; 266 | out.value = ev[0].z * map->accel_map[WG_ACCELZ][AXIS_SCALE]; 267 | write(uinput_fd, &out, sizeof(out)); 268 | 269 | 270 | 271 | out.type = EV_SYN; 272 | out.code = SYN_REPORT; 273 | out.value = 0; 274 | write(uinput_fd, &out, sizeof(out)); 275 | } 276 | void handle_IR(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 277 | struct input_event out; 278 | memset(&out,0,sizeof(out)); 279 | out.type = EV_ABS; 280 | int num = 0; 281 | float x = 1023; 282 | float y = 1023; 283 | int i; 284 | for (i = 0; i < 4; i++) { 285 | int ir_x = ev[i].x; 286 | int ir_y = ev[i].y; 287 | if (ir_x < x && ir_x != 1023 && ir_x > 1) { 288 | x = ir_x; 289 | y = ir_y; 290 | num++; 291 | } 292 | } 293 | if (num != 0) { 294 | out.code = map->IR_map[WG_IR_X][AXIS_CODE]; 295 | out.value = (int) (-((x - 512) * map->IR_map[WG_IR_X][AXIS_SCALE])); 296 | write(uinput_fd, &out, sizeof(out)); 297 | out.code = map->IR_map[WG_IR_Y][AXIS_CODE]; 298 | out.value = (int) (((y - 380) * map->IR_map[WG_IR_Y][AXIS_SCALE])); 299 | write(uinput_fd, &out, sizeof(out)); 300 | } 301 | 302 | out.type = EV_SYN; 303 | out.code = SYN_REPORT; 304 | out.value = 0; 305 | write(uinput_fd, &out, sizeof(out)); 306 | } 307 | void handle_balance(int uinput_fd, struct event_map *map, struct xwii_event_abs ev[]) { 308 | struct input_event out; 309 | memset(&out,0,sizeof(out)); 310 | out.type = EV_ABS; 311 | int total = ev[0].x + ev[1].x + ev[2].x + ev[3].x; 312 | int left = ev[2].x + ev[3].x; 313 | int right = total - left; 314 | int front = ev[0].x + ev[2].x; 315 | int back = total - front; 316 | 317 | /*Beware: lots of constants from experimentation below!*/ 318 | 319 | float x = (right - left)/((total + 1)*0.7f); 320 | float y = (back - front)/((total + 1)*0.7f); 321 | 322 | if (total < 125) { 323 | x = 0; 324 | y = 0; 325 | } 326 | 327 | out.code = map->balance_map[WG_BAL_X][AXIS_CODE]; 328 | out.value = (int)(x * map->balance_map[WG_BAL_X][AXIS_SCALE]); 329 | write(uinput_fd, &out, sizeof(out)); 330 | 331 | out.code = map->balance_map[WG_BAL_Y][AXIS_CODE]; 332 | out.value = (int)(y * map->balance_map[WG_BAL_Y][AXIS_SCALE]); 333 | write(uinput_fd, &out, sizeof(out)); 334 | 335 | 336 | out.type = EV_SYN; 337 | out.code = SYN_REPORT; 338 | out.value = 0; 339 | write(uinput_fd, &out, sizeof(out)); 340 | } 341 | 342 | 343 | 344 | -------------------------------------------------------------------------------- /src/control_mappings.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "wiimoteglue.h" 4 | #include 5 | 6 | 7 | /*This file handles the data structures 8 | *used for storing control mappings. 9 | * 10 | *If you are looking for the code that 11 | *actually translates wiimote events, 12 | *look in process_xwiimote_events.c 13 | */ 14 | 15 | void mappings_ref(struct mode_mappings *maps); 16 | void mappings_unref(struct mode_mappings *maps); 17 | 18 | int compute_device_map(struct wiimoteglue_state* state, struct wii_device* dev) { 19 | if (dev == NULL) 20 | return -1; 21 | struct mode_mappings* maps = &state->head_map.maps; 22 | 23 | if (dev->slot != NULL && dev->slot->slot_specific_mappings != NULL) { 24 | maps = dev->slot->slot_specific_mappings; 25 | } 26 | 27 | if (dev->dev_specific_mappings != NULL) 28 | maps = dev->dev_specific_mappings; 29 | 30 | if (dev->ifaces & XWII_IFACE_NUNCHUK) { 31 | dev->map = &maps->mode_nunchuk; 32 | dev->mode = NUNCHUK; 33 | } else if (dev->ifaces & (XWII_IFACE_CLASSIC_CONTROLLER | XWII_IFACE_PRO_CONTROLLER)) { 34 | dev->map = &maps->mode_classic; 35 | dev->mode = CLASSIC; 36 | } else { 37 | dev->map = &maps->mode_no_ext; 38 | dev->mode = NO_EXT; 39 | } 40 | 41 | wiimoteglue_update_wiimote_ifaces(dev); 42 | 43 | return 0; 44 | 45 | } 46 | 47 | int wiimoteglue_compute_all_device_maps(struct wiimoteglue_state* state, struct wii_device_list *devlist) { 48 | if (devlist == NULL) { 49 | return -1; 50 | } 51 | 52 | struct wii_device_list* list_node = devlist->next; 53 | 54 | while (list_node != devlist && list_node != NULL) { 55 | struct wii_device* dev = list_node->dev; 56 | 57 | 58 | if (dev != NULL) { 59 | compute_device_map(state,dev); 60 | } 61 | 62 | 63 | 64 | list_node = list_node->next; 65 | } 66 | return 0; 67 | } 68 | 69 | int mode_name_check(char* mode_name) { 70 | if (mode_name == NULL) 71 | return -1; 72 | 73 | if (strcmp(mode_name,"all") == 0) 74 | return 0; 75 | if (strcmp(mode_name,"wiimote") == 0) 76 | return 1; 77 | if (strcmp(mode_name,"nunchuk") == 0) 78 | return 2; 79 | if (strcmp(mode_name,"classic") == 0) 80 | return 3; 81 | 82 | return -2; 83 | } 84 | 85 | struct mode_mappings* lookup_mappings(struct wiimoteglue_state* state, char* map_name) { 86 | if (map_name == NULL) 87 | return NULL; 88 | 89 | if (strncmp(map_name,state->head_map.maps.name,WG_MAX_NAME_SIZE) == 0) 90 | return &state->head_map.maps; 91 | struct map_list *list_node; 92 | list_node = state->head_map.next; 93 | for (; *KEEP_LOOPING && list_node != NULL && list_node != &state->head_map; list_node = list_node->next) { 94 | if (strncmp(map_name,list_node->maps.name,WG_MAX_NAME_SIZE) == 0) 95 | return &list_node->maps; 96 | } 97 | 98 | return NULL; 99 | } 100 | 101 | int copy_mappings(struct mode_mappings *dest, struct mode_mappings *src) { 102 | char *name = dest->name; 103 | memcpy(dest,src,sizeof(struct mode_mappings)); 104 | dest->name = name; 105 | return 0; 106 | } 107 | 108 | struct map_list* create_mappings(struct wiimoteglue_state *state, char *name) { 109 | if (name == NULL) 110 | return NULL; 111 | 112 | struct map_list *new_map = calloc(1,sizeof(struct map_list)); 113 | new_map->maps.name = calloc(WG_MAX_NAME_SIZE,sizeof(char)); 114 | strncpy(new_map->maps.name,name,WG_MAX_NAME_SIZE); 115 | 116 | new_map->next = &state->head_map; 117 | new_map->prev = state->head_map.prev; 118 | 119 | state->head_map.prev = new_map; 120 | new_map->prev->next = new_map; 121 | 122 | mappings_ref(&new_map->maps); 123 | 124 | init_blank_mappings(&new_map->maps); 125 | 126 | return new_map; 127 | 128 | } 129 | 130 | struct map_list * get_map_list_container(struct mode_mappings *maps) { 131 | /*ugly code for a quick 132 | *and dirty container_of 133 | */ 134 | struct map_list temp; 135 | const int offset = (void*)(&temp.maps) - (void*)(&temp); 136 | void *list_entry = (void*)maps - offset; 137 | 138 | return (struct map_list*)list_entry; 139 | } 140 | 141 | int forget_mapping(struct wiimoteglue_state *state, struct mode_mappings *maps) { 142 | if (maps == &state->head_map.maps || maps == state->slots[0].slot_specific_mappings) { 143 | printf("Cannot forget default mapping \"%s\"\n",maps->name); 144 | return -1; 145 | } 146 | 147 | /*cut it out of the mapping list, 148 | *but don't delete it if some slot 149 | *or device is still using it. 150 | */ 151 | struct map_list *list_node = get_map_list_container(maps); 152 | if (list_node->next) 153 | list_node->next->prev = list_node->prev; 154 | if (list_node->prev) 155 | list_node->prev->next = list_node->next; 156 | 157 | list_node->next = NULL; 158 | list_node->prev = NULL; 159 | 160 | mappings_unref(maps); 161 | 162 | return 0; 163 | 164 | } 165 | 166 | 167 | void mappings_ref(struct mode_mappings *maps) { 168 | maps->reference_count++; 169 | } 170 | 171 | void mappings_unref(struct mode_mappings *maps) { 172 | maps->reference_count--; 173 | 174 | if (maps->reference_count == 0) { 175 | 176 | printf("mapping \"%s\" is unreferenced and deleted.\n",maps->name); 177 | free(maps->name); 178 | free(get_map_list_container(maps)); 179 | } 180 | 181 | } 182 | 183 | 184 | int init_keyboardmouse_mappings(struct mode_mappings *maps) { 185 | 186 | 187 | /* Default wiimote only mapping. 188 | * Mainly useful for controlling media playback 189 | */ 190 | int *button_map = maps->mode_no_ext.button_map; 191 | struct event_map *map = &maps->mode_no_ext; 192 | memset(map, 0, sizeof(maps->mode_no_ext)); 193 | button_map[XWII_KEY_LEFT] = KEY_LEFT; 194 | button_map[XWII_KEY_RIGHT] = KEY_RIGHT; 195 | button_map[XWII_KEY_UP] = KEY_UP; 196 | button_map[XWII_KEY_DOWN] = KEY_DOWN; 197 | button_map[XWII_KEY_A] = BTN_LEFT; 198 | button_map[XWII_KEY_B] = BTN_RIGHT; 199 | button_map[XWII_KEY_PLUS] = KEY_VOLUMEUP; 200 | button_map[XWII_KEY_MINUS] = KEY_VOLUMEDOWN; 201 | button_map[XWII_KEY_HOME] = KEY_ESC; 202 | button_map[XWII_KEY_ONE] = BTN_MIDDLE; 203 | button_map[XWII_KEY_TWO] = KEY_MUTE; 204 | button_map[XWII_KEY_X] = NO_MAP; 205 | button_map[XWII_KEY_Y] = NO_MAP; 206 | button_map[XWII_KEY_TL] = NO_MAP; 207 | button_map[XWII_KEY_TR] = NO_MAP; 208 | button_map[XWII_KEY_ZL] = NO_MAP; 209 | button_map[XWII_KEY_ZR] = NO_MAP; 210 | button_map[XWII_KEY_THUMBL] = NO_MAP; 211 | button_map[XWII_KEY_THUMBR] = NO_MAP; 212 | button_map[XWII_KEY_C] = NO_MAP; 213 | button_map[XWII_KEY_Z] = NO_MAP; 214 | 215 | 216 | int no_ext_accel_map[6][2] = { 217 | {ABS_Y, -TILT_SCALE}, /*accelx*/ 218 | {ABS_X, -TILT_SCALE}, /*accely*/ 219 | {NO_MAP, TILT_SCALE},/*accelz*/ 220 | {NO_MAP, TILT_SCALE},/*n_accelx*/ 221 | {NO_MAP, TILT_SCALE},/*n_accely*/ 222 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 223 | }; 224 | memcpy(map->accel_map,no_ext_accel_map,sizeof(no_ext_accel_map)); 225 | 226 | map->accel_active = 0; 227 | 228 | int no_ext_stick_map[6][2] = { 229 | {NO_MAP, CLASSIC_SCALE},/*left_x*/ 230 | {NO_MAP, -CLASSIC_SCALE},/*left_y*/ 231 | {NO_MAP, CLASSIC_SCALE},/*right_x*/ 232 | {NO_MAP, -CLASSIC_SCALE},/*right_y*/ 233 | {NO_MAP, NUNCHUK_SCALE},/*n_x*/ 234 | {NO_MAP, -NUNCHUK_SCALE},/*n_y*/ 235 | }; 236 | memcpy(map->stick_map, no_ext_stick_map, sizeof(no_ext_stick_map)); 237 | 238 | int no_ext_balance_map[6][2] = { 239 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 240 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 241 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 242 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 243 | {ABS_X, ABS_LIMIT},/*bal_x*/ 244 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 245 | }; 246 | memcpy(map->balance_map, no_ext_balance_map, sizeof(no_ext_balance_map)); 247 | 248 | int no_ext_IR_map[2][2] = { 249 | {ABS_X, ABS_LIMIT/400},/*ir_x*/ 250 | {ABS_Y, ABS_LIMIT/300},/*ir_y*/ 251 | }; 252 | memcpy(map->IR_map, no_ext_IR_map, sizeof(no_ext_IR_map)); 253 | 254 | /*Default mapping with nunchuk. 255 | *I don't know what keyboard/mouse 256 | *mappings are reasonable. 257 | */ 258 | button_map = maps->mode_nunchuk.button_map; 259 | map = &maps->mode_nunchuk; 260 | memset(map, 0, sizeof(maps->mode_nunchuk)); 261 | button_map[XWII_KEY_LEFT] = KEY_LEFT; 262 | button_map[XWII_KEY_RIGHT] = KEY_RIGHT; 263 | button_map[XWII_KEY_UP] = KEY_UP; 264 | button_map[XWII_KEY_DOWN] = KEY_DOWN; 265 | button_map[XWII_KEY_A] = BTN_LEFT; 266 | button_map[XWII_KEY_B] = BTN_RIGHT; 267 | button_map[XWII_KEY_PLUS] = KEY_VOLUMEUP; 268 | button_map[XWII_KEY_MINUS] = KEY_VOLUMEDOWN; 269 | button_map[XWII_KEY_HOME] = KEY_ESC; 270 | button_map[XWII_KEY_ONE] = BTN_MIDDLE; 271 | button_map[XWII_KEY_TWO] = KEY_MUTE; 272 | button_map[XWII_KEY_X] = NO_MAP; 273 | button_map[XWII_KEY_Y] = NO_MAP; 274 | button_map[XWII_KEY_TL] = NO_MAP; 275 | button_map[XWII_KEY_TR] = NO_MAP; 276 | button_map[XWII_KEY_ZL] = NO_MAP; 277 | button_map[XWII_KEY_ZR] = NO_MAP; 278 | button_map[XWII_KEY_THUMBL] = NO_MAP; 279 | button_map[XWII_KEY_THUMBR] = NO_MAP; 280 | button_map[XWII_KEY_C] = BTN_TL; 281 | button_map[XWII_KEY_Z] = BTN_TL2; 282 | 283 | int nunchuk_accel_map[6][2] = { 284 | {ABS_RX, TILT_SCALE}, /*accelx*/ 285 | {ABS_RY, TILT_SCALE}, /*accely*/ 286 | {NO_MAP, TILT_SCALE},/*accelz*/ 287 | {NO_MAP, TILT_SCALE},/*n_accelx*/ 288 | {NO_MAP, TILT_SCALE},/*n_accely*/ 289 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 290 | }; 291 | memcpy(map->accel_map,nunchuk_accel_map,sizeof(nunchuk_accel_map)); 292 | 293 | map->accel_active = 0; 294 | 295 | int nunchuk_stick_map[6][2] = { 296 | {NO_MAP, CLASSIC_SCALE},/*left_x*/ 297 | {NO_MAP, -CLASSIC_SCALE},/*left_y*/ 298 | {NO_MAP, CLASSIC_SCALE},/*right_x*/ 299 | {NO_MAP, -CLASSIC_SCALE},/*right_y*/ 300 | {ABS_X, NUNCHUK_SCALE},/*n_x*/ 301 | {ABS_Y, -NUNCHUK_SCALE},/*n_y*/ 302 | }; 303 | memcpy(map->stick_map, nunchuk_stick_map, sizeof(nunchuk_stick_map)); 304 | 305 | int nunchuk_balance_map[6][2] = { 306 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 307 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 308 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 309 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 310 | {ABS_X, ABS_LIMIT},/*bal_x*/ 311 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 312 | }; 313 | memcpy(map->balance_map, nunchuk_balance_map, sizeof(nunchuk_balance_map)); 314 | 315 | int nunchuk_IR_map[2][2] = { 316 | {ABS_X, ABS_LIMIT/400},/*ir_x*/ 317 | {ABS_Y, ABS_LIMIT/300},/*ir_y*/ 318 | }; 319 | memcpy(map->IR_map, nunchuk_IR_map, sizeof(nunchuk_IR_map)); 320 | 321 | 322 | /*Mapping for Classic-style controllers. 323 | *I don't know what keyboard/mouse 324 | *mappings are reasonable. 325 | */ 326 | button_map = maps->mode_classic.button_map; 327 | map = &maps->mode_classic; 328 | memset(map, 0, sizeof(maps->mode_classic)); 329 | button_map[XWII_KEY_LEFT] = KEY_LEFT; 330 | button_map[XWII_KEY_RIGHT] = KEY_RIGHT; 331 | button_map[XWII_KEY_UP] = KEY_UP; 332 | button_map[XWII_KEY_DOWN] = KEY_DOWN; 333 | button_map[XWII_KEY_A] = BTN_LEFT; 334 | button_map[XWII_KEY_B] = BTN_RIGHT; 335 | button_map[XWII_KEY_PLUS] = KEY_VOLUMEUP; 336 | button_map[XWII_KEY_MINUS] = KEY_VOLUMEDOWN; 337 | button_map[XWII_KEY_HOME] = KEY_ESC; 338 | button_map[XWII_KEY_ONE] = BTN_MIDDLE; 339 | button_map[XWII_KEY_TWO] = KEY_MUTE; 340 | button_map[XWII_KEY_X] = BTN_NORTH; 341 | button_map[XWII_KEY_Y] = BTN_WEST; 342 | button_map[XWII_KEY_TL] = BTN_TL; 343 | button_map[XWII_KEY_TR] = BTN_TR; 344 | button_map[XWII_KEY_ZL] = BTN_TL2; 345 | button_map[XWII_KEY_ZR] = BTN_TR2; 346 | button_map[XWII_KEY_THUMBL] = BTN_THUMBL; 347 | button_map[XWII_KEY_THUMBR] = BTN_THUMBR; 348 | button_map[XWII_KEY_C] = NO_MAP; 349 | button_map[XWII_KEY_Z] = NO_MAP; 350 | 351 | int classic_accel_map[6][2] = { 352 | {ABS_RX, TILT_SCALE}, /*accelx*/ 353 | {ABS_RY, TILT_SCALE}, /*accely*/ 354 | {NO_MAP, TILT_SCALE},/*accelz*/ 355 | {ABS_X, TILT_SCALE},/*n_accelx*/ 356 | {ABS_Y, TILT_SCALE},/*n_accely*/ 357 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 358 | }; 359 | memcpy(map->accel_map,classic_accel_map,sizeof(classic_accel_map)); 360 | 361 | int classic_stick_map[6][2] = { 362 | {ABS_X, CLASSIC_SCALE},/*left_x*/ 363 | {ABS_Y, -CLASSIC_SCALE},/*left_y*/ 364 | {ABS_RX, CLASSIC_SCALE},/*right_x*/ 365 | {ABS_RY, -CLASSIC_SCALE},/*right_y*/ 366 | {NO_MAP, NUNCHUK_SCALE},/*n_x*/ 367 | {NO_MAP, -NUNCHUK_SCALE},/*n_y*/ 368 | }; 369 | memcpy(map->stick_map, classic_stick_map, sizeof(classic_stick_map)); 370 | 371 | int classic_balance_map[6][2] = { 372 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 373 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 374 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 375 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 376 | {ABS_X, ABS_LIMIT},/*bal_x*/ 377 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 378 | }; 379 | memcpy(map->balance_map, classic_balance_map, sizeof(classic_balance_map)); 380 | 381 | int classic_IR_map[2][2] = { 382 | {ABS_X, ABS_LIMIT/400},/*ir_x*/ 383 | {ABS_Y, ABS_LIMIT/300},/*ir_y*/ 384 | }; 385 | memcpy(map->IR_map, classic_IR_map, sizeof(classic_IR_map)); 386 | 387 | 388 | 389 | return 0; 390 | 391 | } 392 | 393 | int init_gamepad_mappings(struct mode_mappings *maps, char *name) { 394 | 395 | 396 | /* Default wiimote only mapping. 397 | * Designed for playing simple games, with the wiimote 398 | * held horizontally. (DPAD on the left.) 399 | */ 400 | int *button_map = maps->mode_no_ext.button_map; 401 | struct event_map *map = &maps->mode_no_ext; 402 | memset(map, 0, sizeof(maps->mode_no_ext)); 403 | button_map[XWII_KEY_LEFT] = BTN_DPAD_DOWN; 404 | button_map[XWII_KEY_RIGHT] = BTN_DPAD_UP; 405 | button_map[XWII_KEY_UP] = BTN_DPAD_LEFT; 406 | button_map[XWII_KEY_DOWN] = BTN_DPAD_RIGHT; 407 | button_map[XWII_KEY_A] = BTN_NORTH; 408 | button_map[XWII_KEY_B] = BTN_WEST; 409 | button_map[XWII_KEY_PLUS] = BTN_START; 410 | button_map[XWII_KEY_MINUS] = BTN_SELECT; 411 | button_map[XWII_KEY_HOME] = BTN_MODE; 412 | button_map[XWII_KEY_ONE] = BTN_SOUTH; 413 | button_map[XWII_KEY_TWO] = BTN_EAST; 414 | button_map[XWII_KEY_X] = NO_MAP; 415 | button_map[XWII_KEY_Y] = NO_MAP; 416 | button_map[XWII_KEY_TL] = NO_MAP; 417 | button_map[XWII_KEY_TR] = NO_MAP; 418 | button_map[XWII_KEY_ZL] = NO_MAP; 419 | button_map[XWII_KEY_ZR] = NO_MAP; 420 | button_map[XWII_KEY_THUMBL] = NO_MAP; 421 | button_map[XWII_KEY_THUMBR] = NO_MAP; 422 | button_map[XWII_KEY_C] = NO_MAP; 423 | button_map[XWII_KEY_Z] = NO_MAP; 424 | 425 | 426 | int no_ext_accel_map[6][2] = { 427 | {ABS_Y, -TILT_SCALE}, /*accelx*/ 428 | {ABS_X, -TILT_SCALE}, /*accely*/ 429 | {NO_MAP, TILT_SCALE},/*accelz*/ 430 | {NO_MAP, TILT_SCALE},/*n_accelx*/ 431 | {NO_MAP, TILT_SCALE},/*n_accely*/ 432 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 433 | }; 434 | memcpy(map->accel_map,no_ext_accel_map,sizeof(no_ext_accel_map)); 435 | 436 | map->accel_active = 0; 437 | 438 | int no_ext_stick_map[6][2] = { 439 | {NO_MAP, CLASSIC_SCALE},/*left_x*/ 440 | {NO_MAP, -CLASSIC_SCALE},/*left_y*/ 441 | {NO_MAP, CLASSIC_SCALE},/*right_x*/ 442 | {NO_MAP, -CLASSIC_SCALE},/*right_y*/ 443 | {NO_MAP, NUNCHUK_SCALE},/*n_x*/ 444 | {NO_MAP, -NUNCHUK_SCALE},/*n_y*/ 445 | }; 446 | memcpy(map->stick_map, no_ext_stick_map, sizeof(no_ext_stick_map)); 447 | 448 | int no_ext_balance_map[6][2] = { 449 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 450 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 451 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 452 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 453 | {ABS_X, ABS_LIMIT},/*bal_x*/ 454 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 455 | }; 456 | memcpy(map->balance_map, no_ext_balance_map, sizeof(no_ext_balance_map)); 457 | 458 | int no_ext_IR_map[2][2] = { 459 | {ABS_RX, ABS_LIMIT/400},/*ir_x*/ 460 | {ABS_RY, ABS_LIMIT/300},/*ir_y*/ 461 | }; 462 | memcpy(map->IR_map, no_ext_IR_map, sizeof(no_ext_IR_map)); 463 | 464 | /*Default mapping with nunchuk. 465 | *No acceleration, just buttons. 466 | * 467 | * 468 | */ 469 | button_map = maps->mode_nunchuk.button_map; 470 | map = &maps->mode_nunchuk; 471 | memset(map, 0, sizeof(maps->mode_nunchuk)); 472 | button_map[XWII_KEY_LEFT] = BTN_DPAD_LEFT; 473 | button_map[XWII_KEY_RIGHT] = BTN_DPAD_RIGHT; 474 | button_map[XWII_KEY_UP] = BTN_DPAD_UP; 475 | button_map[XWII_KEY_DOWN] = BTN_DPAD_DOWN; 476 | button_map[XWII_KEY_A] = BTN_SOUTH; 477 | button_map[XWII_KEY_B] = BTN_TR2; 478 | button_map[XWII_KEY_PLUS] = BTN_START; 479 | button_map[XWII_KEY_MINUS] = BTN_SELECT; 480 | button_map[XWII_KEY_HOME] = BTN_MODE; 481 | button_map[XWII_KEY_ONE] = BTN_EAST; 482 | button_map[XWII_KEY_TWO] = BTN_TR; 483 | button_map[XWII_KEY_X] = NO_MAP; 484 | button_map[XWII_KEY_Y] = NO_MAP; 485 | button_map[XWII_KEY_TL] = NO_MAP; 486 | button_map[XWII_KEY_TR] = NO_MAP; 487 | button_map[XWII_KEY_ZL] = NO_MAP; 488 | button_map[XWII_KEY_ZR] = NO_MAP; 489 | button_map[XWII_KEY_THUMBL] = NO_MAP; 490 | button_map[XWII_KEY_THUMBR] = NO_MAP; 491 | button_map[XWII_KEY_C] = BTN_TL; 492 | button_map[XWII_KEY_Z] = BTN_TL2; 493 | 494 | int nunchuk_accel_map[6][2] = { 495 | {ABS_RX, TILT_SCALE}, /*accelx*/ 496 | {ABS_RY, TILT_SCALE}, /*accely*/ 497 | {NO_MAP, TILT_SCALE},/*accelz*/ 498 | {NO_MAP, TILT_SCALE},/*n_accelx*/ 499 | {NO_MAP, TILT_SCALE},/*n_accely*/ 500 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 501 | }; 502 | memcpy(map->accel_map,nunchuk_accel_map,sizeof(nunchuk_accel_map)); 503 | 504 | map->accel_active = 0; 505 | 506 | int nunchuk_stick_map[6][2] = { 507 | {NO_MAP, CLASSIC_SCALE},/*left_x*/ 508 | {NO_MAP, -CLASSIC_SCALE},/*left_y*/ 509 | {NO_MAP, CLASSIC_SCALE},/*right_x*/ 510 | {NO_MAP, -CLASSIC_SCALE},/*right_y*/ 511 | {ABS_X, NUNCHUK_SCALE},/*n_x*/ 512 | {ABS_Y, -NUNCHUK_SCALE},/*n_y*/ 513 | }; 514 | memcpy(map->stick_map, nunchuk_stick_map, sizeof(nunchuk_stick_map)); 515 | 516 | int nunchuk_balance_map[6][2] = { 517 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 518 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 519 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 520 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 521 | {ABS_X, ABS_LIMIT},/*bal_x*/ 522 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 523 | }; 524 | memcpy(map->balance_map, nunchuk_balance_map, sizeof(nunchuk_balance_map)); 525 | 526 | int nunchuk_IR_map[2][2] = { 527 | {ABS_RX, ABS_LIMIT/400},/*ir_x*/ 528 | {ABS_RY, ABS_LIMIT/300},/*ir_y*/ 529 | }; 530 | memcpy(map->IR_map, nunchuk_IR_map, sizeof(nunchuk_IR_map)); 531 | 532 | 533 | /*Mapping for Classic-style controllers. 534 | *Wii Classic Controllers and Wii U Pro 535 | *controllers use this. It matches the 536 | *Linux gamepad layout. 537 | */ 538 | button_map = maps->mode_classic.button_map; 539 | map = &maps->mode_classic; 540 | memset(map, 0, sizeof(maps->mode_classic)); 541 | button_map[XWII_KEY_LEFT] = BTN_DPAD_LEFT; 542 | button_map[XWII_KEY_RIGHT] = BTN_DPAD_RIGHT; 543 | button_map[XWII_KEY_UP] = BTN_DPAD_UP; 544 | button_map[XWII_KEY_DOWN] = BTN_DPAD_DOWN; 545 | button_map[XWII_KEY_A] = BTN_EAST; 546 | button_map[XWII_KEY_B] = BTN_SOUTH; 547 | button_map[XWII_KEY_PLUS] = BTN_START; 548 | button_map[XWII_KEY_MINUS] = BTN_SELECT; 549 | button_map[XWII_KEY_HOME] = BTN_MODE; 550 | button_map[XWII_KEY_ONE] = NO_MAP; 551 | button_map[XWII_KEY_TWO] =NO_MAP; 552 | button_map[XWII_KEY_X] = BTN_NORTH; 553 | button_map[XWII_KEY_Y] = BTN_WEST; 554 | button_map[XWII_KEY_TL] = BTN_TL; 555 | button_map[XWII_KEY_TR] = BTN_TR; 556 | button_map[XWII_KEY_ZL] = BTN_TL2; 557 | button_map[XWII_KEY_ZR] = BTN_TR2; 558 | button_map[XWII_KEY_THUMBL] = BTN_THUMBL; 559 | button_map[XWII_KEY_THUMBR] = BTN_THUMBR; 560 | button_map[XWII_KEY_C] = NO_MAP; 561 | button_map[XWII_KEY_Z] = NO_MAP; 562 | 563 | int classic_accel_map[6][2] = { 564 | {ABS_RX, TILT_SCALE}, /*accelx*/ 565 | {ABS_RY, TILT_SCALE}, /*accely*/ 566 | {NO_MAP, TILT_SCALE},/*accelz*/ 567 | {ABS_X, TILT_SCALE},/*n_accelx*/ 568 | {ABS_Y, TILT_SCALE},/*n_accely*/ 569 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 570 | }; 571 | memcpy(map->accel_map,classic_accel_map,sizeof(classic_accel_map)); 572 | 573 | int classic_stick_map[6][2] = { 574 | {ABS_X, CLASSIC_SCALE},/*left_x*/ 575 | {ABS_Y, -CLASSIC_SCALE},/*left_y*/ 576 | {ABS_RX, CLASSIC_SCALE},/*right_x*/ 577 | {ABS_RY, -CLASSIC_SCALE},/*right_y*/ 578 | {NO_MAP, NUNCHUK_SCALE},/*n_x*/ 579 | {NO_MAP, -NUNCHUK_SCALE},/*n_y*/ 580 | }; 581 | memcpy(map->stick_map, classic_stick_map, sizeof(classic_stick_map)); 582 | 583 | int classic_balance_map[6][2] = { 584 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 585 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 586 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 587 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 588 | {ABS_X, ABS_LIMIT},/*bal_x*/ 589 | {ABS_Y, ABS_LIMIT},/*bal_y*/ 590 | }; 591 | memcpy(map->balance_map, classic_balance_map, sizeof(classic_balance_map)); 592 | 593 | int classic_IR_map[2][2] = { 594 | {ABS_RX, ABS_LIMIT/400},/*ir_x*/ 595 | {ABS_RY, ABS_LIMIT/300},/*ir_y*/ 596 | }; 597 | memcpy(map->IR_map, classic_IR_map, sizeof(classic_IR_map)); 598 | 599 | maps->name = name; 600 | 601 | return 0; 602 | 603 | } 604 | 605 | int init_blank_mappings(struct mode_mappings *maps) { 606 | 607 | 608 | /* Default wiimote only mapping. 609 | * This mapping is blank; 610 | * everthing is not mapped. 611 | */ 612 | int *button_map = maps->mode_no_ext.button_map; 613 | struct event_map *map = &maps->mode_no_ext; 614 | memset(map, 0, sizeof(maps->mode_no_ext)); 615 | button_map[XWII_KEY_LEFT] = NO_MAP; 616 | button_map[XWII_KEY_RIGHT] = NO_MAP; 617 | button_map[XWII_KEY_UP] = NO_MAP; 618 | button_map[XWII_KEY_DOWN] = NO_MAP; 619 | button_map[XWII_KEY_A] = NO_MAP; 620 | button_map[XWII_KEY_B] = NO_MAP; 621 | button_map[XWII_KEY_PLUS] = NO_MAP; 622 | button_map[XWII_KEY_MINUS] = NO_MAP; 623 | button_map[XWII_KEY_HOME] = NO_MAP; 624 | button_map[XWII_KEY_ONE] = NO_MAP; 625 | button_map[XWII_KEY_TWO] = NO_MAP; 626 | button_map[XWII_KEY_X] = NO_MAP; 627 | button_map[XWII_KEY_Y] = NO_MAP; 628 | button_map[XWII_KEY_TL] = NO_MAP; 629 | button_map[XWII_KEY_TR] = NO_MAP; 630 | button_map[XWII_KEY_ZL] = NO_MAP; 631 | button_map[XWII_KEY_ZR] = NO_MAP; 632 | button_map[XWII_KEY_THUMBL] = NO_MAP; 633 | button_map[XWII_KEY_THUMBR] = NO_MAP; 634 | button_map[XWII_KEY_C] = NO_MAP; 635 | button_map[XWII_KEY_Z] = NO_MAP; 636 | 637 | 638 | int no_ext_accel_map[6][2] = { 639 | {NO_MAP, -TILT_SCALE}, /*accelx*/ 640 | {NO_MAP, -TILT_SCALE}, /*accely*/ 641 | {NO_MAP, TILT_SCALE},/*accelz*/ 642 | {NO_MAP, TILT_SCALE},/*n_accelx*/ 643 | {NO_MAP, TILT_SCALE},/*n_accely*/ 644 | {NO_MAP, TILT_SCALE} /*n_accelz*/ 645 | }; 646 | memcpy(map->accel_map,no_ext_accel_map,sizeof(no_ext_accel_map)); 647 | 648 | map->accel_active = 0; 649 | 650 | int no_ext_stick_map[6][2] = { 651 | {NO_MAP, CLASSIC_SCALE},/*left_x*/ 652 | {NO_MAP, -CLASSIC_SCALE},/*left_y*/ 653 | {NO_MAP, CLASSIC_SCALE},/*right_x*/ 654 | {NO_MAP, -CLASSIC_SCALE},/*right_y*/ 655 | {NO_MAP, NUNCHUK_SCALE},/*n_x*/ 656 | {NO_MAP, -NUNCHUK_SCALE},/*n_y*/ 657 | }; 658 | memcpy(map->stick_map, no_ext_stick_map, sizeof(no_ext_stick_map)); 659 | 660 | int no_ext_balance_map[6][2] = { 661 | {NO_MAP, ABS_LIMIT/600},/*bal_fl*/ 662 | {NO_MAP, ABS_LIMIT/600},/*bal_fr*/ 663 | {NO_MAP, ABS_LIMIT/600},/*bal_bl*/ 664 | {NO_MAP, ABS_LIMIT/600},/*bal_br*/ 665 | {NO_MAP, ABS_LIMIT},/*bal_x*/ 666 | {NO_MAP, ABS_LIMIT},/*bal_y*/ 667 | }; 668 | memcpy(map->balance_map, no_ext_balance_map, sizeof(no_ext_balance_map)); 669 | 670 | int no_ext_IR_map[2][2] = { 671 | {NO_MAP, ABS_LIMIT/400},/*ir_x*/ 672 | {NO_MAP, ABS_LIMIT/300},/*ir_y*/ 673 | }; 674 | memcpy(map->IR_map, no_ext_IR_map, sizeof(no_ext_IR_map)); 675 | 676 | /*Default mapping for nunchuk 677 | *and classic are the same: 678 | *all empty 679 | */ 680 | memcpy(&maps->mode_nunchuk,&maps->mode_no_ext,sizeof(struct event_map)); 681 | memcpy(&maps->mode_classic,&maps->mode_no_ext,sizeof(struct event_map)); 682 | 683 | 684 | 685 | 686 | 687 | return 0; 688 | 689 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #WiimoteGlue 2 | *Userspace driver for Wii remotes and their extensions to simulate standard gamepads* 3 | 4 | (Tested only on Arch Linux, 64-bit) 5 | 6 | This project is not under active development, but will still respond to bug reports. It's successor is MoltenGamepad, which aims to offer the same ease of use with wiimotes while also including other devices as well. 7 | 8 | ##Building 9 | 10 | make 11 | 12 | If you get undefined KEY_* errors, try 13 | 14 | make keycodefix 15 | make 16 | 17 | This will generate new key_codes.c that should use only KEY_* constants that you have defined. 18 | 19 | It requires udev, uinput, and xwiimote. 20 | 21 | https://github.com/dvdhrm/xwiimote 22 | 23 | (also available in the AUR https://aur.archlinux.org/packages/xwiimote/ ) 24 | 25 | ##Running 26 | 27 | ./wiimoteglue 28 | 29 | WiimoteGlue will start up and wait for Wii remotes to show up. WiimoteGlue will read commands to from its standard input. 30 | 31 | ./wiimoteglue --help 32 | 33 | to see the (very few) command line arguments. 34 | 35 | 36 | You'll need certain file permissions on the uinput and wiimote event devices. 37 | 38 | You might need to use --uinput-path to tell WiimoteGlue where the uinput device is on your system. (You might even need to modprobe uinput) 39 | 40 | 41 | 42 | ##Motivation 43 | 44 | The Linux kernel driver for wiimotes is pretty handy, but the extension controllers like the Nunchuk show up as separate devices. Not just that, extra features like the accelerometers or infared sensors also show up as separate devices. Not many games support taking input from multiple devices for a single player, so using a wiimote for tilt controls or using the wiimote/nunchuk combo is often not possible. WiimoteGlue acts to combine these into a synthetic gamepad, and adds some extra features to further improve usability. 45 | 46 | ##Features 47 | 48 | * Creates synthetic virtual gamepads that work in most modern software that expect gamepads. 49 | * Supports extension controllers such as the nunchuk or classic controller. Just plug and play! 50 | * Configurable at run-time button mappings to get that ideal control scheme. 51 | * Also grabs Wii U pro controllers and allows remapping buttons. 52 | * Dynamic control mappings that change when extensions are inserted or removed. 53 | * Controller LEDs are changed to match the virtual gamepad slot they are in. 54 | * Basic processing of accelerometer or infared data. 55 | * Basic support of the Wii Balance Board in addition to a standard controller. Surf your way through your games! 56 | * Read in control mappings from files. Set up a file per game, and you can switch between them easily. 57 | * Uses the Linux gamepad API button defintions rather than ambiguous labels like "A","B","X","Y" or "Button 0" for the virtual gamepad. 58 | * Virtual gamepads persist for as long as WiimoteGlue is running, so even software not supporting gamepad hotplugging can be oblivious to Wii remotes connecting/disconnecting. 59 | * Can also map events to a keyboard or mouse, rather than a gamepad. 60 | * Assuming proper file permissions on input devices, this does not require super-user privileges. 61 | 62 | ##Example of Why You Might Use WiimoteGlue 63 | 64 | You decide to play \ with just a sideways Wii remote, tilting the controller to steer for some silly fun. 65 | 66 | After veering off the track repeatedly, it is time to get serious. You plug in the Nunchuk extension controller, and instantly the controls change. Rather than flimsy tilt-based steering, you now have the reliable Nunchuk's control stick handling your steering, and the buttons on the Wii remote have changed as well to match your new grip. 67 | 68 | After a while, a friend comes by. "Oh hey, it's \! Can I play? Wait. What's with that funky controller? I don't trust my left and right hands to be separated by a cord, and there's no way that has enough buttons." 69 | 70 | Before they turn away, you manage to swap the Nunchuk out for a Wii Classic Controller. Like magic, the controller works as expected. No need to fiddle with control mappings every time an extension changes, and no need to change the game options to use the newly connected Classic Controller. Your friend, eased by the comforting vague familiarity of the Classic Controller, enjoys their race. 71 | 72 | After they leave, you remove the Classic Controller, change a few mappings in WiimoteGlue, connect a Wii Balance Board, and decide to try steering with your feet. 73 | 74 | ##Documentation 75 | 76 | This README, the help text produced while running WiimoteGlue, and the sample file "maps/demo_readme" are the only documentation at the moment. 77 | 78 | This README deals mostly with what WiimoteGlue is, and what it does. 79 | 80 | The help text in the program gives the specifics of the available commands and their expected formats. 81 | 82 | The demo_readme file offers a quick explanation/demonstration on how to map buttons, but does not demonstrate all commands, features. 83 | 84 | (The media_control mapping file offers a demo of the keyboard/mouse mapping.) 85 | 86 | ##Requirements 87 | 88 | * Needs the wiimote kernel driver, hid-wiimote. 89 | * Built on top of the xwiimote library, a handy wrapper for the kernel driver. 90 | * Uses uinput for creating the virtual gamepads 91 | * Uses udev for finding connected Wii controllers. 92 | * Uses epoll to wait for events to process. 93 | * You need to have read permissions on the various wiimote devices, and write permission to uinput. 94 | 95 | You also need to be able to connect your controllers in the first place. This task is done by your bluetooth system, not this software. It has been tested on Bluez 5.26 using bluetoothctl. The wiimote plugin for Bluez 4.96 should be sufficient. Various bluetooth GUIs can work, but some don't handle the wiimote pairing peculiarities well. Using the wiimote sync button can work better than pushing 1+2. 96 | 97 | See https://wiki.archlinux.org/index.php/XWiimote for more info on connecting wiimotes. 98 | 99 | ##Future Goals 100 | 101 | 102 | * Add multi-threading for processing the input events. 103 | * Improve the accelerometer/infared/balance board processing 104 | * Add a "waggle button" that is triggered when the wiimote or nunchuk are shaken. 105 | * Add a mode for the balance board that modulates an axis (or axes?) by walking in place. 106 | * Add in rumble support. 107 | * Allow buttons to be mapped to axes, and vice versa. 108 | * Improve the control mapping files to be less cumbersome. 109 | * Way off: add in a GUI or interface for controlling the driver outside of the the driver's STDIN. System tray icon? 110 | * A means of calibrating the axes? 111 | * Clean and document the code in general. 112 | * A way to store device aliases based on their unique bluetooth addresses. 113 | 114 | ##Known Issues 115 | 116 | * Sometimes extensions aren't detected, especially when already inserted when a wiimote connects. Unplugging them and re-inserting generally fixes this. 117 | * Though the Wii U Pro supports changing the button mappings and axis mappings, it does not allow inverting the axes. 118 | * Since the Wii U Pro is already detected by SDL, WiimoteGlue leads to "duplicate" controllers. 119 | * Currently single-threaded, handling all input events across all controllers. May introduce latency? 120 | * Virtual gamepads don't change their axis sensitivities or deadzones when their input sources change. The deadzone ideal for a thumb stick might not be the ideal for a tilt control. 121 | * Code is messy as a personal project. Particularly, i18n was not a concern when writing it. Sorry. 122 | * Uses a udev monitor per wiimote despite xwiimote saying not to do that. 123 | * Wiimote buttons are still processed when a classic controller is present, despite duplicate buttons. The duplicate button events are mapped the same, and interleaved onto to the synthetic gamepad, but this generally isn't a huge problem. 124 | * Virtual output devices aren't "cleared" when their input sources are removed. If you remap a button while it is held down (or an uncentered axis), the old mapping will be "frozen" to whatever input it had last. 125 | 126 | 127 | 128 | ##Troubleshooting FAQ-ish Section 129 | 130 | ###What's this about file permissions for the devices? 131 | WiimoteGlue will fail if you don't have the right permissions, and you likely won't have the right permissions unless you do some extra work. Though not recommended for regular use, running WiimoteGlue as a super-user can be a useful way to try it out before you have the permissions sorted out. 132 | 133 | You need write access to uinput to create the virtual gamepads. WiimoteGlue assumes uinput is located at /dev/uinput which might not be true on other distros. If you know where uinput is on your system, change the location at the top of uinput.c 134 | 135 | You need read access to the various event devices created by the kernel driver. Either run WiimoteGlue as root (not recommended) or set up some udev rules to automatically change the permissions. I'd recommed creating some sort of "input" group, changing the group ownership of the devices to be that group, and add your user account to that group (Reminder: you need to open a new shell to update your group permissions after adding yourself to the group!) 136 | 137 | KERNEL=="event*", DRIVERS=="wiimote", GROUP="", MODE="0660" 138 | 139 | (where \ is the name of some user group you've added yourself to. "input" might be a reasonable choice already in use by your system) 140 | 141 | When rumble support is added, you'll need write access as well. (though only to the core wiimote and Wii U pro devices; nunchuks and classic controllers don't have rumble) 142 | 143 | When LED changing is added, you'll also need write access to the LED brightness files. These LED devices are handled with by the kernel LED subsystem instead of the input subsystem. 144 | 145 | SUBSYSTEM=="leds", ACTION=="add", DRIVERS=="wiimote", RUN+="/bin/sh -c 'chgrp /sys%p/brightness'", RUN+="/bin/sh -c 'chmod g+w /sys%p/brightness'" 146 | 147 | seems to be working for me. Note that both of these rules are present in the xwiimote repo, where they use the group "input". Further, recent versions of systemd have added a udev rule for all input event devices to be owned by the "input" group (however the LEDs still need the above rule). 148 | 149 | ###How do I connect a wiimote? 150 | 151 | That is outside the scope of WiimoteGlue. Your bluetooth system handles this. This software assumes your bluetooth stack and kernel wiimote driver are already working and usable. 152 | 153 | See https://wiki.archlinux.org/index.php/XWiimote for more information on connecting wiimotes. 154 | 155 | Note that this uses xwiimote and the kernel driver, not one of the various wiimote libraries like cwiid that do handle connections, so the info on https://wiki.archlinux.org/index.php/Wiimote is not applicable. To use Wiimoteglue, use XWiimote; do not use cwiid and wminput. 156 | 157 | Aside from seeing the device entries created by the kernel driver, a successful connection can be verified by the Wiimote LEDs switching to having just the left-most one lit. Prior to that, all 4 LEDs will be blinking while the wiimote is in sync mode. 158 | 159 | I have had some confusing experience of the wiimote connections sometimes consistently failing then magically working when I try later. I've also seen an unrelated issue when repeatedly and quickly disconnecting and reconnecting a controller. These are once again, outside the scope of WiimoteGlue. Some of this might be my bluetooth hardware being flakey. 160 | 161 | In the former case, the bluetooth connection fails. In the latter case, the connection succeeds, but the no kernel devices are created. It seemed like the wiimote was connected and was on, but all 4 of its LEDs were off since the kernel driver never set them. 162 | 163 | ###Mapping(s)? Modes? I'm confused. 164 | 165 | In WiimoteGlue, a *mapping* is says what output events a certain Wiimote input event should send. A *mapping* has 3 *modes*: wiimote, nunchuk, and classic. Each *mode* describes a separate set of output bindings, and a wiimote chooses its *mode* based on what extensions, if any, are currently connected. Even though two devices may be using the same *mapping*, pressing the same button on each of them can have different effects depending on what *mode* each device is in. 166 | 167 | WiimoteGlue starts with two *mappings* defined: "gamepad" and "keyboardmouse", and each has their own 3 *modes*. WiimoteGlue will create by default 4 virtual gamepad slots: "1", "2", "3", and "4". There is also an extra slot named "keyboardmouse," and naturally it uses the "keyboardmouse" *mapping*. 168 | 169 | When you issue a 170 | 171 | map 172 | 173 | command and omit the *mapping* name, the "gamepad" *mapping* is assumed. 174 | 175 | A slot can be assigned its own *mapping*, in which case it will be used instead of the default "gamepad" *mapping*. Further, a device can be assigned a personal *mapping*, and it will be used instead of either the default "gamepad" or the slot specific mapping. 176 | 177 | # Set a slot's specific mapping 178 | slot mapping 179 | # Set a device's specific mapping 180 | device mapping 181 | 182 | ###Slot types? What are those? 183 | 184 | WiimoteGlue keeps separate virtual devices for gamepad and keyboard/mouse events, and you need to tell a slot what virtual device to use. Events sent to a device of the wrong type will be ignored. 185 | 186 | slot type keyboardmouse 187 | slot type gamepad 188 | 189 | Will change the type of a slot. These commands also work if you omit the word "type". 190 | 191 | 192 | ###North, south, east, west? What are those? My "A" button isn't acting like an "A" button. 193 | 194 | See the Linux gamepad documentation. These are the "face buttons" generally pushed by one's right thumb. 195 | 196 | https://www.kernel.org/doc/Documentation/input/gamepad.txt 197 | 198 | Note that WiimoteGlue uses the event names TR2 and TL2 instead of ZR and ZL. 199 | 200 | Nintendo's "A" button isn't placed where the Xbox "A" button is. WiimoteGlue's default mapping for classic-style controllers matches the Linux gamepad documentation. Be aware the usual Nintendo layout, the usual Xbox layout, and the Linux gamepad layout for the face buttons are all different. You'll need to make your own decisions on what mapping is best for you, (Many games today expect Xbox controllers; just because a game says "push A" doesn't mean it knows what button on your controller has an "A" on it.) 201 | 202 | For reference: 203 | 204 | * Nintendo ABXY is ESNW 205 | * Xbox ABXY is SEWN 206 | * Linux Gamepad ABXY is SENW 207 | 208 | (Hence why BTN_A,BTN_B etc. are deprecated event names... but many utilities like evtest still print out BTN_A instead of BTN_SOUTH) 209 | 210 | Playstation controllers don't even use labels like A,B, or Y but instead use shapes. One of those shapes is "X," and it doesn't line up with any of the three layouts above. Aren't game controllers fun? 211 | 212 | 213 | ###When I mapped my control stick to the mouse, centering the stick centers the cursor. this doesn't seem very useful? 214 | 215 | This is the intended functionality of WiimoteGlue. It outputs the absolute positions from the stick as absolute positions on the virtual mouse. 216 | 217 | "Steering" the cursor with the stick would likely be more useful, but would need to be handled in a way fundamentally different from how WiimoteGlue now works. In WiimoteGlue, if the stick doesn't move, no events are generated at all. To steer the cursor, we'd need to consistently and regularly generate events even when the stick is held still in a certain direction. 218 | 219 | ###This fake mouse pointer is all wonky. Is it working right? 220 | 221 | The fake mouse should be auto-detected by evdev in "absolute" mode, but it might have been set to "relative" which is the general mode used by mice. 222 | 223 | xinput --set-mode "WiimoteGlue Virtual Keyboard and Mouse" ABSOLUTE 224 | 225 | will fix this, and this setting does not persist after closing WiimoteGlue. 226 | 227 | Also note that the infared and accelerometer readings aren't smoothed at all, so using them for controlling the mouse cursor will be noisy. 228 | 229 | 230 | ###I mapped buttons to the keyboard/mouse, but they aren't doing anything? 231 | 232 | Please check the following is true: 233 | 234 | * Your device is assigned to slot with the "keyboardmouse" type, rather than the type "gamepad". "gamepad" slots ignore keyboard and mouse events. 235 | * You updated the actual mapping (and mode of that mapping) in use by the device. 236 | 237 | As a reminder, WiimoteGlue also starts with two named mappings: "gamepad" and "keyboardmouse". A mapping is set via 238 | 239 | map 240 | 241 | and if no mapping name is given, "gamepad" is implied. 242 | 243 | WiimoteGlue starts with one special "keyboardmouse" slot (of type "keyboardmouse") in addition to the default slots 1, 2, etc. which are of type "gamepad." 244 | 245 | slot 246 | 247 | will change the type of a slot. 248 | 249 | Finally, note that the keyboard and mouse slot is set to use the keyboard and mouse mapping. If a slot has no specific mapping set, changing the type will also change the slot's mapping to the appropriate default. 250 | 251 | ###My classic controller d-pad directions are acting like arrow keys? 252 | 253 | This is a result of the kernel driver's mapping for the classic controller. The DPAD is indeed mapped to the arrow keys, and the classic controller is picked up as keyboard. Use "xinput" to disable the classic controller as a keyboard if this poses a problem. "xinput" is also useful if your joysticks are being picked up as mice to move the cursor. 254 | 255 | xinput --disable "Nintendo Wii Remote Classic Controller" 256 | 257 | Another fun fact about the classic controller kernel driver: since it doesn't map the left-stick to ABS_X/ABS_Y, the classic controller is not picked up as a gamepad by SDL, which makes it invisible to many modern games. Further, the Y-axes were inverted. WiimoteGlue's virtual gamepads are picked up by SDL, so even without the gluing/dynamic remapping feature, WiimoteGlue already improves classic controller usability. 258 | 259 | (To be fair, I'll point out that the kernel driver for the classic controller predates the Linux gamepad API where the dpad event codes were formalized, and it is thanks to David Herrmann that both the kernel driver and the gamepad API exist, along with xwiimote. Thanks for all the work!) 260 | 261 | [For those curious, SDL requires a device to give out BTN_SOUTH and ABS_X/ABS_Y to be detected. The wiimote alone doesn't have ABS_X, the nunchuk doesn't have BTN_SOUTH, and the classic controller doesn't have ABS_X. The Wii U Pro does meet the SDL gamepad requirements under the kernel driver.] 262 | 263 | ###That duplicated Wii U Pro controller issue is annoying. What can I do? 264 | 265 | There are a few work arounds of various ugliness: 266 | 267 | 1. Assign the pro controller to the "none" slot in WiimoteGlue. WiimoteGlue will ignore it, and you can use the original Wii U Pro device. 268 | 2. Delete the original pro controller device after WiimoteGlue has opened it, but before you start the game. WiimoteGlue will hold onto its already opened interface, but the game won't. 269 | 270 | If Option #1 sounds better to you, the "--ignore-pro" command line argument for WiimoteGlue is likely what you seek. 271 | 272 | One potential work-around would be to have the Wii U Pro event device grabbed with EVIOCGRAB to get it's events exclusively, but I don't think xwiimote has a convenient way to do this. Since Pro controllers don't have extensions to track, it might be worth handling them manually just to do this. (We'd just have to track the single event device + the four LED devices for full functionality.) 273 | 274 | ##Features of WiimoteGlue FAQ-ish section 275 | 276 | ###Infared data? 277 | 278 | The Wii remote has an IR camera that detects infared sources for tracking. This is the "pointer" functionality for the Wii. One can easily purchase USB versions of the Wii sensor bar to get some usable IR sources, or make your own from IR LEDs or even flames if you are bold enough. 279 | 280 | Currently WiimoteGlue will take only the left-most detected IR source. This means mutlipe IR sources (such as the two sides of a sensor bar) are not used to improve the reading, and may in fact lead to strange results. 281 | 282 | Adding in an extra big deadzone specifically when handling IR data might be useful, if one wants to use it for panning first-person cameras. 283 | 284 | Adding in support for multiple IR sources can improve the data, and allow for some extra virtual axes like rotation or scale (which would translate to distance from the IR sources) 285 | 286 | ###Balance Board support? 287 | 288 | Every virtual gamepad slot can have at most one standard controller (wiimote+extensions or Wii U pro controller) and one balance board allocated to it. When a balance board is connected, it gets assigned to the first virtual gamepad with no board assigned yet. 289 | 290 | Currently does a rough average across the four weight sensors to get a center of gravity, and also adds a fair bit of margin to allow it to go full tilt. 291 | 292 | Note that the balance board *always* uses the "wiimote" mode mappings, even when extensions are connected. 293 | 294 | map wiimote bal_x left_x 295 | 296 | will map *all* balance boards to left_x, regardless of the the presence or absence of nunchuks or other extensions on the controller assigned to the same slot as the balance board. 297 | 298 | map nunchuk bal_x left_x 299 | 300 | should have no effect. 301 | 302 | Most games don't really handle the large shifts of a standing person well, but using it with one's feet while seated in a chair is surprisingly effective. 303 | 304 | In the future, I'd like it if the balance board can use the shifts from walking in place to modulate an output axis. A standard controller could pick the axis direction, but one's pace would affect the magnitude. It might be fun, but probably not very "immersive" compared to other foot-based input devices. 305 | 306 | All in all, the balance board functionality will probably always remain a novelty rather than an actually nice control scheme. Why not challenge some friends to some balance-board steering time trials for a laugh? 307 | 308 | In the future, WiimoteGlue might also export the four sensors themselves for mapping. One might be able to find uses, like trying to use the balance board as a set of pedals. 309 | 310 | ###Acceleration Tilt Controls? 311 | 312 | The accelerometer values are scaled a little to make them usable as a rough pitch/roll reading, but are otherwise sent directly. These values are very noisy; some extra processing to smooth them might be useful. 313 | 314 | Different wiimotes can often have different biases and scaling for their tilting, but WiimoteGlue does not support changing the axis calibrations. 315 | 316 | ###Rumble? 317 | 318 | Not supported. (yet?) 319 | 320 | ###Keyboard and mouse mappings? 321 | 322 | Still in rough early stages, but the basic functionality is there. 323 | 324 | For the full list of recognized key names, look at include/uapi/linux/input.h from the Linux kernel source for all the constants. Most things of the form "KEY_" are recognized if you make it all lowercase. 325 | 326 | Or you can look at the ugly huge key name lookup function in commandline.c present in WiimoteGlue. 327 | 328 | ###Analog triggers? 329 | 330 | Unsupported. However, only the original Classic controller extension for the wiimote has analog triggers. (The Classic controller pro, distinct from the Wii U pro controller, does not have analog triggers.) 331 | 332 | Unless you are using the oddly shaped oval classic controller with no hand grips, you aren't going to have analog triggers anyways. 333 | 334 | Mapping one of the various input axes to a virtual analog trigger is also unsupported, but this might change. 335 | 336 | ###Buttons to sticks? Sticks to buttons? 337 | 338 | Not supported. 339 | 340 | Currently buttons can only be mapped to buttons, and axes can only be mapped to axes. 341 | 342 | ###What are the default mappings anyways? 343 | 344 | I don't have this information in a handy format. Hopefully the "init_*_mapping()" functions in control_mappings.c will be sufficiently readable for the curious. 345 | 346 | ###Motion Plus? 347 | 348 | Unsupported, but it should be successfully ignored when present. Xwiimote does expose the motionplus data and even does a little calibration. If someone wants to write an effective way of using the gyroscope data on a virtual gamepad, please do so. 349 | 350 | Theoretically the Motion Plus gyroscope data and the Wii remote accelerometerscould be used together to create a fairly stable reading of the Wii remote's orientation of pitch, yaw, and roll in the real world. (The infared sensor could also be used for a nice re-calibration whenever the IR sources come into view again.) 351 | 352 | As is, the accelerometers provide a fairly noisy reading of pitch and roll, but yaw is entirely unknown. (The accelerometers can tell you the direction of gravity, when the Wii remote is held still.) 353 | 354 | ###Wiimote Guitar or Drum Controller? 355 | 356 | Unsupported, but reasonably easy to add. Xwiimote exposes these. I don't own either of these, so I didn't bother writing code I can't test. 357 | 358 | ###Wii U Gamepad? [that thing with the screen on it] 359 | 360 | Unsupported. It doesn't use bluetooth, but wifi to communicate. It is unlikely to ever be supported by this software. 361 | 362 | An an aside: Check out libDRC for some existing work on using the Wii U Gamepad under Linux. (It is rough at the the moment, and held back by the need to expose wifi TSF values to userspace, and not all wifi hardware handles TSF sufficiently for the gamepad.) As far I'm aware, once it is working, libDRC can handle the buttons on the Wii U Gamepad easily; the main challenge is streaming images to the screen in a way that the Gamepad will accept. 363 | 364 | 365 | ###Why not use the kernel driver itself, or the existing X11 driver xf86-input-xwiimote? 366 | 367 | As noted above, the kernel driver makes separate devices for different features/extensions of the wiimote, making them all but unusable in most games. The classic controller has legacy mapping issues leading to it being ignored by SDL. With the kernel driver alone, only the Wii U Pro controller is useful. 368 | 369 | The X11 driver is also handy, but it is designed for emulating a keyboard/mouse instead of a gamepad. Though it allows configuring the button mappings, it is not dynamic and cannot be changed while running. These two aspects make it not the most useful for playing games. 370 | 371 | 372 | ###Why all this hassle over switching between the fake gamepads and the fake keyboard? 373 | 374 | One could create a virtual device that has all the functionality of a gamepad, keyboard, and mouse all-in-one. However, both mice and gamepads use ABS_X and ABS_Y. If it was one device, We'd need to tell X to ignore or pay attention to ABS_X/Y depending on whether we are in gamepad mode or mouse mode, since most people don't want their gamepads controlling the cursor. 375 | 376 | By separating them, the gamepads are automagically picked up as gamepads, the fake keyboard/mouse is picked up as a keyboard/mouse, and not much extra work is needed. 377 | 378 | The evdev autodetection is pretty nice; let's let it do the work, even if we need to jump through a couple hoops to give it the right nudges. 379 | 380 | Theoretically WiimoteGlue could keep track of virtual device outputs on a per-button basis rather than per-device, but that seems like a lot of extra complexity for little gain. If you have a valid use case for a single wiimote having both gamepad buttons and keyboard keys on it, it'll be considered. 381 | 382 | 383 | ###Why not have WiimoteGlue talk to X directly to emulate the mouse when needed? 384 | 385 | * I don't want to deal with X code. 386 | * With Wayland potentially replacing X in the future, that sort of direct interaction doesn't seem wise. The Linux input system used by WiimoteGlue will likely be relatively stable. 387 | 388 | ###Why does WiimoteGlue capture Wii U Pro controllers? 389 | 390 | At the moment, this functionality doesn't give much advantage over just using the Wii U Pro controller directly. It does let the buttons be remapped, which can be nice for switching around the face buttons. 391 | 392 | Since WiimoteGlue handles LEDs based on slots, it makes a handy indicator on the pro controller. 393 | 394 | If one desires the balance board combo control schemes, grabbing the Wii U Pro controllers makes them usable for that. 395 | 396 | Overall, it seemed like a reasonably easy thing to add with little harm, and in the future it will allow some better consistency for playing with a mix of pro controllers and wiimotes. 397 | 398 | 399 | 400 | -------------------------------------------------------------------------------- /src/commandline.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "wiimoteglue.h" 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | /* Handles user input from STDIN and command files. */ 10 | 11 | /* Line reading and splitting based off of basic snippets 12 | * seen online in various places. 13 | * 14 | * Command parsing done entirely by hand. No need to 15 | * over-engineer this just yet, although consider 16 | * this fair warning that ugly code lies below. 17 | */ 18 | 19 | /* should be sufficient, and lets us avoid chewing memory 20 | * if the user opens a file with huge lines. 21 | * any command has limited length keywords, 22 | * so this should be a fair assumption. 23 | * 24 | * The maximum linelength is 25 | * (start size) * 2^n 26 | * since each realloc doubles the buffer. 27 | */ 28 | #define MAX_REALLOC 5 29 | 30 | char * getwholeline(int file) { 31 | char *buffer = malloc(50); 32 | char *ptr = buffer; 33 | size_t totallength = 50; 34 | int spaceleft = totallength; 35 | char nextchar[2]; 36 | int ret; 37 | int reallocs = 0; 38 | 39 | if(buffer == NULL) 40 | return NULL; 41 | 42 | /*Loop until a break, or the program as a whole receives a signal 43 | *to stop 44 | */ 45 | while(*KEEP_LOOPING) { 46 | ret = read(file,nextchar,1); 47 | if(ret <= 0) 48 | break; 49 | 50 | if(spaceleft > 0 && --spaceleft == 0 && reallocs < MAX_REALLOC ) { 51 | spaceleft = totallength; 52 | char *newbuff = realloc(buffer, totallength *= 2); 53 | 54 | if(newbuff == NULL) { 55 | free(buffer); 56 | return NULL; 57 | } 58 | 59 | ptr = newbuff + (ptr - buffer); 60 | buffer = newbuff; 61 | reallocs++; 62 | } 63 | 64 | if (spaceleft > 0 ) 65 | *ptr++ = nextchar[0]; 66 | 67 | if (nextchar[0] == '\n') 68 | break; 69 | } 70 | 71 | if (ptr == buffer) { 72 | /* nothing was read! Something wrong, EOF? */ 73 | free(buffer); 74 | return NULL; 75 | } 76 | 77 | *ptr = '\0'; 78 | return buffer; 79 | } 80 | 81 | #define NUM_WORDS 6 82 | void process_command(struct wiimoteglue_state *state, char *args[]); 83 | void update_mapping(struct wiimoteglue_state *state, struct mode_mappings* maps, char *mode, char *in, char *out, char *opt); 84 | void toggle_setting(struct wiimoteglue_state *state, struct mode_mappings* maps, int active, char *mode, char *setting, char *opt); 85 | int slot_command(struct wiimoteglue_state *state, char *slotname, char *setting, char *value); 86 | int list_objects(struct wiimoteglue_state *state, char *type, char *option); 87 | int list_devices(struct wii_device_list *devlist, char *option); 88 | int list_slots(struct wiimoteglue_state *state, char *option); 89 | int list_mappings(struct wiimoteglue_state *state, char *option); 90 | 91 | struct wii_device* lookup_device(struct wii_device_list *devlist, char *name); 92 | int * get_input_key(char *key_name, int button_map[]); 93 | int * get_input_axis(char *axis_name, struct event_map *map); 94 | int get_output_key(char *key_name); 95 | int get_output_axis(char *key_name); 96 | 97 | int wiimoteglue_handle_input(struct wiimoteglue_state *state, int file) { 98 | char *line = getwholeline(file); 99 | if (line != NULL) { 100 | char *lineptr = line; 101 | char *args[NUM_WORDS]; 102 | char **argptr; 103 | 104 | for (argptr = args; (*argptr = strsep(&lineptr, " \t\n")) != NULL;) { 105 | if (**argptr != '\0') { 106 | if (++argptr >= &args[NUM_WORDS]) { 107 | break; 108 | } 109 | } 110 | } 111 | 112 | 113 | process_command(state,args); 114 | 115 | 116 | free(line); 117 | return 0; 118 | } 119 | return -1; 120 | } 121 | 122 | void process_command(struct wiimoteglue_state *state, char *args[]) { 123 | /* lets avoid endless loops on our main thread, and 124 | * add some sanity if a person accidentally tries 125 | * to open a huge file. 126 | */ 127 | if (state->load_lines == MAX_LOAD_LINES) { 128 | printf("Maximum number of lines for command files exceeded.\n"); 129 | printf("Either you have an endless loop in files loading files,\n"); 130 | printf("or your command files are too big. There are only so many buttons to map...\n"); 131 | state->load_lines++; 132 | return; 133 | } 134 | state->load_lines++; 135 | 136 | if (args[0] == NULL) { 137 | return; 138 | } 139 | if (args[0][0] == '#') { 140 | return; 141 | } 142 | 143 | if (strcmp(args[0],"quit") == 0) { 144 | state->keep_looping = 0; 145 | return; 146 | } 147 | if (strcmp(args[0],"help") == 0) { 148 | printf("The following commands are recognized:\n"); 149 | printf("\thelp - show this message\n"); 150 | printf("\tmap - change a button/axis mapping\n"); 151 | printf("\tenable/disable - control extra controller features\n"); 152 | printf("\tlist [type] - list various WiimoteGlue structures\n"); 153 | printf("\tassign - assign a device to a virtual slot\n"); 154 | printf("\tslot - slot specific commands\n"); 155 | printf("\tdevice - device specific commands\n"); 156 | printf("\tmapping - mapping specific commands\n"); 157 | printf("\tnew mapping - create a new named mapping\n"); 158 | printf("\tload - opens a file and runs the commands inside\n"); 159 | printf("\tquit - close down WiimoteGlue\n"); 160 | printf("\tmodes - show recognized keywords for controller modes\n"); 161 | printf("\tevents - show recognized keywords for input/output events\n"); 162 | printf("\tfeatures - show recognized controller features to enable/disable\n"); 163 | printf("\nCommands expecting arguments will show their usage formats.\n"); 164 | return; 165 | } 166 | if (strcmp(args[0],"modes") == 0) { 167 | printf("A separate input mapping is maintained for each of the following modes.\n"); 168 | printf("The mode used changes automatically when extensions are inserted/removed.\n"); 169 | printf("\t\"wiimote\" - used when the wiimote has no extension. (Motion Plus is ignored.)\n"); 170 | printf("\t\"nunchuk\" - used when a nunchuk is present.\n"); 171 | printf("\t\"classic\" - used when a classic controller is present, or for a Wii U pro controller\n"); 172 | printf("\t\"all\" - applies to all three modes.\n"); 173 | return; 174 | } 175 | if (strcmp(args[0],"events") == 0) { 176 | printf("The recognized names for input buttons are:\n"); 177 | printf("up, down, left, right, a, b, c, x, y, z, plus, minus, home, 1, 2, l, r, zl, zr, thumbl, thumbr\n\n"); 178 | 179 | printf("The recognized names for input axes are:\n"); 180 | printf("\taccelx - wiimote acceleration x (tilt forward/back)\n"); 181 | printf("\taccely - wiimote acceleration y (tilt left/right)\n"); 182 | printf("\taccelz - wiimote acceleration z\n"); 183 | printf("\tir_x,ir_y - Infared \"pointer\" axes.\n"); 184 | printf("\tn_accelx - nunchuk acceleration x (tilt forward/back)\n"); 185 | printf("\tn_accely - nunchuk acceleration y (tilt left/right)\n"); 186 | printf("\tn_accelz - nunchuk acceleration z\n"); 187 | printf("\tn_x, n_y - nunchuck control stick axes\n"); 188 | printf("\tleft_x, left_y - classic/pro left stick axes\n"); 189 | printf("\tright_x, right_y - classic/pro right stick axes\n"); 190 | /*Not implemented at the moment. 191 | * printf("\tbal_fl,bal_fr,bal_bl,bal_br - balance board front/back left/right axes\n"); 192 | */ 193 | printf("\tbal_x,bal_y - balance board center-of-gravity axes.\n"); 194 | printf("\n"); 195 | 196 | printf("The recognized names for the synthetic gamepad output buttons are:\n"); 197 | printf("up, down, left, right, north, south, east, west, start, select, mode, tl, tr, tl2, tr2, thumbl, thumbr, none\n"); 198 | printf("(See the Linux gamepad API for these definitions. North/south/etc. refer to the action face buttons.)\n\n"); 199 | 200 | printf("When mapped to a keyboard/mouse, these button mappings are available:\n"); 201 | printf("\tleft_click, right_click, middle_click, key_a, key_leftshift, etc.\n"); 202 | printf("(look up uapi/linux/input.h for all key names, just make them lowercase)\n\n"); 203 | 204 | printf("The recognized names for the output axes are:\n"); 205 | printf("\tleft_x, left_y - left stick axes\n"); 206 | printf("\tright_x, right_y - right stick axes\n"); 207 | printf("\tnone - an ignored axis\n"); 208 | 209 | printf("\tmouse_x, mouse_y - aliases for left_x, left_y\n"); 210 | 211 | printf("Add \"invert\" at the end of an axis mapping to invert it.\n"); 212 | 213 | 214 | return; 215 | } 216 | if (strcmp(args[0],"features") == 0) { 217 | printf("The recognized extra features are:\n"); 218 | printf("\taccel - process and output acceleration axis mappings\n"); 219 | printf("\tir - process the wiimotes infared pointer axes\n"); 220 | printf("(currently no extra options for these features are recognized)\n"); 221 | return; 222 | } 223 | if (strcmp(args[0],"map") == 0) { 224 | struct mode_mappings* maps; 225 | if (mode_name_check(args[1]) >= 0) { 226 | /*The first argument was a mode name. 227 | *We assume the gamepad mapping by default. 228 | */ 229 | maps = lookup_mappings(state,"gamepad"); 230 | update_mapping(state,maps,args[1],args[2],args[3],args[4]); 231 | } else { 232 | maps = lookup_mappings(state,args[1]); 233 | update_mapping(state,maps,args[2],args[3],args[4],args[5]); 234 | } 235 | return; 236 | } 237 | if (strcmp(args[0],"enable") == 0) { 238 | struct mode_mappings* maps; 239 | if (mode_name_check(args[1]) >= 0) { 240 | /*The first argument was a mode name. 241 | *We assume the gamepad mapping by default. 242 | */ 243 | maps = lookup_mappings(state,"gamepad"); 244 | toggle_setting(state,maps,1,args[1],args[2],args[3]); 245 | 246 | } else { 247 | maps = lookup_mappings(state,args[1]); 248 | toggle_setting(state,maps,1,args[2],args[3],args[4]); 249 | } 250 | return; 251 | } 252 | if (strcmp(args[0],"disable") == 0) { 253 | struct mode_mappings* maps; 254 | if (mode_name_check(args[1]) >= 0) { 255 | /*The first argument was a mode name. 256 | *We assume the gamepad mapping by default. 257 | */ 258 | maps = lookup_mappings(state,"gamepad"); 259 | toggle_setting(state,maps,0,args[1],args[2],args[3]); 260 | 261 | } else { 262 | maps = lookup_mappings(state,args[1]); 263 | toggle_setting(state,maps,0,args[2],args[3],args[4]); 264 | } 265 | return; 266 | } 267 | if (strcmp(args[0],"load") == 0) { 268 | wiimoteglue_load_command_file(state,args[1]); 269 | return; 270 | } 271 | if (strcmp(args[0],"slot") == 0) { 272 | slot_command(state,args[1],args[2],args[3]); 273 | return; 274 | } 275 | if (strcmp(args[0],"assign") == 0) { 276 | assign_device(state,args[1],args[2]); 277 | return; 278 | } 279 | if (strcmp(args[0],"list") == 0) { 280 | list_objects(state,args[1],args[2]); 281 | return; 282 | } 283 | if (strcmp(args[0],"new") == 0) { 284 | create_user_item(state,args[1],args[2]); 285 | return; 286 | } 287 | if (strcmp(args[0],"delete") == 0) { 288 | delete_user_item(state,args[1],args[2]); 289 | return; 290 | } 291 | if (strcmp(args[0],"mapping") == 0) { 292 | mapping_command(state,args[1],args[2],args[3],args[4]); 293 | return; 294 | } 295 | if (strcmp(args[0],"device") == 0) { 296 | device_command(state,args[1],args[2],args[3],args[4]); 297 | return; 298 | } 299 | 300 | 301 | printf("Command not recognized.\n"); 302 | } 303 | 304 | void update_mapping(struct wiimoteglue_state *state, struct mode_mappings* maps, char *mode, char *in, char *out, char *opt) { 305 | struct event_map *mapping = NULL; 306 | 307 | 308 | if (maps == NULL || mode == NULL || in == NULL || out == NULL) { 309 | printf("Invalid command format.\n"); 310 | printf("usage: map [mapname] [invert]\n"); 311 | printf("If the gamepad/keyboardmouse specifier is omitted, gamepad is assumed.\n"); 312 | return; 313 | } 314 | 315 | if (strcmp(mode,"wiimote") == 0) { 316 | mapping = &maps->mode_no_ext; 317 | } else if (strcmp(mode,"nunchuk") == 0) { 318 | mapping = &maps->mode_nunchuk; 319 | } else if (strcmp(mode,"classic") == 0) { 320 | mapping = &maps->mode_classic; 321 | } else if (strcmp(mode,"all") == 0) { 322 | /*This is rather hack-ish. oh well.*/ 323 | update_mapping(state,maps,"wiimote",in,out,opt); 324 | update_mapping(state,maps,"nunchuk",in,out,opt); 325 | update_mapping(state,maps,"classic",in,out,opt); 326 | return; 327 | } 328 | 329 | if (mapping == NULL) { 330 | printf("Controller mode \"%s\" not recognized.\n(Valid modes are \"wiimote\",\"nunchuk\", and \"classic\")\n",mode); 331 | return; 332 | } 333 | 334 | int *button = get_input_key(in,mapping->button_map); 335 | if (button != NULL) { 336 | int new_key = get_output_key(out); 337 | if (new_key == -2) { 338 | printf("Output button \"%s\" not recognized. See \"events\" for valid values.\n",out); 339 | return; 340 | } 341 | 342 | *button = new_key; 343 | return; 344 | } 345 | 346 | int *axis = get_input_axis(in,mapping); 347 | 348 | if (axis != NULL) { 349 | int new_axis = get_output_axis(out); 350 | if (new_axis == -2) { 351 | printf("Output axis \"%s\" not recognized. See \"events\" for valid values.\n",out); 352 | return; 353 | } 354 | 355 | axis[0] = new_axis; 356 | 357 | if (opt != NULL && strcmp(opt,"invert") == 0) { 358 | axis[1] = -abs(axis[1]); 359 | } else { 360 | axis[1] = abs(axis[1]); 361 | } 362 | return; 363 | } 364 | 365 | 366 | printf("Input event \"%s\" not recognized. See \"events\" for valid values.\n",in); 367 | printf("usage: map [gamepad|keyboardmouse] [invert]\n"); 368 | return; 369 | 370 | 371 | } 372 | 373 | void toggle_setting(struct wiimoteglue_state *state, struct mode_mappings* maps, int active, char *mode, char *setting, char *opt) { 374 | struct event_map *mapping = NULL; 375 | 376 | if (maps == NULL || mode == NULL || setting == NULL) { 377 | printf("Invalid command format.\n"); 378 | printf("usage: [gamepad|keyboardmouse] [option]\n"); 379 | return; 380 | } 381 | 382 | if (strcmp(mode,"wiimote") == 0) { 383 | mapping = &maps->mode_no_ext; 384 | } else if (strcmp(mode,"nunchuk") == 0) { 385 | mapping = &maps->mode_nunchuk; 386 | } else if (strcmp(mode,"classic") == 0) { 387 | mapping = &maps->mode_classic; 388 | } else if (strcmp(mode,"all") == 0) { 389 | /* also hackish*/ 390 | toggle_setting(state,maps,active,"wiimote",setting,opt); 391 | toggle_setting(state,maps,active,"nunchuk",setting,opt); 392 | toggle_setting(state,maps,active,"classic",setting,opt); 393 | return; 394 | } 395 | 396 | if (mapping == NULL) { 397 | printf("Controller mode \"%s\" not recognized.\n(Valid modes are \"wiimote\",\"nunchuk\", and \"classic\")\n",mode); 398 | return; 399 | } 400 | 401 | if (strcmp(setting, "accel") == 0) { 402 | mapping->accel_active = active; 403 | wiimoteglue_update_all_wiimote_ifaces(&state->dev_list); 404 | return; 405 | } 406 | 407 | if (strcmp(setting, "ir") == 0) { 408 | int ir_count = 1; 409 | 410 | if (opt != NULL && strcmp(opt,"multiple") == 0) ir_count = 2; 411 | 412 | if (!active) ir_count = 0; 413 | 414 | /*currently multiple IR sources, or a single one are treated identically*/ 415 | mapping->IR_count = ir_count; 416 | wiimoteglue_update_all_wiimote_ifaces(&state->dev_list); 417 | return; 418 | } 419 | 420 | printf("Feature \"%s\" not recognized.\n",setting); 421 | printf("usage: [mapname] [option]\n"); 422 | } 423 | 424 | 425 | 426 | 427 | int wiimoteglue_load_command_file(struct wiimoteglue_state *state, char *filename) { 428 | if (filename == NULL) { 429 | printf("usage: load \n"); 430 | return 0; 431 | } 432 | int fd = open(filename,O_RDONLY); 433 | if (fd < 0) { 434 | printf("Failed to open file \'%s\'\n",filename); 435 | perror("Open"); 436 | return -1; 437 | } 438 | printf("Reading commands from file \'%s\'\n",filename); 439 | int ret = 0; 440 | while (ret >= 0) { 441 | if (state->load_lines > MAX_LOAD_LINES) { 442 | /*exceeded number of lines read, start backing out.*/ 443 | close(fd); 444 | return -2; 445 | } 446 | ret = wiimoteglue_handle_input(state, fd); 447 | } 448 | 449 | close(fd); 450 | return 0; 451 | 452 | } 453 | 454 | int slot_command(struct wiimoteglue_state* state, char* slotname, char* setting, char* value) { 455 | if (slotname == NULL || setting == NULL) { 456 | printf("usage: slot [value]\n"); 457 | printf("\tPossible settings: type, list, mapping, gamepad, keyboardmouse\n"); 458 | return -1; 459 | } 460 | 461 | 462 | int ret; 463 | struct virtual_controller* slot = lookup_slot(state,slotname); 464 | if (slot == NULL) { 465 | printf("\'%s\' was not a valid slot.\n",slotname); 466 | printf("Valid choices are "); 467 | int i; 468 | for (i = 0; i < state->num_slots; i++) { 469 | printf("%s, ",state->slots[i].slot_name); 470 | } 471 | /*Yes, that comma makes this worthwhile.*/ 472 | printf("%s",state->slots[state->num_slots].slot_name); 473 | return -1; 474 | } 475 | 476 | if (strcmp(setting, "gamepad") == 0) 477 | return slot_command(state,slotname,"type","gamepad"); 478 | 479 | if (strcmp(setting, "keyboardmouse") == 0) 480 | return slot_command(state,slotname,"type","keyboardmouse"); 481 | 482 | if (strcmp(setting, "list") == 0) { 483 | list_devices(&slot->dev_list,NULL); 484 | return 0; 485 | } 486 | 487 | if (strcmp(setting, "mapping") == 0) { 488 | if (value == NULL) { 489 | printf("Missing mapping name.\n"); 490 | return -1; 491 | } 492 | struct mode_mappings* maps = lookup_mappings(state,value); 493 | if (maps == NULL && strcmp(value,"none") != 0) { 494 | printf("Mapping named \"%s\" not found.\n",value); 495 | return -1; 496 | } 497 | set_slot_specific_mappings(slot,maps); 498 | wiimoteglue_compute_all_device_maps(state,&slot->dev_list); 499 | return 0; 500 | 501 | 502 | } 503 | 504 | if (strcmp(setting, "type") == 0) { 505 | if (value == NULL) { 506 | printf("Missing slot type value. \n(Either \"gamepad\" or \"keyboardmouse\");\n"); 507 | return -1; 508 | } 509 | int slot_type = -1; 510 | if (strcmp(value, "gamepad") == 0) 511 | slot_type = SLOT_GAMEPAD; 512 | if (strcmp(value, "keyboardmouse") == 0) 513 | slot_type = SLOT_KEYBOARDMOUSE; 514 | 515 | if (slot_type == -1) { 516 | printf("\"%s\" was not a slot type.\n(Either \"gamepad\" or \"keyboardmouse\")\n",value); 517 | return -1; 518 | } 519 | 520 | ret = change_slot_type(state,slot,slot_type); 521 | if (ret >= 0) { 522 | printf("Switched the slot %s's virtual device type.\n",slot->slot_name); 523 | } else { 524 | printf("Could not change slot %s's type.\n",slot->slot_name); 525 | return -1; 526 | } 527 | wiimoteglue_compute_all_device_maps(state,&slot->dev_list); 528 | return 0; 529 | 530 | } 531 | 532 | 533 | 534 | 535 | printf("\'%s\' was not a recognized slot command.\n",setting); 536 | printf("(\"type\",\"mapping\", and \"list\" are choices)\n"); 537 | 538 | return -1; 539 | } 540 | 541 | int assign_device(struct wiimoteglue_state *state, char *devname, char *slotname) { 542 | if (devname == NULL || slotname == NULL) { 543 | printf("usage: assign \n"); 544 | return 0; 545 | } 546 | struct wii_device* device = lookup_device(&state->dev_list,devname); 547 | if (device == NULL) { 548 | printf("\'%s\' did not match a device id or address.\n",devname); 549 | printf("Use \"list\" to see devices.\n"); 550 | return -1; 551 | } 552 | struct virtual_controller* slot = lookup_slot(state,slotname); 553 | 554 | if (slot == NULL && strcmp(slotname,"none") != 0) { 555 | printf("\'%s\' was not a valid slot.\n",slotname); 556 | printf("Valid choices are "); 557 | int i; 558 | for (i = 0; i <= state->num_slots; i++) { 559 | printf("%s, ",state->slots[i].slot_name); 560 | } 561 | printf("none\n"); 562 | return -1; 563 | } 564 | 565 | int ret; 566 | /*Both of these functions handle NULL slots correctly*/ 567 | ret = remove_device_from_slot(device); 568 | if (ret < 0) { 569 | printf("Something went wrong when removing from previous slot.\n"); 570 | return -1; 571 | } 572 | 573 | 574 | ret = add_device_to_slot(state,device,slot); 575 | if (ret < 0) { 576 | printf("Something went wrong when adding to new slot.\n"); 577 | return -1; 578 | } 579 | 580 | if (device->slot == NULL) { 581 | close_wii_device(state,device); 582 | } else { 583 | open_wii_device(state,device); 584 | } 585 | 586 | return 0; 587 | 588 | } 589 | 590 | int device_command(struct wiimoteglue_state *state, char *devname, char *command, char *value) { 591 | if (devname == NULL || command == NULL || value == NULL) { 592 | printf("\"device mapping \"\n"); 593 | printf("\"device rename \"\n"); 594 | return -1; 595 | } 596 | 597 | struct wii_device *dev = lookup_device(&state->dev_list,devname); 598 | if (dev == NULL && strcmp(command,"rename") != 0) { 599 | printf("Could not find device \"%s\"\n",devname); 600 | return -1; 601 | } 602 | 603 | if (strcmp(command,"mapping") == 0) { 604 | struct mode_mappings *maps = lookup_mappings(state,value); 605 | if (maps == NULL && strcmp(value,"none") != 0) { 606 | printf("Could not find mapping \"%s\"\n",value); 607 | return -1; 608 | } 609 | 610 | set_device_specific_mappings(dev,maps); 611 | return 0; 612 | } 613 | 614 | if (strcmp(command,"rename") == 0) { 615 | if (memchr(value,'\0',WG_MAX_NAME_SIZE) == NULL) { 616 | printf("New name is too long. Must be %d characters or less.\n",WG_MAX_NAME_SIZE-1); 617 | return -1; 618 | } 619 | if (strchr(value,':') != NULL || strchr(value,' ') != NULL) { 620 | printf("Invalid name. \":\" and \" \" are forbidden.\n"); 621 | return -1; 622 | } 623 | 624 | if (dev == NULL) { 625 | if (strchr(devname,':') == NULL || strchr(devname,' ') != NULL) { 626 | printf("Device %s not found, and that is not a possible unique device address.\n",devname); 627 | return -1; 628 | } 629 | struct wii_device_list* node = new_wii_device(state,devname); 630 | dev = node->dev; 631 | } 632 | 633 | strncpy(dev->id, value, WG_MAX_NAME_SIZE); 634 | return 0; 635 | } 636 | 637 | 638 | 639 | return 0; 640 | } 641 | 642 | int mapping_command(struct wiimoteglue_state *state, char *mapname, char *command, char *value) { 643 | if (mapname == NULL || command == NULL || value == NULL || strcmp(command,"copyfrom") != 0) { 644 | printf("Currently only \"mapping copyfrom \" is supported.\n"); 645 | return -1; 646 | } 647 | 648 | struct mode_mappings *maps = lookup_mappings(state,mapname); 649 | if (maps == NULL) { 650 | printf("Could not find mapping \"%s\"\n",mapname); 651 | return -1; 652 | } 653 | 654 | if (strcmp(command,"copyfrom") == 0) { 655 | struct mode_mappings *mapsrc = lookup_mappings(state,value); 656 | if (mapsrc == NULL) { 657 | printf("Could not find mapping \"%s\"\n",value); 658 | return -1; 659 | } 660 | 661 | copy_mappings(maps,mapsrc); 662 | return 0; 663 | } 664 | 665 | 666 | return 0; 667 | } 668 | 669 | int list_objects(struct wiimoteglue_state *state, char *type, char *option) { 670 | if (type == NULL) { 671 | printf("Slots:\n"); 672 | list_slots(state,NULL); 673 | printf("\nMappings:\n"); 674 | list_mappings(state,NULL); 675 | printf("\nDevices:\n"); 676 | list_devices(&state->dev_list,NULL); 677 | return; 678 | } 679 | 680 | if (strcmp(type,"devices") == 0) 681 | return list_devices(&state->dev_list,option); 682 | 683 | if (strcmp(type,"slots") == 0) 684 | return list_slots(state,option); 685 | 686 | if (strcmp(type,"mappings") == 0) 687 | return list_mappings(state,option); 688 | 689 | printf("\"%s\" not recognized.\n",type); 690 | printf("Valid list types are \"devices\", \"slots\", and \"mappings\"\n"); 691 | return -1; 692 | 693 | 694 | } 695 | 696 | void display_mapping(struct mode_mappings *maps) { 697 | /*This will be more useful 698 | *when there is more info to show about a map. 699 | */ 700 | printf("- %s\n",maps->name); 701 | if (maps->reference_count > 1) 702 | printf("\t%d devices/slots using this as their specific mapping\n",maps->reference_count-1); 703 | } 704 | 705 | int list_mappings(struct wiimoteglue_state *state, char *option) { 706 | struct map_list *list_node = &state->head_map; 707 | display_mapping(&list_node->maps); 708 | list_node = list_node->next; 709 | 710 | for (;*KEEP_LOOPING && list_node != NULL && list_node != &state->head_map; list_node = list_node->next) { 711 | display_mapping(&list_node->maps); 712 | } 713 | return 0; 714 | } 715 | 716 | int list_slots(struct wiimoteglue_state *state, char *option) { 717 | int i; 718 | for (i = 0; i <= state->num_slots; i++) { 719 | struct virtual_controller *slot = &state->slots[i]; 720 | printf("- %s:\n",slot->slot_name); 721 | if (slot->has_wiimote) 722 | printf("\tcontrollers: %d\n",slot->has_wiimote); 723 | if (slot->has_board) 724 | printf("\tboards: %d\n",slot->has_board); 725 | if (slot->slot_specific_mappings != NULL) 726 | printf("\tspecific mapping: %s\n",slot->slot_specific_mappings->name); 727 | } 728 | 729 | return 0; 730 | } 731 | 732 | int create_user_item(struct wiimoteglue_state *state, char *type, char *name) { 733 | if (type == NULL || strcmp(type,"mapping") != 0) { 734 | printf("Currently only \"new mapping \" is supported"); 735 | return -1; 736 | } 737 | 738 | if (name == NULL) { 739 | printf("A name for the new mapping is required."); 740 | return -1; 741 | } 742 | 743 | if (strncmp(name,"dev",3) == 0) { 744 | printf("Cannot create something that conflicts with device naming.\n"); 745 | return -1; 746 | } 747 | 748 | if (mode_name_check(name) >= 0) { 749 | printf("Cannot create something that conflicts with a mode name.\n"); 750 | return -1; 751 | } 752 | 753 | if (lookup_mappings(state,name) != NULL) { 754 | printf("A mapping already exists with that name."); 755 | return -1; 756 | } 757 | 758 | if (lookup_slot(state,name) != NULL) { 759 | printf("Cannot create something that conflicts with a slot name\n"); 760 | return -1; 761 | } 762 | 763 | create_mappings(state,name); 764 | return 0; 765 | } 766 | 767 | int delete_user_item(struct wiimoteglue_state *state, char *type, char *name) { 768 | if (type == NULL || strcmp(type,"mapping") != 0) { 769 | printf("Currently only \"delete mapping \" is supported"); 770 | return -1; 771 | } 772 | 773 | if (name == NULL) { 774 | printf("A name for the mapping to delete is required."); 775 | } 776 | 777 | struct mode_mappings *maps = lookup_mappings(state,name); 778 | if (maps == NULL) { 779 | printf("No mapping exists with that name."); 780 | return -1; 781 | } 782 | 783 | return forget_mapping(state,maps); 784 | } 785 | 786 | int list_devices(struct wii_device_list *devlist, char *option) { 787 | if (devlist == NULL) { 788 | return -1; 789 | } 790 | struct wii_device_list* list_node = devlist->next; 791 | 792 | static char* wiimote = "Wii Remote"; 793 | static char* pro = "Wii U Pro Controller"; 794 | static char* board = "Balance Board"; 795 | static char* unknown = "Unknown Device Type"; 796 | static char* nunchuk = " + Nunchuk"; 797 | static char* classic = " + Classic Controller"; 798 | char* type = unknown; 799 | char* ext = ""; 800 | 801 | while (*KEEP_LOOPING && list_node != devlist && list_node != NULL) { 802 | struct wii_device* dev = list_node->dev; 803 | if (dev != NULL) { 804 | if (dev->type == REMOTE) { 805 | type = wiimote; 806 | if (dev->mode == NUNCHUK) 807 | ext = nunchuk; 808 | if (dev->mode == CLASSIC) 809 | ext = classic; 810 | } 811 | if (dev->type == PRO) 812 | type = pro; 813 | if (dev->type == BALANCE) 814 | type = board; 815 | 816 | printf("\n- %s (%s)\n",dev->id,dev->bluetooth_addr); 817 | printf("\t%s%s\n",type,ext); 818 | if (dev->dev_specific_mappings != NULL) { 819 | printf("\tDevice specific mapping: %s\n",dev->dev_specific_mappings->name); 820 | } 821 | 822 | if (dev->slot != NULL) { 823 | printf("\tAssigned to slot %s\n",dev->slot->slot_name); 824 | 825 | if (dev->slot->slot_specific_mappings != NULL) 826 | printf("\t (slot has a specific mapping: %s)\n",dev->slot->slot_specific_mappings->name); 827 | } else { 828 | printf("\tNot assigned to any slot\n"); 829 | } 830 | if (dev->xwii == NULL) { 831 | printf("\tThis device is currently closed.\n"); 832 | } 833 | if (dev->udev == NULL) { 834 | printf("\tThis device is not connected.\n"); 835 | } 836 | 837 | 838 | } 839 | 840 | list_node = list_node->next; 841 | } 842 | 843 | 844 | return 0; 845 | } 846 | 847 | struct wii_device * lookup_device(struct wii_device_list *devlist, char *name) { 848 | 849 | if (devlist == NULL) { 850 | return NULL; 851 | } 852 | 853 | struct wii_device_list* list_node = devlist->next; 854 | 855 | while (*KEEP_LOOPING && list_node != devlist && list_node != NULL) { 856 | 857 | 858 | if (list_node->dev != NULL) { 859 | if (strncmp(name,list_node->dev->id,WG_MAX_NAME_SIZE) == 0) 860 | return list_node->dev; 861 | if (strncmp(name,list_node->dev->bluetooth_addr,18) == 0) 862 | return list_node->dev; 863 | } 864 | 865 | list_node = list_node->next; 866 | } 867 | 868 | 869 | return NULL; 870 | } 871 | 872 | 873 | 874 | -------------------------------------------------------------------------------- /src/key_codes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "wiimoteglue.h" 6 | 7 | /*If you can't compile this file because some KEY_* 8 | *constant is undefined, check the build_util/generate_key_codes 9 | *script. 10 | * 11 | *It will make a brand new version of this entire file. 12 | */ 13 | 14 | int * get_input_key(char *key_name, int button_map[]) { 15 | if (key_name == NULL) return NULL; 16 | if (strcmp(key_name,"up") == 0) return &button_map[XWII_KEY_UP]; 17 | if (strcmp(key_name,"down") == 0) return &button_map[XWII_KEY_DOWN]; 18 | if (strcmp(key_name,"left") == 0) return &button_map[XWII_KEY_LEFT]; 19 | if (strcmp(key_name,"right") == 0) return &button_map[XWII_KEY_RIGHT]; 20 | if (strcmp(key_name,"a") == 0) return &button_map[XWII_KEY_A]; 21 | if (strcmp(key_name,"b") == 0) return &button_map[XWII_KEY_B]; 22 | if (strcmp(key_name,"c") == 0) return &button_map[XWII_KEY_C]; 23 | if (strcmp(key_name,"x") == 0) return &button_map[XWII_KEY_X]; 24 | if (strcmp(key_name,"y") == 0) return &button_map[XWII_KEY_Y]; 25 | if (strcmp(key_name,"z") == 0) return &button_map[XWII_KEY_Z]; 26 | if (strcmp(key_name,"plus") == 0) return &button_map[XWII_KEY_PLUS]; 27 | if (strcmp(key_name,"minus") == 0) return &button_map[XWII_KEY_MINUS]; 28 | if (strcmp(key_name,"home") == 0) return &button_map[XWII_KEY_HOME]; 29 | if (strcmp(key_name,"1") == 0) return &button_map[XWII_KEY_ONE]; 30 | if (strcmp(key_name,"2") == 0) return &button_map[XWII_KEY_TWO]; 31 | if (strcmp(key_name,"l") == 0) return &button_map[XWII_KEY_TL]; 32 | if (strcmp(key_name,"r") == 0) return &button_map[XWII_KEY_TR]; 33 | if (strcmp(key_name,"zl") == 0) return &button_map[XWII_KEY_ZL]; 34 | if (strcmp(key_name,"zr") == 0) return &button_map[XWII_KEY_ZR]; 35 | if (strcmp(key_name,"thumbl") == 0) return &button_map[XWII_KEY_THUMBL]; 36 | if (strcmp(key_name,"thumbr") == 0) return &button_map[XWII_KEY_THUMBR]; 37 | return NULL; 38 | } 39 | 40 | int * get_input_axis(char *axis_name, struct event_map *map) { 41 | if (axis_name == NULL) return NULL; 42 | if (strcmp(axis_name,"accelx") == 0) return map->accel_map[0]; 43 | if (strcmp(axis_name,"accely") == 0) return map->accel_map[1]; 44 | if (strcmp(axis_name,"accelz") == 0) return map->accel_map[2]; 45 | if (strcmp(axis_name,"n_accelx") == 0) return map->accel_map[3]; 46 | if (strcmp(axis_name,"n_accely") == 0) return map->accel_map[4]; 47 | if (strcmp(axis_name,"n_accelz") == 0) return map->accel_map[5]; 48 | if (strcmp(axis_name,"left_x") == 0) return map->stick_map[0]; 49 | if (strcmp(axis_name,"left_y") == 0) return map->stick_map[1]; 50 | if (strcmp(axis_name,"right_x") == 0) return map->stick_map[2]; 51 | if (strcmp(axis_name,"right_y") == 0) return map->stick_map[3]; 52 | if (strcmp(axis_name,"n_x") == 0) return map->stick_map[4]; 53 | if (strcmp(axis_name,"n_y") == 0) return map->stick_map[5]; 54 | if (strcmp(axis_name,"ir_x") == 0) return map->IR_map[0]; 55 | if (strcmp(axis_name,"ir_y") == 0) return map->IR_map[1]; 56 | if (strcmp(axis_name,"bal_fl") == 0) return map->balance_map[0]; 57 | if (strcmp(axis_name,"bal_fr") == 0) return map->balance_map[1]; 58 | if (strcmp(axis_name,"bal_bl") == 0) return map->balance_map[2]; 59 | if (strcmp(axis_name,"bal_br") == 0) return map->balance_map[3]; 60 | if (strcmp(axis_name,"bal_x") == 0) return map->balance_map[4]; 61 | if (strcmp(axis_name,"bal_y") == 0) return map->balance_map[5]; 62 | 63 | return NULL; 64 | } 65 | 66 | int get_output_key(char *key_name) { 67 | if (key_name == NULL) return -2; 68 | if (strcmp(key_name,"up") == 0) return BTN_DPAD_UP; 69 | if (strcmp(key_name,"down") == 0) return BTN_DPAD_DOWN; 70 | if (strcmp(key_name,"left") == 0) return BTN_DPAD_LEFT; 71 | if (strcmp(key_name,"right") == 0) return BTN_DPAD_RIGHT; 72 | if (strcmp(key_name,"north") == 0) return BTN_NORTH; 73 | if (strcmp(key_name,"south") == 0) return BTN_SOUTH; 74 | if (strcmp(key_name,"east") == 0) return BTN_EAST; 75 | if (strcmp(key_name,"west") == 0) return BTN_WEST; 76 | if (strcmp(key_name,"start") == 0) return BTN_START; 77 | if (strcmp(key_name,"select") == 0) return BTN_SELECT; 78 | if (strcmp(key_name,"mode") == 0) return BTN_MODE; 79 | if (strcmp(key_name,"tr") == 0) return BTN_TR; 80 | if (strcmp(key_name,"tl") == 0) return BTN_TL; 81 | if (strcmp(key_name,"tr2") == 0) return BTN_TR2; 82 | if (strcmp(key_name,"tl2") == 0) return BTN_TL2; 83 | if (strcmp(key_name,"thumbr") == 0) return BTN_THUMBR; 84 | if (strcmp(key_name,"thumbl") == 0) return BTN_THUMBL; 85 | if (strcmp(key_name,"thumbl") == 0) return BTN_THUMBL; 86 | if (strcmp(key_name,"none") == 0) return NO_MAP; 87 | if (strcmp(key_name,"left_click") == 0) return BTN_LEFT; 88 | if (strcmp(key_name,"right_click") == 0) return BTN_RIGHT; 89 | if (strcmp(key_name,"middle_click") == 0) return BTN_MIDDLE; 90 | if (strcmp(key_name,"key_esc") == 0) return KEY_ESC; 91 | if (strcmp(key_name,"key_1") == 0) return KEY_1; 92 | if (strcmp(key_name,"key_2") == 0) return KEY_2; 93 | if (strcmp(key_name,"key_3") == 0) return KEY_3; 94 | if (strcmp(key_name,"key_4") == 0) return KEY_4; 95 | if (strcmp(key_name,"key_5") == 0) return KEY_5; 96 | if (strcmp(key_name,"key_6") == 0) return KEY_6; 97 | if (strcmp(key_name,"key_7") == 0) return KEY_7; 98 | if (strcmp(key_name,"key_8") == 0) return KEY_8; 99 | if (strcmp(key_name,"key_9") == 0) return KEY_9; 100 | if (strcmp(key_name,"key_0") == 0) return KEY_0; 101 | if (strcmp(key_name,"key_minus") == 0) return KEY_MINUS; 102 | if (strcmp(key_name,"key_equal") == 0) return KEY_EQUAL; 103 | if (strcmp(key_name,"key_backspace") == 0) return KEY_BACKSPACE; 104 | if (strcmp(key_name,"key_tab") == 0) return KEY_TAB; 105 | if (strcmp(key_name,"key_q") == 0) return KEY_Q; 106 | if (strcmp(key_name,"key_w") == 0) return KEY_W; 107 | if (strcmp(key_name,"key_e") == 0) return KEY_E; 108 | if (strcmp(key_name,"key_r") == 0) return KEY_R; 109 | if (strcmp(key_name,"key_t") == 0) return KEY_T; 110 | if (strcmp(key_name,"key_y") == 0) return KEY_Y; 111 | if (strcmp(key_name,"key_u") == 0) return KEY_U; 112 | if (strcmp(key_name,"key_i") == 0) return KEY_I; 113 | if (strcmp(key_name,"key_o") == 0) return KEY_O; 114 | if (strcmp(key_name,"key_p") == 0) return KEY_P; 115 | if (strcmp(key_name,"key_leftbrace") == 0) return KEY_LEFTBRACE; 116 | if (strcmp(key_name,"key_rightbrace") == 0) return KEY_RIGHTBRACE; 117 | if (strcmp(key_name,"key_enter") == 0) return KEY_ENTER; 118 | if (strcmp(key_name,"key_leftctrl") == 0) return KEY_LEFTCTRL; 119 | if (strcmp(key_name,"key_a") == 0) return KEY_A; 120 | if (strcmp(key_name,"key_s") == 0) return KEY_S; 121 | if (strcmp(key_name,"key_d") == 0) return KEY_D; 122 | if (strcmp(key_name,"key_f") == 0) return KEY_F; 123 | if (strcmp(key_name,"key_g") == 0) return KEY_G; 124 | if (strcmp(key_name,"key_h") == 0) return KEY_H; 125 | if (strcmp(key_name,"key_j") == 0) return KEY_J; 126 | if (strcmp(key_name,"key_k") == 0) return KEY_K; 127 | if (strcmp(key_name,"key_l") == 0) return KEY_L; 128 | if (strcmp(key_name,"key_semicolon") == 0) return KEY_SEMICOLON; 129 | if (strcmp(key_name,"key_apostrophe") == 0) return KEY_APOSTROPHE; 130 | if (strcmp(key_name,"key_grave") == 0) return KEY_GRAVE; 131 | if (strcmp(key_name,"key_leftshift") == 0) return KEY_LEFTSHIFT; 132 | if (strcmp(key_name,"key_backslash") == 0) return KEY_BACKSLASH; 133 | if (strcmp(key_name,"key_z") == 0) return KEY_Z; 134 | if (strcmp(key_name,"key_x") == 0) return KEY_X; 135 | if (strcmp(key_name,"key_c") == 0) return KEY_C; 136 | if (strcmp(key_name,"key_v") == 0) return KEY_V; 137 | if (strcmp(key_name,"key_b") == 0) return KEY_B; 138 | if (strcmp(key_name,"key_n") == 0) return KEY_N; 139 | if (strcmp(key_name,"key_m") == 0) return KEY_M; 140 | if (strcmp(key_name,"key_comma") == 0) return KEY_COMMA; 141 | if (strcmp(key_name,"key_dot") == 0) return KEY_DOT; 142 | if (strcmp(key_name,"key_slash") == 0) return KEY_SLASH; 143 | if (strcmp(key_name,"key_rightshift") == 0) return KEY_RIGHTSHIFT; 144 | if (strcmp(key_name,"key_kpasterisk") == 0) return KEY_KPASTERISK; 145 | if (strcmp(key_name,"key_leftalt") == 0) return KEY_LEFTALT; 146 | if (strcmp(key_name,"key_space") == 0) return KEY_SPACE; 147 | if (strcmp(key_name,"key_capslock") == 0) return KEY_CAPSLOCK; 148 | if (strcmp(key_name,"key_f1") == 0) return KEY_F1; 149 | if (strcmp(key_name,"key_f2") == 0) return KEY_F2; 150 | if (strcmp(key_name,"key_f3") == 0) return KEY_F3; 151 | if (strcmp(key_name,"key_f4") == 0) return KEY_F4; 152 | if (strcmp(key_name,"key_f5") == 0) return KEY_F5; 153 | if (strcmp(key_name,"key_f6") == 0) return KEY_F6; 154 | if (strcmp(key_name,"key_f7") == 0) return KEY_F7; 155 | if (strcmp(key_name,"key_f8") == 0) return KEY_F8; 156 | if (strcmp(key_name,"key_f9") == 0) return KEY_F9; 157 | if (strcmp(key_name,"key_f10") == 0) return KEY_F10; 158 | if (strcmp(key_name,"key_numlock") == 0) return KEY_NUMLOCK; 159 | if (strcmp(key_name,"key_scrolllock") == 0) return KEY_SCROLLLOCK; 160 | if (strcmp(key_name,"key_kp7") == 0) return KEY_KP7; 161 | if (strcmp(key_name,"key_kp8") == 0) return KEY_KP8; 162 | if (strcmp(key_name,"key_kp9") == 0) return KEY_KP9; 163 | if (strcmp(key_name,"key_kpminus") == 0) return KEY_KPMINUS; 164 | if (strcmp(key_name,"key_kp4") == 0) return KEY_KP4; 165 | if (strcmp(key_name,"key_kp5") == 0) return KEY_KP5; 166 | if (strcmp(key_name,"key_kp6") == 0) return KEY_KP6; 167 | if (strcmp(key_name,"key_kpplus") == 0) return KEY_KPPLUS; 168 | if (strcmp(key_name,"key_kp1") == 0) return KEY_KP1; 169 | if (strcmp(key_name,"key_kp2") == 0) return KEY_KP2; 170 | if (strcmp(key_name,"key_kp3") == 0) return KEY_KP3; 171 | if (strcmp(key_name,"key_kp0") == 0) return KEY_KP0; 172 | #ifndef NO_EXTRA_KEYBOARD_KEYS 173 | if (strcmp(key_name,"key_kpdot") == 0) return KEY_KPDOT; 174 | if (strcmp(key_name,"key_zenkakuhankaku") == 0) return KEY_ZENKAKUHANKAKU; 175 | if (strcmp(key_name,"key_102nd") == 0) return KEY_102ND; 176 | if (strcmp(key_name,"key_f11") == 0) return KEY_F11; 177 | if (strcmp(key_name,"key_f12") == 0) return KEY_F12; 178 | if (strcmp(key_name,"key_ro") == 0) return KEY_RO; 179 | if (strcmp(key_name,"key_katakana") == 0) return KEY_KATAKANA; 180 | if (strcmp(key_name,"key_hiragana") == 0) return KEY_HIRAGANA; 181 | if (strcmp(key_name,"key_henkan") == 0) return KEY_HENKAN; 182 | if (strcmp(key_name,"key_katakanahiragana") == 0) return KEY_KATAKANAHIRAGANA; 183 | if (strcmp(key_name,"key_muhenkan") == 0) return KEY_MUHENKAN; 184 | if (strcmp(key_name,"key_kpjpcomma") == 0) return KEY_KPJPCOMMA; 185 | if (strcmp(key_name,"key_kpenter") == 0) return KEY_KPENTER; 186 | if (strcmp(key_name,"key_rightctrl") == 0) return KEY_RIGHTCTRL; 187 | if (strcmp(key_name,"key_kpslash") == 0) return KEY_KPSLASH; 188 | if (strcmp(key_name,"key_sysrq") == 0) return KEY_SYSRQ; 189 | if (strcmp(key_name,"key_rightalt") == 0) return KEY_RIGHTALT; 190 | if (strcmp(key_name,"key_linefeed") == 0) return KEY_LINEFEED; 191 | if (strcmp(key_name,"key_home") == 0) return KEY_HOME; 192 | if (strcmp(key_name,"key_up") == 0) return KEY_UP; 193 | if (strcmp(key_name,"key_pageup") == 0) return KEY_PAGEUP; 194 | if (strcmp(key_name,"key_left") == 0) return KEY_LEFT; 195 | if (strcmp(key_name,"key_right") == 0) return KEY_RIGHT; 196 | if (strcmp(key_name,"key_end") == 0) return KEY_END; 197 | if (strcmp(key_name,"key_down") == 0) return KEY_DOWN; 198 | if (strcmp(key_name,"key_pagedown") == 0) return KEY_PAGEDOWN; 199 | if (strcmp(key_name,"key_insert") == 0) return KEY_INSERT; 200 | if (strcmp(key_name,"key_delete") == 0) return KEY_DELETE; 201 | if (strcmp(key_name,"key_macro") == 0) return KEY_MACRO; 202 | if (strcmp(key_name,"key_mute") == 0) return KEY_MUTE; 203 | if (strcmp(key_name,"key_volumedown") == 0) return KEY_VOLUMEDOWN; 204 | if (strcmp(key_name,"key_volumeup") == 0) return KEY_VOLUMEUP; 205 | if (strcmp(key_name,"key_power") == 0) return KEY_POWER; 206 | if (strcmp(key_name,"key_kpequal") == 0) return KEY_KPEQUAL; 207 | if (strcmp(key_name,"key_kpplusminus") == 0) return KEY_KPPLUSMINUS; 208 | if (strcmp(key_name,"key_pause") == 0) return KEY_PAUSE; 209 | if (strcmp(key_name,"key_scale") == 0) return KEY_SCALE; 210 | if (strcmp(key_name,"key_kpcomma") == 0) return KEY_KPCOMMA; 211 | if (strcmp(key_name,"key_hangeul") == 0) return KEY_HANGEUL; 212 | if (strcmp(key_name,"key_hanguel") == 0) return KEY_HANGUEL; 213 | if (strcmp(key_name,"key_hangeul") == 0) return KEY_HANGEUL; 214 | if (strcmp(key_name,"key_hanja") == 0) return KEY_HANJA; 215 | if (strcmp(key_name,"key_yen") == 0) return KEY_YEN; 216 | if (strcmp(key_name,"key_leftmeta") == 0) return KEY_LEFTMETA; 217 | if (strcmp(key_name,"key_rightmeta") == 0) return KEY_RIGHTMETA; 218 | if (strcmp(key_name,"key_compose") == 0) return KEY_COMPOSE; 219 | if (strcmp(key_name,"key_stop") == 0) return KEY_STOP; 220 | if (strcmp(key_name,"key_again") == 0) return KEY_AGAIN; 221 | if (strcmp(key_name,"key_props") == 0) return KEY_PROPS; 222 | if (strcmp(key_name,"key_undo") == 0) return KEY_UNDO; 223 | if (strcmp(key_name,"key_front") == 0) return KEY_FRONT; 224 | if (strcmp(key_name,"key_copy") == 0) return KEY_COPY; 225 | if (strcmp(key_name,"key_open") == 0) return KEY_OPEN; 226 | if (strcmp(key_name,"key_paste") == 0) return KEY_PASTE; 227 | if (strcmp(key_name,"key_find") == 0) return KEY_FIND; 228 | if (strcmp(key_name,"key_cut") == 0) return KEY_CUT; 229 | if (strcmp(key_name,"key_help") == 0) return KEY_HELP; 230 | if (strcmp(key_name,"key_menu") == 0) return KEY_MENU; 231 | if (strcmp(key_name,"key_calc") == 0) return KEY_CALC; 232 | if (strcmp(key_name,"key_setup") == 0) return KEY_SETUP; 233 | if (strcmp(key_name,"key_sleep") == 0) return KEY_SLEEP; 234 | if (strcmp(key_name,"key_wakeup") == 0) return KEY_WAKEUP; 235 | if (strcmp(key_name,"key_file") == 0) return KEY_FILE; 236 | if (strcmp(key_name,"key_sendfile") == 0) return KEY_SENDFILE; 237 | if (strcmp(key_name,"key_deletefile") == 0) return KEY_DELETEFILE; 238 | if (strcmp(key_name,"key_xfer") == 0) return KEY_XFER; 239 | if (strcmp(key_name,"key_prog1") == 0) return KEY_PROG1; 240 | if (strcmp(key_name,"key_prog2") == 0) return KEY_PROG2; 241 | if (strcmp(key_name,"key_www") == 0) return KEY_WWW; 242 | if (strcmp(key_name,"key_msdos") == 0) return KEY_MSDOS; 243 | if (strcmp(key_name,"key_coffee") == 0) return KEY_COFFEE; 244 | if (strcmp(key_name,"key_screenlock") == 0) return KEY_SCREENLOCK; 245 | if (strcmp(key_name,"key_coffee") == 0) return KEY_COFFEE; 246 | if (strcmp(key_name,"key_direction") == 0) return KEY_DIRECTION; 247 | if (strcmp(key_name,"key_cyclewindows") == 0) return KEY_CYCLEWINDOWS; 248 | if (strcmp(key_name,"key_mail") == 0) return KEY_MAIL; 249 | if (strcmp(key_name,"key_bookmarks") == 0) return KEY_BOOKMARKS; 250 | if (strcmp(key_name,"key_computer") == 0) return KEY_COMPUTER; 251 | if (strcmp(key_name,"key_back") == 0) return KEY_BACK; 252 | if (strcmp(key_name,"key_forward") == 0) return KEY_FORWARD; 253 | if (strcmp(key_name,"key_closecd") == 0) return KEY_CLOSECD; 254 | if (strcmp(key_name,"key_ejectcd") == 0) return KEY_EJECTCD; 255 | if (strcmp(key_name,"key_ejectclosecd") == 0) return KEY_EJECTCLOSECD; 256 | if (strcmp(key_name,"key_nextsong") == 0) return KEY_NEXTSONG; 257 | if (strcmp(key_name,"key_playpause") == 0) return KEY_PLAYPAUSE; 258 | if (strcmp(key_name,"key_previoussong") == 0) return KEY_PREVIOUSSONG; 259 | if (strcmp(key_name,"key_stopcd") == 0) return KEY_STOPCD; 260 | if (strcmp(key_name,"key_record") == 0) return KEY_RECORD; 261 | if (strcmp(key_name,"key_rewind") == 0) return KEY_REWIND; 262 | if (strcmp(key_name,"key_phone") == 0) return KEY_PHONE; 263 | if (strcmp(key_name,"key_iso") == 0) return KEY_ISO; 264 | if (strcmp(key_name,"key_config") == 0) return KEY_CONFIG; 265 | if (strcmp(key_name,"key_homepage") == 0) return KEY_HOMEPAGE; 266 | if (strcmp(key_name,"key_refresh") == 0) return KEY_REFRESH; 267 | if (strcmp(key_name,"key_exit") == 0) return KEY_EXIT; 268 | if (strcmp(key_name,"key_move") == 0) return KEY_MOVE; 269 | if (strcmp(key_name,"key_edit") == 0) return KEY_EDIT; 270 | if (strcmp(key_name,"key_scrollup") == 0) return KEY_SCROLLUP; 271 | if (strcmp(key_name,"key_scrolldown") == 0) return KEY_SCROLLDOWN; 272 | if (strcmp(key_name,"key_kpleftparen") == 0) return KEY_KPLEFTPAREN; 273 | if (strcmp(key_name,"key_kprightparen") == 0) return KEY_KPRIGHTPAREN; 274 | if (strcmp(key_name,"key_new") == 0) return KEY_NEW; 275 | if (strcmp(key_name,"key_redo") == 0) return KEY_REDO; 276 | if (strcmp(key_name,"key_f13") == 0) return KEY_F13; 277 | if (strcmp(key_name,"key_f14") == 0) return KEY_F14; 278 | if (strcmp(key_name,"key_f15") == 0) return KEY_F15; 279 | if (strcmp(key_name,"key_f16") == 0) return KEY_F16; 280 | if (strcmp(key_name,"key_f17") == 0) return KEY_F17; 281 | if (strcmp(key_name,"key_f18") == 0) return KEY_F18; 282 | if (strcmp(key_name,"key_f19") == 0) return KEY_F19; 283 | if (strcmp(key_name,"key_f20") == 0) return KEY_F20; 284 | if (strcmp(key_name,"key_f21") == 0) return KEY_F21; 285 | if (strcmp(key_name,"key_f22") == 0) return KEY_F22; 286 | if (strcmp(key_name,"key_f23") == 0) return KEY_F23; 287 | if (strcmp(key_name,"key_f24") == 0) return KEY_F24; 288 | if (strcmp(key_name,"key_playcd") == 0) return KEY_PLAYCD; 289 | if (strcmp(key_name,"key_pausecd") == 0) return KEY_PAUSECD; 290 | if (strcmp(key_name,"key_prog3") == 0) return KEY_PROG3; 291 | if (strcmp(key_name,"key_prog4") == 0) return KEY_PROG4; 292 | if (strcmp(key_name,"key_dashboard") == 0) return KEY_DASHBOARD; 293 | if (strcmp(key_name,"key_suspend") == 0) return KEY_SUSPEND; 294 | if (strcmp(key_name,"key_close") == 0) return KEY_CLOSE; 295 | if (strcmp(key_name,"key_play") == 0) return KEY_PLAY; 296 | if (strcmp(key_name,"key_fastforward") == 0) return KEY_FASTFORWARD; 297 | if (strcmp(key_name,"key_bassboost") == 0) return KEY_BASSBOOST; 298 | if (strcmp(key_name,"key_print") == 0) return KEY_PRINT; 299 | if (strcmp(key_name,"key_hp") == 0) return KEY_HP; 300 | if (strcmp(key_name,"key_camera") == 0) return KEY_CAMERA; 301 | if (strcmp(key_name,"key_sound") == 0) return KEY_SOUND; 302 | if (strcmp(key_name,"key_question") == 0) return KEY_QUESTION; 303 | if (strcmp(key_name,"key_email") == 0) return KEY_EMAIL; 304 | if (strcmp(key_name,"key_chat") == 0) return KEY_CHAT; 305 | if (strcmp(key_name,"key_search") == 0) return KEY_SEARCH; 306 | if (strcmp(key_name,"key_connect") == 0) return KEY_CONNECT; 307 | if (strcmp(key_name,"key_finance") == 0) return KEY_FINANCE; 308 | if (strcmp(key_name,"key_sport") == 0) return KEY_SPORT; 309 | if (strcmp(key_name,"key_shop") == 0) return KEY_SHOP; 310 | if (strcmp(key_name,"key_alterase") == 0) return KEY_ALTERASE; 311 | if (strcmp(key_name,"key_cancel") == 0) return KEY_CANCEL; 312 | if (strcmp(key_name,"key_brightnessdown") == 0) return KEY_BRIGHTNESSDOWN; 313 | if (strcmp(key_name,"key_brightnessup") == 0) return KEY_BRIGHTNESSUP; 314 | if (strcmp(key_name,"key_media") == 0) return KEY_MEDIA; 315 | if (strcmp(key_name,"key_switchvideomode") == 0) return KEY_SWITCHVIDEOMODE; 316 | if (strcmp(key_name,"key_kbdillumtoggle") == 0) return KEY_KBDILLUMTOGGLE; 317 | if (strcmp(key_name,"key_kbdillumdown") == 0) return KEY_KBDILLUMDOWN; 318 | if (strcmp(key_name,"key_kbdillumup") == 0) return KEY_KBDILLUMUP; 319 | if (strcmp(key_name,"key_send") == 0) return KEY_SEND; 320 | if (strcmp(key_name,"key_reply") == 0) return KEY_REPLY; 321 | if (strcmp(key_name,"key_forwardmail") == 0) return KEY_FORWARDMAIL; 322 | if (strcmp(key_name,"key_save") == 0) return KEY_SAVE; 323 | if (strcmp(key_name,"key_documents") == 0) return KEY_DOCUMENTS; 324 | if (strcmp(key_name,"key_battery") == 0) return KEY_BATTERY; 325 | if (strcmp(key_name,"key_bluetooth") == 0) return KEY_BLUETOOTH; 326 | if (strcmp(key_name,"key_wlan") == 0) return KEY_WLAN; 327 | if (strcmp(key_name,"key_uwb") == 0) return KEY_UWB; 328 | if (strcmp(key_name,"key_unknown") == 0) return KEY_UNKNOWN; 329 | if (strcmp(key_name,"key_video_next") == 0) return KEY_VIDEO_NEXT; 330 | if (strcmp(key_name,"key_video_prev") == 0) return KEY_VIDEO_PREV; 331 | if (strcmp(key_name,"key_brightness_cycle") == 0) return KEY_BRIGHTNESS_CYCLE; 332 | if (strcmp(key_name,"key_brightness_auto") == 0) return KEY_BRIGHTNESS_AUTO; 333 | if (strcmp(key_name,"key_brightness_zero") == 0) return KEY_BRIGHTNESS_ZERO; 334 | if (strcmp(key_name,"key_brightness_auto") == 0) return KEY_BRIGHTNESS_AUTO; 335 | if (strcmp(key_name,"key_display_off") == 0) return KEY_DISPLAY_OFF; 336 | if (strcmp(key_name,"key_wwan") == 0) return KEY_WWAN; 337 | if (strcmp(key_name,"key_wimax") == 0) return KEY_WIMAX; 338 | if (strcmp(key_name,"key_wwan") == 0) return KEY_WWAN; 339 | if (strcmp(key_name,"key_rfkill") == 0) return KEY_RFKILL; 340 | if (strcmp(key_name,"key_micmute") == 0) return KEY_MICMUTE; 341 | if (strcmp(key_name,"key_ok") == 0) return KEY_OK; 342 | if (strcmp(key_name,"key_select") == 0) return KEY_SELECT; 343 | if (strcmp(key_name,"key_goto") == 0) return KEY_GOTO; 344 | if (strcmp(key_name,"key_clear") == 0) return KEY_CLEAR; 345 | if (strcmp(key_name,"key_power2") == 0) return KEY_POWER2; 346 | if (strcmp(key_name,"key_option") == 0) return KEY_OPTION; 347 | if (strcmp(key_name,"key_info") == 0) return KEY_INFO; 348 | if (strcmp(key_name,"key_time") == 0) return KEY_TIME; 349 | if (strcmp(key_name,"key_vendor") == 0) return KEY_VENDOR; 350 | if (strcmp(key_name,"key_archive") == 0) return KEY_ARCHIVE; 351 | if (strcmp(key_name,"key_program") == 0) return KEY_PROGRAM; 352 | if (strcmp(key_name,"key_channel") == 0) return KEY_CHANNEL; 353 | if (strcmp(key_name,"key_favorites") == 0) return KEY_FAVORITES; 354 | if (strcmp(key_name,"key_epg") == 0) return KEY_EPG; 355 | if (strcmp(key_name,"key_pvr") == 0) return KEY_PVR; 356 | if (strcmp(key_name,"key_mhp") == 0) return KEY_MHP; 357 | if (strcmp(key_name,"key_language") == 0) return KEY_LANGUAGE; 358 | if (strcmp(key_name,"key_title") == 0) return KEY_TITLE; 359 | if (strcmp(key_name,"key_subtitle") == 0) return KEY_SUBTITLE; 360 | if (strcmp(key_name,"key_angle") == 0) return KEY_ANGLE; 361 | if (strcmp(key_name,"key_zoom") == 0) return KEY_ZOOM; 362 | if (strcmp(key_name,"key_mode") == 0) return KEY_MODE; 363 | if (strcmp(key_name,"key_keyboard") == 0) return KEY_KEYBOARD; 364 | if (strcmp(key_name,"key_screen") == 0) return KEY_SCREEN; 365 | if (strcmp(key_name,"key_pc") == 0) return KEY_PC; 366 | if (strcmp(key_name,"key_tv") == 0) return KEY_TV; 367 | if (strcmp(key_name,"key_tv2") == 0) return KEY_TV2; 368 | if (strcmp(key_name,"key_vcr") == 0) return KEY_VCR; 369 | if (strcmp(key_name,"key_vcr2") == 0) return KEY_VCR2; 370 | if (strcmp(key_name,"key_sat") == 0) return KEY_SAT; 371 | if (strcmp(key_name,"key_sat2") == 0) return KEY_SAT2; 372 | if (strcmp(key_name,"key_cd") == 0) return KEY_CD; 373 | if (strcmp(key_name,"key_tape") == 0) return KEY_TAPE; 374 | if (strcmp(key_name,"key_radio") == 0) return KEY_RADIO; 375 | if (strcmp(key_name,"key_tuner") == 0) return KEY_TUNER; 376 | if (strcmp(key_name,"key_player") == 0) return KEY_PLAYER; 377 | if (strcmp(key_name,"key_text") == 0) return KEY_TEXT; 378 | if (strcmp(key_name,"key_dvd") == 0) return KEY_DVD; 379 | if (strcmp(key_name,"key_aux") == 0) return KEY_AUX; 380 | if (strcmp(key_name,"key_mp3") == 0) return KEY_MP3; 381 | if (strcmp(key_name,"key_audio") == 0) return KEY_AUDIO; 382 | if (strcmp(key_name,"key_video") == 0) return KEY_VIDEO; 383 | if (strcmp(key_name,"key_directory") == 0) return KEY_DIRECTORY; 384 | if (strcmp(key_name,"key_list") == 0) return KEY_LIST; 385 | if (strcmp(key_name,"key_memo") == 0) return KEY_MEMO; 386 | if (strcmp(key_name,"key_calendar") == 0) return KEY_CALENDAR; 387 | if (strcmp(key_name,"key_red") == 0) return KEY_RED; 388 | if (strcmp(key_name,"key_green") == 0) return KEY_GREEN; 389 | if (strcmp(key_name,"key_yellow") == 0) return KEY_YELLOW; 390 | if (strcmp(key_name,"key_blue") == 0) return KEY_BLUE; 391 | if (strcmp(key_name,"key_channelup") == 0) return KEY_CHANNELUP; 392 | if (strcmp(key_name,"key_channeldown") == 0) return KEY_CHANNELDOWN; 393 | if (strcmp(key_name,"key_first") == 0) return KEY_FIRST; 394 | if (strcmp(key_name,"key_last") == 0) return KEY_LAST; 395 | if (strcmp(key_name,"key_ab") == 0) return KEY_AB; 396 | if (strcmp(key_name,"key_next") == 0) return KEY_NEXT; 397 | if (strcmp(key_name,"key_restart") == 0) return KEY_RESTART; 398 | if (strcmp(key_name,"key_slow") == 0) return KEY_SLOW; 399 | if (strcmp(key_name,"key_shuffle") == 0) return KEY_SHUFFLE; 400 | if (strcmp(key_name,"key_break") == 0) return KEY_BREAK; 401 | if (strcmp(key_name,"key_previous") == 0) return KEY_PREVIOUS; 402 | if (strcmp(key_name,"key_digits") == 0) return KEY_DIGITS; 403 | if (strcmp(key_name,"key_teen") == 0) return KEY_TEEN; 404 | if (strcmp(key_name,"key_twen") == 0) return KEY_TWEN; 405 | if (strcmp(key_name,"key_videophone") == 0) return KEY_VIDEOPHONE; 406 | if (strcmp(key_name,"key_games") == 0) return KEY_GAMES; 407 | if (strcmp(key_name,"key_zoomin") == 0) return KEY_ZOOMIN; 408 | if (strcmp(key_name,"key_zoomout") == 0) return KEY_ZOOMOUT; 409 | if (strcmp(key_name,"key_zoomreset") == 0) return KEY_ZOOMRESET; 410 | if (strcmp(key_name,"key_wordprocessor") == 0) return KEY_WORDPROCESSOR; 411 | if (strcmp(key_name,"key_editor") == 0) return KEY_EDITOR; 412 | if (strcmp(key_name,"key_spreadsheet") == 0) return KEY_SPREADSHEET; 413 | if (strcmp(key_name,"key_graphicseditor") == 0) return KEY_GRAPHICSEDITOR; 414 | if (strcmp(key_name,"key_presentation") == 0) return KEY_PRESENTATION; 415 | if (strcmp(key_name,"key_database") == 0) return KEY_DATABASE; 416 | if (strcmp(key_name,"key_news") == 0) return KEY_NEWS; 417 | if (strcmp(key_name,"key_voicemail") == 0) return KEY_VOICEMAIL; 418 | if (strcmp(key_name,"key_addressbook") == 0) return KEY_ADDRESSBOOK; 419 | if (strcmp(key_name,"key_messenger") == 0) return KEY_MESSENGER; 420 | if (strcmp(key_name,"key_displaytoggle") == 0) return KEY_DISPLAYTOGGLE; 421 | if (strcmp(key_name,"key_brightness_toggle") == 0) return KEY_BRIGHTNESS_TOGGLE; 422 | if (strcmp(key_name,"key_displaytoggle") == 0) return KEY_DISPLAYTOGGLE; 423 | if (strcmp(key_name,"key_spellcheck") == 0) return KEY_SPELLCHECK; 424 | if (strcmp(key_name,"key_logoff") == 0) return KEY_LOGOFF; 425 | if (strcmp(key_name,"key_dollar") == 0) return KEY_DOLLAR; 426 | if (strcmp(key_name,"key_euro") == 0) return KEY_EURO; 427 | if (strcmp(key_name,"key_frameback") == 0) return KEY_FRAMEBACK; 428 | if (strcmp(key_name,"key_frameforward") == 0) return KEY_FRAMEFORWARD; 429 | if (strcmp(key_name,"key_context_menu") == 0) return KEY_CONTEXT_MENU; 430 | if (strcmp(key_name,"key_media_repeat") == 0) return KEY_MEDIA_REPEAT; 431 | if (strcmp(key_name,"key_10channelsup") == 0) return KEY_10CHANNELSUP; 432 | if (strcmp(key_name,"key_10channelsdown") == 0) return KEY_10CHANNELSDOWN; 433 | if (strcmp(key_name,"key_images") == 0) return KEY_IMAGES; 434 | if (strcmp(key_name,"key_del_eol") == 0) return KEY_DEL_EOL; 435 | if (strcmp(key_name,"key_del_eos") == 0) return KEY_DEL_EOS; 436 | if (strcmp(key_name,"key_ins_line") == 0) return KEY_INS_LINE; 437 | if (strcmp(key_name,"key_del_line") == 0) return KEY_DEL_LINE; 438 | if (strcmp(key_name,"key_fn") == 0) return KEY_FN; 439 | if (strcmp(key_name,"key_fn_esc") == 0) return KEY_FN_ESC; 440 | if (strcmp(key_name,"key_fn_f1") == 0) return KEY_FN_F1; 441 | if (strcmp(key_name,"key_fn_f2") == 0) return KEY_FN_F2; 442 | if (strcmp(key_name,"key_fn_f3") == 0) return KEY_FN_F3; 443 | if (strcmp(key_name,"key_fn_f4") == 0) return KEY_FN_F4; 444 | if (strcmp(key_name,"key_fn_f5") == 0) return KEY_FN_F5; 445 | if (strcmp(key_name,"key_fn_f6") == 0) return KEY_FN_F6; 446 | if (strcmp(key_name,"key_fn_f7") == 0) return KEY_FN_F7; 447 | if (strcmp(key_name,"key_fn_f8") == 0) return KEY_FN_F8; 448 | if (strcmp(key_name,"key_fn_f9") == 0) return KEY_FN_F9; 449 | if (strcmp(key_name,"key_fn_f10") == 0) return KEY_FN_F10; 450 | if (strcmp(key_name,"key_fn_f11") == 0) return KEY_FN_F11; 451 | if (strcmp(key_name,"key_fn_f12") == 0) return KEY_FN_F12; 452 | if (strcmp(key_name,"key_fn_1") == 0) return KEY_FN_1; 453 | if (strcmp(key_name,"key_fn_2") == 0) return KEY_FN_2; 454 | if (strcmp(key_name,"key_fn_d") == 0) return KEY_FN_D; 455 | if (strcmp(key_name,"key_fn_e") == 0) return KEY_FN_E; 456 | if (strcmp(key_name,"key_fn_f") == 0) return KEY_FN_F; 457 | if (strcmp(key_name,"key_fn_s") == 0) return KEY_FN_S; 458 | if (strcmp(key_name,"key_fn_b") == 0) return KEY_FN_B; 459 | if (strcmp(key_name,"key_brl_dot1") == 0) return KEY_BRL_DOT1; 460 | if (strcmp(key_name,"key_brl_dot2") == 0) return KEY_BRL_DOT2; 461 | if (strcmp(key_name,"key_brl_dot3") == 0) return KEY_BRL_DOT3; 462 | if (strcmp(key_name,"key_brl_dot4") == 0) return KEY_BRL_DOT4; 463 | if (strcmp(key_name,"key_brl_dot5") == 0) return KEY_BRL_DOT5; 464 | if (strcmp(key_name,"key_brl_dot6") == 0) return KEY_BRL_DOT6; 465 | if (strcmp(key_name,"key_brl_dot7") == 0) return KEY_BRL_DOT7; 466 | if (strcmp(key_name,"key_brl_dot8") == 0) return KEY_BRL_DOT8; 467 | if (strcmp(key_name,"key_brl_dot9") == 0) return KEY_BRL_DOT9; 468 | if (strcmp(key_name,"key_brl_dot10") == 0) return KEY_BRL_DOT10; 469 | if (strcmp(key_name,"key_numeric_0") == 0) return KEY_NUMERIC_0; 470 | if (strcmp(key_name,"key_numeric_1") == 0) return KEY_NUMERIC_1; 471 | if (strcmp(key_name,"key_numeric_2") == 0) return KEY_NUMERIC_2; 472 | if (strcmp(key_name,"key_numeric_3") == 0) return KEY_NUMERIC_3; 473 | if (strcmp(key_name,"key_numeric_4") == 0) return KEY_NUMERIC_4; 474 | if (strcmp(key_name,"key_numeric_5") == 0) return KEY_NUMERIC_5; 475 | if (strcmp(key_name,"key_numeric_6") == 0) return KEY_NUMERIC_6; 476 | if (strcmp(key_name,"key_numeric_7") == 0) return KEY_NUMERIC_7; 477 | if (strcmp(key_name,"key_numeric_8") == 0) return KEY_NUMERIC_8; 478 | if (strcmp(key_name,"key_numeric_9") == 0) return KEY_NUMERIC_9; 479 | if (strcmp(key_name,"key_numeric_star") == 0) return KEY_NUMERIC_STAR; 480 | if (strcmp(key_name,"key_numeric_pound") == 0) return KEY_NUMERIC_POUND; 481 | if (strcmp(key_name,"key_camera_focus") == 0) return KEY_CAMERA_FOCUS; 482 | if (strcmp(key_name,"key_wps_button") == 0) return KEY_WPS_BUTTON; 483 | if (strcmp(key_name,"key_touchpad_toggle") == 0) return KEY_TOUCHPAD_TOGGLE; 484 | if (strcmp(key_name,"key_touchpad_on") == 0) return KEY_TOUCHPAD_ON; 485 | if (strcmp(key_name,"key_touchpad_off") == 0) return KEY_TOUCHPAD_OFF; 486 | if (strcmp(key_name,"key_camera_zoomin") == 0) return KEY_CAMERA_ZOOMIN; 487 | if (strcmp(key_name,"key_camera_zoomout") == 0) return KEY_CAMERA_ZOOMOUT; 488 | if (strcmp(key_name,"key_camera_up") == 0) return KEY_CAMERA_UP; 489 | if (strcmp(key_name,"key_camera_down") == 0) return KEY_CAMERA_DOWN; 490 | if (strcmp(key_name,"key_camera_left") == 0) return KEY_CAMERA_LEFT; 491 | if (strcmp(key_name,"key_camera_right") == 0) return KEY_CAMERA_RIGHT; 492 | if (strcmp(key_name,"key_attendant_on") == 0) return KEY_ATTENDANT_ON; 493 | if (strcmp(key_name,"key_attendant_off") == 0) return KEY_ATTENDANT_OFF; 494 | if (strcmp(key_name,"key_attendant_toggle") == 0) return KEY_ATTENDANT_TOGGLE; 495 | if (strcmp(key_name,"key_lights_toggle") == 0) return KEY_LIGHTS_TOGGLE; 496 | if (strcmp(key_name,"key_als_toggle") == 0) return KEY_ALS_TOGGLE; 497 | if (strcmp(key_name,"key_buttonconfig") == 0) return KEY_BUTTONCONFIG; 498 | if (strcmp(key_name,"key_taskmanager") == 0) return KEY_TASKMANAGER; 499 | if (strcmp(key_name,"key_journal") == 0) return KEY_JOURNAL; 500 | if (strcmp(key_name,"key_controlpanel") == 0) return KEY_CONTROLPANEL; 501 | if (strcmp(key_name,"key_appselect") == 0) return KEY_APPSELECT; 502 | if (strcmp(key_name,"key_screensaver") == 0) return KEY_SCREENSAVER; 503 | if (strcmp(key_name,"key_voicecommand") == 0) return KEY_VOICECOMMAND; 504 | if (strcmp(key_name,"key_brightness_min") == 0) return KEY_BRIGHTNESS_MIN; 505 | if (strcmp(key_name,"key_brightness_max") == 0) return KEY_BRIGHTNESS_MAX; 506 | if (strcmp(key_name,"key_kbdinputassist_prev") == 0) return KEY_KBDINPUTASSIST_PREV; 507 | if (strcmp(key_name,"key_kbdinputassist_next") == 0) return KEY_KBDINPUTASSIST_NEXT; 508 | if (strcmp(key_name,"key_kbdinputassist_prevgroup") == 0) return KEY_KBDINPUTASSIST_PREVGROUP; 509 | if (strcmp(key_name,"key_kbdinputassist_nextgroup") == 0) return KEY_KBDINPUTASSIST_NEXTGROUP; 510 | if (strcmp(key_name,"key_kbdinputassist_accept") == 0) return KEY_KBDINPUTASSIST_ACCEPT; 511 | if (strcmp(key_name,"key_kbdinputassist_cancel") == 0) return KEY_KBDINPUTASSIST_CANCEL; 512 | #endif 513 | 514 | return -2; 515 | } 516 | 517 | int get_output_axis(char *axis_name) { 518 | if (axis_name == NULL) return -2; 519 | if (strcmp(axis_name,"left_x") == 0) return ABS_X; 520 | if (strcmp(axis_name,"left_y") == 0) return ABS_Y; 521 | if (strcmp(axis_name,"right_x") == 0) return ABS_RX; 522 | if (strcmp(axis_name,"right_y") == 0) return ABS_RY; 523 | if (strcmp(axis_name,"mouse_x") == 0) return ABS_X; 524 | if (strcmp(axis_name,"mouse_y") == 0) return ABS_Y; 525 | if (strcmp(axis_name,"none") == 0) return NO_MAP; 526 | 527 | return -2; 528 | } 529 | --------------------------------------------------------------------------------