RetroArch/runahead/dirty_input.c

177 lines
4.4 KiB
C
Raw Normal View History

2018-03-29 13:49:39 +00:00
#include <stdlib.h>
#include <boolean.h>
#include "../core.h"
#include "../dynamic.h"
2018-03-28 19:22:07 +00:00
#include "mylist.h"
#include "mem_util.h"
2018-04-08 18:26:47 +00:00
#include "dirty_input.h"
2018-03-28 19:22:07 +00:00
bool input_is_dirty = false;
static MyList *input_state_list = NULL;
2018-03-28 19:22:07 +00:00
typedef struct InputListElement_t
{
unsigned port;
unsigned device;
unsigned index;
int16_t state[36];
} InputListElement;
2018-03-29 16:10:12 +00:00
extern struct retro_core_t current_core;
2018-03-28 19:22:07 +00:00
extern struct retro_callbacks retro_ctx;
typedef bool(*LoadStateFunction)(const void*, size_t);
static function_t retro_reset_callback_original = NULL;
static LoadStateFunction retro_unserialize_callback_original = NULL;
static retro_input_state_t input_state_callback_original;
static void reset_hook(void);
static bool unserialze_hook(const void *buf, size_t size);
static void* InputListElementConstructor(void)
{
const int size = sizeof(InputListElement);
void *ptr = calloc(1, size);
2018-03-28 19:22:07 +00:00
return ptr;
}
static void input_state_destroy(void)
2018-03-28 19:22:07 +00:00
{
mylist_destroy(&input_state_list);
2018-03-28 19:22:07 +00:00
}
static void input_state_set_last(unsigned port, unsigned device,
unsigned index, unsigned id, int16_t value)
2018-03-28 19:22:07 +00:00
{
unsigned i;
InputListElement *element = NULL;
2018-03-28 19:22:07 +00:00
if (!input_state_list)
mylist_create(&input_state_list, 16,
InputListElementConstructor, free);
2018-03-28 19:22:07 +00:00
/* find list item */
2018-04-08 21:13:20 +00:00
for (i = 0; i < (unsigned)input_state_list->size; i++)
2018-03-28 19:22:07 +00:00
{
element = (InputListElement*)input_state_list->data[i];
if ( element->port == port
&& element->device == device && element->index == index)
2018-03-28 19:22:07 +00:00
{
element->state[id] = value;
return;
}
}
element = (InputListElement*)
mylist_add_element(input_state_list);
element->port = port;
element->device = device;
element->index = index;
2018-03-28 19:22:07 +00:00
element->state[id] = value;
}
static int16_t input_state_get_last(unsigned port,
unsigned device, unsigned index, unsigned id)
2018-03-28 19:22:07 +00:00
{
unsigned i;
if (!input_state_list)
2018-03-28 19:22:07 +00:00
return 0;
2018-03-28 19:22:07 +00:00
/* find list item */
2018-04-08 21:13:20 +00:00
for (i = 0; i < (unsigned)input_state_list->size; i++)
2018-03-28 19:22:07 +00:00
{
InputListElement *element =
(InputListElement*)input_state_list->data[i];
if ( (element->port == port) &&
(element->device == device) &&
(element->index == index)
)
2018-03-28 19:22:07 +00:00
return element->state[id];
}
return 0;
}
static int16_t input_state_with_logging(unsigned port,
unsigned device, unsigned index, unsigned id)
2018-03-28 19:22:07 +00:00
{
if (input_state_callback_original)
2018-03-28 19:22:07 +00:00
{
int16_t result = input_state_callback_original(
port, device, index, id);
int16_t last_input = input_state_get_last(port, device, index, id);
if (result != last_input)
2018-03-28 19:22:07 +00:00
input_is_dirty = true;
input_state_set_last(port, device, index, id, result);
2018-03-28 19:22:07 +00:00
return result;
}
return 0;
}
static void reset_hook(void)
{
input_is_dirty = true;
if (retro_reset_callback_original)
retro_reset_callback_original();
}
static bool unserialze_hook(const void *buf, size_t size)
{
input_is_dirty = true;
if (retro_unserialize_callback_original)
return retro_unserialize_callback_original(buf, size);
return false;
}
void add_input_state_hook(void)
{
if (!input_state_callback_original)
2018-03-28 19:22:07 +00:00
{
input_state_callback_original = retro_ctx.state_cb;
retro_ctx.state_cb = input_state_with_logging;
2018-03-28 19:22:07 +00:00
current_core.retro_set_input_state(retro_ctx.state_cb);
}
if (!retro_reset_callback_original)
2018-03-28 19:22:07 +00:00
{
retro_reset_callback_original = current_core.retro_reset;
current_core.retro_reset = reset_hook;
2018-03-28 19:22:07 +00:00
}
if (!retro_unserialize_callback_original)
2018-03-28 19:22:07 +00:00
{
retro_unserialize_callback_original = current_core.retro_unserialize;
current_core.retro_unserialize = unserialze_hook;
2018-03-28 19:22:07 +00:00
}
}
void remove_input_state_hook(void)
{
if (input_state_callback_original)
2018-03-28 19:22:07 +00:00
{
retro_ctx.state_cb = input_state_callback_original;
2018-03-28 19:22:07 +00:00
current_core.retro_set_input_state(retro_ctx.state_cb);
input_state_callback_original = NULL;
input_state_destroy();
2018-03-28 19:22:07 +00:00
}
if (retro_reset_callback_original)
2018-03-28 19:22:07 +00:00
{
current_core.retro_reset = retro_reset_callback_original;
2018-03-28 19:22:07 +00:00
retro_reset_callback_original = NULL;
}
if (retro_unserialize_callback_original)
2018-03-28 19:22:07 +00:00
{
current_core.retro_unserialize = retro_unserialize_callback_original;
2018-03-28 19:22:07 +00:00
retro_unserialize_callback_original = NULL;
}
}