Mercurial > repos > blastem
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; |