all repos — mgba @ e6ea94d2296eae963a48a18d009217a38d92bf9b

mGBA Game Boy Advance Emulator

src/gba/gba-input.c (view raw)

  1#include "gba-input.h"
  2
  3#include "util/configuration.h"
  4
  5#include <inttypes.h>
  6
  7#define SECTION_NAME_MAX 128
  8#define KEY_NAME_MAX 32
  9#define KEY_VALUE_MAX 16
 10
 11struct GBAInputMapImpl {
 12	int* map;
 13	uint32_t type;
 14};
 15
 16static void _loadKey(struct GBAInputMap* map, uint32_t type, const struct Configuration* config, enum GBAKey key, const char* keyName) {
 17	char sectionName[SECTION_NAME_MAX];
 18	snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
 19	sectionName[SECTION_NAME_MAX - 1] = '\0';
 20
 21	char keyKey[KEY_NAME_MAX];
 22	snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
 23	keyKey[KEY_NAME_MAX - 1] = '\0';
 24
 25	const char* value = ConfigurationGetValue(config, sectionName, keyKey);
 26	if (!value) {
 27		return;
 28	}
 29	char* end;
 30	long intValue = strtol(value, &end, 10);
 31	if (*end) {
 32		return;
 33	}
 34	GBAInputBindKey(map, type, intValue, key);
 35}
 36
 37static void _saveKey(const struct GBAInputMap* map, uint32_t type, struct Configuration* config, enum GBAKey key, const char* keyName) {
 38	char sectionName[SECTION_NAME_MAX];
 39	snprintf(sectionName, SECTION_NAME_MAX, "input.%c%c%c%c", type >> 24, type >> 16, type >> 8, type);
 40	sectionName[SECTION_NAME_MAX - 1] = '\0';
 41
 42	char keyKey[KEY_NAME_MAX];
 43	snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
 44	keyKey[KEY_NAME_MAX - 1] = '\0';
 45
 46	int value = GBAInputQueryBinding(map, type, key);
 47	char keyValue[KEY_VALUE_MAX];
 48	snprintf(keyValue, KEY_VALUE_MAX, "%" PRIi32, value);
 49
 50	ConfigurationSetValue(config, sectionName, keyKey, keyValue);
 51}
 52
 53void GBAInputMapInit(struct GBAInputMap* map) {
 54	map->maps = 0;
 55	map->numMaps = 0;
 56}
 57
 58void GBAInputMapDeinit(struct GBAInputMap* map) {
 59	size_t m;
 60	for (m = 0; m < map->numMaps; ++m) {
 61		free(map->maps[m].map);
 62	}
 63	free(map->maps);
 64	map->maps = 0;
 65	map->numMaps = 0;
 66}
 67
 68enum GBAKey GBAInputMapKey(const struct GBAInputMap* map, uint32_t type, int key) {
 69	size_t m;
 70	const struct GBAInputMapImpl* impl = 0;
 71	for (m = 0; m < map->numMaps; ++m) {
 72		if (map->maps[m].type == type) {
 73			impl = &map->maps[m];
 74			break;
 75		}
 76	}
 77	if (!impl || !impl->map) {
 78		return GBA_KEY_NONE;
 79	}
 80
 81	for (m = 0; m < GBA_KEY_MAX; ++m) {
 82		if (impl->map[m] == key) {
 83			return m;
 84		}
 85	}
 86	return GBA_KEY_NONE;
 87}
 88
 89void GBAInputBindKey(struct GBAInputMap* map, uint32_t type, int key, enum GBAKey input) {
 90	struct GBAInputMapImpl* impl = 0;
 91	if (map->numMaps == 0) {
 92		map->maps = malloc(sizeof(*map->maps));
 93		map->numMaps = 1;
 94		impl = &map->maps[0];
 95		impl->type = type;
 96		impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
 97	} else {
 98		size_t m;
 99		for (m = 0; m < map->numMaps; ++m) {
100			if (map->maps[m].type == type) {
101				impl = &map->maps[m];
102				break;
103			}
104		}
105	}
106	if (!impl) {
107		size_t m;
108		for (m = 0; m < map->numMaps; ++m) {
109			if (!map->maps[m].type) {
110				impl = &map->maps[m];
111				break;
112			}
113		}
114		if (impl) {
115			impl->type = type;
116			impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
117		} else {
118			map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2);
119			for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) {
120				map->maps[m].type = 0;
121				map->maps[m].map = 0;
122			}
123			map->numMaps *= 2;
124			impl = &map->maps[m];
125			impl->type = type;
126			impl->map = calloc(GBA_KEY_MAX, sizeof(enum GBAKey));
127		}
128	}
129	impl->map[input] = key;
130}
131
132int GBAInputQueryBinding(const struct GBAInputMap* map, uint32_t type, enum GBAKey input) {
133	if (input >= GBA_KEY_MAX) {
134		return 0;
135	}
136
137	size_t m;
138	const struct GBAInputMapImpl* impl = 0;
139	for (m = 0; m < map->numMaps; ++m) {
140		if (map->maps[m].type == type) {
141			impl = &map->maps[m];
142			break;
143		}
144	}
145	if (!impl || !impl->map) {
146		return 0;
147	}
148
149	return impl->map[input];
150}
151
152void GBAInputMapLoad(struct GBAInputMap* map, uint32_t type, const struct Configuration* config) {
153	_loadKey(map, type, config, GBA_KEY_A, "A");
154	_loadKey(map, type, config, GBA_KEY_B, "B");
155	_loadKey(map, type, config, GBA_KEY_L, "L");
156	_loadKey(map, type, config, GBA_KEY_R, "R");
157	_loadKey(map, type, config, GBA_KEY_START, "Start");
158	_loadKey(map, type, config, GBA_KEY_SELECT, "Select");
159	_loadKey(map, type, config, GBA_KEY_UP, "Up");
160	_loadKey(map, type, config, GBA_KEY_DOWN, "Down");
161	_loadKey(map, type, config, GBA_KEY_LEFT, "Left");
162	_loadKey(map, type, config, GBA_KEY_RIGHT, "Right");
163}
164
165void GBAInputMapSave(const struct GBAInputMap* map, uint32_t type, struct Configuration* config) {
166	_saveKey(map, type, config, GBA_KEY_A, "A");
167	_saveKey(map, type, config, GBA_KEY_B, "B");
168	_saveKey(map, type, config, GBA_KEY_L, "L");
169	_saveKey(map, type, config, GBA_KEY_R, "R");
170	_saveKey(map, type, config, GBA_KEY_START, "Start");
171	_saveKey(map, type, config, GBA_KEY_SELECT, "Select");
172	_saveKey(map, type, config, GBA_KEY_UP, "Up");
173	_saveKey(map, type, config, GBA_KEY_DOWN, "Down");
174	_saveKey(map, type, config, GBA_KEY_LEFT, "Left");
175	_saveKey(map, type, config, GBA_KEY_RIGHT, "Right");
176}