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