comparison io.c @ 1207:9d6f155732ed

Basic support for mapping an analog axis to functionality
author Michael Pavone <pavone@retrodev.com>
date Thu, 26 Jan 2017 23:49:13 -0800
parents a6ae693974e0
children 95f5253e75c7
comparison
equal deleted inserted replaced
1206:32265f6b79e9 1207:9d6f155732ed
93 keybinding bindings[4]; 93 keybinding bindings[4];
94 uint8_t state; 94 uint8_t state;
95 } joydpad; 95 } joydpad;
96 96
97 typedef struct { 97 typedef struct {
98 keybinding positive;
99 keybinding negative;
100 int16_t value;
101 } joyaxis;
102
103 typedef struct {
98 keybinding *buttons; 104 keybinding *buttons;
99 joydpad *dpads; 105 joydpad *dpads;
106 joyaxis *axes;
100 uint32_t num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device 107 uint32_t num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device
101 uint32_t num_dpads; //number of entries in the dpads array, not necessarily the number of dpads on the device 108 uint32_t num_dpads; //number of entries in the dpads array, not necessarily the number of dpads on the device
109 uint32_t num_axes; //number of entries in the axes array, not necessarily the number of dpads on the device
102 } joystick; 110 } joystick;
103 111
104 typedef struct { 112 typedef struct {
105 io_port *motion_port; 113 io_port *motion_port;
106 keybinding buttons[MAX_MOUSE_BUTTONS]; 114 keybinding buttons[MAX_MOUSE_BUTTONS];
114 static joystick joysticks[MAX_JOYSTICKS]; 122 static joystick joysticks[MAX_JOYSTICKS];
115 static mousebinding mice[MAX_MICE]; 123 static mousebinding mice[MAX_MICE];
116 static io_port *keyboard_port; 124 static io_port *keyboard_port;
117 const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; 125 const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
118 126
127 static void do_bind(keybinding *binding, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
128 {
129 binding->bind_type = bind_type;
130 binding->subtype_a = subtype_a;
131 binding->subtype_b = subtype_b;
132 binding->value = value;
133 }
134
119 void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 135 void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
120 { 136 {
121 int bucket = keycode >> 15 & 0xFFFF; 137 int bucket = keycode >> 15 & 0xFFFF;
122 if (!bindings[bucket]) { 138 if (!bindings[bucket]) {
123 bindings[bucket] = malloc(sizeof(keybinding) * 0x8000); 139 bindings[bucket] = malloc(sizeof(keybinding) * 0x8000);
124 memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000); 140 memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000);
125 } 141 }
126 int idx = keycode & 0x7FFF; 142 int idx = keycode & 0x7FFF;
127 bindings[bucket][idx].bind_type = bind_type; 143 do_bind(bindings[bucket] + idx, bind_type, subtype_a, subtype_b, value);
128 bindings[bucket][idx].subtype_a = subtype_a;
129 bindings[bucket][idx].subtype_b = subtype_b;
130 bindings[bucket][idx].value = value;
131 } 144 }
132 145
133 void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 146 void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
134 { 147 {
135 if (joystick >= MAX_JOYSTICKS) { 148 if (joystick >= MAX_JOYSTICKS) {
142 uint32_t old_capacity = joysticks[joystick].num_buttons; 155 uint32_t old_capacity = joysticks[joystick].num_buttons;
143 joysticks[joystick].num_buttons *= 2; 156 joysticks[joystick].num_buttons *= 2;
144 joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons); 157 joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons);
145 memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity); 158 memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity);
146 } 159 }
147 joysticks[joystick].buttons[button].bind_type = bind_type; 160 do_bind(joysticks[joystick].buttons + button, bind_type, subtype_a, subtype_b, value);
148 joysticks[joystick].buttons[button].subtype_a = subtype_a;
149 joysticks[joystick].buttons[button].subtype_b = subtype_b;
150 joysticks[joystick].buttons[button].value = value;
151 } 161 }
152 162
153 void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 163 void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
154 { 164 {
155 if (joystick >= MAX_JOYSTICKS) { 165 if (joystick >= MAX_JOYSTICKS) {
156 return; 166 return;
157 } 167 }
158 if (!joysticks[joystick].dpads) { 168 if (!joysticks[joystick].dpads) {
159 //multiple D-pads hats are not common, so don't allocate any extra space 169 //multiple D-pads/hats are not common, so don't allocate any extra space
160 joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad)); 170 joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad));
161 joysticks[joystick].num_dpads = dpad+1; 171 joysticks[joystick].num_dpads = dpad+1;
162 } else if (joysticks[joystick].num_dpads <= dpad) { 172 } else if (joysticks[joystick].num_dpads <= dpad) {
163 uint32_t old_capacity = joysticks[joystick].num_dpads; 173 uint32_t old_capacity = joysticks[joystick].num_dpads;
164 joysticks[joystick].num_dpads *= 2; 174 joysticks[joystick].num_dpads *= 2;
165 joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads); 175 joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads);
166 memset(joysticks[joystick].dpads + old_capacity, 0, joysticks[joystick].num_dpads - old_capacity); 176 memset(joysticks[joystick].dpads + old_capacity, 0, (joysticks[joystick].num_dpads - old_capacity) * sizeof(joydpad));
167 } 177 }
168 for (int i = 0; i < 4; i ++) { 178 for (int i = 0; i < 4; i ++) {
169 if (dpadbits[i] & direction) { 179 if (dpadbits[i] & direction) {
170 joysticks[joystick].dpads[dpad].bindings[i].bind_type = bind_type; 180 do_bind(joysticks[joystick].dpads[dpad].bindings + i, bind_type, subtype_a, subtype_b, value);
171 joysticks[joystick].dpads[dpad].bindings[i].subtype_a = subtype_a;
172 joysticks[joystick].dpads[dpad].bindings[i].subtype_b = subtype_b;
173 joysticks[joystick].dpads[dpad].bindings[i].value = value;
174 break; 181 break;
175 } 182 }
183 }
184 }
185
186 void bind_axis(int joystick, int axis, int positive, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value)
187 {
188 if (joystick >= MAX_JOYSTICKS) {
189 return;
190 }
191 if (!joysticks[joystick].axes) {
192 //typical gamepad has 4 axes
193 joysticks[joystick].num_axes = axis+1 > 4 ? axis+1 : 4;
194 joysticks[joystick].axes = calloc(joysticks[joystick].num_axes, sizeof(joyaxis));
195 } else if (joysticks[joystick].num_axes <= axis) {
196 uint32_t old_capacity = joysticks[joystick].num_axes;
197 joysticks[joystick].num_axes *= 2;
198 joysticks[joystick].axes = realloc(joysticks[joystick].axes, sizeof(joyaxis) * joysticks[joystick].num_axes);
199 memset(joysticks[joystick].axes + old_capacity, 0, (joysticks[joystick].num_axes - old_capacity) * sizeof(joyaxis));
200 }
201 if (positive) {
202 do_bind(&joysticks[joystick].axes[axis].positive, bind_type, subtype_a, subtype_b, value);
203 } else {
204 do_bind(&joysticks[joystick].axes[axis].negative, bind_type, subtype_a, subtype_b, value);
176 } 205 }
177 } 206 }
178 207
179 void reset_joystick_bindings(int joystick) 208 void reset_joystick_bindings(int joystick)
180 { 209 {
192 { 221 {
193 for (int dir = 0; dir < 4; dir++) 222 for (int dir = 0; dir < 4; dir++)
194 { 223 {
195 joysticks[joystick].dpads[i].bindings[dir].bind_type = BIND_NONE; 224 joysticks[joystick].dpads[i].bindings[dir].bind_type = BIND_NONE;
196 } 225 }
226 }
227 }
228 if (joysticks[joystick].axes) {
229 for (int i = 0; i < joysticks[joystick].num_axes; i++)
230 {
231 joysticks[joystick].axes[i].positive.bind_type = BIND_NONE;
232 joysticks[joystick].axes[i].negative.bind_type = BIND_NONE;
197 } 233 }
198 } 234 }
199 } 235 }
200 236
201 #define GAMEPAD_BUTTON(PRI_SLOT, SEC_SLOT, VALUE) (PRI_SLOT << 12 | SEC_SLOT << 8 | VALUE) 237 #define GAMEPAD_BUTTON(PRI_SLOT, SEC_SLOT, VALUE) (PRI_SLOT << 12 | SEC_SLOT << 8 | VALUE)
217 #define MOUSE_LEFT 1 253 #define MOUSE_LEFT 1
218 #define MOUSE_RIGHT 2 254 #define MOUSE_RIGHT 2
219 #define MOUSE_MIDDLE 4 255 #define MOUSE_MIDDLE 4
220 #define MOUSE_START 8 256 #define MOUSE_START 8
221 257
222
223
224 void bind_gamepad(int keycode, int gamepadnum, int button) 258 void bind_gamepad(int keycode, int gamepadnum, int button)
225 { 259 {
226 260
227 if (gamepadnum < 1 || gamepadnum > 8) { 261 if (gamepadnum < 1 || gamepadnum > 8) {
228 return; 262 return;
247 } 281 }
248 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; 282 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
249 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); 283 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
250 } 284 }
251 285
286 void bind_axis_gamepad(int joystick, int axis, uint8_t positive, int gamepadnum, int button)
287 {
288 if (gamepadnum < 1 || gamepadnum > 8) {
289 return;
290 }
291 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
292 bind_axis(joystick, axis, positive, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
293 }
294
252 void bind_ui(int keycode, ui_action action, uint8_t param) 295 void bind_ui(int keycode, ui_action action, uint8_t param)
253 { 296 {
254 bind_key(keycode, BIND_UI, action, 0, param); 297 bind_key(keycode, BIND_UI, action, 0, param);
255 } 298 }
256 299
260 } 303 }
261 304
262 void bind_dpad_ui(int joystick, int dpad, uint8_t direction, ui_action action, uint8_t param) 305 void bind_dpad_ui(int joystick, int dpad, uint8_t direction, ui_action action, uint8_t param)
263 { 306 {
264 bind_dpad(joystick, dpad, direction, BIND_UI, action, 0, param); 307 bind_dpad(joystick, dpad, direction, BIND_UI, action, 0, param);
308 }
309
310 void bind_axis_ui(int joystick, int axis, uint8_t positive, ui_action action, uint8_t param)
311 {
312 bind_axis(joystick, axis, positive, BIND_UI, action, 0, param);
265 } 313 }
266 314
267 void handle_binding_down(keybinding * binding) 315 void handle_binding_down(keybinding * binding)
268 { 316 {
269 if (binding->bind_type >= BIND_GAMEPAD1 && binding->bind_type <= BIND_GAMEPAD8) 317 if (binding->bind_type >= BIND_GAMEPAD1 && binding->bind_type <= BIND_GAMEPAD8)
461 if (newdown & dpadbits[i]) { 509 if (newdown & dpadbits[i]) {
462 handle_binding_down(dpad->bindings + i); 510 handle_binding_down(dpad->bindings + i);
463 } else if(newup & dpadbits[i]) { 511 } else if(newup & dpadbits[i]) {
464 handle_binding_up(dpad->bindings + i); 512 handle_binding_up(dpad->bindings + i);
465 } 513 }
514 }
515 }
516
517 #define JOY_AXIS_THRESHOLD 2000
518
519 void handle_joy_axis(int joystick, int axis, int16_t value)
520 {
521 if (joystick >= MAX_JOYSTICKS || axis >= joysticks[joystick].num_axes) {
522 return;
523 }
524 joyaxis *jaxis = joysticks[joystick].axes + axis;
525 int old_active = abs(jaxis->value) > JOY_AXIS_THRESHOLD;
526 int new_active = abs(value) > JOY_AXIS_THRESHOLD;
527 int old_pos = jaxis->value > 0;
528 int new_pos = value > 0;
529 jaxis->value = value;
530 if (old_active && (!new_active || old_pos != new_pos)) {
531 //previously activated direction is no longer active
532 handle_binding_up(old_pos ? &jaxis->positive : &jaxis->negative);
533 }
534 if (new_active && (!old_active || old_pos != new_pos)) {
535 //previously unactivated direction is now active
536 handle_binding_down(new_pos ? &jaxis->positive : &jaxis->negative);
466 } 537 }
467 } 538 }
468 539
469 void handle_mouseup(int mouse, int button) 540 void handle_mouseup(int mouse, int button)
470 { 541 {
965 int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button); 1036 int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button);
966 char *end; 1037 char *end;
967 long hostbutton = strtol(key, &end, 10); 1038 long hostbutton = strtol(key, &end, 10);
968 if (*end) { 1039 if (*end) {
969 //key is not a valid base 10 integer 1040 //key is not a valid base 10 integer
970 hostbutton = render_translate_input_name(hostpadnum, key); 1041 hostbutton = render_translate_input_name(hostpadnum, key, 0);
971 if (hostbutton < 0) { 1042 if (hostbutton < 0) {
972 if (hostbutton == RENDER_INVALID_NAME) { 1043 if (hostbutton == RENDER_INVALID_NAME) {
973 warning("%s is not a valid gamepad input name\n", key); 1044 warning("%s is not a valid gamepad input name\n", key);
974 } else if (hostbutton == RENDER_NOT_MAPPED) { 1045 } else if (hostbutton == RENDER_NOT_MAPPED) {
975 warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum); 1046 warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
980 if (bindtype == BIND_GAMEPAD1) { 1051 if (bindtype == BIND_GAMEPAD1) {
981 bind_dpad_gamepad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), padnum, button); 1052 bind_dpad_gamepad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), padnum, button);
982 } else { 1053 } else {
983 bind_dpad_ui(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), ui_func, button); 1054 bind_dpad_ui(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), ui_func, button);
984 } 1055 }
1056 return;
985 } else if (hostbutton & RENDER_AXIS_BIT) { 1057 } else if (hostbutton & RENDER_AXIS_BIT) {
986 //TODO: support analog axes 1058 if (bindtype == BIND_GAMEPAD1) {
1059 bind_axis_gamepad(hostpadnum, render_axis_part(hostbutton), 1, padnum, button);
1060 } else {
1061 bind_axis_ui(hostpadnum, render_axis_part(hostbutton), 1, padnum, button);
1062 }
987 return; 1063 return;
988 } 1064 }
989 } 1065 }
990 if (bindtype == BIND_GAMEPAD1) { 1066 if (bindtype == BIND_GAMEPAD1) {
991 bind_button_gamepad(hostpadnum, hostbutton, padnum, button); 1067 bind_button_gamepad(hostpadnum, hostbutton, padnum, button);
992 } else if (bindtype == BIND_UI) { 1068 } else if (bindtype == BIND_UI) {
993 bind_button_ui(hostpadnum, hostbutton, ui_func, button); 1069 bind_button_ui(hostpadnum, hostbutton, ui_func, button);
994 } 1070 }
1071 }
1072
1073 void process_pad_axis(char *key, tern_val val, void *data)
1074 {
1075 key = strdup(key);
1076 pad_button_state *state = data;
1077 int hostpadnum = state->padnum;
1078 int ui_func, padnum, button;
1079 int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button);
1080 char *modifier = strchr(key, '.');
1081 int positive = 1;
1082 if (modifier) {
1083 *modifier = 0;
1084 modifier++;
1085 if (!strcmp("negative", modifier)) {
1086 positive = 0;
1087 } else if(strcmp("positive", modifier)) {
1088 warning("Invalid axis modifier %s for axis %s on pad %d\n", modifier, key, hostpadnum);
1089 }
1090 }
1091 char *end;
1092 long axis = strtol(key, &end, 10);
1093 if (*end) {
1094 //key is not a valid base 10 integer
1095 axis = render_translate_input_name(hostpadnum, key, 1);
1096 if (axis < 0) {
1097 if (axis == RENDER_INVALID_NAME) {
1098 warning("%s is not a valid gamepad input name\n", key);
1099 } else if (axis == RENDER_NOT_MAPPED) {
1100 warning("No mapping exists for input %s on gamepad %d\n", key, hostpadnum);
1101 }
1102 goto done;
1103 }
1104 if (axis & RENDER_DPAD_BIT) {
1105 if (bindtype == BIND_GAMEPAD1) {
1106 bind_dpad_gamepad(hostpadnum, render_dpad_part(axis), render_direction_part(axis), padnum, button);
1107 } else {
1108 bind_dpad_ui(hostpadnum, render_dpad_part(axis), render_direction_part(axis), ui_func, button);
1109 }
1110 goto done;
1111 } else if (axis & RENDER_AXIS_BIT) {
1112 axis = render_axis_part(axis);
1113 } else {
1114 if (bindtype == BIND_GAMEPAD1) {
1115 bind_button_gamepad(hostpadnum, axis, padnum, button);
1116 } else if (bindtype == BIND_UI) {
1117 bind_button_ui(hostpadnum, axis, ui_func, button);
1118 }
1119 goto done;
1120 }
1121 }
1122 if (bindtype == BIND_GAMEPAD1) {
1123 bind_axis_gamepad(hostpadnum, axis, positive, padnum, button);
1124 } else {
1125 bind_axis_ui(hostpadnum, axis, positive, ui_func, button);
1126 }
1127 done:
1128 free(key);
1129 return;
995 } 1130 }
996 1131
997 static tern_node *get_pad_buttons() 1132 static tern_node *get_pad_buttons()
998 { 1133 {
999 static tern_node *padbuttons; 1134 static tern_node *padbuttons;
1068 .padbuttons = get_pad_buttons(), 1203 .padbuttons = get_pad_buttons(),
1069 .mousebuttons = get_mouse_buttons() 1204 .mousebuttons = get_mouse_buttons()
1070 }; 1205 };
1071 tern_foreach(button_node, process_pad_button, &state); 1206 tern_foreach(button_node, process_pad_button, &state);
1072 } 1207 }
1208 tern_node *axes_node = tern_find_ptr(pad, "axes");
1209 if (axes_node) {
1210 pad_button_state state = {
1211 .padnum = joystick,
1212 .padbuttons = get_pad_buttons(),
1213 .mousebuttons = get_mouse_buttons()
1214 };
1215 tern_foreach(axes_node, process_pad_axis, &state);
1216 }
1073 if (current_io) { 1217 if (current_io) {
1074 if (joysticks[joystick].buttons) { 1218 if (joysticks[joystick].buttons) {
1075 map_bindings(current_io->ports, joysticks[joystick].buttons, joysticks[joystick].num_buttons); 1219 map_bindings(current_io->ports, joysticks[joystick].buttons, joysticks[joystick].num_buttons);
1076 } 1220 }
1077 if (joysticks[joystick].dpads) 1221 if (joysticks[joystick].dpads)
1078 { 1222 {
1079 for (uint32_t i = 0; i < joysticks[joystick].num_dpads; i++) { 1223 for (uint32_t i = 0; i < joysticks[joystick].num_dpads; i++)
1224 {
1080 map_bindings(current_io->ports, joysticks[joystick].dpads[i].bindings, 4); 1225 map_bindings(current_io->ports, joysticks[joystick].dpads[i].bindings, 4);
1226 }
1227 }
1228 if (joysticks[joystick].axes) {
1229 for (uint32_t i = 0; i < joysticks[joystick].num_axes; i++)
1230 {
1231 map_bindings(current_io->ports, &joysticks[joystick].axes[i].positive, 1);
1232 map_bindings(current_io->ports, &joysticks[joystick].axes[i].negative, 1);
1081 } 1233 }
1082 } 1234 }
1083 } 1235 }
1084 } 1236 }
1085 } 1237 }
1191 if (joysticks[stick].buttons) { 1343 if (joysticks[stick].buttons) {
1192 map_bindings(ports, joysticks[stick].buttons, joysticks[stick].num_buttons); 1344 map_bindings(ports, joysticks[stick].buttons, joysticks[stick].num_buttons);
1193 } 1345 }
1194 if (joysticks[stick].dpads) 1346 if (joysticks[stick].dpads)
1195 { 1347 {
1196 for (uint32_t i = 0; i < joysticks[stick].num_dpads; i++) { 1348 for (uint32_t i = 0; i < joysticks[stick].num_dpads; i++)
1349 {
1197 map_bindings(ports, joysticks[stick].dpads[i].bindings, 4); 1350 map_bindings(ports, joysticks[stick].dpads[i].bindings, 4);
1198 } 1351 }
1352 }
1353 for (uint32_t i = 0; i < joysticks[stick].num_axes; i++)
1354 {
1355 map_bindings(current_io->ports, &joysticks[stick].axes[i].positive, 1);
1356 map_bindings(current_io->ports, &joysticks[stick].axes[i].negative, 1);
1199 } 1357 }
1200 } 1358 }
1201 for (int mouse = 0; mouse < MAX_MICE; mouse++) 1359 for (int mouse = 0; mouse < MAX_MICE; mouse++)
1202 { 1360 {
1203 if (mice[mouse].bind_type >= BIND_MOUSE1 && mice[mouse].bind_type <= BIND_MOUSE8) { 1361 if (mice[mouse].bind_type >= BIND_MOUSE1 && mice[mouse].bind_type <= BIND_MOUSE8) {