comparison io.c @ 1583:430dd12e4010

Refactor to split device bindings from IO emulation code
author Michael Pavone <pavone@retrodev.com>
date Sat, 05 May 2018 23:30:40 -0700
parents 2b132d894d76
children 360d5bab199f
comparison
equal deleted inserted replaced
1582:a74db49fa6b1 1583:430dd12e4010
16 #include <stdlib.h> 16 #include <stdlib.h>
17 17
18 #include "serialize.h" 18 #include "serialize.h"
19 #include "io.h" 19 #include "io.h"
20 #include "blastem.h" 20 #include "blastem.h"
21 #include "genesis.h"
22 #include "sms.h"
23 #include "render.h" 21 #include "render.h"
24 #include "util.h" 22 #include "util.h"
25 #include "menu.h" 23 #include "bindings.h"
26 #include "saves.h"
27 #ifndef DISABLE_NUKLEAR
28 #include "nuklear_ui/blastem_nuklear.h"
29 #endif
30 24
31 #define CYCLE_NEVER 0xFFFFFFFF 25 #define CYCLE_NEVER 0xFFFFFFFF
32 #define MIN_POLL_INTERVAL 6840 26 #define MIN_POLL_INTERVAL 6840
33 27
34 const char * device_type_names[] = { 28 const char * device_type_names[] = {
46 "Sega Parallel Transfer Board", 40 "Sega Parallel Transfer Board",
47 "Generic Device", 41 "Generic Device",
48 "None" 42 "None"
49 }; 43 };
50 44
45 #define GAMEPAD_TH0 0
46 #define GAMEPAD_TH1 1
47 #define GAMEPAD_EXTRA 2
48 #define GAMEPAD_NONE 0xF
49
50 #define IO_TH0 0
51 #define IO_TH1 1
52 #define IO_STATE 2
53
51 enum { 54 enum {
52 BIND_NONE, 55 IO_WRITE_PENDING,
53 BIND_UI, 56 IO_WRITTEN,
54 BIND_GAMEPAD1, 57 IO_READ_PENDING,
55 BIND_GAMEPAD2, 58 IO_READ
56 BIND_GAMEPAD3,
57 BIND_GAMEPAD4,
58 BIND_GAMEPAD5,
59 BIND_GAMEPAD6,
60 BIND_GAMEPAD7,
61 BIND_GAMEPAD8,
62 BIND_MOUSE1,
63 BIND_MOUSE2,
64 BIND_MOUSE3,
65 BIND_MOUSE4,
66 BIND_MOUSE5,
67 BIND_MOUSE6,
68 BIND_MOUSE7,
69 BIND_MOUSE8
70 }; 59 };
71 60
72 typedef enum {
73 UI_DEBUG_MODE_INC,
74 UI_DEBUG_PAL_INC,
75 UI_ENTER_DEBUGGER,
76 UI_SAVE_STATE,
77 UI_SET_SPEED,
78 UI_NEXT_SPEED,
79 UI_PREV_SPEED,
80 UI_RELEASE_MOUSE,
81 UI_TOGGLE_KEYBOARD_CAPTURE,
82 UI_TOGGLE_FULLSCREEN,
83 UI_SOFT_RESET,
84 UI_RELOAD,
85 UI_SMS_PAUSE,
86 UI_SCREENSHOT,
87 UI_EXIT
88 } ui_action;
89
90 typedef enum {
91 MOUSE_NONE, //mouse is ignored
92 MOUSE_ABSOLUTE, //really only useful for menu ROM
93 MOUSE_RELATIVE, //for full screen
94 MOUSE_CAPTURE //for windowed mode
95 } mouse_modes;
96
97
98 typedef struct { 61 typedef struct {
99 io_port *port; 62 uint8_t states[2], value;
100 uint8_t bind_type; 63 } gp_button_def;
101 uint8_t subtype_a; 64
102 uint8_t subtype_b; 65
103 uint8_t value; 66 static gp_button_def button_defs[NUM_GAMEPAD_BUTTONS] = {
104 } keybinding; 67 [DPAD_UP] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x1},
105 68 [DPAD_DOWN] = {.states = {GAMEPAD_TH0, GAMEPAD_TH1}, .value = 0x2},
106 typedef struct { 69 [DPAD_LEFT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x4},
107 keybinding bindings[4]; 70 [DPAD_RIGHT] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x8},
108 uint8_t state; 71 [BUTTON_A] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x10},
109 } joydpad; 72 [BUTTON_B] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x10},
110 73 [BUTTON_C] = {.states = {GAMEPAD_TH1, GAMEPAD_NONE}, .value = 0x20},
111 typedef struct { 74 [BUTTON_START] = {.states = {GAMEPAD_TH0, GAMEPAD_NONE}, .value = 0x20},
112 keybinding positive; 75 [BUTTON_X] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x4},
113 keybinding negative; 76 [BUTTON_Y] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x2},
114 int16_t value; 77 [BUTTON_Z] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x1},
115 } joyaxis; 78 [BUTTON_MODE] = {.states = {GAMEPAD_EXTRA, GAMEPAD_NONE}, .value = 0x8},
116 79 };
117 typedef struct { 80
118 keybinding *buttons; 81 static io_port *find_gamepad(sega_io *io, uint8_t gamepad_num)
119 joydpad *dpads; 82 {
120 joyaxis *axes; 83 for (int i = 0; i < 3; i++)
121 uint32_t num_buttons; //number of entries in the buttons array, not necessarily the number of buttons on the device 84 {
122 uint32_t num_dpads; //number of entries in the dpads array, not necessarily the number of dpads on the device 85 io_port *port = io->ports + i;
123 uint32_t num_axes; //number of entries in the axes array, not necessarily the number of dpads on the device 86 if (port->device_type < IO_MOUSE && port->device.pad.gamepad_num == gamepad_num) {
124 } joystick; 87 return port;
125 88 }
126 typedef struct { 89 }
127 io_port *motion_port; 90 return NULL;
128 keybinding buttons[MAX_MOUSE_BUTTONS]; 91 }
129 uint8_t bind_type; 92
130 } mousebinding; 93 static io_port *find_mouse(sega_io *io, uint8_t mouse_num)
131 94 {
132 #define DEFAULT_JOYBUTTON_ALLOC 12 95 for (int i = 0; i < 3; i++)
133 96 {
134 static sega_io *current_io; 97 io_port *port = io->ports + i;
135 static keybinding *bindings[0x10000]; 98 if (port->device_type == IO_MOUSE && port->device.mouse.mouse_num == mouse_num) {
136 static joystick joysticks[MAX_JOYSTICKS]; 99 return port;
137 static mousebinding mice[MAX_MICE]; 100 }
138 static io_port *keyboard_port; 101 }
139 const uint8_t dpadbits[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT}; 102 return NULL;
140 103 }
141 static void do_bind(keybinding *binding, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 104
142 { 105 static io_port *find_keyboard(sega_io *io)
143 binding->bind_type = bind_type; 106 {
144 binding->subtype_a = subtype_a; 107 for (int i = 0; i < 3; i++)
145 binding->subtype_b = subtype_b; 108 {
146 binding->value = value; 109 io_port *port = io->ports + i;
147 } 110 if (port->device_type == IO_SATURN_KEYBOARD || port->device_type == IO_XBAND_KEYBOARD) {
148 111 return port;
149 void bind_key(int keycode, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 112 }
150 { 113 }
151 int bucket = keycode >> 15 & 0xFFFF; 114 return NULL;
152 if (!bindings[bucket]) { 115 }
153 bindings[bucket] = malloc(sizeof(keybinding) * 0x8000); 116
154 memset(bindings[bucket], 0, sizeof(keybinding) * 0x8000); 117 void io_gamepad_down(sega_io *io, uint8_t gamepad_num, uint8_t button)
155 } 118 {
156 int idx = keycode & 0x7FFF; 119 io_port *port = find_gamepad(io, gamepad_num);
157 do_bind(bindings[bucket] + idx, bind_type, subtype_a, subtype_b, value); 120 if (port) {
158 } 121 gp_button_def *def = button_defs + button;
159 122 port->input[def->states[0]] |= def->value;
160 void bind_button(int joystick, int button, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 123 if (def->states[1] != GAMEPAD_NONE) {
161 { 124 port->input[def->states[1]] |= def->value;
162 if (joystick >= MAX_JOYSTICKS) { 125 }
163 return; 126 }
164 } 127 }
165 if (!joysticks[joystick].buttons) { 128
166 joysticks[joystick].num_buttons = button < DEFAULT_JOYBUTTON_ALLOC ? DEFAULT_JOYBUTTON_ALLOC : button + 1; 129 void io_gamepad_up(sega_io *io, uint8_t gamepad_num, uint8_t button)
167 joysticks[joystick].buttons = calloc(joysticks[joystick].num_buttons, sizeof(keybinding)); 130 {
168 } else if (joysticks[joystick].num_buttons <= button) { 131 io_port *port = find_gamepad(io, gamepad_num);
169 uint32_t old_capacity = joysticks[joystick].num_buttons; 132 if (port) {
170 joysticks[joystick].num_buttons *= 2; 133 gp_button_def *def = button_defs + button;
171 joysticks[joystick].buttons = realloc(joysticks[joystick].buttons, sizeof(keybinding) * joysticks[joystick].num_buttons); 134 port->input[def->states[0]] &= ~def->value;
172 memset(joysticks[joystick].buttons + old_capacity, 0, joysticks[joystick].num_buttons - old_capacity); 135 if (def->states[1] != GAMEPAD_NONE) {
173 } 136 port->input[def->states[1]] &= ~def->value;
174 do_bind(joysticks[joystick].buttons + button, bind_type, subtype_a, subtype_b, value); 137 }
175 } 138 }
176 139 }
177 void bind_dpad(int joystick, int dpad, int direction, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 140
178 { 141 void io_mouse_down(sega_io *io, uint8_t mouse_num, uint8_t button)
179 if (joystick >= MAX_JOYSTICKS) { 142 {
180 return; 143 io_port *port = find_mouse(io, mouse_num);
181 } 144 if (port) {
182 if (!joysticks[joystick].dpads) { 145 port->input[0] |= button;
183 //multiple D-pads/hats are not common, so don't allocate any extra space 146 }
184 joysticks[joystick].dpads = calloc(dpad+1, sizeof(joydpad)); 147 }
185 joysticks[joystick].num_dpads = dpad+1; 148
186 } else if (joysticks[joystick].num_dpads <= dpad) { 149 void io_mouse_up(sega_io *io, uint8_t mouse_num, uint8_t button)
187 uint32_t old_capacity = joysticks[joystick].num_dpads; 150 {
188 joysticks[joystick].num_dpads *= 2; 151 io_port *port = find_mouse(io, mouse_num);
189 joysticks[joystick].dpads = realloc(joysticks[joystick].dpads, sizeof(joydpad) * joysticks[joystick].num_dpads); 152 if (port) {
190 memset(joysticks[joystick].dpads + old_capacity, 0, (joysticks[joystick].num_dpads - old_capacity) * sizeof(joydpad)); 153 port->input[0] &= ~button;
191 } 154 }
192 for (int i = 0; i < 4; i ++) { 155 }
193 if (dpadbits[i] & direction) { 156
194 do_bind(joysticks[joystick].dpads[dpad].bindings + i, bind_type, subtype_a, subtype_b, value); 157 void io_mouse_motion_absolute(sega_io *io, uint8_t mouse_num, uint16_t x, uint16_t y)
195 break; 158 {
196 } 159 io_port *port = find_mouse(io, mouse_num);
197 } 160 if (port) {
198 } 161 port->device.mouse.cur_x = x;
199 162 port->device.mouse.cur_y = y;
200 void bind_axis(int joystick, int axis, int positive, uint8_t bind_type, uint8_t subtype_a, uint8_t subtype_b, uint8_t value) 163 }
201 { 164 }
202 if (joystick >= MAX_JOYSTICKS) { 165
203 return; 166 void io_mouse_motion_relative(sega_io *io, uint8_t mouse_num, int32_t x, int32_t y)
204 } 167 {
205 if (!joysticks[joystick].axes) { 168 io_port *port = find_mouse(io, mouse_num);
206 //typical gamepad has 4 axes 169 if (port) {
207 joysticks[joystick].num_axes = axis+1 > 4 ? axis+1 : 4; 170 port->device.mouse.cur_x += x;
208 joysticks[joystick].axes = calloc(joysticks[joystick].num_axes, sizeof(joyaxis)); 171 port->device.mouse.cur_y += y;
209 } else if (joysticks[joystick].num_axes <= axis) { 172 }
210 uint32_t old_capacity = joysticks[joystick].num_axes; 173 }
211 joysticks[joystick].num_axes *= 2; 174
212 joysticks[joystick].axes = realloc(joysticks[joystick].axes, sizeof(joyaxis) * joysticks[joystick].num_axes); 175 void store_key_event(io_port *keyboard_port, uint16_t code)
213 memset(joysticks[joystick].axes + old_capacity, 0, (joysticks[joystick].num_axes - old_capacity) * sizeof(joyaxis));
214 }
215 if (positive) {
216 do_bind(&joysticks[joystick].axes[axis].positive, bind_type, subtype_a, subtype_b, value);
217 } else {
218 do_bind(&joysticks[joystick].axes[axis].negative, bind_type, subtype_a, subtype_b, value);
219 }
220 }
221
222 void reset_joystick_bindings(int joystick)
223 {
224 if (joystick >= MAX_JOYSTICKS) {
225 return;
226 }
227 if (joysticks[joystick].buttons) {
228 for (int i = 0; i < joysticks[joystick].num_buttons; i++)
229 {
230 joysticks[joystick].buttons[i].bind_type = BIND_NONE;
231 }
232 }
233 if (joysticks[joystick].dpads) {
234 for (int i = 0; i < joysticks[joystick].num_dpads; i++)
235 {
236 for (int dir = 0; dir < 4; dir++)
237 {
238 joysticks[joystick].dpads[i].bindings[dir].bind_type = BIND_NONE;
239 }
240 }
241 }
242 if (joysticks[joystick].axes) {
243 for (int i = 0; i < joysticks[joystick].num_axes; i++)
244 {
245 joysticks[joystick].axes[i].positive.bind_type = BIND_NONE;
246 joysticks[joystick].axes[i].negative.bind_type = BIND_NONE;
247 }
248 }
249 }
250
251 #define GAMEPAD_BUTTON(PRI_SLOT, SEC_SLOT, VALUE) (PRI_SLOT << 12 | SEC_SLOT << 8 | VALUE)
252
253 #define DPAD_UP GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x01)
254 #define BUTTON_Z GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x01)
255 #define DPAD_DOWN GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_TH1, 0x02)
256 #define BUTTON_Y GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x02)
257 #define DPAD_LEFT GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x04)
258 #define BUTTON_X GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x04)
259 #define DPAD_RIGHT GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x08)
260 #define BUTTON_MODE GAMEPAD_BUTTON(GAMEPAD_EXTRA, GAMEPAD_NONE, 0x08)
261 #define BUTTON_A GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x10)
262 #define BUTTON_B GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x10)
263 #define BUTTON_START GAMEPAD_BUTTON(GAMEPAD_TH0, GAMEPAD_NONE, 0x20)
264 #define BUTTON_C GAMEPAD_BUTTON(GAMEPAD_TH1, GAMEPAD_NONE, 0x20)
265
266 #define PSEUDO_BUTTON_MOTION 0xFFFF
267 #define MOUSE_LEFT 1
268 #define MOUSE_RIGHT 2
269 #define MOUSE_MIDDLE 4
270 #define MOUSE_START 8
271
272 void bind_gamepad(int keycode, int gamepadnum, int button)
273 {
274
275 if (gamepadnum < 1 || gamepadnum > 8) {
276 return;
277 }
278 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
279 bind_key(keycode, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
280 }
281
282 void bind_button_gamepad(int joystick, int joybutton, int gamepadnum, int padbutton)
283 {
284 if (gamepadnum < 1 || gamepadnum > 8) {
285 return;
286 }
287 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
288 bind_button(joystick, joybutton, bind_type, padbutton >> 12, padbutton >> 8 & 0xF, padbutton & 0xFF);
289 }
290
291 void bind_dpad_gamepad(int joystick, int dpad, uint8_t direction, int gamepadnum, int button)
292 {
293 if (gamepadnum < 1 || gamepadnum > 8) {
294 return;
295 }
296 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
297 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
298 }
299
300 void bind_axis_gamepad(int joystick, int axis, uint8_t positive, int gamepadnum, int button)
301 {
302 if (gamepadnum < 1 || gamepadnum > 8) {
303 return;
304 }
305 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1;
306 bind_axis(joystick, axis, positive, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF);
307 }
308
309 void bind_ui(int keycode, ui_action action, uint8_t param)
310 {
311 bind_key(keycode, BIND_UI, action, 0, param);
312 }
313
314 void bind_button_ui(int joystick, int joybutton, ui_action action, uint8_t param)
315 {
316 bind_button(joystick, joybutton, BIND_UI, action, 0, param);
317 }
318
319 void bind_dpad_ui(int joystick, int dpad, uint8_t direction, ui_action action, uint8_t param)
320 {
321 bind_dpad(joystick, dpad, direction, BIND_UI, action, 0, param);
322 }
323
324 void bind_axis_ui(int joystick, int axis, uint8_t positive, ui_action action, uint8_t param)
325 {
326 bind_axis(joystick, axis, positive, BIND_UI, action, 0, param);
327 }
328
329 void handle_binding_down(keybinding * binding)
330 {
331 if (binding->bind_type >= BIND_GAMEPAD1 && binding->bind_type <= BIND_GAMEPAD8)
332 {
333 if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) {
334 binding->port->input[binding->subtype_a] |= binding->value;
335 }
336 if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) {
337 binding->port->input[binding->subtype_b] |= binding->value;
338 }
339 }
340 else if (binding->bind_type >= BIND_MOUSE1 && binding->bind_type <= BIND_MOUSE8)
341 {
342 if (binding->port) {
343 binding->port->input[0] |= binding->value;
344 }
345 }
346 }
347
348 void store_key_event(uint16_t code)
349 { 176 {
350 if (keyboard_port && keyboard_port->device.keyboard.write_pos != keyboard_port->device.keyboard.read_pos) { 177 if (keyboard_port && keyboard_port->device.keyboard.write_pos != keyboard_port->device.keyboard.read_pos) {
351 //there's room in the buffer, record this event 178 //there's room in the buffer, record this event
352 keyboard_port->device.keyboard.events[keyboard_port->device.keyboard.write_pos] = code; 179 keyboard_port->device.keyboard.events[keyboard_port->device.keyboard.write_pos] = code;
353 if (keyboard_port->device.keyboard.read_pos == 0xFF) { 180 if (keyboard_port->device.keyboard.read_pos == 0xFF) {
356 } 183 }
357 keyboard_port->device.keyboard.write_pos = (keyboard_port->device.keyboard.write_pos + 1) & 7; 184 keyboard_port->device.keyboard.write_pos = (keyboard_port->device.keyboard.write_pos + 1) & 7;
358 } 185 }
359 } 186 }
360 187
361 void handle_keydown(int keycode, uint8_t scancode) 188 void io_keyboard_down(sega_io *io, uint8_t scancode)
362 { 189 {
363 if (!current_io) { 190 store_key_event(find_keyboard(io), scancode);
364 return; 191 }
365 } 192
366 int bucket = keycode >> 15 & 0xFFFF; 193 void io_keyboard_up(sega_io *io, uint8_t scancode)
367 int idx = keycode & 0x7FFF; 194 {
368 keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL; 195 store_key_event(find_keyboard(io), 0xF000 | scancode);
369 if (binding && (!current_io->keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) { 196 }
370 handle_binding_down(binding); 197
371 } else if (current_io->keyboard_captured) { 198 uint8_t io_has_keyboard(sega_io *io)
372 store_key_event(scancode); 199 {
373 } 200 return find_keyboard(io) != NULL;
374 }
375
376 void handle_joydown(int joystick, int button)
377 {
378 if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) {
379 return;
380 }
381 keybinding * binding = joysticks[joystick].buttons + button;
382 handle_binding_down(binding);
383 }
384
385 void handle_mousedown(int mouse, int button)
386 {
387 if (!current_io) {
388 return;
389 }
390 if (current_io->mouse_mode == MOUSE_CAPTURE && !current_io->mouse_captured) {
391 current_io->mouse_captured = 1;
392 render_relative_mouse(1);
393 return;
394 }
395 if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
396 return;
397 }
398 keybinding * binding = mice[mouse].buttons + button - 1;
399 handle_binding_down(binding);
400 }
401
402 uint8_t ui_debug_mode = 0;
403 uint8_t ui_debug_pal = 0;
404
405 int current_speed = 0;
406 int num_speeds = 1;
407 uint32_t * speeds = NULL;
408
409 uint8_t is_keyboard(io_port *port)
410 {
411 return port->device_type == IO_SATURN_KEYBOARD || port->device_type == IO_XBAND_KEYBOARD;
412 }
413
414 uint8_t keyboard_connected(sega_io *io)
415 {
416 return is_keyboard(io->ports) || is_keyboard(io->ports+1) || is_keyboard(io->ports+2);
417 }
418
419 #ifdef _WIN32
420 #define localtime_r(a,b) localtime(a)
421 #endif
422
423 void handle_binding_up(keybinding * binding)
424 {
425 switch(binding->bind_type)
426 {
427 case BIND_GAMEPAD1:
428 case BIND_GAMEPAD2:
429 case BIND_GAMEPAD3:
430 case BIND_GAMEPAD4:
431 case BIND_GAMEPAD5:
432 case BIND_GAMEPAD6:
433 case BIND_GAMEPAD7:
434 case BIND_GAMEPAD8:
435 if (binding->subtype_a <= GAMEPAD_EXTRA && binding->port) {
436 binding->port->input[binding->subtype_a] &= ~binding->value;
437 }
438 if (binding->subtype_b <= GAMEPAD_EXTRA && binding->port) {
439 binding->port->input[binding->subtype_b] &= ~binding->value;
440 }
441 break;
442 case BIND_MOUSE1:
443 case BIND_MOUSE2:
444 case BIND_MOUSE3:
445 case BIND_MOUSE4:
446 case BIND_MOUSE5:
447 case BIND_MOUSE6:
448 case BIND_MOUSE7:
449 case BIND_MOUSE8:
450 if (binding->port) {
451 binding->port->input[0] &= ~binding->value;
452 }
453 break;
454 case BIND_UI:
455 switch (binding->subtype_a)
456 {
457 case UI_DEBUG_MODE_INC:
458 current_system->inc_debug_mode(current_system);
459 break;
460 case UI_DEBUG_PAL_INC:
461 current_system->inc_debug_pal(current_system);
462 break;
463 case UI_ENTER_DEBUGGER:
464 current_system->enter_debugger = 1;
465 break;
466 case UI_SAVE_STATE:
467 current_system->save_state = QUICK_SAVE_SLOT+1;
468 break;
469 case UI_NEXT_SPEED:
470 current_speed++;
471 if (current_speed >= num_speeds) {
472 current_speed = 0;
473 }
474 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
475 current_system->set_speed_percent(current_system, speeds[current_speed]);
476 break;
477 case UI_PREV_SPEED:
478 current_speed--;
479 if (current_speed < 0) {
480 current_speed = num_speeds - 1;
481 }
482 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
483 current_system->set_speed_percent(current_system, speeds[current_speed]);
484 break;
485 case UI_SET_SPEED:
486 if (binding->value < num_speeds) {
487 current_speed = binding->value;
488 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]);
489 current_system->set_speed_percent(current_system, speeds[current_speed]);
490 } else {
491 printf("Setting speed to %d\n", speeds[current_speed]);
492 current_system->set_speed_percent(current_system, speeds[current_speed]);
493 }
494 break;
495 case UI_RELEASE_MOUSE:
496 if (current_io->mouse_captured) {
497 current_io->mouse_captured = 0;
498 render_relative_mouse(0);
499 }
500 break;
501 case UI_TOGGLE_KEYBOARD_CAPTURE:
502 if (keyboard_connected(current_io)) {
503 current_io->keyboard_captured = !current_io->keyboard_captured;
504 }
505 break;
506 case UI_TOGGLE_FULLSCREEN:
507 render_toggle_fullscreen();
508 break;
509 case UI_SOFT_RESET:
510 current_system->soft_reset(current_system);
511 break;
512 case UI_RELOAD:
513 reload_media();
514 break;
515 case UI_SMS_PAUSE:
516 if (current_system->type == SYSTEM_SMS) {
517 sms_context *sms = (sms_context *)current_system;
518 vdp_pbc_pause(sms->vdp);
519 }
520 break;
521 case UI_SCREENSHOT: {
522 char *screenshot_base = tern_find_path(config, "ui\0screenshot_path\0", TVAL_PTR).ptrval;
523 if (!screenshot_base) {
524 screenshot_base = "$HOME";
525 }
526 tern_node *vars = tern_insert_ptr(NULL, "HOME", get_home_dir());
527 vars = tern_insert_ptr(vars, "EXEDIR", get_exe_dir());
528 screenshot_base = replace_vars(screenshot_base, vars, 1);
529 tern_free(vars);
530 time_t now = time(NULL);
531 struct tm local_store;
532 char fname_part[256];
533 char *template = tern_find_path(config, "ui\0screenshot_template\0", TVAL_PTR).ptrval;
534 if (!template) {
535 template = "blastem_%c.ppm";
536 }
537 strftime(fname_part, sizeof(fname_part), template, localtime_r(&now, &local_store));
538 char const *parts[] = {screenshot_base, PATH_SEP, fname_part};
539 char *path = alloc_concat_m(3, parts);
540 free(screenshot_base);
541 render_save_screenshot(path);
542 break;
543 }
544 case UI_EXIT:
545 #ifndef DISABLE_NUKLEAR
546 if (is_nuklear_active()) {
547 show_pause_menu();
548 } else {
549 #endif
550 current_system->request_exit(current_system);
551 if (current_system->type == SYSTEM_GENESIS) {
552 genesis_context *gen = (genesis_context *)current_system;
553 if (gen->extra) {
554 //TODO: More robust mechanism for detecting menu
555 menu_context *menu = gen->extra;
556 menu->external_game_load = 1;
557 }
558 }
559 #ifndef DISABLE_NUKLEAR
560 }
561 #endif
562 break;
563 }
564 break;
565 }
566 }
567
568 void handle_keyup(int keycode, uint8_t scancode)
569 {
570 if (!current_io) {
571 return;
572 }
573 int bucket = keycode >> 15 & 0xFFFF;
574 int idx = keycode & 0x7FFF;
575 keybinding * binding = bindings[bucket] ? bindings[bucket] + idx : NULL;
576 if (binding && (!current_io->keyboard_captured || (binding->bind_type == BIND_UI && binding->subtype_a == UI_TOGGLE_KEYBOARD_CAPTURE))) {
577 handle_binding_up(binding);
578 } else if (current_io->keyboard_captured) {
579 store_key_event(0xF000 | scancode);
580 }
581 }
582
583 void handle_joyup(int joystick, int button)
584 {
585 if (joystick >= MAX_JOYSTICKS || button >= joysticks[joystick].num_buttons) {
586 return;
587 }
588 keybinding * binding = joysticks[joystick].buttons + button;
589 handle_binding_up(binding);
590 }
591
592 void handle_joy_dpad(int joystick, int dpadnum, uint8_t value)
593 {
594 if (joystick >= MAX_JOYSTICKS || dpadnum >= joysticks[joystick].num_dpads) {
595 return;
596 }
597 joydpad * dpad = joysticks[joystick].dpads + dpadnum;
598 uint8_t newdown = (value ^ dpad->state) & value;
599 uint8_t newup = ((~value) ^ (~dpad->state)) & (~value);
600 dpad->state = value;
601 for (int i = 0; i < 4; i++) {
602 if (newdown & dpadbits[i]) {
603 handle_binding_down(dpad->bindings + i);
604 } else if(newup & dpadbits[i]) {
605 handle_binding_up(dpad->bindings + i);
606 }
607 }
608 }
609
610 #define JOY_AXIS_THRESHOLD 2000
611
612 void handle_joy_axis(int joystick, int axis, int16_t value)
613 {
614 if (joystick >= MAX_JOYSTICKS || axis >= joysticks[joystick].num_axes) {
615 return;
616 }
617 joyaxis *jaxis = joysticks[joystick].axes + axis;
618 int old_active = abs(jaxis->value) > JOY_AXIS_THRESHOLD;
619 int new_active = abs(value) > JOY_AXIS_THRESHOLD;
620 int old_pos = jaxis->value > 0;
621 int new_pos = value > 0;
622 jaxis->value = value;
623 if (old_active && (!new_active || old_pos != new_pos)) {
624 //previously activated direction is no longer active
625 handle_binding_up(old_pos ? &jaxis->positive : &jaxis->negative);
626 }
627 if (new_active && (!old_active || old_pos != new_pos)) {
628 //previously unactivated direction is now active
629 handle_binding_down(new_pos ? &jaxis->positive : &jaxis->negative);
630 }
631 }
632
633 void handle_mouseup(int mouse, int button)
634 {
635 if (mouse >= MAX_MICE || button > MAX_MOUSE_BUTTONS || button <= 0) {
636 return;
637 }
638 keybinding * binding = mice[mouse].buttons + button - 1;
639 handle_binding_up(binding);
640 }
641
642 void handle_mouse_moved(int mouse, uint16_t x, uint16_t y, int16_t deltax, int16_t deltay)
643 {
644 if (mouse >= MAX_MICE || !mice[mouse].motion_port) {
645 return;
646 }
647 switch(current_io->mouse_mode)
648 {
649 case MOUSE_NONE:
650 break;
651 case MOUSE_ABSOLUTE: {
652 float scale_x = (render_emulated_width() * 2.0f) / ((float)render_width());
653 float scale_y = (render_emulated_height() * 2.0f) / ((float)render_height());
654 int32_t adj_x = x * scale_x + 2 * render_overscan_left() - 2 * BORDER_LEFT;
655 int32_t adj_y = y * scale_y + 2 * render_overscan_top() - 4;
656 if (adj_x >= 0 && adj_y >= 0) {
657 mice[mouse].motion_port->device.mouse.cur_x = adj_x;
658 mice[mouse].motion_port->device.mouse.cur_y = adj_y;
659 }
660 break;
661 }
662 case MOUSE_RELATIVE: {
663 mice[mouse].motion_port->device.mouse.cur_x += deltax;
664 mice[mouse].motion_port->device.mouse.cur_y += deltay;
665 break;
666 }
667 case MOUSE_CAPTURE: {
668 if (current_io->mouse_captured) {
669 mice[mouse].motion_port->device.mouse.cur_x += deltax;
670 mice[mouse].motion_port->device.mouse.cur_y += deltay;
671 }
672 break;
673 }
674 }
675 }
676
677 void io_release_capture(sega_io *io)
678 {
679 if (io->mouse_mode == MOUSE_RELATIVE || (io->mouse_mode == MOUSE_CAPTURE && io->mouse_captured)) {
680 render_relative_mouse(0);
681 }
682 current_io->keyboard_captured = 0;
683 }
684
685 void io_reacquire_capture(sega_io *io)
686 {
687 if (io->mouse_mode == MOUSE_RELATIVE || (io->mouse_mode == MOUSE_CAPTURE && io->mouse_captured)) {
688 render_relative_mouse(1);
689 }
690 }
691
692 int parse_binding_target(char * target, tern_node * padbuttons, tern_node *mousebuttons, int * ui_out, int * padnum_out, int * padbutton_out)
693 {
694 const int gpadslen = strlen("gamepads.");
695 const int mouselen = strlen("mouse.");
696 if (!strncmp(target, "gamepads.", gpadslen)) {
697 if (target[gpadslen] >= '1' && target[gpadslen] <= '8') {
698 int padnum = target[gpadslen] - '0';
699 int button = tern_find_int(padbuttons, target + gpadslen + 1, 0);
700 if (button) {
701 *padnum_out = padnum;
702 *padbutton_out = button;
703 return BIND_GAMEPAD1;
704 } else {
705 if (target[gpadslen+1]) {
706 warning("Gamepad mapping string '%s' refers to an invalid button '%s'\n", target, target + gpadslen + 1);
707 } else {
708 warning("Gamepad mapping string '%s' has no button component\n", target);
709 }
710 }
711 } else {
712 warning("Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]);
713 }
714 } else if(!strncmp(target, "mouse.", mouselen)) {
715 if (target[mouselen] >= '1' && target[mouselen] <= '8') {
716 int mousenum = target[mouselen] - '0';
717 int button = tern_find_int(mousebuttons, target + mouselen + 1, 0);
718 if (button) {
719 *padnum_out = mousenum;
720 *padbutton_out = button;
721 return BIND_MOUSE1;
722 } else {
723 if (target[mouselen+1]) {
724 warning("Mouse mapping string '%s' refers to an invalid button '%s'\n", target, target + mouselen + 1);
725 } else {
726 warning("Mouse mapping string '%s' has no button component\n", target);
727 }
728 }
729 } else {
730 warning("Gamepad mapping string '%s' refers to an invalid mouse number %c\n", target, target[mouselen]);
731 }
732 } else if(!strncmp(target, "ui.", strlen("ui."))) {
733 *padbutton_out = 0;
734 if (!strcmp(target + 3, "vdp_debug_mode")) {
735 *ui_out = UI_DEBUG_MODE_INC;
736 } else if(!strcmp(target + 3, "vdp_debug_pal")) {
737 *ui_out = UI_DEBUG_PAL_INC;
738 } else if(!strcmp(target + 3, "enter_debugger")) {
739 *ui_out = UI_ENTER_DEBUGGER;
740 } else if(!strcmp(target + 3, "save_state")) {
741 *ui_out = UI_SAVE_STATE;
742 } else if(!strncmp(target + 3, "set_speed.", strlen("set_speed."))) {
743 *ui_out = UI_SET_SPEED;
744 *padbutton_out = atoi(target + 3 + strlen("set_speed."));
745 } else if(!strcmp(target + 3, "next_speed")) {
746 *ui_out = UI_NEXT_SPEED;
747 } else if(!strcmp(target + 3, "prev_speed")) {
748 *ui_out = UI_PREV_SPEED;
749 } else if(!strcmp(target + 3, "release_mouse")) {
750 *ui_out = UI_RELEASE_MOUSE;
751 } else if(!strcmp(target + 3, "toggle_keyboard_captured")) {
752 *ui_out = UI_TOGGLE_KEYBOARD_CAPTURE;
753 } else if (!strcmp(target + 3, "toggle_fullscreen")) {
754 *ui_out = UI_TOGGLE_FULLSCREEN;
755 } else if (!strcmp(target + 3, "soft_reset")) {
756 *ui_out = UI_SOFT_RESET;
757 } else if (!strcmp(target + 3, "reload")) {
758 *ui_out = UI_RELOAD;
759 } else if (!strcmp(target + 3, "sms_pause")) {
760 *ui_out = UI_SMS_PAUSE;
761 } else if (!strcmp(target + 3, "screenshot")) {
762 *ui_out = UI_SCREENSHOT;
763 } else if(!strcmp(target + 3, "exit")) {
764 *ui_out = UI_EXIT;
765 } else {
766 warning("Unreconized UI binding type %s\n", target);
767 return 0;
768 }
769 return BIND_UI;
770 } else {
771 warning("Unrecognized binding type %s\n", target);
772 }
773 return 0;
774 }
775
776 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, tern_node *mousebuttons, char * prefix)
777 {
778 char * curstr = NULL;
779 int len;
780 if (!cur) {
781 return;
782 }
783 char onec[2];
784 if (prefix) {
785 len = strlen(prefix);
786 curstr = malloc(len + 2);
787 memcpy(curstr, prefix, len);
788 } else {
789 curstr = onec;
790 len = 0;
791 }
792 curstr[len] = cur->el;
793 curstr[len+1] = 0;
794 if (cur->el) {
795 process_keys(cur->straight.next, special, padbuttons, mousebuttons, curstr);
796 } else {
797 int keycode = tern_find_int(special, curstr, 0);
798 if (!keycode) {
799 keycode = curstr[0];
800 if (curstr[1] != 0) {
801 warning("%s is not recognized as a key identifier, truncating to %c\n", curstr, curstr[0]);
802 }
803 }
804 char * target = cur->straight.value.ptrval;
805 int ui_func, padnum, button;
806 int bindtype = parse_binding_target(target, padbuttons, mousebuttons, &ui_func, &padnum, &button);
807 if (bindtype == BIND_GAMEPAD1) {
808 bind_gamepad(keycode, padnum, button);
809 } else if(bindtype == BIND_UI) {
810 bind_ui(keycode, ui_func, button);
811 }
812 }
813 process_keys(cur->left, special, padbuttons, mousebuttons, prefix);
814 process_keys(cur->right, special, padbuttons, mousebuttons, prefix);
815 if (curstr && len) {
816 free(curstr);
817 }
818 }
819
820 void process_speeds(tern_node * cur, char * prefix)
821 {
822 char * curstr = NULL;
823 int len;
824 if (!cur) {
825 return;
826 }
827 char onec[2];
828 if (prefix) {
829 len = strlen(prefix);
830 curstr = malloc(len + 2);
831 memcpy(curstr, prefix, len);
832 } else {
833 curstr = onec;
834 len = 0;
835 }
836 curstr[len] = cur->el;
837 curstr[len+1] = 0;
838 if (cur->el) {
839 process_speeds(cur->straight.next, curstr);
840 } else {
841 char *end;
842 long speed_index = strtol(curstr, &end, 10);
843 if (speed_index < 0 || end == curstr || *end) {
844 warning("%s is not a valid speed index", curstr);
845 } else {
846 if (speed_index >= num_speeds) {
847 speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1));
848 for(; num_speeds < speed_index + 1; num_speeds++) {
849 speeds[num_speeds] = 0;
850 }
851 }
852 speeds[speed_index] = atoi(cur->straight.value.ptrval);
853 if (speeds[speed_index] < 1) {
854 warning("%s is not a valid speed percentage, setting speed %d to 100", cur->straight.value.ptrval, speed_index);
855 speeds[speed_index] = 100;
856 }
857 }
858 }
859 process_speeds(cur->left, prefix);
860 process_speeds(cur->right, prefix);
861 if (curstr && len) {
862 free(curstr);
863 }
864 } 201 }
865 202
866 void process_device(char * device_type, io_port * port) 203 void process_device(char * device_type, io_port * port)
867 { 204 {
868 port->device_type = IO_NONE; 205 port->device_type = IO_NONE;
886 } else if (device_type[gamepad_len] == '2') { 223 } else if (device_type[gamepad_len] == '2') {
887 port->device_type = IO_GAMEPAD2; 224 port->device_type = IO_GAMEPAD2;
888 } else { 225 } else {
889 port->device_type = IO_GAMEPAD6; 226 port->device_type = IO_GAMEPAD6;
890 } 227 }
891 port->device.pad.gamepad_num = device_type[gamepad_len+2] - '1'; 228 port->device.pad.gamepad_num = device_type[gamepad_len+2] - '0';
892 } else if(!strncmp(device_type, "mouse", mouse_len)) { 229 } else if(!strncmp(device_type, "mouse", mouse_len)) {
893 port->device_type = IO_MOUSE; 230 port->device_type = IO_MOUSE;
894 port->device.mouse.mouse_num = device_type[mouse_len+1] - '1'; 231 port->device.mouse.mouse_num = device_type[mouse_len+1] - '0';
895 port->device.mouse.last_read_x = 0; 232 port->device.mouse.last_read_x = 0;
896 port->device.mouse.last_read_y = 0; 233 port->device.mouse.last_read_y = 0;
897 port->device.mouse.cur_x = 0; 234 port->device.mouse.cur_x = 0;
898 port->device.mouse.cur_y = 0; 235 port->device.mouse.cur_y = 0;
899 port->device.mouse.latched_x = 0; 236 port->device.mouse.latched_x = 0;
940 unlink(sockfile_name); 277 unlink(sockfile_name);
941 } 278 }
942 279
943 void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io) 280 void setup_io_devices(tern_node * config, rom_info *rom, sega_io *io)
944 { 281 {
945 current_io = io; 282 io_port * ports = io->ports;
946 io_port * ports = current_io->ports;
947 tern_node *io_nodes = tern_find_path(config, "io\0devices\0", TVAL_NODE).ptrval; 283 tern_node *io_nodes = tern_find_path(config, "io\0devices\0", TVAL_NODE).ptrval;
948 char * io_1 = rom->port1_override ? rom->port1_override : io_nodes ? tern_find_ptr(io_nodes, "1") : NULL; 284 char * io_1 = rom->port1_override ? rom->port1_override : io_nodes ? tern_find_ptr(io_nodes, "1") : NULL;
949 char * io_2 = rom->port2_override ? rom->port2_override : io_nodes ? tern_find_ptr(io_nodes, "2") : NULL; 285 char * io_2 = rom->port2_override ? rom->port2_override : io_nodes ? tern_find_ptr(io_nodes, "2") : NULL;
950 char * io_ext = rom->ext_override ? rom->ext_override : io_nodes ? tern_find_ptr(io_nodes, "ext") : NULL; 286 char * io_ext = rom->ext_override ? rom->ext_override : io_nodes ? tern_find_ptr(io_nodes, "ext") : NULL;
951 287
952 process_device(io_1, ports); 288 process_device(io_1, ports);
953 process_device(io_2, ports+1); 289 process_device(io_2, ports+1);
954 process_device(io_ext, ports+2); 290 process_device(io_ext, ports+2);
955 291
292 uint8_t mouse_mode;
956 if (ports[0].device_type == IO_MOUSE || ports[1].device_type == IO_MOUSE || ports[2].device_type == IO_MOUSE) { 293 if (ports[0].device_type == IO_MOUSE || ports[1].device_type == IO_MOUSE || ports[2].device_type == IO_MOUSE) {
957 if (render_fullscreen()) { 294 if (render_fullscreen()) {
958 current_io->mouse_mode = MOUSE_RELATIVE; 295 mouse_mode = MOUSE_RELATIVE;
959 render_relative_mouse(1);
960 } else { 296 } else {
961 if (rom->mouse_mode && !strcmp(rom->mouse_mode, "absolute")) { 297 if (rom->mouse_mode && !strcmp(rom->mouse_mode, "absolute")) {
962 current_io->mouse_mode = MOUSE_ABSOLUTE; 298 mouse_mode = MOUSE_ABSOLUTE;
963 } else { 299 } else {
964 current_io->mouse_mode = MOUSE_CAPTURE; 300 mouse_mode = MOUSE_CAPTURE;
965 } 301 }
966 } 302 }
967 } else { 303 } else {
968 current_io->mouse_mode = MOUSE_NONE; 304 mouse_mode = MOUSE_NONE;
969 } 305 }
306 bindings_set_mouse_mode(mouse_mode);
970 307
971 for (int i = 0; i < 3; i++) 308 for (int i = 0; i < 3; i++)
972 { 309 {
973 #ifndef _WIN32 310 #ifndef _WIN32
974 if (ports[i].device_type == IO_SEGA_PARALLEL) 311 if (ports[i].device_type == IO_SEGA_PARALLEL)
1040 printf("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]); 377 printf("IO port %s connected to device '%s'\n", io_name(i), device_type_names[ports[i].device_type]);
1041 } 378 }
1042 } 379 }
1043 } 380 }
1044 381
1045 void map_bindings(io_port *ports, keybinding *bindings, int numbindings)
1046 {
1047 for (int i = 0; i < numbindings; i++)
1048 {
1049 if (bindings[i].bind_type >= BIND_GAMEPAD1 && bindings[i].bind_type <= BIND_GAMEPAD8)
1050 {
1051 int num = bindings[i].bind_type - BIND_GAMEPAD1;
1052 for (int j = 0; j < 3; j++)
1053 {
1054 if ((ports[j].device_type == IO_GAMEPAD3
1055 || ports[j].device_type == IO_GAMEPAD6
1056 || ports[j].device_type == IO_GAMEPAD2)
1057 && ports[j].device.pad.gamepad_num == num
1058 )
1059 {
1060 memset(ports[j].input, 0, sizeof(ports[j].input));
1061 bindings[i].port = ports + j;
1062 break;
1063 }
1064 }
1065 }
1066 else if (bindings[i].bind_type >= BIND_MOUSE1 && bindings[i].bind_type <= BIND_MOUSE8)
1067 {
1068 int num = bindings[i].bind_type - BIND_MOUSE1;
1069 for (int j = 0; j < 3; j++)
1070 {
1071 if (ports[j].device_type == IO_MOUSE && ports[j].device.mouse.mouse_num == num)
1072 {
1073 memset(ports[j].input, 0, sizeof(ports[j].input));
1074 bindings[i].port = ports + j;
1075 break;
1076 }
1077 }
1078 }
1079 }
1080 }
1081
1082 typedef struct {
1083 tern_node *padbuttons;
1084 tern_node *mousebuttons;
1085 int mouseidx;
1086 } pmb_state;
1087
1088 void process_mouse_button(char *buttonstr, tern_val value, uint8_t valtype, void *data)
1089 {
1090 pmb_state *state = data;
1091 int buttonnum = atoi(buttonstr);
1092 if (buttonnum < 1 || buttonnum > MAX_MOUSE_BUTTONS) {
1093 warning("Mouse button %s is out of the supported range of 1-8\n", buttonstr);
1094 return;
1095 }
1096 if (valtype != TVAL_PTR) {
1097 warning("Mouse button %s is not a scalar value!\n", buttonstr);
1098 return;
1099 }
1100 buttonnum--;
1101 int ui_func, devicenum, button;
1102 int bindtype = parse_binding_target(value.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &devicenum, &button);
1103 switch (bindtype)
1104 {
1105 case BIND_UI:
1106 mice[state->mouseidx].buttons[buttonnum].subtype_a = ui_func;
1107 break;
1108 case BIND_GAMEPAD1:
1109 mice[state->mouseidx].buttons[buttonnum].subtype_a = button >> 12;
1110 mice[state->mouseidx].buttons[buttonnum].subtype_b = button >> 8 & 0xF;
1111 mice[state->mouseidx].buttons[buttonnum].value = button & 0xFF;
1112 break;
1113 case BIND_MOUSE1:
1114 mice[state->mouseidx].buttons[buttonnum].value = button & 0xFF;
1115 break;
1116 }
1117 if (bindtype != BIND_UI) {
1118 bindtype += devicenum-1;
1119 }
1120 mice[state->mouseidx].buttons[buttonnum].bind_type = bindtype;
1121
1122 }
1123
1124 void process_mouse(char *mousenum, tern_val value, uint8_t valtype, void *data)
1125 {
1126 tern_node **buttonmaps = data;
1127 if (valtype != TVAL_NODE) {
1128 warning("Binding for mouse %s is a scalar!\n", mousenum);
1129 return;
1130 }
1131 tern_node *mousedef = value.ptrval;
1132 tern_node *padbuttons = buttonmaps[0];
1133 tern_node *mousebuttons = buttonmaps[1];
1134
1135 int mouseidx = atoi(mousenum);
1136 if (mouseidx < 0 || mouseidx >= MAX_MICE) {
1137 warning("Mouse numbers must be between 0 and %d, but %d is not\n", MAX_MICE, mouseidx);
1138 return;
1139 }
1140 char *motion = tern_find_ptr(mousedef, "motion");
1141 if (motion) {
1142 int ui_func,devicenum,button;
1143 int bindtype = parse_binding_target(motion, padbuttons, mousebuttons, &ui_func, &devicenum, &button);
1144 if (bindtype != BIND_UI) {
1145 bindtype += devicenum-1;
1146 }
1147 if (button == PSEUDO_BUTTON_MOTION) {
1148 mice[mouseidx].bind_type = bindtype;
1149 } else {
1150 warning("Mouse motion can't be bound to target %s\n", motion);
1151 }
1152 }
1153 tern_node *buttons = tern_find_path(mousedef, "buttons\0\0", TVAL_NODE).ptrval;
1154 if (buttons) {
1155 pmb_state state = {padbuttons, mousebuttons, mouseidx};
1156 tern_foreach(buttons, process_mouse_button, &state);
1157 }
1158 }
1159
1160 typedef struct {
1161 int padnum;
1162 tern_node *padbuttons;
1163 tern_node *mousebuttons;
1164 } pad_button_state;
1165
1166
1167 static long map_warning_pad = -1;
1168 void process_pad_button(char *key, tern_val val, uint8_t valtype, void *data)
1169 {
1170 pad_button_state *state = data;
1171 int hostpadnum = state->padnum;
1172 int ui_func, padnum, button;
1173 if (valtype != TVAL_PTR) {
1174 warning("Pad button %s has a non-scalar value\n", key);
1175 return;
1176 }
1177 int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button);
1178 char *end;
1179 long hostbutton = strtol(key, &end, 10);
1180 if (*end) {
1181 //key is not a valid base 10 integer
1182 hostbutton = render_translate_input_name(hostpadnum, key, 0);
1183 if (hostbutton < 0) {
1184 if (hostbutton == RENDER_INVALID_NAME) {
1185 warning("%s is not a valid gamepad input name\n", key);
1186 } else if (hostbutton == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
1187 warning("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
1188 map_warning_pad = hostpadnum;
1189 }
1190 return;
1191 }
1192 if (hostbutton & RENDER_DPAD_BIT) {
1193 if (bindtype == BIND_GAMEPAD1) {
1194 bind_dpad_gamepad(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), padnum, button);
1195 } else {
1196 bind_dpad_ui(hostpadnum, render_dpad_part(hostbutton), render_direction_part(hostbutton), ui_func, button);
1197 }
1198 return;
1199 } else if (hostbutton & RENDER_AXIS_BIT) {
1200 if (bindtype == BIND_GAMEPAD1) {
1201 bind_axis_gamepad(hostpadnum, render_axis_part(hostbutton), 1, padnum, button);
1202 } else {
1203 bind_axis_ui(hostpadnum, render_axis_part(hostbutton), 1, padnum, button);
1204 }
1205 return;
1206 }
1207 }
1208 if (bindtype == BIND_GAMEPAD1) {
1209 bind_button_gamepad(hostpadnum, hostbutton, padnum, button);
1210 } else if (bindtype == BIND_UI) {
1211 bind_button_ui(hostpadnum, hostbutton, ui_func, button);
1212 }
1213 }
1214
1215 void process_pad_axis(char *key, tern_val val, uint8_t valtype, void *data)
1216 {
1217 key = strdup(key);
1218 pad_button_state *state = data;
1219 int hostpadnum = state->padnum;
1220 int ui_func, padnum, button;
1221 if (valtype != TVAL_PTR) {
1222 warning("Mapping for axis %s has a non-scalar value", key);
1223 return;
1224 }
1225 int bindtype = parse_binding_target(val.ptrval, state->padbuttons, state->mousebuttons, &ui_func, &padnum, &button);
1226 char *modifier = strchr(key, '.');
1227 int positive = 1;
1228 if (modifier) {
1229 *modifier = 0;
1230 modifier++;
1231 if (!strcmp("negative", modifier)) {
1232 positive = 0;
1233 } else if(strcmp("positive", modifier)) {
1234 warning("Invalid axis modifier %s for axis %s on pad %d\n", modifier, key, hostpadnum);
1235 }
1236 }
1237 char *end;
1238 long axis = strtol(key, &end, 10);
1239 if (*end) {
1240 //key is not a valid base 10 integer
1241 axis = render_translate_input_name(hostpadnum, key, 1);
1242 if (axis < 0) {
1243 if (axis == RENDER_INVALID_NAME) {
1244 warning("%s is not a valid gamepad input name\n", key);
1245 } else if (axis == RENDER_NOT_MAPPED && hostpadnum != map_warning_pad) {
1246 warning("No SDL 2 mapping exists for input %s on gamepad %d\n", key, hostpadnum);
1247 map_warning_pad = hostpadnum;
1248 }
1249 goto done;
1250 }
1251 if (axis & RENDER_DPAD_BIT) {
1252 if (bindtype == BIND_GAMEPAD1) {
1253 bind_dpad_gamepad(hostpadnum, render_dpad_part(axis), render_direction_part(axis), padnum, button);
1254 } else {
1255 bind_dpad_ui(hostpadnum, render_dpad_part(axis), render_direction_part(axis), ui_func, button);
1256 }
1257 goto done;
1258 } else if (axis & RENDER_AXIS_BIT) {
1259 axis = render_axis_part(axis);
1260 } else {
1261 if (bindtype == BIND_GAMEPAD1) {
1262 bind_button_gamepad(hostpadnum, axis, padnum, button);
1263 } else if (bindtype == BIND_UI) {
1264 bind_button_ui(hostpadnum, axis, ui_func, button);
1265 }
1266 goto done;
1267 }
1268 }
1269 if (bindtype == BIND_GAMEPAD1) {
1270 bind_axis_gamepad(hostpadnum, axis, positive, padnum, button);
1271 } else {
1272 bind_axis_ui(hostpadnum, axis, positive, ui_func, button);
1273 }
1274 done:
1275 free(key);
1276 return;
1277 }
1278
1279 static tern_node *get_pad_buttons()
1280 {
1281 static tern_node *padbuttons;
1282 if (!padbuttons) {
1283 padbuttons = tern_insert_int(NULL, ".up", DPAD_UP);
1284 padbuttons = tern_insert_int(padbuttons, ".down", DPAD_DOWN);
1285 padbuttons = tern_insert_int(padbuttons, ".left", DPAD_LEFT);
1286 padbuttons = tern_insert_int(padbuttons, ".right", DPAD_RIGHT);
1287 padbuttons = tern_insert_int(padbuttons, ".a", BUTTON_A);
1288 padbuttons = tern_insert_int(padbuttons, ".b", BUTTON_B);
1289 padbuttons = tern_insert_int(padbuttons, ".c", BUTTON_C);
1290 padbuttons = tern_insert_int(padbuttons, ".x", BUTTON_X);
1291 padbuttons = tern_insert_int(padbuttons, ".y", BUTTON_Y);
1292 padbuttons = tern_insert_int(padbuttons, ".z", BUTTON_Z);
1293 padbuttons = tern_insert_int(padbuttons, ".start", BUTTON_START);
1294 padbuttons = tern_insert_int(padbuttons, ".mode", BUTTON_MODE);
1295 }
1296 return padbuttons;
1297 }
1298
1299 static tern_node *get_mouse_buttons()
1300 {
1301 static tern_node *mousebuttons;
1302 if (!mousebuttons) {
1303 mousebuttons = tern_insert_int(NULL, ".left", MOUSE_LEFT);
1304 mousebuttons = tern_insert_int(mousebuttons, ".middle", MOUSE_MIDDLE);
1305 mousebuttons = tern_insert_int(mousebuttons, ".right", MOUSE_RIGHT);
1306 mousebuttons = tern_insert_int(mousebuttons, ".start", MOUSE_START);
1307 mousebuttons = tern_insert_int(mousebuttons, ".motion", PSEUDO_BUTTON_MOTION);
1308 }
1309 return mousebuttons;
1310 }
1311
1312 void handle_joy_added(int joystick)
1313 {
1314 if (joystick > MAX_JOYSTICKS) {
1315 return;
1316 }
1317 tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval;
1318 if (pads) {
1319 char numstr[11];
1320 sprintf(numstr, "%d", joystick);
1321 tern_node * pad = tern_find_node(pads, numstr);
1322 if (pad) {
1323 tern_node * dpad_node = tern_find_node(pad, "dpads");
1324 if (dpad_node) {
1325 for (int dpad = 0; dpad < 10; dpad++)
1326 {
1327 numstr[0] = dpad + '0';
1328 numstr[1] = 0;
1329 tern_node * pad_dpad = tern_find_node(dpad_node, numstr);
1330 char * dirs[] = {"up", "down", "left", "right"};
1331 int dirnums[] = {RENDER_DPAD_UP, RENDER_DPAD_DOWN, RENDER_DPAD_LEFT, RENDER_DPAD_RIGHT};
1332 for (int dir = 0; dir < sizeof(dirs)/sizeof(dirs[0]); dir++) {
1333 char * target = tern_find_ptr(pad_dpad, dirs[dir]);
1334 if (target) {
1335 int ui_func, padnum, button;
1336 int bindtype = parse_binding_target(target, get_pad_buttons(), get_mouse_buttons(), &ui_func, &padnum, &button);
1337 if (bindtype == BIND_GAMEPAD1) {
1338 bind_dpad_gamepad(joystick, dpad, dirnums[dir], padnum, button);
1339 } else if (bindtype == BIND_UI) {
1340 bind_dpad_ui(joystick, dpad, dirnums[dir], ui_func, button);
1341 }
1342 }
1343 }
1344 }
1345 }
1346 tern_node *button_node = tern_find_node(pad, "buttons");
1347 if (button_node) {
1348 pad_button_state state = {
1349 .padnum = joystick,
1350 .padbuttons = get_pad_buttons(),
1351 .mousebuttons = get_mouse_buttons()
1352 };
1353 tern_foreach(button_node, process_pad_button, &state);
1354 }
1355 tern_node *axes_node = tern_find_node(pad, "axes");
1356 if (axes_node) {
1357 pad_button_state state = {
1358 .padnum = joystick,
1359 .padbuttons = get_pad_buttons(),
1360 .mousebuttons = get_mouse_buttons()
1361 };
1362 tern_foreach(axes_node, process_pad_axis, &state);
1363 }
1364 if (current_io) {
1365 if (joysticks[joystick].buttons) {
1366 map_bindings(current_io->ports, joysticks[joystick].buttons, joysticks[joystick].num_buttons);
1367 }
1368 if (joysticks[joystick].dpads)
1369 {
1370 for (uint32_t i = 0; i < joysticks[joystick].num_dpads; i++)
1371 {
1372 map_bindings(current_io->ports, joysticks[joystick].dpads[i].bindings, 4);
1373 }
1374 }
1375 if (joysticks[joystick].axes) {
1376 for (uint32_t i = 0; i < joysticks[joystick].num_axes; i++)
1377 {
1378 map_bindings(current_io->ports, &joysticks[joystick].axes[i].positive, 1);
1379 map_bindings(current_io->ports, &joysticks[joystick].axes[i].negative, 1);
1380 }
1381 }
1382 }
1383 }
1384 }
1385
1386 }
1387
1388 void set_keybindings(sega_io *io)
1389 {
1390 static uint8_t already_done;
1391 if (already_done) {
1392 map_all_bindings(io);
1393 return;
1394 }
1395 already_done = 1;
1396 io_port *ports = io->ports;
1397 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP);
1398 special = tern_insert_int(special, "down", RENDERKEY_DOWN);
1399 special = tern_insert_int(special, "left", RENDERKEY_LEFT);
1400 special = tern_insert_int(special, "right", RENDERKEY_RIGHT);
1401 special = tern_insert_int(special, "enter", '\r');
1402 special = tern_insert_int(special, "space", ' ');
1403 special = tern_insert_int(special, "tab", '\t');
1404 special = tern_insert_int(special, "backspace", '\b');
1405 special = tern_insert_int(special, "esc", RENDERKEY_ESC);
1406 special = tern_insert_int(special, "delete", RENDERKEY_DEL);
1407 special = tern_insert_int(special, "lshift", RENDERKEY_LSHIFT);
1408 special = tern_insert_int(special, "rshift", RENDERKEY_RSHIFT);
1409 special = tern_insert_int(special, "lctrl", RENDERKEY_LCTRL);
1410 special = tern_insert_int(special, "rctrl", RENDERKEY_RCTRL);
1411 special = tern_insert_int(special, "lalt", RENDERKEY_LALT);
1412 special = tern_insert_int(special, "ralt", RENDERKEY_RALT);
1413 special = tern_insert_int(special, "home", RENDERKEY_HOME);
1414 special = tern_insert_int(special, "end", RENDERKEY_END);
1415 special = tern_insert_int(special, "pageup", RENDERKEY_PAGEUP);
1416 special = tern_insert_int(special, "pagedown", RENDERKEY_PAGEDOWN);
1417 special = tern_insert_int(special, "f1", RENDERKEY_F1);
1418 special = tern_insert_int(special, "f2", RENDERKEY_F2);
1419 special = tern_insert_int(special, "f3", RENDERKEY_F3);
1420 special = tern_insert_int(special, "f4", RENDERKEY_F4);
1421 special = tern_insert_int(special, "f5", RENDERKEY_F5);
1422 special = tern_insert_int(special, "f6", RENDERKEY_F6);
1423 special = tern_insert_int(special, "f7", RENDERKEY_F7);
1424 special = tern_insert_int(special, "f8", RENDERKEY_F8);
1425 special = tern_insert_int(special, "f9", RENDERKEY_F9);
1426 special = tern_insert_int(special, "f10", RENDERKEY_F10);
1427 special = tern_insert_int(special, "f11", RENDERKEY_F11);
1428 special = tern_insert_int(special, "f12", RENDERKEY_F12);
1429 special = tern_insert_int(special, "select", RENDERKEY_SELECT);
1430 special = tern_insert_int(special, "play", RENDERKEY_PLAY);
1431 special = tern_insert_int(special, "search", RENDERKEY_SEARCH);
1432 special = tern_insert_int(special, "back", RENDERKEY_BACK);
1433 special = tern_insert_int(special, "np0", RENDERKEY_NP0);
1434 special = tern_insert_int(special, "np1", RENDERKEY_NP1);
1435 special = tern_insert_int(special, "np2", RENDERKEY_NP2);
1436 special = tern_insert_int(special, "np3", RENDERKEY_NP3);
1437 special = tern_insert_int(special, "np4", RENDERKEY_NP4);
1438 special = tern_insert_int(special, "np5", RENDERKEY_NP5);
1439 special = tern_insert_int(special, "np6", RENDERKEY_NP6);
1440 special = tern_insert_int(special, "np7", RENDERKEY_NP7);
1441 special = tern_insert_int(special, "np8", RENDERKEY_NP8);
1442 special = tern_insert_int(special, "np9", RENDERKEY_NP9);
1443 special = tern_insert_int(special, "np/", RENDERKEY_NP_DIV);
1444 special = tern_insert_int(special, "np*", RENDERKEY_NP_MUL);
1445 special = tern_insert_int(special, "np-", RENDERKEY_NP_MIN);
1446 special = tern_insert_int(special, "np+", RENDERKEY_NP_PLUS);
1447 special = tern_insert_int(special, "npenter", RENDERKEY_NP_ENTER);
1448 special = tern_insert_int(special, "np.", RENDERKEY_NP_STOP);
1449
1450 tern_node *padbuttons = get_pad_buttons();
1451
1452 tern_node *mousebuttons = get_mouse_buttons();
1453
1454 tern_node * keys = tern_find_path(config, "bindings\0keys\0", TVAL_NODE).ptrval;
1455 process_keys(keys, special, padbuttons, mousebuttons, NULL);
1456 char numstr[] = "00";
1457 tern_node * pads = tern_find_path(config, "bindings\0pads\0", TVAL_NODE).ptrval;
1458 if (pads) {
1459 for (int i = 0; i < MAX_JOYSTICKS; i++)
1460 {
1461
1462 if (i < 10) {
1463 numstr[0] = i + '0';
1464 numstr[1] = 0;
1465 } else {
1466 numstr[0] = i/10 + '0';
1467 numstr[1] = i%10 + '0';
1468 }
1469
1470 }
1471 }
1472 memset(mice, 0, sizeof(mice));
1473 tern_node * mice = tern_find_path(config, "bindings\0mice\0", TVAL_NODE).ptrval;
1474 if (mice) {
1475 tern_node *buttonmaps[2] = {padbuttons, mousebuttons};
1476 tern_foreach(mice, process_mouse, buttonmaps);
1477 }
1478 tern_node * speed_nodes = tern_find_path(config, "clocks\0speeds\0", TVAL_NODE).ptrval;
1479 speeds = malloc(sizeof(uint32_t));
1480 speeds[0] = 100;
1481 process_speeds(speed_nodes, NULL);
1482 for (int i = 0; i < num_speeds; i++)
1483 {
1484 if (!speeds[i]) {
1485 warning("Speed index %d was not set to a valid percentage!", i);
1486 speeds[i] = 100;
1487 }
1488 }
1489 map_all_bindings(io);
1490 }
1491
1492 void map_all_bindings(sega_io *io)
1493 {
1494 current_io = io;
1495 io_port *ports = io->ports;
1496
1497 for (int bucket = 0; bucket < 0x10000; bucket++)
1498 {
1499 if (bindings[bucket])
1500 {
1501 map_bindings(ports, bindings[bucket], 0x8000);
1502 }
1503 }
1504 for (int stick = 0; stick < MAX_JOYSTICKS; stick++)
1505 {
1506 if (joysticks[stick].buttons) {
1507 map_bindings(ports, joysticks[stick].buttons, joysticks[stick].num_buttons);
1508 }
1509 if (joysticks[stick].dpads)
1510 {
1511 for (uint32_t i = 0; i < joysticks[stick].num_dpads; i++)
1512 {
1513 map_bindings(ports, joysticks[stick].dpads[i].bindings, 4);
1514 }
1515 }
1516 for (uint32_t i = 0; i < joysticks[stick].num_axes; i++)
1517 {
1518 map_bindings(current_io->ports, &joysticks[stick].axes[i].positive, 1);
1519 map_bindings(current_io->ports, &joysticks[stick].axes[i].negative, 1);
1520 }
1521 }
1522 for (int mouse = 0; mouse < MAX_MICE; mouse++)
1523 {
1524 if (mice[mouse].bind_type >= BIND_MOUSE1 && mice[mouse].bind_type <= BIND_MOUSE8) {
1525 int num = mice[mouse].bind_type - BIND_MOUSE1;
1526 for (int j = 0; j < 3; j++)
1527 {
1528 if (ports[j].device_type == IO_MOUSE && ports[j].device.mouse.mouse_num == num)
1529 {
1530 memset(ports[j].input, 0, sizeof(ports[j].input));
1531 mice[mouse].motion_port = ports + j;
1532 break;
1533 }
1534 }
1535 }
1536 map_bindings(ports, mice[mouse].buttons, MAX_MOUSE_BUTTONS);
1537 }
1538 keyboard_port = NULL;
1539 for (int i = 0; i < 3; i++)
1540 {
1541 if (ports[i].device_type == IO_SATURN_KEYBOARD || ports[i].device_type == IO_XBAND_KEYBOARD) {
1542 keyboard_port = ports + i;
1543 break;
1544 }
1545 }
1546 //not really related to the intention of this function, but the best place to do this currently
1547 if (speeds[0] != 100) {
1548 current_system->set_speed_percent(current_system, speeds[0]);
1549 }
1550 }
1551 382
1552 #define TH 0x40 383 #define TH 0x40
1553 #define TR 0x20 384 #define TR 0x20
1554 #define TH_TIMEOUT 56000 385 #define TH_TIMEOUT 56000
1555 386
1559 port->device.mouse.tr_counter++; 390 port->device.mouse.tr_counter++;
1560 port->device.mouse.ready_cycle = CYCLE_NEVER; 391 port->device.mouse.ready_cycle = CYCLE_NEVER;
1561 if (port->device.mouse.tr_counter == 3) { 392 if (port->device.mouse.tr_counter == 3) {
1562 port->device.mouse.latched_x = port->device.mouse.cur_x; 393 port->device.mouse.latched_x = port->device.mouse.cur_x;
1563 port->device.mouse.latched_y = port->device.mouse.cur_y; 394 port->device.mouse.latched_y = port->device.mouse.cur_y;
395 /* FIXME mouse mode owned by bindings now
1564 if (current_io->mouse_mode == MOUSE_ABSOLUTE) { 396 if (current_io->mouse_mode == MOUSE_ABSOLUTE) {
1565 //avoid overflow in absolute mode 397 //avoid overflow in absolute mode
1566 int deltax = port->device.mouse.latched_x - port->device.mouse.last_read_x; 398 int deltax = port->device.mouse.latched_x - port->device.mouse.last_read_x;
1567 if (abs(deltax) > 255) { 399 if (abs(deltax) > 255) {
1568 port->device.mouse.latched_x = port->device.mouse.last_read_x + (deltax > 0 ? 255 : -255); 400 port->device.mouse.latched_x = port->device.mouse.last_read_x + (deltax > 0 ? 255 : -255);
1569 } 401 }
1570 int deltay = port->device.mouse.latched_y - port->device.mouse.last_read_y; 402 int deltay = port->device.mouse.latched_y - port->device.mouse.last_read_y;
1571 if (abs(deltay) > 255) { 403 if (abs(deltay) > 255) {
1572 port->device.mouse.latched_y = port->device.mouse.last_read_y + (deltay > 0 ? 255 : -255); 404 port->device.mouse.latched_y = port->device.mouse.last_read_y + (deltay > 0 ? 255 : -255);
1573 } 405 }
1574 } 406 }*/
1575 } 407 }
1576 } 408 }
1577 } 409 }
1578 410
1579 uint32_t last_poll_cycle; 411 uint32_t last_poll_cycle;