#include "IZ_joystick.h" void IZ_JoystickHandleDeviceEvents(IZ_JoystickState* state, SDL_Event e) { if (e.type == SDL_JOYDEVICEADDED) { if (SDL_NumJoysticks() <= IZ_PLAYERS && !state->device) { state->device = SDL_JoystickOpen(e.jdevice.which); } return; } if (e.type == SDL_JOYDEVICEREMOVED) { if ( state->device && SDL_JoystickInstanceID(state->device) == e.jdevice.which ) { state->device = NULL; } } } void IZ_JoystickHandleAxisEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { if (e.type == SDL_JOYAXISMOTION) { if ( e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_HORIZONTAL1 || e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_HORIZONTAL2 ) { *action &= ~(0x1 << IZ_ACTION_INDEX_RIGHT); *action &= ~(0x1 << IZ_ACTION_INDEX_LEFT); if (e.jaxis.value > state->config.axis_threshold) { *action |= (0x1 << IZ_ACTION_INDEX_RIGHT); return; } if (e.jaxis.value <= -state->config.axis_threshold) { *action |= (0x1 << IZ_ACTION_INDEX_LEFT); } return; } if ( e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_VERTICAL1 || e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_VERTICAL2 ) { *action &= ~(0x1 << IZ_ACTION_INDEX_UP); *action &= ~(0x1 << IZ_ACTION_INDEX_DOWN); if (e.jaxis.value > state->config.axis_threshold) { *action |= (0x1 << IZ_ACTION_INDEX_DOWN); return; } if (e.jaxis.value <= -state->config.axis_threshold) { *action |= (0x1 << IZ_ACTION_INDEX_UP); } } } } void IZ_JoystickHandleHatEvents(IZ_Action* action, SDL_Event e) { if (e.type == SDL_JOYHATMOTION) { *action &= ~(0x1 << IZ_ACTION_INDEX_UP); *action &= ~(0x1 << IZ_ACTION_INDEX_RIGHT); *action &= ~(0x1 << IZ_ACTION_INDEX_DOWN); *action &= ~(0x1 << IZ_ACTION_INDEX_LEFT); if (e.jhat.value != 0) { *action |= e.jhat.value; } } } void IZ_JoystickHandleButtonEvents(IZ_JoystickState* state, IZ_Action* action, SDL_Event e) { u8 control_index; for (control_index = 4; control_index < CONTROLS; control_index += 1) { if (e.jbutton.button == state->config.control_mapping[control_index]) { const u16 bitflag = (0x1 << control_index); if (e.type == SDL_JOYBUTTONDOWN) { *action |= bitflag; return; } if (e.type == SDL_JOYBUTTONUP) { *action &= ~bitflag; return; } } } } void IZ_JoystickHandleEvents(IZ_JoystickState(* state)[IZ_PLAYERS], IZ_Action(* action)[IZ_PLAYERS], SDL_Event e) { u8 player_index; for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { IZ_JoystickHandleDeviceEvents(&(*state)[player_index], e); IZ_JoystickHandleAxisEvents(&(*state)[player_index], &(*action)[player_index], e); IZ_JoystickHandleHatEvents(&(*action)[player_index], e); IZ_JoystickHandleButtonEvents(&(*state)[player_index], &(*action)[player_index], e); } } void IZ_JoystickLoadConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path) { char control_mapping_section_name[26]; char main_section_name[11]; u8 player_index; u8 control_index; for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { sprintf_s(control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index); for (control_index = 4; control_index < CONTROLS; control_index += 1) { (*state)[player_index].config.control_mapping[control_index] = ini_getl( control_mapping_section_name, ACTION_NAMES[control_index], IZ_JOYSTICK_DEFAULT_STATE[player_index].config.control_mapping[control_index], config_path ); } sprintf_s(main_section_name, 11, "Joystick.%d", player_index); (*state)[player_index].config.axis_threshold = ini_getl(main_section_name, "AxisThreshold", IZ_DEFAULT_AXIS_THRESHOLD, config_path); (*state)[player_index].config.device_id = ini_getl(main_section_name, "DeviceID", player_index, config_path); } } IZ_ProcedureResult IZ_JoystickSaveConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path) { u8 problem = 0; char control_mapping_section_name[26]; char main_section_name[11]; u8 player_index; u8 control_index; for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { sprintf_s(control_mapping_section_name, 26, "Joystick.%d.ControlMapping", player_index); for (control_index = 4; control_index < CONTROLS; control_index += 1) { if (!ini_putl( control_mapping_section_name, ACTION_NAMES[control_index], (*state)[player_index].config.control_mapping[control_index], config_path )) { problem |= (1 << player_index); } } sprintf_s(main_section_name, 11, "Joystick.%d", player_index); if (!ini_putl( main_section_name, "DeviceID", (*state)[player_index].config.device_id, config_path )) { problem |= (1 << player_index); } if (!ini_putl( main_section_name, "AxisThreshold", (*state)[player_index].config.axis_threshold, config_path )) { problem |= (1 << player_index); } } return -problem; } IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) { SDL_memcpy(state, &IZ_JOYSTICK_DEFAULT_STATE, sizeof(IZ_JoystickState)); IZ_JoystickLoadConfig(state, config_path); if (IZ_JoystickSaveConfig(state, config_path) < 0) { return -1; } u8 joysticks_count = SDL_NumJoysticks(); u8 player_index; for (player_index = 0; player_index < joysticks_count; player_index += 1) { if (player_index >= IZ_PLAYERS) { break; } (*state)[player_index].device = SDL_JoystickOpen(state[player_index]->config.device_id); } return 0; } void IZ_JoystickTeardown(IZ_JoystickState(* state)[IZ_PLAYERS]) { u8 player_index; for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) { if (!(*state)[player_index].device) { continue; } SDL_JoystickClose((*state)[player_index].device); } }