all repos — mgba @ 9c92a29b28d1f81224ba28d5fc83a9481eccd5eb

mGBA Game Boy Advance Emulator

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

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