Input bind complete.

This commit is contained in:
2025-09-08 13:30:27 -05:00
parent 16a0403fd4
commit 6fad5bef4a
9 changed files with 374 additions and 99 deletions

View File

@@ -17,11 +17,12 @@ void cmdBind(const consolecmdexec_t *exec) {
if(exec->argc == 1) {
consolePrint("TODO: Show binds");
// consolePrint("Current binds:");
// inputbinddata_t *data = INPUT.binds;
// do {
return;
}
// } while(data < INPUT.binds + INPUT_BIND_COUNT);
inputbutton_t button = inputButtonGetByName(exec->argv[0]);
if(button.type == INPUT_BUTTON_TYPE_NONE) {
consolePrint("Unknown button \"%s\"", exec->argv[0]);
return;
}
@@ -31,5 +32,7 @@ void cmdBind(const consolecmdexec_t *exec) {
return;
}
consolePrint("test");
// By default I unbind all.
inputUnbindButton(button);
inputBind(bind, button);
}

View File

@@ -7,6 +7,8 @@
target_sources(${DUSK_TARGET_NAME}
PRIVATE
input.c
inputbutton.c
inputbind.c
)
if(DUSK_TARGET_SYSTEM STREQUAL "linux")

View File

@@ -9,30 +9,23 @@
#include "assert/assert.h"
#include "util/memory.h"
#include "util/string.h"
char_t INPUT_BIND_NAMES[INPUT_BIND_COUNT][16] = {
[INPUT_BIND_UP] = "UP",
[INPUT_BIND_DOWN] = "DOWN",
[INPUT_BIND_LEFT] = "LEFT",
[INPUT_BIND_RIGHT] = "RIGHT",
[INPUT_BIND_ACCEPT] = "ACCEPT",
[INPUT_BIND_CANCEL] = "CANCEL",
[INPUT_BIND_CONSOLE] = "CONSOLE"
};
#include "util/math.h"
input_t INPUT;
void inputInit(void) {
memoryZero(&INPUT, sizeof(input_t));
INPUT.binds[INPUT_BIND_UP].keyboard[0] = SDL_SCANCODE_W;
INPUT.binds[INPUT_BIND_UP].keyboard[1] = SDL_SCANCODE_UP;
INPUT.binds[INPUT_BIND_CONSOLE].keyboard[0] = SDL_SCANCODE_GRAVE;
for(uint8_t i = 0; i < INPUT_BIND_COUNT; i++) {
INPUT.binds[i].bind = (inputbind_t)i;
INPUT.binds[i].lastValue = 0.0f;
INPUT.binds[i].currentValue = 0.0f;
}
}
void inputUpdate(void) {
#if INPUT_SDL2 == 1
const uint8_t *keyboardState = SDL_GetKeyboardState(NULL);
INPUT.keyboardState = SDL_GetKeyboardState(NULL);
#endif
// For each input bind...
@@ -41,20 +34,13 @@ void inputUpdate(void) {
data->lastValue = data->currentValue;
data->currentValue = 0.0f;
// Handle keyboard
#if INPUT_KEYBOARD == 1
for(uint32_t i = 0; i < INPUT_BIND_KEYBOARD_BUTTONS_MAX; i++) {
if(data->keyboard[i] == 0) break;
#if INPUT_SDL2 == 1
if(keyboardState[data->keyboard[i]]) {
data->currentValue = 1.0f;
break;
for(uint8_t i = 0; i < INPUT_BIND_BUTTONS_MAX; i++) {
inputbutton_t button = data->buttons[i];
if(button.type == INPUT_BUTTON_TYPE_NONE) continue;// TODO: Break?
data->currentValue = mathMax(
inputButtonGetValue(button), data->currentValue
);
}
#endif
}
#endif
data++;
} while(data < INPUT.binds + INPUT_BIND_COUNT);
}
@@ -85,12 +71,68 @@ bool_t inputReleased(const inputbind_t bind) {
return !inputIsDown(bind) && inputWasDown(bind);
}
inputbind_t inputBindGetByName(const char_t *name) {
assertNotNull(name, "name must not be NULL");
for(inputbind_t i = 0; i < INPUT_BIND_COUNT; i++) {
if(stringCompareInsensitive(INPUT_BIND_NAMES[i], name) == 0) {
return i;
void inputBind(const inputbind_t bind, const inputbutton_t button) {
assertTrue(bind < INPUT_BIND_COUNT, "Input bind out of bounds");
inputbinddata_t *data = &INPUT.binds[bind];
for(uint8_t i = 0; i < INPUT_BIND_BUTTONS_MAX; i++) {
if(data->buttons[i].type != INPUT_BUTTON_TYPE_NONE) continue;
data->buttons[i] = button;
return;
}
}
return INPUT_BIND_COUNT;
void inputUnbind(const inputbind_t bind, const inputbutton_t button) {
assertTrue(bind < INPUT_BIND_COUNT, "Input bind out of bounds");
inputbinddata_t *data = &INPUT.binds[bind];
for(uint8_t i = 0; i < INPUT_BIND_BUTTONS_MAX; i++) {
if(data->buttons[i].type == INPUT_BUTTON_TYPE_NONE) break;
if(memoryCompare(&data->buttons[i], &button, sizeof(inputbutton_t)) != 0) {
continue;
}
// Shift remaining buttons down
memoryMove(
&data->buttons[i],
&data->buttons[i + 1],
sizeof(inputbutton_t) * (INPUT_BIND_BUTTONS_MAX - i - 1)
);
data->buttons[INPUT_BIND_BUTTONS_MAX - 1].type = INPUT_BUTTON_TYPE_NONE;
return;
}
}
void inputUnbindAll(void) {
for(uint8_t i = 0; i < INPUT_BIND_COUNT; i++) {
memoryZero(
&INPUT.binds[i].buttons,
sizeof(inputbutton_t) * INPUT_BIND_BUTTONS_MAX
);
}
}
void inputUnbindButton(const inputbutton_t button) {
for(uint8_t i = 0; i < INPUT_BIND_COUNT; i++) {
inputbinddata_t *data = &INPUT.binds[i];
for(uint8_t j = 0; j < INPUT_BIND_BUTTONS_MAX; j++) {
if(data->buttons[j].type == INPUT_BUTTON_TYPE_NONE) break;
if(memoryCompare(&data->buttons[j], &button, sizeof(inputbutton_t)) != 0) {
continue;
}
inputUnbind((inputbind_t)i, button);
}
}
}
void inputUnbindBind(const inputbind_t bind) {
assertTrue(bind < INPUT_BIND_COUNT, "Input bind out of bounds");
memoryZero(
&INPUT.binds[bind].buttons,
sizeof(inputbutton_t) * INPUT_BIND_BUTTONS_MAX
);
}

View File

@@ -6,65 +6,19 @@
*/
#pragma once
#include "dusk.h"
#if INPUT_SDL2 == 1
#include <SDL2/SDL.h>
#else
#error "No input backend defined"
#endif
// Keyboard defs
#if INPUT_KEYBOARD == 1
#define INPUT_BIND_KEYBOARD_BUTTONS_MAX 32
#if INPUT_SDL2 == 1
typedef SDL_Scancode inputscancode_t;
#endif
#endif
// Gamepad defs
#if INPUT_GAMEPAD == 1
#define INPUT_GAMEPAD_BUTTON_NAME_MAX 8
#define INPUT_BIND_GAMEPAD_BUTTONS_MAX 8
#if INPUT_SDL2 == 1
typedef SDL_GameControllerButton inputgamepadbutton_t;
#endif
#endif
typedef enum {
INPUT_BIND_UP,
INPUT_BIND_DOWN,
INPUT_BIND_LEFT,
INPUT_BIND_RIGHT,
INPUT_BIND_ACCEPT,
INPUT_BIND_CANCEL,
INPUT_BIND_CONSOLE,
INPUT_BIND_COUNT
} inputbind_t;
typedef struct {
inputbind_t bind;
float_t lastValue;
float_t currentValue;
#if INPUT_GAMEPAD == 1
inputgamepadbutton_t gamepad[INPUT_BIND_GAMEPAD_BUTTONS_MAX];
uint8_t gamepadButtonCount;
#endif
#if INPUT_KEYBOARD == 1
inputscancode_t keyboard[INPUT_BIND_KEYBOARD_BUTTONS_MAX];
#endif
} inputbinddata_t;
#include "inputbutton.h"
#include "inputbind.h"
typedef struct {
inputbinddata_t binds[INPUT_BIND_COUNT];
#if INPUT_SDL2 == 1
#if INPUT_KEYBOARD == 1
const uint8_t *keyboardState;
#endif
#endif
} input_t;
extern char_t INPUT_BIND_NAMES[INPUT_BIND_COUNT][16];
extern input_t INPUT;
/**
@@ -127,9 +81,36 @@ bool_t inputPressed(const inputbind_t bind);
bool_t inputReleased(const inputbind_t bind);
/**
* Gets an input bind by its name.
* Binds an input button to a specific input bind.
*
* @param name The name of the input bind.
* @return The input bind, or INPUT_BIND_COUNT if not found.
* @param bind The input bind to bind the button to.
* @param button The input button to bind.
*/
inputbind_t inputBindGetByName(const char_t *name);
void inputBind(const inputbind_t bind, const inputbutton_t button);
/**
* Unbinds an input button from a specific input bind.
*
* @param bind The input bind to unbind the button from.
* @param button The input button to unbind.
*/
void inputUnbind(const inputbind_t bind, const inputbutton_t button);
/**
* Unbinds all input buttons from all input binds.
*/
void inputUnbindAll();
/**
* Unbinds an input button from all input binds.
*
* @param button The input button to unbind.
*/
void inputUnbindButton(const inputbutton_t button);
/**
* Unbinds all input buttons from a specific input bind.
*
* @param bind The input bind to unbind all buttons from.
*/
void inputUnbindBind(const inputbind_t bind);

30
src/input/inputbind.c Normal file
View File

@@ -0,0 +1,30 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "inputbind.h"
#include "assert/assert.h"
#include "util/string.h"
const char_t INPUT_BIND_NAMES[INPUT_BIND_COUNT][INPUT_BIND_NAME_MAX] = {
[INPUT_BIND_UP] = "UP",
[INPUT_BIND_DOWN] = "DOWN",
[INPUT_BIND_LEFT] = "LEFT",
[INPUT_BIND_RIGHT] = "RIGHT",
[INPUT_BIND_ACCEPT] = "ACCEPT",
[INPUT_BIND_CANCEL] = "CANCEL",
[INPUT_BIND_CONSOLE] = "CONSOLE"
};
inputbind_t inputBindGetByName(const char_t *name) {
assertNotNull(name, "name must not be NULL");
for(inputbind_t i = 0; i < INPUT_BIND_COUNT; i++) {
if(stringCompareInsensitive(INPUT_BIND_NAMES[i], name) == 0) {
return i;
}
}
return INPUT_BIND_COUNT;
}

41
src/input/inputbind.h Normal file
View File

@@ -0,0 +1,41 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "inputbutton.h"
#define INPUT_BIND_NAME_MAX 16
#define INPUT_BIND_BUTTONS_MAX 32
typedef enum {
INPUT_BIND_UP,
INPUT_BIND_DOWN,
INPUT_BIND_LEFT,
INPUT_BIND_RIGHT,
INPUT_BIND_ACCEPT,
INPUT_BIND_CANCEL,
INPUT_BIND_CONSOLE,
INPUT_BIND_COUNT
} inputbind_t;
typedef struct {
inputbind_t bind;
float_t lastValue;
float_t currentValue;
inputbutton_t buttons[INPUT_BIND_BUTTONS_MAX];
} inputbinddata_t;
extern const char_t INPUT_BIND_NAMES[INPUT_BIND_COUNT][INPUT_BIND_NAME_MAX];
/**
* Gets an input bind by its name.
*
* @param name The name of the input bind.
* @return The input bind, or INPUT_BIND_COUNT if not found.
*/
inputbind_t inputBindGetByName(const char_t *name);

69
src/input/inputbutton.c Normal file
View File

@@ -0,0 +1,69 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "inputbutton.h"
#include "input.h"
#include "assert/assert.h"
#include "util/string.h"
const inputbuttondata_t INPUT_BUTTON_DATA[] = {
#if INPUT_SDL2 == 1
#if INPUT_GAMEPAD == 1
#if PSP
#else
#endif
#endif
#if INPUT_KEYBOARD == 1
{ .name = "a", { .type = INPUT_BUTTON_TYPE_KEYBOARD, .scancode = SDL_SCANCODE_A } },
{ .name = "`", { .type = INPUT_BUTTON_TYPE_KEYBOARD, .scancode = SDL_SCANCODE_GRAVE } },
#endif
#endif
};
inputbutton_t inputButtonGetByName(const char_t *name) {
assertNotNull(name, "name must not be NULL");
uint32_t len = sizeof(INPUT_BUTTON_DATA) / sizeof(inputbuttondata_t);
for(uint32_t i = 0; i < len; i++) {
if(stringCompareInsensitive(INPUT_BUTTON_DATA[i].name, name) != 0) continue;
return INPUT_BUTTON_DATA[i].button;
}
return (inputbutton_t){ .type = INPUT_BUTTON_TYPE_NONE };
}
float_t inputButtonGetValue(const inputbutton_t button) {
switch(button.type) {
#if INPUT_KEYBOARD == 1
case INPUT_BUTTON_TYPE_KEYBOARD: {
#if INPUT_SDL2 == 1
return INPUT.keyboardState[button.scancode] ? 1.0f : 0.0f;
#else
return 0.0f;
#endif
}
#endif
#if INPUT_GAMEPAD == 1
case INPUT_BUTTON_TYPE_GAMEPAD: {
#if INPUT_SDL2 == 1
if(SDL_GameControllerGetButton(
SDL_GameControllerFromInstanceID(0), button.gpButton
)) return 1.0f;
#endif
return 0.0f;
}
#endif
default: {
assertUnreachable("Unknown input button type");
return 0.0f;
}
}
}

79
src/input/inputbutton.h Normal file
View File

@@ -0,0 +1,79 @@
/**
* Copyright (c) 2025 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dusk.h"
#if INPUT_SDL2 == 1
#include <SDL2/SDL.h>
#else
#error "No input backend defined"
#endif
// Keyboard defs
#if INPUT_KEYBOARD == 1
#if INPUT_SDL2 == 1
typedef SDL_Scancode inputscancode_t;
#endif
#endif
// Gamepad defs
#if INPUT_GAMEPAD == 1
#if INPUT_SDL2 == 1
typedef SDL_GameControllerButton inputgamepadbutton_t;
#endif
#endif
typedef enum {
INPUT_BUTTON_TYPE_NONE,
#if INPUT_KEYBOARD == 1
INPUT_BUTTON_TYPE_KEYBOARD,
#endif
#if INPUT_GAMEPAD == 1
INPUT_BUTTON_TYPE_GAMEPAD,
#endif
INPUT_BUTTON_TYPE_COUNT
} inputbuttontype_t;
typedef struct {
inputbuttontype_t type;
union {
#if INPUT_GAMEPAD == 1
inputgamepadbutton_t gpButton;
#endif
#if INPUT_KEYBOARD == 1
inputscancode_t scancode;
#endif
};
} inputbutton_t;
typedef struct {
const char_t *name;
inputbutton_t button;
} inputbuttondata_t;
extern const inputbuttondata_t INPUT_BUTTON_DATA[];
/**
* Gets an input button by its name.
*
* @param name The name of the input button.
* @return The input button, or .type = INPUT_BUTTON_TYPE_NONE if not found.
*/
inputbutton_t inputButtonGetByName(const char_t *name);
/**
* Gets the current value of an input button.
*
* @param button The input button.
* @return The current value of the input button (0.0f to 1.0f).
*/
float_t inputButtonGetValue(const inputbutton_t button);

View File

@@ -15,3 +15,31 @@
* @return The next power of two greater than or equal to the value.
*/
uint32_t mathNextPowTwo(uint32_t value);
/**
* Returns the maximum of two values.
*
* @param a The first value.
* @param b The second value.
* @return The maximum of the two values.
*/
#define mathMax(a, b) ((a) > (b) ? (a) : (b))
/**
* Returns the minimum of two values.
*
* @param a The first value.
* @param b The second value.
* @return The minimum of the two values.
*/
#define mathMin(a, b) ((a) < (b) ? (a) : (b))
/**
* Clamps a value between a lower and upper bound.
*
* @param x The value to clamp.
* @param lower The lower bound.
* @param upper The upper bound.
* @return The clamped value.
*/
#define mathClamp(x, lower, upper) (mathMin(upper, mathMax(lower, x)))