@@ -1,5 +1,7 @@ | |||||
# Controls | # Controls | ||||
![Defailt Gamepad Controls](./controls.svg) | |||||
| Action | Default Gamepad Control | Effect | Remarks | | | Action | Default Gamepad Control | Effect | Remarks | | ||||
|---------|-----------------------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------------| | |---------|-----------------------------------------------|-----------------------------------|--------------------------------------------------------------------------------------------------------| | ||||
| Up | DPad Up/Left Stick Up/Right Stick Up | Select Menu Item Up/Look Up | | | | Up | DPad Up/Left Stick Up/Right Stick Up | Select Menu Item Up/Look Up | | | ||||
@@ -54,10 +54,25 @@ void IZ_GameControllerHandleAxisEvents(IZ_GameControllerState* state, IZ_Action* | |||||
bool is_capture = false; | bool is_capture = false; | ||||
const u16 bitflag = (0x1 << control_index); | const u16 bitflag = (0x1 << control_index); | ||||
if ( | |||||
strstr(state->config.control_mapping[control_index], current_positive_axis_full_name) | |||||
|| strstr(state->config.control_mapping[control_index], current_negative_axis_full_name) | |||||
) { | |||||
if (strstr(state->config.control_mapping[control_index], current_positive_axis_full_name)) { | |||||
if (*action & bitflag) { | |||||
IZ_LogInfo(IZ_LOG_CATEGORY_INPUT, "input/gamepad", "up %s", IZ_ACTION_NAMES[control_index]); | |||||
} | |||||
// TODO: optimize unsetting of action | |||||
*action &= ~bitflag; | |||||
// should we implement actions that do not cancel out across input controllers? | |||||
// add extra byte for source of action: | |||||
// 0x1 - keyboard | |||||
// 0x2 - game controller dpad | |||||
// 0x4 - game controller left stick | |||||
// 0x8 - game controller right stick | |||||
// 0x10 - other device | |||||
} | |||||
if (strstr(state->config.control_mapping[control_index], current_negative_axis_full_name)) { | |||||
if (*action & bitflag) { | |||||
IZ_LogInfo(IZ_LOG_CATEGORY_INPUT, "input/gamepad", "up %s", IZ_ACTION_NAMES[control_index]); | |||||
} | |||||
*action &= ~bitflag; | *action &= ~bitflag; | ||||
// should we implement actions that do not cancel out across input controllers? | // should we implement actions that do not cancel out across input controllers? | ||||
// add extra byte for source of action: | // add extra byte for source of action: | ||||
@@ -69,6 +84,7 @@ void IZ_GameControllerHandleAxisEvents(IZ_GameControllerState* state, IZ_Action* | |||||
} | } | ||||
char current_axis_full_name[IZ_GAME_CONTROLLER_MAX_CONTROL_NAME_LENGTH]; | char current_axis_full_name[IZ_GAME_CONTROLLER_MAX_CONTROL_NAME_LENGTH]; | ||||
IZ_memset(current_axis_full_name, 0, IZ_GAME_CONTROLLER_MAX_CONTROL_NAME_LENGTH); | |||||
if (e.caxis.value > 0) { | if (e.caxis.value > 0) { | ||||
IZ_memcpy( | IZ_memcpy( | ||||
current_axis_full_name, | current_axis_full_name, | ||||
@@ -97,6 +113,7 @@ void IZ_GameControllerHandleAxisEvents(IZ_GameControllerState* state, IZ_Action* | |||||
} | } | ||||
*action |= bitflag; | *action |= bitflag; | ||||
IZ_LogInfo(IZ_LOG_CATEGORY_INPUT, "input/gamepad", "dn %s (%s)", IZ_ACTION_NAMES[control_index], current_axis_full_name); | |||||
} | } | ||||
} | } | ||||
@@ -115,17 +132,19 @@ void IZ_GameControllerHandleButtonEvents(IZ_GameControllerState* state, IZ_Actio | |||||
current_button_name | current_button_name | ||||
); | ); | ||||
if (!strstr(state->config.control_mapping[control_index], current_button_full_name)) { | |||||
if (!IZ_contains(state->config.control_mapping[control_index], IZ_GAME_CONTROLLER_MAX_CONTROL_NAME_LENGTH, current_button_full_name, IZ_GAME_CONTROLLER_MAX_CONTROL_NAME_LENGTH)) { | |||||
continue; | continue; | ||||
} | } | ||||
const u16 bitflag = (0x1 << control_index); | const u16 bitflag = (0x1 << control_index); | ||||
if (e.type == SDL_CONTROLLERBUTTONDOWN) { | if (e.type == SDL_CONTROLLERBUTTONDOWN) { | ||||
IZ_LogInfo(IZ_LOG_CATEGORY_INPUT, "input/gamepad", "dn %s (%s)", IZ_ACTION_NAMES[control_index], current_button_full_name); | |||||
*action |= bitflag; | *action |= bitflag; | ||||
return; | return; | ||||
} | } | ||||
if (e.type == SDL_CONTROLLERBUTTONUP) { | if (e.type == SDL_CONTROLLERBUTTONUP) { | ||||
IZ_LogInfo(IZ_LOG_CATEGORY_INPUT, "input/gamepad", "up %s (%s)", IZ_ACTION_NAMES[control_index], current_button_full_name); | |||||
*action &= ~bitflag; | *action &= ~bitflag; | ||||
return; | return; | ||||
} | } | ||||
@@ -246,9 +265,18 @@ IZ_ProcedureResult IZ_GameControllerInitialize(IZ_GameControllerState(* state)[I | |||||
if (!(*state)[player_index].device) { | if (!(*state)[player_index].device) { | ||||
break; | break; | ||||
} | } | ||||
(*state)[player_index].config.device_id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick((*state)[player_index].device)); | (*state)[player_index].config.device_id = SDL_JoystickInstanceID(SDL_GameControllerGetJoystick((*state)[player_index].device)); | ||||
SDL_GUID game_controller_guid = SDL_JoystickGetGUID(SDL_GameControllerGetJoystick((*state)[player_index].device)); | SDL_GUID game_controller_guid = SDL_JoystickGetGUID(SDL_GameControllerGetJoystick((*state)[player_index].device)); | ||||
IZ_memcpy(&(*state)[player_index].config.guid, sizeof(SDL_GUID), &game_controller_guid, sizeof(SDL_GUID)); | IZ_memcpy(&(*state)[player_index].config.guid, sizeof(SDL_GUID), &game_controller_guid, sizeof(SDL_GUID)); | ||||
IZ_LogInfo( | |||||
IZ_LOG_CATEGORY_GENERIC, | |||||
"input/gamepad", | |||||
"Found device for player %u: %s", | |||||
player_index, | |||||
SDL_GameControllerName((*state)[player_index].device) | |||||
); | |||||
} | } | ||||
// Post config (after game_controller GUIDs have been queried), this is unique to game_controllers since they can be plugged in any | // Post config (after game_controller GUIDs have been queried), this is unique to game_controllers since they can be plugged in any | ||||
@@ -38,9 +38,9 @@ static const IZ_GameControllerState IZ_GAME_CONTROLLER_DEFAULT_STATE[IZ_PLAYERS] | |||||
{ | { | ||||
.config = { | .config = { | ||||
.control_mapping = { | .control_mapping = { | ||||
"button:dpup axis:+lefty axis:+righty", | |||||
"button:dpup axis:-lefty axis:-righty", | |||||
"button:dpright axis:+leftx axis:+rightx", | "button:dpright axis:+leftx axis:+rightx", | ||||
"button:dpdown axis:-lefty axis:-righty", | |||||
"button:dpdown axis:+lefty axis:+righty", | |||||
"button:dpleft axis:-leftx axis:-rightx", | "button:dpleft axis:-leftx axis:-rightx", | ||||
"button:start", | "button:start", | ||||
"button:back", | "button:back", | ||||
@@ -16,11 +16,25 @@ void IZ_KeyboardHandleKeyUpDownEvents(IZ_KeyboardState* state, IZ_Action* action | |||||
for (control_index = 0; control_index < IZ_CONTROLS; control_index += 1) { | for (control_index = 0; control_index < IZ_CONTROLS; control_index += 1) { | ||||
if (e.key.keysym.sym == state->config.control_mapping[control_index]) { | if (e.key.keysym.sym == state->config.control_mapping[control_index]) { | ||||
const u16 bitflag = (0x1 << control_index); | const u16 bitflag = (0x1 << control_index); | ||||
if (e.type == SDL_KEYDOWN) { | |||||
if (e.type == SDL_KEYDOWN && !(*action & bitflag)) { | |||||
IZ_LogInfo( | |||||
IZ_LOG_CATEGORY_INPUT, | |||||
"input/keyboard", | |||||
"dn %s (%s)", | |||||
IZ_ACTION_NAMES[control_index], | |||||
SDL_GetKeyName(e.key.keysym.sym) | |||||
); | |||||
*action |= bitflag; | *action |= bitflag; | ||||
return; | return; | ||||
} | } | ||||
if (e.type == SDL_KEYUP) { | |||||
if (e.type == SDL_KEYUP && (*action & bitflag)) { | |||||
IZ_LogInfo( | |||||
IZ_LOG_CATEGORY_INPUT, | |||||
"input/keyboard", | |||||
"up %s (%s)", | |||||
IZ_ACTION_NAMES[control_index], | |||||
SDL_GetKeyName(e.key.keysym.sym) | |||||
); | |||||
*action &= ~bitflag; | *action &= ~bitflag; | ||||
return; | return; | ||||
} | } | ||||
@@ -7,6 +7,7 @@ | |||||
#include <ini-config/source/types/int.h> | #include <ini-config/source/types/int.h> | ||||
#include "../../stdinc/IZ_string.h" | #include "../../stdinc/IZ_string.h" | ||||
#include "../../stdinc/IZ_stdlib.h" | #include "../../stdinc/IZ_stdlib.h" | ||||
#include "../../log/IZ_log.h" | |||||
#include "IZ_action.h" | #include "IZ_action.h" | ||||
typedef struct { | typedef struct { | ||||
@@ -83,11 +83,11 @@ void IZ_LogError(const char* context, const char* fmt, ...) { | |||||
va_end(args); | va_end(args); | ||||
if (IZ_LogIsSupportedColor(stdout_dest)) { | if (IZ_LogIsSupportedColor(stdout_dest)) { | ||||
fprintf(stdout_dest, RED "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, RED "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
return; | return; | ||||
} | } | ||||
fprintf(stderr_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stderr_dest, "%-" IZ_LOG_WIDTH_TIMESTAMP "s" " " "%-" IZ_LOG_WIDTH_CATEGORY "s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -103,20 +103,20 @@ void IZ_LogInfo(IZ_LogCategory category, const char* context, const char* fmt, . | |||||
switch (category) { | switch (category) { | ||||
default: | default: | ||||
case IZ_LOG_CATEGORY_GENERIC: | case IZ_LOG_CATEGORY_GENERIC: | ||||
fprintf(stdout_dest, CYN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, CYN "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
break; | break; | ||||
case IZ_LOG_CATEGORY_GLOBAL: | case IZ_LOG_CATEGORY_GLOBAL: | ||||
fprintf(stdout_dest, MAG "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, MAG "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
break; | break; | ||||
case IZ_LOG_CATEGORY_INPUT: | case IZ_LOG_CATEGORY_INPUT: | ||||
fprintf(stdout_dest, WHT "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, WHT "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
break; | break; | ||||
} | } | ||||
return; | return; | ||||
} | } | ||||
fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, "%-" IZ_LOG_WIDTH_TIMESTAMP "s" " " "%-" IZ_LOG_WIDTH_CATEGORY "s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -130,14 +130,14 @@ void IZ_LogWarn(bool is_critical, const char* context, const char* fmt, ...) { | |||||
if (IZ_LogIsSupportedColor(stdout_dest)) { | if (IZ_LogIsSupportedColor(stdout_dest)) { | ||||
if (is_critical) { | if (is_critical) { | ||||
fprintf(stdout_dest, GRN "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, GRN "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
} else { | } else { | ||||
fprintf(stdout_dest, YEL "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, YEL "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
} | } | ||||
return; | return; | ||||
} | } | ||||
fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, "%-" IZ_LOG_WIDTH_TIMESTAMP "s" " " "%-" IZ_LOG_WIDTH_CATEGORY "s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
#endif | #endif | ||||
} | } | ||||
@@ -149,11 +149,11 @@ void IZ_Log(const char* context, const char* fmt, ...) { | |||||
vsnprintf(buffer, sizeof(buffer), fmt, args); | vsnprintf(buffer, sizeof(buffer), fmt, args); | ||||
va_end(args); | va_end(args); | ||||
if (IZ_LogIsSupportedColor(stdout_dest)) { | if (IZ_LogIsSupportedColor(stdout_dest)) { | ||||
fprintf(stdout_dest, BLU "%24s" RESET " " BOLD "%-6s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, BLU "%-" IZ_LOG_WIDTH_TIMESTAMP "s" RESET " " BOLD "%-" IZ_LOG_WIDTH_CATEGORY "s" RESET " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
return; | return; | ||||
} | } | ||||
fprintf(stdout_dest, "%24s" " " "%-6s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fprintf(stdout_dest, "%-" IZ_LOG_WIDTH_TIMESTAMP "s" " " "%-" IZ_LOG_WIDTH_CATEGORY "s" " %s\n", IZ_LOG_DATE_FUNCTION(), context, buffer); | |||||
fflush(stdout_dest); | fflush(stdout_dest); | ||||
#endif | #endif | ||||
} | } |
@@ -16,6 +16,9 @@ | |||||
#define IZ_LOG_LEVEL_FLAG_WARN | #define IZ_LOG_LEVEL_FLAG_WARN | ||||
#define IZ_LOG_LEVEL_FLAG_ERROR | #define IZ_LOG_LEVEL_FLAG_ERROR | ||||
#define IZ_LOG_WIDTH_TIMESTAMP "24" | |||||
#define IZ_LOG_WIDTH_CATEGORY "14" | |||||
#include <SDL_filesystem.h> | #include <SDL_filesystem.h> | ||||
#if defined IZ_WINDOWS | #if defined IZ_WINDOWS | ||||
#include <io.h> | #include <io.h> | ||||
@@ -39,3 +39,19 @@ errno_t IZ_strlwr(char* dest, const char* str, rsize_t str_size) { | |||||
void* IZ_memset(void* dest, int value, rsize_t dest_size) { | void* IZ_memset(void* dest, int value, rsize_t dest_size) { | ||||
return memset(dest, value, dest_size); | return memset(dest, value, dest_size); | ||||
} | } | ||||
const char* IZ_contains(const char* haystack, rsize_t haystack_size, const char* needle, rsize_t needle_size) { | |||||
int i; | |||||
for (i = 0; i < haystack_size; i += 1) { | |||||
int j; | |||||
for (j = 0; j <= needle_size; j += 1) { | |||||
if ((haystack[j] == ' ' || haystack[j] == '\0' || j == needle_size) && (haystack[i + j] == ' ' || haystack[i + j] == '\0')) { | |||||
return haystack + i; | |||||
} | |||||
if (haystack[i + j] != needle[j]) { | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
return NULL; | |||||
} |
@@ -19,4 +19,6 @@ errno_t IZ_strlwr(char*, const char*, rsize_t); | |||||
void* IZ_memset(void*, int, rsize_t); | void* IZ_memset(void*, int, rsize_t); | ||||
const char* IZ_contains(const char*, rsize_t, const char*, rsize_t); | |||||
#endif | #endif |