src/core/input.c (view raw)
1/* Copyright (c) 2013-2016 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 <mgba/core/input.h>
7
8#include <mgba-util/configuration.h>
9#include <mgba-util/table.h>
10#include <mgba-util/vector.h>
11
12#include <inttypes.h>
13
14#define SECTION_NAME_MAX 128
15#define KEY_NAME_MAX 32
16#define KEY_VALUE_MAX 16
17#define AXIS_INFO_MAX 12
18
19DECLARE_VECTOR(mInputHatList, struct mInputHatBindings);
20DEFINE_VECTOR(mInputHatList, struct mInputHatBindings);
21
22struct mInputMapImpl {
23 int* map;
24 uint32_t type;
25
26 struct Table axes;
27 struct mInputHatList hats;
28};
29
30struct mInputAxisSave {
31 struct Configuration* config;
32 const char* sectionName;
33 const struct mInputPlatformInfo* info;
34};
35
36struct mInputAxisEnumerate {
37 void (*handler)(int axis, const struct mInputAxis* description, void* user);
38 void* user;
39};
40
41static void _makeSectionName(const char* platform, char* sectionName, size_t len, uint32_t type) {
42 snprintf(sectionName, len, "%s.input.%c%c%c%c", platform, type >> 24, type >> 16, type >> 8, type);
43 sectionName[len - 1] = '\0';
44}
45
46static bool _getIntValue(const struct Configuration* config, const char* section, const char* key, int* value) {
47 const char* strValue = ConfigurationGetValue(config, section, key);
48 if (!strValue) {
49 return false;
50 }
51 char* end;
52 long intValue = strtol(strValue, &end, 10);
53 if (*end) {
54 return false;
55 }
56 *value = intValue;
57 return true;
58}
59
60static struct mInputMapImpl* _lookupMap(struct mInputMap* map, uint32_t type) {
61 size_t m;
62 struct mInputMapImpl* impl = 0;
63 for (m = 0; m < map->numMaps; ++m) {
64 if (map->maps[m].type == type) {
65 impl = &map->maps[m];
66 break;
67 }
68 }
69 return impl;
70}
71
72static const struct mInputMapImpl* _lookupMapConst(const struct mInputMap* map, uint32_t type) {
73 size_t m;
74 const struct mInputMapImpl* impl = 0;
75 for (m = 0; m < map->numMaps; ++m) {
76 if (map->maps[m].type == type) {
77 impl = &map->maps[m];
78 break;
79 }
80 }
81 return impl;
82}
83
84static struct mInputMapImpl* _guaranteeMap(struct mInputMap* map, uint32_t type) {
85 struct mInputMapImpl* impl = 0;
86 if (map->numMaps == 0) {
87 map->maps = malloc(sizeof(*map->maps));
88 map->numMaps = 1;
89 impl = &map->maps[0];
90 impl->type = type;
91 impl->map = calloc(map->info->nKeys, sizeof(int));
92 size_t i;
93 for (i = 0; i < map->info->nKeys; ++i) {
94 impl->map[i] = -1;
95 }
96 TableInit(&impl->axes, 2, free);
97 mInputHatListInit(&impl->hats, 1);
98 } else {
99 impl = _lookupMap(map, type);
100 }
101 if (!impl) {
102 size_t m;
103 for (m = 0; m < map->numMaps; ++m) {
104 if (!map->maps[m].type) {
105 impl = &map->maps[m];
106 break;
107 }
108 }
109 if (impl) {
110 impl->type = type;
111 impl->map = calloc(map->info->nKeys, sizeof(int));
112 size_t i;
113 for (i = 0; i < map->info->nKeys; ++i) {
114 impl->map[i] = -1;
115 }
116 } else {
117 map->maps = realloc(map->maps, sizeof(*map->maps) * map->numMaps * 2);
118 for (m = map->numMaps * 2 - 1; m > map->numMaps; --m) {
119 map->maps[m].type = 0;
120 map->maps[m].map = 0;
121 }
122 map->numMaps *= 2;
123 impl = &map->maps[m];
124 impl->type = type;
125 impl->map = calloc(map->info->nKeys, sizeof(int));
126 size_t i;
127 for (i = 0; i < map->info->nKeys; ++i) {
128 impl->map[i] = -1;
129 }
130 }
131 TableInit(&impl->axes, 2, free);
132 mInputHatListInit(&impl->hats, 1);
133 }
134 return impl;
135}
136
137static void _loadKey(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int key, const char* keyName) {
138 char keyKey[KEY_NAME_MAX];
139 snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
140 keyKey[KEY_NAME_MAX - 1] = '\0';
141
142 int value;
143 if (!_getIntValue(config, sectionName, keyKey, &value)) {
144 return;
145 }
146 mInputBindKey(map, type, value, key);
147}
148
149static void _loadAxis(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int direction, const char* axisName) {
150 char axisKey[KEY_NAME_MAX];
151 snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName);
152 axisKey[KEY_NAME_MAX - 1] = '\0';
153 int value;
154 if (!_getIntValue(config, sectionName, axisKey, &value)) {
155 return;
156 }
157
158 snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName);
159 axisKey[KEY_NAME_MAX - 1] = '\0';
160 int axis;
161 const char* strValue = ConfigurationGetValue(config, sectionName, axisKey);
162 if (!strValue || !strValue[0]) {
163 return;
164 }
165 char* end;
166 axis = strtoul(&strValue[1], &end, 10);
167 if (*end) {
168 return;
169 }
170
171 const struct mInputAxis* description = mInputQueryAxis(map, type, axis);
172 struct mInputAxis realDescription = { -1, -1, 0, 0 };
173 if (description) {
174 realDescription = *description;
175 }
176 if (strValue[0] == '+') {
177 realDescription.deadHigh = value;
178 realDescription.highDirection = direction;
179 } else if (strValue[0] == '-') {
180 realDescription.deadLow = value;
181 realDescription.lowDirection = direction;
182 }
183 mInputBindAxis(map, type, axis, &realDescription);
184}
185
186static bool _loadHat(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config, int hatId) {
187 char hatKey[KEY_NAME_MAX];
188
189 struct mInputHatBindings hatBindings = { -1, -1, -1, -1 };
190
191 bool found = false;
192 snprintf(hatKey, KEY_NAME_MAX, "hat%iUp", hatId);
193 found = _getIntValue(config, sectionName, hatKey, &hatBindings.up) || found;
194 snprintf(hatKey, KEY_NAME_MAX, "hat%iRight", hatId);
195 found = _getIntValue(config, sectionName, hatKey, &hatBindings.right) || found;
196 snprintf(hatKey, KEY_NAME_MAX, "hat%iDown", hatId);
197 found = _getIntValue(config, sectionName, hatKey, &hatBindings.down) || found;
198 snprintf(hatKey, KEY_NAME_MAX, "hat%iLeft", hatId);
199 found = _getIntValue(config, sectionName, hatKey, &hatBindings.left) || found;
200
201 if (!found) {
202 return false;
203 }
204 mInputBindHat(map, type, hatId, &hatBindings);
205 return true;
206}
207
208static void _saveKey(const struct mInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config, int key, const char* keyName) {
209 char keyKey[KEY_NAME_MAX];
210 snprintf(keyKey, KEY_NAME_MAX, "key%s", keyName);
211 keyKey[KEY_NAME_MAX - 1] = '\0';
212
213 int value = mInputQueryBinding(map, type, key);
214 char keyValue[KEY_VALUE_MAX];
215 snprintf(keyValue, KEY_VALUE_MAX, "%" PRIi32, value);
216
217 ConfigurationSetValue(config, sectionName, keyKey, keyValue);
218}
219
220static void _clearAxis(const char* sectionName, struct Configuration* config, const char* axisName) {
221 char axisKey[KEY_NAME_MAX];
222 snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", axisName);
223 axisKey[KEY_NAME_MAX - 1] = '\0';
224 ConfigurationClearValue(config, sectionName, axisKey);
225
226 snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", axisName);
227 axisKey[KEY_NAME_MAX - 1] = '\0';
228 ConfigurationClearValue(config, sectionName, axisKey);
229}
230
231static void _saveAxis(uint32_t axis, void* dp, void* up) {
232 struct mInputAxisSave* user = up;
233 const struct mInputAxis* description = dp;
234
235 const char* sectionName = user->sectionName;
236
237 if (description->lowDirection != -1) {
238 const char* keyName = user->info->keyId[description->lowDirection];
239
240 char axisKey[KEY_NAME_MAX];
241 snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName);
242 axisKey[KEY_NAME_MAX - 1] = '\0';
243 ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadLow);
244
245 snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName);
246 axisKey[KEY_NAME_MAX - 1] = '\0';
247
248 char axisInfo[AXIS_INFO_MAX];
249 snprintf(axisInfo, AXIS_INFO_MAX, "-%u", axis);
250 axisInfo[AXIS_INFO_MAX - 1] = '\0';
251 ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo);
252 }
253 if (description->highDirection != -1) {
254 const char* keyName = user->info->keyId[description->highDirection];
255
256 char axisKey[KEY_NAME_MAX];
257 snprintf(axisKey, KEY_NAME_MAX, "axis%sValue", keyName);
258 axisKey[KEY_NAME_MAX - 1] = '\0';
259 ConfigurationSetIntValue(user->config, sectionName, axisKey, description->deadHigh);
260
261 snprintf(axisKey, KEY_NAME_MAX, "axis%sAxis", keyName);
262 axisKey[KEY_NAME_MAX - 1] = '\0';
263
264 char axisInfo[AXIS_INFO_MAX];
265 snprintf(axisInfo, AXIS_INFO_MAX, "+%u", axis);
266 axisInfo[AXIS_INFO_MAX - 1] = '\0';
267 ConfigurationSetValue(user->config, sectionName, axisKey, axisInfo);
268 }
269}
270
271static void _saveHat(const char* sectionName, struct Configuration* config, int hatId, const struct mInputHatBindings* hat) {
272 char hatKey[KEY_NAME_MAX];
273 char hatValue[KEY_VALUE_MAX];
274
275 snprintf(hatKey, KEY_NAME_MAX, "hat%iUp", hatId);
276 snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->up);
277 ConfigurationSetValue(config, sectionName, hatKey, hatValue);
278 snprintf(hatKey, KEY_NAME_MAX, "hat%iRight", hatId);
279 snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->right);
280 ConfigurationSetValue(config, sectionName, hatKey, hatValue);
281 snprintf(hatKey, KEY_NAME_MAX, "hat%iDown", hatId);
282 snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->down);
283 ConfigurationSetValue(config, sectionName, hatKey, hatValue);
284 snprintf(hatKey, KEY_NAME_MAX, "hat%iLeft", hatId);
285 snprintf(hatValue, KEY_VALUE_MAX, "%i", hat->left);
286 ConfigurationSetValue(config, sectionName, hatKey, hatValue);
287}
288
289void _enumerateAxis(uint32_t axis, void* dp, void* ep) {
290 struct mInputAxisEnumerate* enumUser = ep;
291 const struct mInputAxis* description = dp;
292 enumUser->handler(axis, description, enumUser->user);
293}
294
295void _unbindAxis(uint32_t axis, void* dp, void* user) {
296 UNUSED(axis);
297 int* key = user;
298 struct mInputAxis* description = dp;
299 if (description->highDirection == *key) {
300 description->highDirection = -1;
301 }
302 if (description->lowDirection == *key) {
303 description->lowDirection = -1;
304 }
305}
306
307static bool _loadAll(struct mInputMap* map, uint32_t type, const char* sectionName, const struct Configuration* config) {
308 if (!ConfigurationHasSection(config, sectionName)) {
309 return false;
310 }
311 size_t i;
312 for (i = 0; i < map->info->nKeys; ++i) {
313 _loadKey(map, type, sectionName, config, i, map->info->keyId[i]);
314 _loadAxis(map, type, sectionName, config, i, map->info->keyId[i]);
315 }
316 i = 0;
317 while (_loadHat(map, type, sectionName, config, i)) {
318 ++i;
319 }
320 return true;
321}
322
323static void _saveAll(const struct mInputMap* map, uint32_t type, const char* sectionName, struct Configuration* config) {
324 size_t i;
325 for (i = 0; i < map->info->nKeys; ++i) {
326 if (!map->info->keyId[i]) {
327 continue;
328 }
329 _saveKey(map, type, sectionName, config, i, map->info->keyId[i]);
330 _clearAxis(sectionName, config, map->info->keyId[i]);
331 }
332
333 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
334 if (!impl) {
335 return;
336 }
337 struct mInputAxisSave save = {
338 config,
339 sectionName,
340 map->info
341 };
342 TableEnumerate(&impl->axes, _saveAxis, &save);
343
344 for (i = 0; i < mInputHatListSize(&impl->hats); ++i) {
345 const struct mInputHatBindings* hat = mInputHatListGetConstPointer(&impl->hats, i);
346 _saveHat(sectionName, config, i, hat);
347 }
348}
349
350void mInputMapInit(struct mInputMap* map, const struct mInputPlatformInfo* info) {
351 map->maps = 0;
352 map->numMaps = 0;
353 map->info = info;
354}
355
356void mInputMapDeinit(struct mInputMap* map) {
357 size_t m;
358 for (m = 0; m < map->numMaps; ++m) {
359 if (map->maps[m].type) {
360 free(map->maps[m].map);
361 TableDeinit(&map->maps[m].axes);
362 mInputHatListDeinit(&map->maps[m].hats);
363 }
364 }
365 free(map->maps);
366 map->maps = 0;
367 map->numMaps = 0;
368}
369
370int mInputMapKey(const struct mInputMap* map, uint32_t type, int key) {
371 size_t m;
372 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
373 if (!impl || !impl->map) {
374 return -1;
375 }
376
377 for (m = 0; m < map->info->nKeys; ++m) {
378 if (impl->map[m] == key) {
379 return m;
380 }
381 }
382 return -1;
383}
384
385int mInputMapKeyBits(const struct mInputMap* map, uint32_t type, uint32_t bits, unsigned offset) {
386 int keys = 0;
387 for (; bits; bits >>= 1, ++offset) {
388 if (bits & 1) {
389 int key = mInputMapKey(map, type, offset);
390 if (key == -1) {
391 continue;
392 }
393 keys |= 1 << key;
394 }
395 }
396 return keys;
397}
398
399void mInputBindKey(struct mInputMap* map, uint32_t type, int key, int input) {
400 struct mInputMapImpl* impl = _guaranteeMap(map, type);
401 if (input < 0 || (size_t) input >= map->info->nKeys) {
402 return;
403 }
404 mInputUnbindKey(map, type, input);
405 impl->map[input] = key;
406}
407
408void mInputUnbindKey(struct mInputMap* map, uint32_t type, int input) {
409 struct mInputMapImpl* impl = _lookupMap(map, type);
410 if (input < 0 || (size_t) input >= map->info->nKeys) {
411 return;
412 }
413 if (impl) {
414 impl->map[input] = -1;
415 }
416}
417
418int mInputQueryBinding(const struct mInputMap* map, uint32_t type, int input) {
419 if (input < 0 || (size_t) input >= map->info->nKeys) {
420 return -1;
421 }
422
423 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
424 if (!impl || !impl->map) {
425 return -1;
426 }
427
428 return impl->map[input];
429}
430
431int mInputMapAxis(const struct mInputMap* map, uint32_t type, int axis, int value) {
432 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
433 if (!impl) {
434 return -1;
435 }
436 struct mInputAxis* description = TableLookup(&impl->axes, axis);
437 if (!description) {
438 return -1;
439 }
440 int state = 0;
441 if (value < description->deadLow) {
442 state = -1;
443 } else if (value > description->deadHigh) {
444 state = 1;
445 }
446 if (state > 0) {
447 return description->highDirection;
448 }
449 if (state < 0) {
450 return description->lowDirection;
451 }
452 return -1;
453}
454
455int mInputClearAxis(const struct mInputMap* map, uint32_t type, int axis, int keys) {
456 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
457 if (!impl) {
458 return keys;
459 }
460 struct mInputAxis* description = TableLookup(&impl->axes, axis);
461 if (!description) {
462 return keys;
463 }
464 return keys &= ~((1 << description->highDirection) | (1 << description->lowDirection));
465}
466
467void mInputBindAxis(struct mInputMap* map, uint32_t type, int axis, const struct mInputAxis* description) {
468 struct mInputMapImpl* impl = _guaranteeMap(map, type);
469 struct mInputAxis d2 = *description;
470 TableEnumerate(&impl->axes, _unbindAxis, &d2.highDirection);
471 TableEnumerate(&impl->axes, _unbindAxis, &d2.lowDirection);
472 struct mInputAxis* dup = malloc(sizeof(struct mInputAxis));
473 *dup = *description;
474 TableInsert(&impl->axes, axis, dup);
475}
476
477void mInputUnbindAxis(struct mInputMap* map, uint32_t type, int axis) {
478 struct mInputMapImpl* impl = _lookupMap(map, type);
479 if (impl) {
480 TableRemove(&impl->axes, axis);
481 }
482}
483
484void mInputUnbindAllAxes(struct mInputMap* map, uint32_t type) {
485 struct mInputMapImpl* impl = _lookupMap(map, type);
486 if (impl) {
487 TableClear(&impl->axes);
488 }
489}
490
491const struct mInputAxis* mInputQueryAxis(const struct mInputMap* map, uint32_t type, int axis) {
492 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
493 if (!impl) {
494 return 0;
495 }
496 return TableLookup(&impl->axes, axis);
497}
498
499void mInputEnumerateAxes(const struct mInputMap* map, uint32_t type, void (handler(int axis, const struct mInputAxis* description, void* user)), void* user) {
500 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
501 if (!impl) {
502 return;
503 }
504 struct mInputAxisEnumerate enumUser = {
505 handler,
506 user
507 };
508 TableEnumerate(&impl->axes, _enumerateAxis, &enumUser);
509}
510
511int mInputMapHat(const struct mInputMap* map, uint32_t type, int id, int direction) {
512 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
513 if (!impl) {
514 return 0;
515 }
516 if (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
517 return 0;
518 }
519 const struct mInputHatBindings* description = mInputHatListGetConstPointer(&impl->hats, id);
520 int mapping = 0;
521 if (direction & M_INPUT_HAT_UP && description->up >= 0) {
522 mapping |= 1 << description->up;
523 }
524 if (direction & M_INPUT_HAT_RIGHT && description->right >= 0) {
525 mapping |= 1 << description->right;
526 }
527 if (direction & M_INPUT_HAT_DOWN && description->down >= 0) {
528 mapping |= 1 << description->down;
529 }
530 if (direction & M_INPUT_HAT_LEFT && description->left >= 0) {
531 mapping |= 1 << description->left;
532 }
533 return mapping;
534}
535
536void mInputBindHat(struct mInputMap* map, uint32_t type, int id, const struct mInputHatBindings* bindings) {
537 struct mInputMapImpl* impl = _guaranteeMap(map, type);
538 while (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
539 *mInputHatListAppend(&impl->hats) = (struct mInputHatBindings) { -1, -1, -1, -1 };
540 }
541 *mInputHatListGetPointer(&impl->hats, id) = *bindings;
542}
543
544bool mInputQueryHat(const struct mInputMap* map, uint32_t type, int id, struct mInputHatBindings* bindings) {
545 const struct mInputMapImpl* impl = _lookupMapConst(map, type);
546 if (!impl) {
547 return false;
548 }
549 if (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
550 return false;
551 }
552 *bindings = *mInputHatListGetConstPointer(&impl->hats, id);
553 return true;
554}
555
556void mInputUnbindHat(struct mInputMap* map, uint32_t type, int id) {
557 struct mInputMapImpl* impl = _lookupMap(map, type);
558 if (!impl) {
559 return;
560 }
561 if (id >= (ssize_t) mInputHatListSize(&impl->hats)) {
562 return;
563 }
564 struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id);
565 memset(description, -1, sizeof(*description));
566}
567
568void mInputUnbindAllHats(struct mInputMap* map, uint32_t type) {
569 struct mInputMapImpl* impl = _lookupMap(map, type);
570 if (!impl) {
571 return;
572 }
573
574 size_t id;
575 for (id = 0; id < mInputHatListSize(&impl->hats); ++id) {
576 struct mInputHatBindings* description = mInputHatListGetPointer(&impl->hats, id);
577 memset(description, -1, sizeof(*description));
578 }
579}
580
581void mInputMapLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config) {
582 char sectionName[SECTION_NAME_MAX];
583 _makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type);
584 _loadAll(map, type, sectionName, config);
585}
586
587void mInputMapSave(const struct mInputMap* map, uint32_t type, struct Configuration* config) {
588 char sectionName[SECTION_NAME_MAX];
589 _makeSectionName(map->info->platformName, sectionName, SECTION_NAME_MAX, type);
590 _saveAll(map, type, sectionName, config);
591}
592
593bool mInputProfileLoad(struct mInputMap* map, uint32_t type, const struct Configuration* config, const char* profile) {
594 char sectionName[SECTION_NAME_MAX];
595 snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", map->info->platformName, profile);
596 sectionName[SECTION_NAME_MAX - 1] = '\0';
597 return _loadAll(map, type, sectionName, config);
598}
599
600void mInputProfileSave(const struct mInputMap* map, uint32_t type, struct Configuration* config, const char* profile) {
601 char sectionName[SECTION_NAME_MAX];
602 snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", map->info->platformName, profile);
603 sectionName[SECTION_NAME_MAX - 1] = '\0';
604 _saveAll(map, type, sectionName, config);
605}
606
607const char* mInputGetPreferredDevice(const struct Configuration* config, const char* platformName, uint32_t type, int playerId) {
608 char sectionName[SECTION_NAME_MAX];
609 _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type);
610
611 char deviceId[KEY_NAME_MAX];
612 snprintf(deviceId, sizeof(deviceId), "device%i", playerId);
613 return ConfigurationGetValue(config, sectionName, deviceId);
614}
615
616void mInputSetPreferredDevice(struct Configuration* config, const char* platformName, uint32_t type, int playerId, const char* deviceName) {
617 char sectionName[SECTION_NAME_MAX];
618 _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type);
619
620 char deviceId[KEY_NAME_MAX];
621 snprintf(deviceId, sizeof(deviceId), "device%i", playerId);
622 return ConfigurationSetValue(config, sectionName, deviceId, deviceName);
623}
624
625const char* mInputGetCustomValue(const struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* profile) {
626 char sectionName[SECTION_NAME_MAX];
627 if (profile) {
628 snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", platformName, profile);
629 const char* value = ConfigurationGetValue(config, sectionName, key);
630 if (value) {
631 return value;
632 }
633 }
634 _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type);
635 return ConfigurationGetValue(config, sectionName, key);
636}
637
638void mInputSetCustomValue(struct Configuration* config, const char* platformName, uint32_t type, const char* key, const char* value, const char* profile) {
639 char sectionName[SECTION_NAME_MAX];
640 if (profile) {
641 snprintf(sectionName, SECTION_NAME_MAX, "%s.input-profile.%s", platformName, profile);
642 ConfigurationSetValue(config, sectionName, key, value);
643 }
644 _makeSectionName(platformName, sectionName, SECTION_NAME_MAX, type);
645 ConfigurationSetValue(config, sectionName, key, value);
646}