Mercurial > molko
changeset 443:dfc65293d984
core: initial gamepad support
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 21 Jan 2023 20:20:34 +0100 |
parents | 9c3b3935f0aa |
children | 9f062143e675 |
files | GNUmakefile libmlk-core/mlk/core/event.c libmlk-core/mlk/core/event.h libmlk-core/mlk/core/gamepad.c libmlk-core/mlk/core/gamepad.h libmlk-core/mlk/core/sys.c |
diffstat | 6 files changed, 257 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/GNUmakefile Thu Nov 03 21:09:25 2022 +0100 +++ b/GNUmakefile Sat Jan 21 20:20:34 2023 +0100 @@ -193,6 +193,7 @@ libmlk-core/mlk/core/event.c \ libmlk-core/mlk/core/font.c \ libmlk-core/mlk/core/game.c \ + libmlk-core/mlk/core/gamepad.c \ libmlk-core/mlk/core/image.c \ libmlk-core/mlk/core/maths.c \ libmlk-core/mlk/core/music.c \
--- a/libmlk-core/mlk/core/event.c Thu Nov 03 21:09:25 2022 +0100 +++ b/libmlk-core/mlk/core/event.c Sat Jan 21 20:20:34 2023 +0100 @@ -175,6 +175,29 @@ { -1, MOUSE_BUTTON_NONE } }; +/* Maintain with enum mlk_gamepad_button in gamepad.h */ +static const struct { + int button; + enum mlk_gamepad_button value; +} pads[] = { + { SDL_CONTROLLER_BUTTON_A, MLK_GAMEPAD_BUTTON_A }, + { SDL_CONTROLLER_BUTTON_B, MLK_GAMEPAD_BUTTON_B }, + { SDL_CONTROLLER_BUTTON_X, MLK_GAMEPAD_BUTTON_X }, + { SDL_CONTROLLER_BUTTON_Y, MLK_GAMEPAD_BUTTON_Y }, + { SDL_CONTROLLER_BUTTON_BACK, MLK_GAMEPAD_BUTTON_BACK }, + { SDL_CONTROLLER_BUTTON_GUIDE, MLK_GAMEPAD_BUTTON_LOGO }, + { SDL_CONTROLLER_BUTTON_START, MLK_GAMEPAD_BUTTON_START }, + { SDL_CONTROLLER_BUTTON_LEFTSTICK, MLK_GAMEPAD_BUTTON_LTHUMB }, + { SDL_CONTROLLER_BUTTON_RIGHTSTICK, MLK_GAMEPAD_BUTTON_RTHUMB }, + { SDL_CONTROLLER_BUTTON_LEFTSHOULDER, MLK_GAMEPAD_BUTTON_LSHOULDER }, + { SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, MLK_GAMEPAD_BUTTON_RSHOULDER }, + { SDL_CONTROLLER_BUTTON_DPAD_UP, MLK_GAMEPAD_BUTTON_UP }, + { SDL_CONTROLLER_BUTTON_DPAD_DOWN, MLK_GAMEPAD_BUTTON_DOWN }, + { SDL_CONTROLLER_BUTTON_DPAD_LEFT, MLK_GAMEPAD_BUTTON_LEFT }, + { SDL_CONTROLLER_BUTTON_DPAD_RIGHT, MLK_GAMEPAD_BUTTON_RIGHT }, + { -1, MLK_GAMEPAD_BUTTON_UNKNOWN } +}; + static void convert_key(const SDL_Event *event, union event *ev) { @@ -222,11 +245,53 @@ } } +static void +convert_pad(const SDL_Event *event, union event *ev) +{ + ev->type = event->type == SDL_CONTROLLERBUTTONDOWN ? EVENT_PADDOWN : EVENT_PADUP; + + for (size_t i = 0; pads[i].value != MLK_GAMEPAD_BUTTON_UNKNOWN; ++i) { + if (pads[i].button == event->cbutton.button) { + ev->pad.button = pads[i].value; + break; + } + } +} + +static const struct { + int axis; + enum mlk_gamepad_axis value; +} axises[] = { + { SDL_CONTROLLER_AXIS_LEFTX, MLK_GAMEPAD_AXIS_LX }, + { SDL_CONTROLLER_AXIS_LEFTY, MLK_GAMEPAD_AXIS_LY }, + { SDL_CONTROLLER_AXIS_RIGHTX, MLK_GAMEPAD_AXIS_RX }, + { SDL_CONTROLLER_AXIS_RIGHTY, MLK_GAMEPAD_AXIS_RY }, + { SDL_CONTROLLER_AXIS_TRIGGERLEFT, MLK_GAMEPAD_AXIS_LTRIGGER }, + { SDL_CONTROLLER_AXIS_TRIGGERRIGHT, MLK_GAMEPAD_AXIS_RTRIGGER }, + { -1, MLK_GAMEPAD_AXIS_UNKNOWN } +}; + +static void +convert_axis(const SDL_Event *event, union event *ev) +{ + ev->type = EVENT_AXIS; + ev->axis.value = event->caxis.value; + + for (size_t i = 0; axises[i].value != MLK_GAMEPAD_AXIS_UNKNOWN; ++i) { + if (axises[i].axis == event->caxis.axis) { + ev->axis.axis = axises[i].value; + break; + } + } +} + int event_poll(union event *ev) { SDL_Event event; + memset(ev, 0, sizeof (*ev)); + /* * Loop until we find an event we want to report, we skip unneeded * ones. @@ -247,6 +312,13 @@ case SDL_MOUSEBUTTONUP: convert_click(&event, ev); return 1; + case SDL_CONTROLLERBUTTONDOWN: + case SDL_CONTROLLERBUTTONUP: + convert_pad(&event, ev); + return 1; + case SDL_CONTROLLERAXISMOTION: + convert_axis(&event, ev); + return 1; default: continue; }
--- a/libmlk-core/mlk/core/event.h Thu Nov 03 21:09:25 2022 +0100 +++ b/libmlk-core/mlk/core/event.h Sat Jan 21 20:20:34 2023 +0100 @@ -22,6 +22,7 @@ #include "core.h" #include "key.h" #include "mouse.h" +#include "gamepad.h" enum event_type { EVENT_CLICKDOWN, @@ -29,6 +30,9 @@ EVENT_KEYDOWN, EVENT_KEYUP, EVENT_MOUSE, + EVENT_PADUP, + EVENT_PADDOWN, + EVENT_AXIS, EVENT_QUIT, EVENT_NUM }; @@ -53,11 +57,24 @@ unsigned int clicks; }; +struct mlk_event_pad { + enum event_type type; + enum mlk_gamepad_button button; +}; + +struct mlk_event_axis { + enum event_type type; + enum mlk_gamepad_axis axis; + int value; +}; + union event { enum event_type type; struct event_key key; struct event_mouse mouse; struct event_click click; + struct mlk_event_pad pad; + struct mlk_event_axis axis; }; CORE_BEGIN_DECLS
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-core/mlk/core/gamepad.c Sat Jan 21 20:20:34 2023 +0100 @@ -0,0 +1,86 @@ +/* + * gamepad.c -- game controller support + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <assert.h> +#include <string.h> + +#include <SDL.h> + +#include "err.h" +#include "gamepad.h" + +int +mlk_gamepad_open(struct mlk_gamepad *pad, int idx) +{ + assert(pad); + + memset(pad, 0, sizeof (*pad)); + + if (!(pad->handle = SDL_GameControllerOpen(idx))) + return MLK_ERR_SDL; + + return 0; +} + +void +mlk_gamepad_finish(struct mlk_gamepad *pad) +{ + assert(pad); + + if (pad->handle) + SDL_GameControllerClose(pad->handle); + + memset(pad, 0, sizeof (*pad)); +} + +int +mlk_gamepad_iter_begin(struct mlk_gamepad_iter *it) +{ + assert(it); + + memset(it, 0, sizeof (*it)); + it->idx = -1; + + if ((it->end = SDL_NumJoysticks()) < 0) { + it->end = 0; + return MLK_ERR_SDL; + } + + return 0; +} + +int +mlk_gamepad_iter_next(struct mlk_gamepad_iter *it) +{ + /* + * Go to the next gamepad, we need to iterate because SDL can combines + * joystick and game controllers with the same API. + */ + for (++it->idx; it->idx < it->end && !SDL_IsGameController(it->idx); ++it->idx) + continue; + + /* End of iteration. */ + if (it->idx >= it->end) { + memset(it, 0, sizeof (*it)); + return 0; + } + + it->name = SDL_GameControllerNameForIndex(it->idx); + + return 1; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libmlk-core/mlk/core/gamepad.h Sat Jan 21 20:20:34 2023 +0100 @@ -0,0 +1,80 @@ +/* + * gamepad.h -- game controller support + * + * Copyright (c) 2020-2022 David Demelier <markand@malikania.fr> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef MLK_CORE_GAMEPAD_H +#define MLK_CORE_GAMEPAD_H + +#include "core.h" + +CORE_BEGIN_DECLS + +enum mlk_gamepad_button { + MLK_GAMEPAD_BUTTON_UNKNOWN, + MLK_GAMEPAD_BUTTON_A, + MLK_GAMEPAD_BUTTON_B, + MLK_GAMEPAD_BUTTON_X, + MLK_GAMEPAD_BUTTON_Y, + MLK_GAMEPAD_BUTTON_BACK, + MLK_GAMEPAD_BUTTON_LOGO, + MLK_GAMEPAD_BUTTON_START, + MLK_GAMEPAD_BUTTON_LTHUMB, + MLK_GAMEPAD_BUTTON_RTHUMB, + MLK_GAMEPAD_BUTTON_LSHOULDER, + MLK_GAMEPAD_BUTTON_RSHOULDER, + MLK_GAMEPAD_BUTTON_UP, + MLK_GAMEPAD_BUTTON_DOWN, + MLK_GAMEPAD_BUTTON_LEFT, + MLK_GAMEPAD_BUTTON_RIGHT +}; + +enum mlk_gamepad_axis { + MLK_GAMEPAD_AXIS_UNKNOWN, + MLK_GAMEPAD_AXIS_LX, + MLK_GAMEPAD_AXIS_LY, + MLK_GAMEPAD_AXIS_RX, + MLK_GAMEPAD_AXIS_RY, + MLK_GAMEPAD_AXIS_LTRIGGER, + MLK_GAMEPAD_AXIS_RTRIGGER +}; + +struct mlk_gamepad { + const char *name; + void *handle; +}; + +struct mlk_gamepad_iter { + const char *name; + int idx; + int end; +}; + +int +mlk_gamepad_open(struct mlk_gamepad *pad, int idx); + +void +mlk_gamepad_finish(struct mlk_gamepad *pad); + +int +mlk_gamepad_iter_begin(struct mlk_gamepad_iter *); + +int +mlk_gamepad_iter_next(struct mlk_gamepad_iter *); + +CORE_END_DECLS + +#endif /* !MLK_CORE_GAMEPAD_H */
--- a/libmlk-core/mlk/core/sys.c Thu Nov 03 21:09:25 2022 +0100 +++ b/libmlk-core/mlk/core/sys.c Sat Jan 21 20:20:34 2023 +0100 @@ -184,7 +184,7 @@ (void)name; /* SDL2. */ - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO) < 0) + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) return errorf("%s", SDL_GetError()); if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) return errorf("%s", SDL_GetError());