GUID config is used for gamepad processing.master
@@ -1,20 +1,20 @@ | |||||
# Controls | # Controls | ||||
| Action | Effect | Remarks | | |||||
|---------|-----------------------------------|--------------------------------------------------------------------------------------------------------| | |||||
| Up | Select Menu Item Up/Look Up | | | |||||
| Right | Select Menu Item Right/Move Right | | | |||||
| Down | Select Menu Item Down/Crouch | | | |||||
| Left | Select Menu Item Left/Move Left | | | |||||
| Affirm | Confirm Selected Option | | | |||||
| Negate | Go Back | | | |||||
| Action0 | Jump | When crouched, player will go down a solid-on-top ground. | | |||||
| Action1 | Primary Fire | Each weapon has firing characteristics, see below. | | |||||
| Action2 | Secondary Fire | Each weapon has firing characteristics, see below. | | |||||
| Action3 | Switch Weapon Mode | Press to select next weapon mode (cycle), hold then press Left/Right to set previous/next weapon mode. | | |||||
| Action4 | Switch Weapon | Press to select next weapon (cycle), hold then press Left/Right to set previous/next weapon. | | |||||
| Action5 | Item/Inventory | Hold to open inventory, double press to use current item. | | |||||
| Action6 | Switch Item | Press to select next item (cycle), hold then press Left/Right to set previous/next item. | | |||||
| Action7 | Take Cover | Enter doors, go between objects to hide from enemies. | | |||||
| Action8 | Sneak | Hold then press Left/Right to sneak. (do we need this control, or crouch is enough?) | | |||||
| Action9 | Reload | Reload always drops current clip regardless if there are rounds left. | | |||||
| Action | XInput | PS4 | Effect | Remarks | | |||||
|---------|---------:|---------:|-----------------------------------|--------------------------------------------------------------------------------------------------------| | |||||
| Up | A1+, A3+ | A1+, A4+ | Select Menu Item Up/Look Up | | | |||||
| Right | A0+, A2+ | A0+, A2+ | Select Menu Item Right/Move Right | | | |||||
| Down | A1-, A3- | A1-, A4- | Select Menu Item Down/Crouch | | | |||||
| Left | A0-, A2- | A0-, A2- | Select Menu Item Left/Move Left | | | |||||
| Affirm | B11 | | Confirm Selected Option | | | |||||
| Negate | B10 | | Go Back | | | |||||
| Action0 | B1 | B2 | Jump | When crouched, player will go down a solid-on-top ground. | | |||||
| Action1 | B0 | B1 | Primary Fire | Each weapon has firing characteristics, see below. | | |||||
| Action2 | B4 | | Secondary Fire | Each weapon has firing characteristics, see below. | | |||||
| Action3 | B3 | | Reload | Reload always drops current clip regardless if there are rounds left. | | |||||
| Action4 | B6 | | Switch Weapon Mode | Press to select next weapon mode (cycle), hold then press Left/Right to set previous/next weapon mode. | | |||||
| Action5 | B7 | | Switch Weapon | Press to select next weapon (cycle), hold then press Left/Right to set previous/next weapon. | | |||||
| Action6 | B8 | | Item/Inventory | Hold to open inventory, double press to use current item. | | |||||
| Action7 | B9 | | Switch Item | Press to select next item (cycle), hold then press Left/Right to set previous/next item. | | |||||
| Action8 | B13 | | Take Cover | Enter doors, go between objects to hide from enemies. | | |||||
| Action9 | B14 | | Sneak | Hold then press Left/Right to sneak. (do we need this control, or crouch is enough?) | |
@@ -5,6 +5,7 @@ MaxFps=30 | |||||
[Joystick.0] | [Joystick.0] | ||||
DeviceID=0 | DeviceID=0 | ||||
AxisThreshold=8000 | AxisThreshold=8000 | ||||
GUID=00000000-0000-0000-0000-000000000000 | |||||
[Joystick.0.ControlMapping] | [Joystick.0.ControlMapping] | ||||
Affirm=11 | Affirm=11 | ||||
Negate=10 | Negate=10 | ||||
@@ -64,6 +65,7 @@ Username=Player 1 | |||||
[Joystick.1] | [Joystick.1] | ||||
DeviceID=1 | DeviceID=1 | ||||
AxisThreshold=8000 | AxisThreshold=8000 | ||||
GUID=00000000-0000-0000-0000-000000000000 | |||||
[Joystick.1.ControlMapping] | [Joystick.1.ControlMapping] | ||||
Affirm=11 | Affirm=11 | ||||
Negate=10 | Negate=10 | ||||
@@ -1,3 +1,4 @@ | |||||
#include <SDL_guid.h> | |||||
#include "IZ_config.h" | #include "IZ_config.h" | ||||
const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const char* val) { | const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const char* val) { | ||||
@@ -5,7 +6,6 @@ const char* IZ_ConfigGetCommandlineOption(u8 argc, const char* argv[], const cha | |||||
int c = argc; | int c = argc; | ||||
while (--c > 0) { | while (--c > 0) { | ||||
if (!strncmp(argv[c], val, n)) { | if (!strncmp(argv[c], val, n)) { | ||||
if (!*(argv[c] + n) && c < argc - 1) { | if (!*(argv[c] + n) && c < argc - 1) { | ||||
/* coverity treats unchecked argv as "tainted" */ | /* coverity treats unchecked argv as "tainted" */ | ||||
@@ -164,6 +164,57 @@ void IZ_ConfigOverrideString(IZ_ConfigItem* item, u8 argc, const char* argv[]) { | |||||
} | } | ||||
} | } | ||||
typedef bool IZ_ConfigLoadParamsGuidValidator(SDL_GUID); | |||||
void IZ_ConfigEnsureValidGuid(IZ_ConfigItem* item, SDL_GUID raw_value, SDL_GUID default_value) { | |||||
SDL_GUID* dest = item->dest; | |||||
if (item->validator) { | |||||
IZ_ConfigLoadParamsGuidValidator* validate = item->validator; | |||||
if (validate(raw_value)) { | |||||
// within valid values | |||||
*dest = raw_value; | |||||
return; | |||||
} | |||||
// outside valid values, we use default value | |||||
// | |||||
// TODO: what if the default value is also invalid? | |||||
*dest = default_value; | |||||
return; | |||||
} | |||||
// no validator, get whatever is the deserialized value | |||||
*dest = raw_value; | |||||
} | |||||
typedef SDL_GUID IZ_ConfigDeserializeGUID(const char*); | |||||
typedef void IZ_ConfigSerializeGUID(SDL_GUID, const char[128]); | |||||
void IZ_ConfigLoadGuid(IZ_ConfigItem* item, const char* config_path) { | |||||
static SDL_GUID raw_value; | |||||
static SDL_GUID default_value = { | |||||
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, | |||||
}; | |||||
if (item->default_value) { | |||||
default_value = *((SDL_GUID *) item->default_value); | |||||
} | |||||
char buffer[128]; | |||||
if (item->transformer.deserialize && item->transformer.serialize) { | |||||
IZ_ConfigDeserializeGUID* deserialize = item->transformer.deserialize; | |||||
IZ_ConfigSerializeGUID* serialize = item->transformer.serialize; | |||||
const char serialized_default_value[128]; | |||||
serialize(default_value, serialized_default_value); | |||||
ini_gets(item->section, item->key, serialized_default_value, buffer, 128, config_path); | |||||
raw_value = deserialize(buffer); | |||||
} else { | |||||
ini_gets(item->section, item->key, "00000000-0000-0000-0000-000000000000", buffer, 128, config_path); | |||||
raw_value = SDL_GUIDFromString(buffer); | |||||
} | |||||
IZ_ConfigEnsureValidGuid(item, raw_value, default_value); | |||||
} | |||||
void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) { | void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) { | ||||
u8 i; | u8 i; | ||||
for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) { | for (i = 0; item[i].type != IZ_CONFIG_TYPE_VOID; i += 1) { | ||||
@@ -179,12 +230,58 @@ void IZ_ConfigLoad(IZ_ConfigItem item[], const char* config_path) { | |||||
break; | break; | ||||
case IZ_CONFIG_TYPE_I32: | case IZ_CONFIG_TYPE_I32: | ||||
IZ_ConfigLoadI32(&item[i], config_path); | IZ_ConfigLoadI32(&item[i], config_path); | ||||
break; | |||||
case IZ_CONFIG_TYPE_GUID: | |||||
IZ_ConfigLoadGuid(&item[i], config_path); | |||||
break; | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
IZ_ConfigSaveItemResult IZ_ConfigSaveGuid(IZ_ConfigItem* item, const char* config_path) { | |||||
SDL_GUID dest = *((SDL_GUID*) item->dest); | |||||
if (item->validator) { | |||||
IZ_ConfigLoadParamsGuidValidator* validate = item->validator; | |||||
if (!validate(dest)) { | |||||
dest = *((const SDL_GUID*) item->default_value); | |||||
} | |||||
} | |||||
if (item->transformer.deserialize && item->transformer.serialize) { | |||||
IZ_ConfigSerializeGUID* serialize = item->transformer.serialize; | |||||
const char serialized_value[128]; | |||||
serialize(dest, serialized_value); | |||||
if (!ini_puts(item->section, item->key, serialized_value, config_path)) { | |||||
return -1; | |||||
} | |||||
return 0; | |||||
} | |||||
char guid_str[128]; | |||||
SDL_GUIDToString(dest, guid_str, 128); | |||||
if (!ini_puts(item->section, item->key, guid_str, config_path)) { | |||||
return -1; | |||||
} | |||||
return 0; | |||||
} | |||||
void IZ_ConfigOverrideGuid(IZ_ConfigItem* item, u8 argc, const char* argv[]) { | |||||
if (!item->cmdline_option) { | |||||
return; | |||||
} | |||||
const char* cmdline_buffer; | |||||
static SDL_GUID dest; | |||||
static SDL_GUID config_value; | |||||
config_value = *((SDL_GUID*) item->dest); | |||||
if((cmdline_buffer = IZ_ConfigGetCommandlineOption(argc, argv, item->cmdline_option))) { | |||||
dest = SDL_GUIDFromString(cmdline_buffer); | |||||
IZ_ConfigEnsureValidGuid(item, dest, config_value); | |||||
} | |||||
} | |||||
IZ_ConfigSaveResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) { | IZ_ConfigSaveResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) { | ||||
u8 i; | u8 i; | ||||
i64 problems = 0; | i64 problems = 0; | ||||
@@ -194,6 +291,9 @@ IZ_ConfigSaveResult IZ_ConfigSave(IZ_ConfigItem item[], const char* config_path) | |||||
case IZ_CONFIG_TYPE_STRING: | case IZ_CONFIG_TYPE_STRING: | ||||
result = IZ_ConfigSaveString(&item[i], config_path); | result = IZ_ConfigSaveString(&item[i], config_path); | ||||
break; | break; | ||||
case IZ_CONFIG_TYPE_GUID: | |||||
result = IZ_ConfigSaveGuid(&item[i], config_path); | |||||
break; | |||||
case IZ_CONFIG_TYPE_U8: | case IZ_CONFIG_TYPE_U8: | ||||
result = IZ_ConfigSaveU8(&item[i], config_path); | result = IZ_ConfigSaveU8(&item[i], config_path); | ||||
break; | break; | ||||
@@ -230,6 +330,9 @@ void IZ_ConfigOverride(IZ_ConfigItem item[], u8 argc, const char* argv[]) { | |||||
case IZ_CONFIG_TYPE_I32: | case IZ_CONFIG_TYPE_I32: | ||||
IZ_ConfigOverrideI32(&item[i], argc, argv); | IZ_ConfigOverrideI32(&item[i], argc, argv); | ||||
break; | break; | ||||
case IZ_CONFIG_TYPE_GUID: | |||||
IZ_ConfigOverrideGuid(&item[i], argc, argv); | |||||
break; | |||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
@@ -12,6 +12,7 @@ typedef enum { | |||||
IZ_CONFIG_TYPE_U8, | IZ_CONFIG_TYPE_U8, | ||||
IZ_CONFIG_TYPE_U16, | IZ_CONFIG_TYPE_U16, | ||||
IZ_CONFIG_TYPE_I32, | IZ_CONFIG_TYPE_I32, | ||||
IZ_CONFIG_TYPE_GUID, | |||||
} IZ_ConfigType; | } IZ_ConfigType; | ||||
typedef struct { | typedef struct { | ||||
@@ -106,6 +106,13 @@ void IZ_JoystickHandleHatEvents(IZ_Action* action, SDL_Event e) { | |||||
void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { | void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { | ||||
u8 control_index; | u8 control_index; | ||||
SDL_JoystickGUID joystick_guid = SDL_JoystickGetGUID(SDL_JoystickFromInstanceID(e.jbutton.which)); | |||||
for (u8 zz = 0; zz < 16; zz += 1) { | |||||
printf("%02x", joystick_guid.data[zz]); | |||||
} | |||||
printf("\n"); | |||||
for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | ||||
u8 normalized_button = e.jbutton.button; | u8 normalized_button = e.jbutton.button; | ||||
@@ -167,8 +174,9 @@ void IZ_JoystickBindStateToConfig(IZ_JoystickState(* state)[IZ_PLAYERS], IZ_Conf | |||||
u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2)); | u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2)); | ||||
config_items[base_index].dest = &((*state)[player_index].config.device_id); | config_items[base_index].dest = &((*state)[player_index].config.device_id); | ||||
config_items[base_index + 1].dest = &((*state)[player_index].config.axis_threshold); | config_items[base_index + 1].dest = &((*state)[player_index].config.axis_threshold); | ||||
config_items[base_index + 2].dest = &((*state)[player_index].config.guid); | |||||
for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | ||||
config_items[base_index + 2 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]); | |||||
config_items[base_index + 3 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -209,10 +217,23 @@ void IZ_JoystickInitializeConfigItems(IZ_ConfigItem config_items[]) { | |||||
NULL, | NULL, | ||||
}; | }; | ||||
config_items[base_index + 2] = (IZ_ConfigItem) { | |||||
IZ_CONFIG_TYPE_STRING, | |||||
sizeof(u16), | |||||
main_section_name, | |||||
"GUID", | |||||
NULL, | |||||
&IZ_JOYSTICK_DEFAULT_STATE[player_index].config.guid, | |||||
NULL, | |||||
NULL, | |||||
}; | |||||
// todo add game controller GUID for determining mappings | |||||
control_mapping_section_name = SDL_malloc(sizeof(char) * 64); | control_mapping_section_name = SDL_malloc(sizeof(char) * 64); | ||||
sprintf(control_mapping_section_name, "Joystick.%d.ControlMapping", player_index); | sprintf(control_mapping_section_name, "Joystick.%d.ControlMapping", player_index); | ||||
for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) { | ||||
config_items[base_index + 2 + (control_index - 4)] = (IZ_ConfigItem) { | |||||
config_items[base_index + 3 + (control_index - 4)] = (IZ_ConfigItem) { | |||||
IZ_CONFIG_TYPE_U8, | IZ_CONFIG_TYPE_U8, | ||||
sizeof(u8), | sizeof(u8), | ||||
control_mapping_section_name, | control_mapping_section_name, | ||||
@@ -252,6 +273,7 @@ IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[IZ_PLAYERS], | |||||
return -2; | return -2; | ||||
} | } | ||||
SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt"); | |||||
u8 player_index; | u8 player_index; | ||||
u8 joysticks_count = SDL_NumJoysticks(); | u8 joysticks_count = SDL_NumJoysticks(); | ||||
for (player_index = 0; player_index < joysticks_count; player_index += 1) { | for (player_index = 0; player_index < joysticks_count; player_index += 1) { | ||||
@@ -3,6 +3,7 @@ | |||||
#include <SDL_stdinc.h> | #include <SDL_stdinc.h> | ||||
#include <SDL_joystick.h> | #include <SDL_joystick.h> | ||||
#include <SDL_gamecontroller.h> | |||||
#include <SDL_events.h> | #include <SDL_events.h> | ||||
#include <minIni.h> | #include <minIni.h> | ||||
#include "../../config/IZ_config.h" | #include "../../config/IZ_config.h" | ||||
@@ -24,6 +25,7 @@ typedef enum { | |||||
typedef struct { | typedef struct { | ||||
u16 axis_threshold; | u16 axis_threshold; | ||||
SDL_JoystickID device_id; | SDL_JoystickID device_id; | ||||
SDL_GUID guid; | |||||
IZ_PadButton control_mapping[IZ_CONTROLS]; | IZ_PadButton control_mapping[IZ_CONTROLS]; | ||||
} IZ_JoystickConfig; | } IZ_JoystickConfig; | ||||
@@ -55,6 +57,9 @@ static const IZ_JoystickState IZ_JOYSTICK_DEFAULT_STATE[IZ_PLAYERS] = { | |||||
}, | }, | ||||
.axis_threshold = 8000u, | .axis_threshold = 8000u, | ||||
.device_id = 0, | .device_id = 0, | ||||
.guid = { | |||||
.data = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } | |||||
} | |||||
}, | }, | ||||
.device = NULL, | .device = NULL, | ||||
}, | }, | ||||