소스 검색

Add gamepad/joystick support

Implement event handling for gamepads and joysticks.

In addition, the events are ordered according to SDL compatibility.
master
부모
커밋
cc63e9e338
6개의 변경된 파일186개의 추가작업 그리고 37개의 파일을 삭제
  1. +20
    -1
      src/packages/game/IZ_action.h
  2. +5
    -0
      src/packages/game/IZ_app.c
  3. +7
    -0
      src/packages/game/IZ_app.h
  4. +30
    -5
      src/packages/game/config/IZ_config.c
  5. +46
    -17
      src/packages/game/config/IZ_config.h
  6. +78
    -14
      src/packages/game/main.c

+ 20
- 1
src/packages/game/IZ_action.h 파일 보기

@@ -6,10 +6,10 @@
typedef uint16_t IZ_Action;

static const char* ACTION_NAMES[CONTROLS] = {
"Up",
"Right",
"Down",
"Left",
"Up",
"Affirm",
"Negate",
"Action0",
@@ -24,4 +24,23 @@ static const char* ACTION_NAMES[CONTROLS] = {
"Action9",
};

typedef enum {
IZ_ACTION_INDEX_UP,
IZ_ACTION_INDEX_RIGHT,
IZ_ACTION_INDEX_DOWN,
IZ_ACTION_INDEX_LEFT,
IZ_ACTION_INDEX_AFFIRM,
IZ_ACTION_INDEX_NEGATE,
IZ_ACTION_INDEX_ACTION0,
IZ_ACTION_INDEX_ACTION1,
IZ_ACTION_INDEX_ACTION2,
IZ_ACTION_INDEX_ACTION3,
IZ_ACTION_INDEX_ACTION4,
IZ_ACTION_INDEX_ACTION5,
IZ_ACTION_INDEX_ACTION6,
IZ_ACTION_INDEX_ACTION7,
IZ_ACTION_INDEX_ACTION8,
IZ_ACTION_INDEX_ACTION9,
} IZ_ActionIndex;

#endif

+ 5
- 0
src/packages/game/IZ_app.c 파일 보기

@@ -4,5 +4,10 @@ int IZ_InitializeApp(IZ_App* app) {
IZ_LoadConfig(&app->config);
IZ_SaveConfig(&app->config);

for (uint8_t p = 0; p < PLAYERS; p += 1) {
app->assigned_joysticks[p] = NULL;
app->actions[p] = 0;
}

return 0;
}

+ 7
- 0
src/packages/game/IZ_app.h 파일 보기

@@ -1,10 +1,17 @@
#ifndef IZ_APP_H
#define IZ_APP_H

#include <SDL_joystick.h>

#include "config/IZ_config.h"
#include "IZ_action.h"

typedef struct {
IZ_Config config;

IZ_Action actions[PLAYERS];

SDL_Joystick* assigned_joysticks[PLAYERS];
} IZ_App;

int IZ_InitializeApp(IZ_App*);


+ 30
- 5
src/packages/game/config/IZ_config.c 파일 보기

@@ -22,6 +22,11 @@ void IZ_SaveConfig(IZ_Config* config) {
fprintf_s(fp, "[Video]\n");
fprintf_s(fp, "Width=%u\n", config->video.width);
fprintf_s(fp, "Height=%u\n", config->video.height);
fprintf_s(fp, "MaxFps=%u\n", config->video.max_fps);
fprintf_s(fp, "\n");

fprintf_s(fp, "[Input]\n");
fprintf_s(fp, "GamepadAxisThreshold=%u\n", config->input.gamepad_axis_threshold);
fprintf_s(fp, "\n");

for (uint8_t p = 0; p < PLAYERS; p += 1) {
@@ -29,6 +34,12 @@ void IZ_SaveConfig(IZ_Config* config) {
for (uint8_t i = 0; i < CONTROLS; i += 1) {
fprintf_s(fp, "%s=%s\n", ACTION_NAMES[i], SDL_GetKeyName(config->controls[p].keyboard[i]));
}

fprintf_s(fp, "\n");
fprintf_s(fp, "[Controls.%u.Joystick]\n", p);
for (uint8_t i = 4; i < CONTROLS; i += 1) {
fprintf_s(fp, "%s=%d\n", ACTION_NAMES[i], config->controls[p].gamepad[i]);
}
}
}

@@ -37,11 +48,25 @@ void IZ_LoadConfig(IZ_Config* config) {
IZ_GetConfigPath(config_path);
config->video.width = ini_getl("Video", "Width", 640l, config_path);
config->video.height = ini_getl("Video", "Height", 480l, config_path);
config->video.max_fps = ini_getl("Video", "MaxFps", 30, config_path);
config->input.gamepad_axis_threshold = ini_getl("Input", "GamepadAxisThreshold", 8000, config_path);
char buffer[128];
char section_name[20] = "Controls.0.Keyboard";
for (uint8_t i = 0; i < CONTROLS; i += 1) {
section_name[9] = (char) (48 + i);
ini_gets(section_name, ACTION_NAMES[i], SDL_GetKeyName(IZ_DEFAULT_KEYBOARD_CONTROLS[i]), buffer, 128, config_path);
config->controls[0].keyboard[i] = SDL_GetKeyFromName(buffer);
char keyboard_section_name[20] = "Controls.0.Keyboard";
for (uint8_t p = 0; p < PLAYERS; p += 1) {
keyboard_section_name[9] = (char) (48 + p);
for (uint8_t i = 0; i < CONTROLS; i += 1) {
ini_gets(keyboard_section_name, ACTION_NAMES[i], SDL_GetKeyName(IZ_DEFAULT_KEYBOARD_CONTROLS[p][i]), buffer, 128,
config_path);
config->controls[p].keyboard[i] = SDL_GetKeyFromName(buffer);
}
}

char joystick_section_name[20] = "Controls.0.Joystick";
for (uint8_t p = 0; p < PLAYERS; p += 1) {
joystick_section_name[9] = (char) (48 + p);

for (uint8_t i = 4; i < CONTROLS; i += 1) {
config->controls[p].gamepad[i] = ini_getl(joystick_section_name, ACTION_NAMES[i], IZ_DEFAULT_JOYSTICK_CONTROLS[p][i], config_path);
}
}
}

+ 46
- 17
src/packages/game/config/IZ_config.h 파일 보기

@@ -7,8 +7,13 @@
typedef struct {
uint16_t width;
uint16_t height;
uint8_t max_fps;
} IZ_VideoConfig;

typedef struct {
uint16_t gamepad_axis_threshold;
} IZ_InputConfig;

typedef SDL_KeyCode IZ_KeyCode;

typedef int IZ_PadButton;
@@ -20,26 +25,50 @@ typedef struct {

typedef struct {
IZ_VideoConfig video;
IZ_InputConfig input;
IZ_ControlsConfig controls[PLAYERS];
} IZ_Config;

static const IZ_KeyCode IZ_DEFAULT_KEYBOARD_CONTROLS[CONTROLS] = {
SDLK_RIGHT,
SDLK_DOWN,
SDLK_LEFT,
SDLK_UP,
SDLK_RETURN, // yes
SDLK_BACKSPACE, // no
SDLK_a, // action0
SDLK_s, // action1
SDLK_d, // action2
SDLK_f, // action3
SDLK_z, // action4
SDLK_x, // action5
SDLK_c, // action6
SDLK_v, // action7
SDLK_w, // action8
SDLK_e, // action9
static const IZ_KeyCode IZ_DEFAULT_KEYBOARD_CONTROLS[PLAYERS][CONTROLS] = {
{
SDLK_UP,
SDLK_RIGHT,
SDLK_DOWN,
SDLK_LEFT,
SDLK_RETURN, // yes
SDLK_BACKSPACE, // no
SDLK_a, // action0
SDLK_s, // action1
SDLK_d, // action2
SDLK_f, // action3
SDLK_z, // action4
SDLK_x, // action5
SDLK_c, // action6
SDLK_v, // action7
SDLK_w, // action8
SDLK_e, // action9
},
};

static const uint8_t IZ_DEFAULT_JOYSTICK_CONTROLS[PLAYERS][CONTROLS] = {
{
255,
255,
255,
255,
11,
10,
1,
0,
4,
3,
6,
7,
8,
9,
13,
14,
},
};

void IZ_GetConfigPath(char* config_path);


+ 78
- 14
src/packages/game/main.c 파일 보기

@@ -39,7 +39,6 @@ int main(int argc, char* args[]) {
SDL_Event e;
screen_surface = SDL_GetWindowSurface(window);

IZ_Action action = 0;
while (!quit) {
SDL_FillRect(screen_surface, NULL, SDL_MapRGB(screen_surface->format, 0x00, 0x00, 0x00));
uint64_t ticks = SDL_GetTicks64();
@@ -63,24 +62,89 @@ int main(int argc, char* args[]) {
quit = true;
}

for (uint8_t i = 0; i < CONTROLS; i += 1) {
// TODO do same for gamepad
if (e.key.keysym.sym == app.config.controls[0].keyboard[i]) {
const uint16_t bitflag = (0x1 << i);
if (e.type == SDL_KEYDOWN) {
action |= bitflag;
} else if (e.type == SDL_KEYUP) {
action &= ~bitflag;
// Handle joystick events
for (uint8_t current_player = 0; current_player < PLAYERS; current_player += 1) {
if (e.type == SDL_JOYDEVICEADDED) {
if (SDL_NumJoysticks() <= PLAYERS && !app.assigned_joysticks[current_player]) {
app.assigned_joysticks[current_player] = SDL_JoystickOpen(e.jdevice.which);
}
}

if (e.type == SDL_JOYDEVICEREMOVED) {
if (
app.assigned_joysticks[current_player]
&& SDL_JoystickInstanceID(app.assigned_joysticks[current_player]) == e.jdevice.which
) {
app.assigned_joysticks[current_player] = NULL;
}
}

if (e.type == SDL_JOYAXISMOTION) {
if (e.jaxis.axis == 0 || e.jaxis.axis == 3) {
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_RIGHT);
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_LEFT);
if (e.jaxis.value > app.config.input.gamepad_axis_threshold) {
app.actions[current_player] |= (0x1 << IZ_ACTION_INDEX_RIGHT);
} else if (e.jaxis.value <= -app.config.input.gamepad_axis_threshold) {
app.actions[current_player] |= (0x1 << IZ_ACTION_INDEX_LEFT);
}
}
if (e.jaxis.axis == 1 || e.jaxis.axis == 4) {
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_UP);
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_DOWN);
if (e.jaxis.value > app.config.input.gamepad_axis_threshold) {
app.actions[current_player] |= (0x1 << IZ_ACTION_INDEX_DOWN);
} else if (e.jaxis.value <= -app.config.input.gamepad_axis_threshold) {
app.actions[current_player] |= (0x1 << IZ_ACTION_INDEX_UP);
}
}
}

if (e.type == SDL_JOYHATMOTION) {
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_UP);
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_RIGHT);
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_DOWN);
app.actions[current_player] &= ~(0x1 << IZ_ACTION_INDEX_LEFT);
if (e.jhat.value != 0) {
app.actions[current_player] |= e.jhat.value;
}
}
}

for (unsigned char i = 0; i < CONTROLS; i += 1) {
// Handle keyboard events
for (uint8_t current_player = 0; current_player < PLAYERS; current_player += 1) {
for (uint8_t i = 0; i < CONTROLS; i += 1) {
if (e.key.keysym.sym == app.config.controls[current_player].keyboard[i]) {
const uint16_t bitflag = (0x1 << i);
if (e.type == SDL_KEYDOWN) {
app.actions[current_player] |= bitflag;
} else if (e.type == SDL_KEYUP) {
app.actions[current_player] &= ~bitflag;
}
}

if (i >= 4) {
if (e.jbutton.button == app.config.controls[current_player].gamepad[i]) {
const uint16_t bitflag = (0x1 << i);
if (e.type == SDL_JOYBUTTONDOWN) {
app.actions[current_player] |= bitflag;
} else if (e.type == SDL_JOYBUTTONUP) {
app.actions[current_player] &= ~bitflag;
}
}
}
}
}
}

// Update window
for (uint8_t current_player = 0; current_player < PLAYERS; current_player += 1) {
for (uint8_t i = 0; i < CONTROLS; i += 1) {
const uint8_t column = i % 4;
const uint8_t row = i / 4;
const IZ_Action bitflag = (0x1 << i);
const IZ_Action bitflag = (0x1 << i);
const uint8_t size = 4;
if (action & bitflag) {
if (app.actions[current_player] & bitflag) {
SDL_FillRect(screen_surface, &(SDL_Rect) {
column * size,
row * size,
@@ -89,9 +153,9 @@ int main(int argc, char* args[]) {
}, SDL_MapRGB(screen_surface->format, 0xff, 0xff, 0x00));
}
}

SDL_UpdateWindowSurface(window);
}

SDL_UpdateWindowSurface(window);
}
SDL_DestroyWindow(window);
SDL_Quit();


불러오는 중...
취소
저장