-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add basic gamepad support and button remapping #35
base: trunk
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this!
src/gamepad.h
Outdated
void Gamepad_Update(void); | ||
void Gamepad_CheckState(void); | ||
|
||
extern int btnbindings[NUM_KEYS]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NUM_KEYS
is the number of keyboard bindings. You'll want to define a new one, eg. NUM_GAMEPAD_BUTTONS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/swconf.h
Outdated
} type; | ||
union { | ||
void *v; | ||
bool *b; | ||
int *i; | ||
int *btn; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be unused. I think you're doing the right thing by just using .i
, but you can get rid of this field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I ended up keeping this for the moment: there's two spots in drawmenu()
and runmenu()
where we need to know whether we're in the keyboard menu, or in the gamepad menu, in order to do the correct action. (ie checking for CONF_KEY
vs CONF_BTN
)
I did play around with another way where CONF_BTN
was completely removed, where it was just like: if (!strcmp(title, "OPTIONS > GAMEPAD BINDINGS")) {
😅, but maybe I could create a new MENU_TYPE
that gets passed to runmenu when it gets executed? That might be the cleanest, and get rid of using CONF_BTN
altogether
src/sdl/swconf.c
Outdated
sprintf(btnString, "%d", *opt->value.i); // Convert integer to string | ||
swputs(btnString); | ||
break; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please remove the {}
braces here; they are misleading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/Makefile.am
Outdated
pcsound.h \ | ||
std.h \ | ||
swasynio.c swasynio.h \ | ||
swauto.c swauto.h \ | ||
swcollsn.c swcollsn.h \ | ||
swconf.c swconf.h \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move swconf.c
and swinit.c
back to their previous location, they don't belong in the sdl/ subdirectory.
I understand why you had to do this: the new feature requires using new SDL functions. But the correct way to do this is to create accessor functions to access them. For example, we have Vid_GetKey()
that is used by the configuration code to read a keypress. You need a similar function that your change_btn_binding
function can call to read a gamepad press.
In case it's not clear: the code in src/ is the "core code" of the game. The idea is that if someone wants to port the game to a new system where SDL isn't available, they should just be able to reimplement the files in src/sdl/ . Think of it as though there were multiple other directories alongside src/sdl/ - we wouldn't want to contain duplicate implementations of the initialization and configuration code for every one of them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad - I should've asked in Discord for some more context. This is all moved back and straightened out.
src/sdl/gamepad.c
Outdated
|
||
void Gamepad_Update(void) { | ||
if (!gamepad_initted || gamepad == NULL) { | ||
Gamepad_Init(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need to try to initialize again every time the function is called. Let's just return here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/sdl/gamepad.c
Outdated
if (!gamepad_initted) { | ||
return; | ||
} | ||
// Close the gamepad |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you try to be more consistent with your formatting? Not just talking about this one function but throughout the PR. You can see here that it's kind of a mess because you mixed up spaces and tabs.
The coding style for the project is to use tabs for indentation. If you configure your editor to not expand tabs to spaces then you'll probably get the right thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oof, sorry about that, I've fixed my settings there
In the changes today, I've also added support for looking up the button names so that they look nice now in the button config menu ✨ |
while (btn == -1) { | ||
if (SDL_WaitEventTimeout(&event, 10)) { | ||
if (event.type == SDL_CONTROLLERBUTTONDOWN) { | ||
btn = event.cbutton.button; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Justreturn event.cbutton.button;
and you can eliminate the btn
variable.
{ | ||
SDL_Event event; | ||
|
||
while (SDL_PollEvent(&event)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doing this means that there are now two event loops: the one in the gamepad code and the one in the video code. This will mean that some events get discarded mistakenly. You need to use a single combined event loop.
{ | ||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { | ||
printf("Gamepad could not initialize! SDL_Error: %s\n", SDL_GetError()); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
else if (...
btn = event.cbutton.button; | ||
break; | ||
} else if (event.type == SDL_KEYDOWN) { | ||
if (event.key.keysym.sym == SDLK_ESCAPE) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can combine the two if
statements with an &&
last_input_gamepad = input; | ||
} | ||
|
||
int isGamepadInitted(void) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can get rid of this function; just add a check to Gamepad_GetGameBtns
that returns 0
if !gamepad_initted
.
int tictime; | ||
|
||
/* generate a new move command and save it */ | ||
|
||
multkey = Vid_GetGameKeys(); | ||
if(isGamepadInitted()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason you can't just:
multkey = Vid_GetGameKeys() | Gamepad_GetGameBtns();
?
Then I think you can get rid of all the "LastInputGamepad" stuff entirely.
@@ -536,12 +533,12 @@ void Vid_SetVideoPalette(int palette) | |||
|
|||
const char* Vid_GetVideoPaletteName(int palette) | |||
{ | |||
return VideoPalettes[palette].name; | |||
return VideoPalettes[palette].name; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is too much indentation. Side note, can you try to avoid including unrelated changes?
Summary
Gamepad support version 1! Players can use their gamepads to fly the plane during gameplay, and remap buttons in the options screen.
In Xbox terms, these default controls have been set up:
Compatibility
These setups have been tested as working in gameplay and in remapping:
Implementation
gamepad.c
andgamepad.h
have been added to handle most gamepad input during gameplay.The most recent input device is tracked, to keep button handling from interfering with keyboard handling.
Gamepad Bindings
The options screen now supports remapping gamepad buttons:
Limitations
Future versions