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;