Mercurial > repos > blastem
comparison io.c @ 483:3e1573fa22cf
Implement turbo/slow motion feature that overclocks or underclocks the entire system at the push of a button
author | Mike Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 01 Oct 2013 23:51:16 -0700 |
parents | 140af5509ce7 |
children | 36c080ece4ed |
comparison
equal
deleted
inserted
replaced
482:4b24260125f3 | 483:3e1573fa22cf |
---|---|
1 /* | 1 /* |
2 Copyright 2013 Michael Pavone | 2 Copyright 2013 Michael Pavone |
3 This file is part of BlastEm. | 3 This file is part of BlastEm. |
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. | 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. |
5 */ | 5 */ |
6 #include "io.h" | 6 #include "io.h" |
7 #include "blastem.h" | 7 #include "blastem.h" |
8 #include "render.h" | 8 #include "render.h" |
16 | 16 |
17 typedef enum { | 17 typedef enum { |
18 UI_DEBUG_MODE_INC, | 18 UI_DEBUG_MODE_INC, |
19 UI_DEBUG_PAL_INC, | 19 UI_DEBUG_PAL_INC, |
20 UI_ENTER_DEBUGGER, | 20 UI_ENTER_DEBUGGER, |
21 UI_SAVE_STATE, | 21 UI_SAVE_STATE, |
22 UI_SET_SPEED, | |
23 UI_NEXT_SPEED, | |
24 UI_PREV_SPEED, | |
22 UI_EXIT | 25 UI_EXIT |
23 } ui_action; | 26 } ui_action; |
24 | 27 |
25 typedef struct { | 28 typedef struct { |
26 uint8_t bind_type; | 29 uint8_t bind_type; |
137 } | 140 } |
138 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; | 141 uint8_t bind_type = gamepadnum - 1 + BIND_GAMEPAD1; |
139 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); | 142 bind_dpad(joystick, dpad, direction, bind_type, button >> 12, button >> 8 & 0xF, button & 0xFF); |
140 } | 143 } |
141 | 144 |
142 void bind_ui(int keycode, ui_action action) | 145 void bind_ui(int keycode, ui_action action, uint8_t param) |
143 { | 146 { |
144 bind_key(keycode, BIND_UI, action, 0, 0); | 147 bind_key(keycode, BIND_UI, action, 0, param); |
145 } | 148 } |
146 | 149 |
147 void handle_binding_down(keybinding * binding) | 150 void handle_binding_down(keybinding * binding) |
148 { | 151 { |
149 switch(binding->bind_type) | 152 switch(binding->bind_type) |
180 handle_binding_down(binding); | 183 handle_binding_down(binding); |
181 } | 184 } |
182 | 185 |
183 uint8_t ui_debug_mode = 0; | 186 uint8_t ui_debug_mode = 0; |
184 uint8_t ui_debug_pal = 0; | 187 uint8_t ui_debug_pal = 0; |
188 | |
189 int current_speed = 0; | |
190 int num_speeds = 1; | |
191 uint32_t * speeds = NULL; | |
185 | 192 |
186 void handle_binding_up(keybinding * binding) | 193 void handle_binding_up(keybinding * binding) |
187 { | 194 { |
188 switch(binding->bind_type) | 195 switch(binding->bind_type) |
189 { | 196 { |
216 case UI_ENTER_DEBUGGER: | 223 case UI_ENTER_DEBUGGER: |
217 break_on_sync = 1; | 224 break_on_sync = 1; |
218 break; | 225 break; |
219 case UI_SAVE_STATE: | 226 case UI_SAVE_STATE: |
220 save_state = 1; | 227 save_state = 1; |
228 break; | |
229 case UI_NEXT_SPEED: | |
230 current_speed++; | |
231 if (current_speed >= num_speeds) { | |
232 current_speed = 0; | |
233 } | |
234 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
235 set_speed_percent(genesis, speeds[current_speed]); | |
236 break; | |
237 case UI_PREV_SPEED: | |
238 current_speed--; | |
239 if (current_speed < 0) { | |
240 current_speed = num_speeds - 1; | |
241 } | |
242 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
243 set_speed_percent(genesis, speeds[current_speed]); | |
244 break; | |
245 case UI_SET_SPEED: | |
246 if (binding->value < num_speeds) { | |
247 current_speed = binding->value; | |
248 printf("Setting speed to %d: %d\n", current_speed, speeds[current_speed]); | |
249 set_speed_percent(genesis, speeds[current_speed]); | |
250 } else { | |
251 printf("Setting speed to %d\n", speeds[current_speed]); | |
252 set_speed_percent(genesis, binding->value); | |
253 } | |
221 break; | 254 break; |
222 case UI_EXIT: | 255 case UI_EXIT: |
223 exit(0); | 256 exit(0); |
224 } | 257 } |
225 break; | 258 break; |
284 } | 317 } |
285 } else { | 318 } else { |
286 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); | 319 fprintf(stderr, "Gamepad mapping string '%s' refers to an invalid gamepad number %c\n", target, target[gpadslen]); |
287 } | 320 } |
288 } else if(!memcmp(target, "ui.", strlen("ui."))) { | 321 } else if(!memcmp(target, "ui.", strlen("ui."))) { |
322 *padbutton_out = 0; | |
289 if (!strcmp(target + 3, "vdp_debug_mode")) { | 323 if (!strcmp(target + 3, "vdp_debug_mode")) { |
290 *ui_out = UI_DEBUG_MODE_INC; | 324 *ui_out = UI_DEBUG_MODE_INC; |
291 } else if(!strcmp(target + 3, "vdp_debug_pal")) { | 325 } else if(!strcmp(target + 3, "vdp_debug_pal")) { |
292 *ui_out = UI_DEBUG_PAL_INC; | 326 *ui_out = UI_DEBUG_PAL_INC; |
293 } else if(!strcmp(target + 3, "enter_debugger")) { | 327 } else if(!strcmp(target + 3, "enter_debugger")) { |
294 *ui_out = UI_ENTER_DEBUGGER; | 328 *ui_out = UI_ENTER_DEBUGGER; |
295 } else if(!strcmp(target + 3, "save_state")) { | 329 } else if(!strcmp(target + 3, "save_state")) { |
296 *ui_out = UI_SAVE_STATE; | 330 *ui_out = UI_SAVE_STATE; |
331 } else if(!memcmp(target + 3, "set_speed.", strlen("set_speed."))) { | |
332 *ui_out = UI_SET_SPEED; | |
333 *padbutton_out = atoi(target + 3 + strlen("set_speed.")); | |
334 } else if(!strcmp(target + 3, "next_speed")) { | |
335 *ui_out = UI_NEXT_SPEED; | |
336 } else if(!strcmp(target + 3, "prev_speed")) { | |
337 *ui_out = UI_PREV_SPEED; | |
297 } else if(!strcmp(target + 3, "exit")) { | 338 } else if(!strcmp(target + 3, "exit")) { |
298 *ui_out = UI_EXIT; | 339 *ui_out = UI_EXIT; |
299 } else { | 340 } else { |
300 fprintf(stderr, "Unreconized UI binding type %s\n", target); | 341 fprintf(stderr, "Unreconized UI binding type %s\n", target); |
301 return 0; | 342 return 0; |
307 return 0; | 348 return 0; |
308 } | 349 } |
309 | 350 |
310 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix) | 351 void process_keys(tern_node * cur, tern_node * special, tern_node * padbuttons, char * prefix) |
311 { | 352 { |
312 char * curstr; | 353 char * curstr = NULL; |
313 int len; | 354 int len; |
314 if (!cur) { | 355 if (!cur) { |
315 return; | 356 return; |
316 } | 357 } |
317 char onec[2]; | 358 char onec[2]; |
322 } else { | 363 } else { |
323 curstr = onec; | 364 curstr = onec; |
324 len = 0; | 365 len = 0; |
325 } | 366 } |
326 curstr[len] = cur->el; | 367 curstr[len] = cur->el; |
368 curstr[len+1] = 0; | |
327 if (cur->el) { | 369 if (cur->el) { |
328 curstr[len+1] = 0; | |
329 process_keys(cur->straight.next, special, padbuttons, curstr); | 370 process_keys(cur->straight.next, special, padbuttons, curstr); |
330 } else { | 371 } else { |
331 int keycode = tern_find_int(special, curstr, 0); | 372 int keycode = tern_find_int(special, curstr, 0); |
332 if (!keycode) { | 373 if (!keycode) { |
333 keycode = curstr[0]; | 374 keycode = curstr[0]; |
339 int ui_func, padnum, button; | 380 int ui_func, padnum, button; |
340 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); | 381 int bindtype = parse_binding_target(target, padbuttons, &ui_func, &padnum, &button); |
341 if (bindtype == 1) { | 382 if (bindtype == 1) { |
342 bind_gamepad(keycode, padnum, button); | 383 bind_gamepad(keycode, padnum, button); |
343 } else if(bindtype == 2) { | 384 } else if(bindtype == 2) { |
344 bind_ui(keycode, ui_func); | 385 bind_ui(keycode, ui_func, button); |
345 } | 386 } |
346 } | 387 } |
347 process_keys(cur->left, special, padbuttons, prefix); | 388 process_keys(cur->left, special, padbuttons, prefix); |
348 process_keys(cur->right, special, padbuttons, prefix); | 389 process_keys(cur->right, special, padbuttons, prefix); |
390 if (curstr && len) { | |
391 free(curstr); | |
392 } | |
393 } | |
394 | |
395 void process_speeds(tern_node * cur, char * prefix) | |
396 { | |
397 char * curstr = NULL; | |
398 int len; | |
399 if (!cur) { | |
400 return; | |
401 } | |
402 char onec[2]; | |
403 if (prefix) { | |
404 len = strlen(prefix); | |
405 curstr = malloc(len + 2); | |
406 memcpy(curstr, prefix, len); | |
407 } else { | |
408 curstr = onec; | |
409 len = 0; | |
410 } | |
411 curstr[len] = cur->el; | |
412 curstr[len+1] = 0; | |
413 if (cur->el) { | |
414 process_speeds(cur->straight.next, curstr); | |
415 } else { | |
416 int speed_index = atoi(curstr); | |
417 if (speed_index < 1) { | |
418 if (!strcmp(curstr, "0")) { | |
419 fputs("Speed index 0 cannot be set to a custom value\n", stderr); | |
420 } else { | |
421 fprintf(stderr, "%s is not a valid speed index", curstr); | |
422 } | |
423 } else { | |
424 if (speed_index >= num_speeds) { | |
425 speeds = realloc(speeds, sizeof(uint32_t) * (speed_index+1)); | |
426 for(; num_speeds < speed_index + 1; num_speeds++) { | |
427 speeds[num_speeds] = 0; | |
428 } | |
429 } | |
430 speeds[speed_index] = atoi(cur->straight.value.ptrval); | |
431 } | |
432 } | |
433 process_speeds(cur->left, prefix); | |
434 process_speeds(cur->right, prefix); | |
435 if (curstr && len) { | |
436 free(curstr); | |
437 } | |
349 } | 438 } |
350 | 439 |
351 void set_keybindings() | 440 void set_keybindings() |
352 { | 441 { |
353 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); | 442 tern_node * special = tern_insert_int(NULL, "up", RENDERKEY_UP); |
423 //TODO: Handle UI bindings | 512 //TODO: Handle UI bindings |
424 } | 513 } |
425 } | 514 } |
426 } | 515 } |
427 } | 516 } |
517 tern_node * speed_nodes = tern_find_prefix(config, "clocksspeeds"); | |
518 speeds = malloc(sizeof(uint32_t)); | |
519 speeds[0] = 100; | |
520 process_speeds(speed_nodes, NULL); | |
521 for (int i = 0; i < num_speeds; i++) { | |
522 if (!speeds[i]) { | |
523 fprintf(stderr, "Speed index %d was not set to a valid percentage!", i); | |
524 speeds[i] = 100; | |
525 } | |
526 } | |
428 } | 527 } |
429 | 528 |
430 #define TH 0x40 | 529 #define TH 0x40 |
431 #define TH_TIMEOUT 8000 | 530 #define TH_TIMEOUT 8000 |
432 | 531 |