forked from libretro/RetroArch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdirty_input.c
183 lines (153 loc) · 4.64 KB
/
dirty_input.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
#include <stdlib.h>
#include <boolean.h>
#include "../core.h"
#include "../dynamic.h"
#include "mylist.h"
#include "mem_util.h"
#include "dirty_input.h"
bool input_is_dirty = false;
static MyList *input_state_list = NULL;
typedef struct InputListElement_t
{
unsigned port;
unsigned device;
unsigned index;
int16_t state[36];
} InputListElement;
extern struct retro_core_t current_core;
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);
return ptr;
}
static void input_state_destroy(void)
{
mylist_destroy(&input_state_list);
}
static void input_state_set_last(unsigned port, unsigned device,
unsigned index, unsigned id, int16_t value)
{
unsigned i;
InputListElement *element = NULL;
const unsigned MAX_ID = sizeof(element->state) / sizeof(int16_t);
if (!input_state_list)
mylist_create(&input_state_list, 16,
InputListElementConstructor, free);
/* find list item */
for (i = 0; i < (unsigned)input_state_list->size; i++)
{
element = (InputListElement*)input_state_list->data[i];
if ( (element->port == port) &&
(element->device == device) &&
(element->index == index) &&
(id < MAX_ID)
)
{
element->state[id] = value;
return;
}
}
element = (InputListElement*)
mylist_add_element(input_state_list);
element->port = port;
element->device = device;
element->index = index;
if (id < MAX_ID)
element->state[id] = value;
}
static int16_t input_state_get_last(unsigned port,
unsigned device, unsigned index, unsigned id)
{
unsigned i;
if (!input_state_list)
return 0;
/* find list item */
for (i = 0; i < (unsigned)input_state_list->size; i++)
{
InputListElement *element =
(InputListElement*)input_state_list->data[i];
const unsigned MAX_ID = sizeof(element->state) / sizeof(int16_t);
if ( (element->port == port) &&
(element->device == device) &&
(element->index == index) &&
(id < MAX_ID)
)
return element->state[id];
}
return 0;
}
static int16_t input_state_with_logging(unsigned port,
unsigned device, unsigned index, unsigned id)
{
if (input_state_callback_original)
{
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)
input_is_dirty = true;
input_state_set_last(port, device, index, id, result);
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)
{
input_state_callback_original = retro_ctx.state_cb;
retro_ctx.state_cb = input_state_with_logging;
current_core.retro_set_input_state(retro_ctx.state_cb);
}
if (!retro_reset_callback_original)
{
retro_reset_callback_original = current_core.retro_reset;
current_core.retro_reset = reset_hook;
}
if (!retro_unserialize_callback_original)
{
retro_unserialize_callback_original = current_core.retro_unserialize;
current_core.retro_unserialize = unserialze_hook;
}
}
void remove_input_state_hook(void)
{
if (input_state_callback_original)
{
retro_ctx.state_cb = input_state_callback_original;
current_core.retro_set_input_state(retro_ctx.state_cb);
input_state_callback_original = NULL;
input_state_destroy();
}
if (retro_reset_callback_original)
{
current_core.retro_reset = retro_reset_callback_original;
retro_reset_callback_original = NULL;
}
if (retro_unserialize_callback_original)
{
current_core.retro_unserialize = retro_unserialize_callback_original;
retro_unserialize_callback_original = NULL;
}
}