|
- #include "IZ_joystick.h"
-
- static INI_ConfigItem joystick_config_items[IZ_PLAYERS * (IZ_CONTROLS - 4 + 3) + 1];
-
- bool IZ_JoystickIsValidAxisThreshold(u16 value) {
- return (4000 <= value && value <= 12000);
- }
-
- void IZ_JoystickHandleDeviceEvents(IZ_JoystickState* state, SDL_Event e) {
- if (e.type == SDL_JOYDEVICEADDED) {
- u8 joysticks_count = SDL_NumJoysticks();
- if (joysticks_count <= 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) {
- // XInput handling
- u8 control_index;
- for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
- if (e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_LEFT_SHOULDER && state->config.control_mapping[control_index] == 10) {
- const u16 bitflag = (0x1 << control_index);
-
- if (e.jaxis.value > state->config.axis_threshold) {
- *action |= bitflag;
- return;
- }
-
- if (e.jaxis.value <= state->config.axis_threshold) {
- *action &= ~bitflag;
- return;
- }
- }
-
- if (e.jaxis.axis == IZ_JOY_AXIS_DIRECTION_RIGHT_SHOULDER && state->config.control_mapping[control_index] == 11) {
- const u16 bitflag = (0x1 << control_index);
-
- if (e.jaxis.value > state->config.axis_threshold) {
- *action |= bitflag;
- return;
- }
-
- if (e.jaxis.value <= state->config.axis_threshold) {
- *action &= ~bitflag;
- return;
- }
- }
- }
-
- 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;
-
- SDL_JoystickGUID joystick_guid = SDL_JoystickGetGUID(SDL_JoystickFromInstanceID(e.jbutton.which));
- bool is_valid_event = false;
- for (u8 zz = 0; zz < 16; zz += 1) {
- is_valid_event |= joystick_guid.data[zz] != 0;
- }
- if (!is_valid_event) {
- return;
- }
-
- // printf("button event from guid: ");
- // 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) {
- u8 normalized_button = e.jbutton.button;
-
- /*
- * ZL ZR
- * L R
- *
- * U SLCT STRT 3
- * L R 2 0
- * D 1
- *
- *
- *
- */
-
- // TODO test with XInput, make compatible with Apple
-
- // TODO honor mapping with controller
-
- #ifdef IZ_MACOS
- //printf("%d\n", e.jbutton.button);
- // if (e.jbutton.button == 2) {
- // normalized_button = 4;
- // } else if (e.jbutton.button == 6) {
- // normalized_button = 11;
- // } else if (e.jbutton.button == 4) {
- // normalized_button = 10;
- // }
- #endif
-
- if (normalized_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_JoystickBindStateToConfig(IZ_JoystickState(* state)[IZ_PLAYERS], INI_ConfigItem config_items[]) {
- u8 player_index;
- u8 control_index;
- for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
- u8 base_index = (player_index * (IZ_CONTROLS - 4 + 2));
- 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 + 2].dest = &((*state)[player_index].config.guid);
- for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
- config_items[base_index + 3 + (control_index - 4)].dest = &((*state)[player_index].config.control_mapping[control_index]);
- }
- }
- }
-
- IZ_ProcedureResult IZ_JoystickSaveConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path) {
- IZ_JoystickBindStateToConfig(state, joystick_config_items);
- return INI_ConfigSave(joystick_config_items, config_path);
- }
-
- void IZ_JoystickInitializeConfigItems(INI_ConfigItem config_items[]) {
- u8 player_index;
- u8 control_index;
- char* main_section_name;
- char* control_mapping_section_name;
- for (player_index = 0; player_index < IZ_PLAYERS; player_index += 1) {
- main_section_name = IZ_calloc(64, sizeof(char));
- sprintf(main_section_name, "Joystick.%d", player_index);
- // The `+ 3` corresponds to the first three config items. Add as appropriate.
- u8 base_index = (player_index * (IZ_CONTROLS - 4 + 3));
- config_items[base_index] = (INI_ConfigItem) {
- INI_CONFIG_TYPE_I32,
- main_section_name,
- "DeviceID",
- NULL,
- &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.device_id,
- NULL,
- INI_CONFIG_TRANSFORMER_NONE,
- NULL,
- };
-
- config_items[base_index + 1] = (INI_ConfigItem) {
- INI_CONFIG_TYPE_U16,
- main_section_name,
- "AxisThreshold",
- NULL,
- &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.axis_threshold,
- IZ_JoystickIsValidAxisThreshold,
- INI_CONFIG_TRANSFORMER_NONE,
- NULL,
- };
-
- config_items[base_index + 2] = (INI_ConfigItem) {
- INI_CONFIG_TYPE_GUID,
- main_section_name,
- "GUID",
- NULL,
- &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.guid,
- NULL,
- INI_CONFIG_TRANSFORMER_NONE,
- NULL,
- };
-
- // todo add game controller GUID for determining mappings
-
- control_mapping_section_name = IZ_calloc(64, sizeof(char));
- sprintf(control_mapping_section_name, "Joystick.%d.ControlMapping", player_index);
- for (control_index = 4; control_index < IZ_CONTROLS; control_index += 1) {
- config_items[base_index + 3 + (control_index - 4)] = (INI_ConfigItem) {
- INI_CONFIG_TYPE_U8,
- control_mapping_section_name,
- IZ_ACTION_NAMES[control_index],
- NULL,
- &IZ_JOYSTICK_DEFAULT_STATE[player_index].config.control_mapping[control_index],
- NULL,
- INI_CONFIG_TRANSFORMER_NONE,
- NULL,
- };
- }
- }
-
- config_items[IZ_PLAYERS * (IZ_CONTROLS - 4 + 3)] = INI_CONFIG_ITEM_NULL;
- }
-
- IZ_ProcedureResult IZ_JoystickInitializeConfig(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
- IZ_JoystickInitializeConfigItems(joystick_config_items);
- IZ_JoystickBindStateToConfig(state, joystick_config_items);
- if (INI_ConfigInitialize(joystick_config_items, config_path, argc, argv) < 0) {
- return -1;
- }
- return 0;
- }
-
- IZ_ProcedureResult IZ_JoystickInitialize(IZ_JoystickState(* state)[IZ_PLAYERS], const char* config_path, u8 argc, const char* argv[]) {
- IZ_memcpy(state, sizeof(IZ_JoystickState) * IZ_PLAYERS, &IZ_JOYSTICK_DEFAULT_STATE, sizeof(IZ_JoystickState) * IZ_PLAYERS);
-
- // TODO query this file from the internet?
- SDL_GameControllerAddMappingsFromFile("assets/gamecontrollerdb.txt");
- u8 player_index;
-
- if (IZ_JoystickInitializeConfig(state, config_path, argc, argv) < 0) {
- return -2;
- }
-
- u8 joysticks_count = SDL_NumJoysticks();
- 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);
- if (!(*state)[player_index].device) {
- break;
- }
-
- (*state)[player_index].config.device_id = SDL_JoystickInstanceID((*state)[player_index].device);
- SDL_GUID joystick_guid = SDL_JoystickGetGUID((*state)[player_index].device);
- IZ_memcpy(&(*state)[player_index].config.guid, sizeof(SDL_GUID), &joystick_guid, sizeof(SDL_GUID));
- //(*state)[player_index].config.guid = joystick_guid;
-
- // printf("[INPUT:JOYSTICK] Initialize event from GUID: ");
- // for (u8 zz = 0; zz < 16; zz += 1) {
- // printf("%02x", (*state)[player_index].config.guid.data[zz]);
- // }
- // printf("\n");
- }
-
- // Post config (after joystick GUIDs have been queried), this is unique to joysticks since they can be plugged in any
- // time.
- INI_ConfigSaveResult post_config_save_result = IZ_JoystickSaveConfig(state, config_path);
- if (post_config_save_result < 0) {
- return -3;
- }
-
- 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);
- }
- }
|