Add better input parsing with key repeat tracking
This commit is contained in:
parent
22973ef51d
commit
80b35d404d
Binary file not shown.
@ -352,6 +352,42 @@ INTERNAL inline v4 getEntityScreenRect(Entity entity)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum ReadKeyType
|
||||||
|
{
|
||||||
|
readkeytype_oneShot,
|
||||||
|
readkeytype_delayedRepeat,
|
||||||
|
readkeytype_repeat,
|
||||||
|
readkeytype_count,
|
||||||
|
};
|
||||||
|
|
||||||
|
INTERNAL b32 getKeyStatus(KeyState key, enum ReadKeyType readType)
|
||||||
|
{
|
||||||
|
switch(readType)
|
||||||
|
{
|
||||||
|
case readkeytype_oneShot:
|
||||||
|
{
|
||||||
|
if (key.endedDown &&
|
||||||
|
(key.newHalfTransitionCount > key.oldHalfTransitionCount))
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case readkeytype_repeat:
|
||||||
|
{
|
||||||
|
if (key.endedDown) return TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case readkeytype_delayedRepeat:
|
||||||
|
default:
|
||||||
|
// TODO(doyle): Add delayed repeat of keys
|
||||||
|
#ifdef DENGINE_DEBUG
|
||||||
|
ASSERT(INVALID_CODE_PATH);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
INTERNAL void parseInput(GameState *state, const f32 dt)
|
INTERNAL void parseInput(GameState *state, const f32 dt)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -370,31 +406,52 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
Entity *hero = &world->entities[entity_getIndex(world, world->heroId)];
|
Entity *hero = &world->entities[entity_getIndex(world, world->heroId)];
|
||||||
v2 ddPos = V2(0, 0);
|
v2 ddPos = V2(0, 0);
|
||||||
|
|
||||||
|
KeyState *keys = state->input.keys;
|
||||||
|
for (i32 i = 0; i < keycode_count; i++)
|
||||||
|
{
|
||||||
|
KeyState *currKey = &keys[i];
|
||||||
|
if (currKey->newHalfTransitionCount > currKey->oldHalfTransitionCount)
|
||||||
|
{
|
||||||
|
i32 numTransitions = currKey->newHalfTransitionCount -
|
||||||
|
currKey->oldHalfTransitionCount;
|
||||||
|
|
||||||
|
if ((numTransitions & 1) == 1)
|
||||||
|
{
|
||||||
|
currKey->endedDown = ~currKey->endedDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(doyle): Multi press within frame override UI input parsing
|
||||||
|
if ((i >= keycode_A && i <= keycode_Z) ||
|
||||||
|
(i >= keycode_a && i <= keycode_z))
|
||||||
|
{
|
||||||
|
if (getKeyStatus(*currKey, readkeytype_oneShot))
|
||||||
|
{
|
||||||
|
state->uiState.keyChar = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (hero->stats->busyDuration <= 0)
|
if (hero->stats->busyDuration <= 0)
|
||||||
{
|
{
|
||||||
// TODO(doyle): As we need to handle more key spam input, we want to
|
if (getKeyStatus(keys[keycode_right], readkeytype_repeat))
|
||||||
// track
|
|
||||||
// if a button ended down
|
|
||||||
LOCAL_PERSIST b32 spaceBarWasDown = FALSE;
|
|
||||||
|
|
||||||
if (state->input.keys[keycode_right])
|
|
||||||
{
|
{
|
||||||
ddPos.x = 1.0f;
|
ddPos.x = 1.0f;
|
||||||
hero->direction = direction_east;
|
hero->direction = direction_east;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->input.keys[keycode_left])
|
if (getKeyStatus(keys[keycode_left], readkeytype_repeat))
|
||||||
{
|
{
|
||||||
ddPos.x = -1.0f;
|
ddPos.x = -1.0f;
|
||||||
hero->direction = direction_west;
|
hero->direction = direction_west;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->input.keys[keycode_up])
|
if (getKeyStatus(keys[keycode_up], readkeytype_repeat))
|
||||||
{
|
{
|
||||||
ddPos.y = 1.0f;
|
ddPos.y = 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->input.keys[keycode_down])
|
if (getKeyStatus(keys[keycode_down], readkeytype_repeat))
|
||||||
{
|
{
|
||||||
ddPos.y = -1.0f;
|
ddPos.y = -1.0f;
|
||||||
}
|
}
|
||||||
@ -408,18 +465,16 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
ddPos = v2_scale(ddPos, 0.70710678118f);
|
ddPos = v2_scale(ddPos, 0.70710678118f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (state->input.keys[keycode_enter])
|
if (getKeyStatus(keys[keycode_enter], readkeytype_oneShot))
|
||||||
{
|
{
|
||||||
state->uiState.keyEntered = keycode_enter;
|
state->uiState.keyEntered = keycode_enter;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCAL_PERSIST b32 toggleFlag = TRUE;
|
if (getKeyStatus(keys[keycode_space], readkeytype_oneShot))
|
||||||
// TODO(doyle): Revisit key input with state checking for last ended down
|
|
||||||
if (state->input.keys[keycode_space] && spaceBarWasDown == FALSE)
|
|
||||||
{
|
{
|
||||||
state->uiState.keyEntered = keycode_space;
|
state->uiState.keyEntered = keycode_space;
|
||||||
|
DEBUG_LOG("push space");
|
||||||
|
|
||||||
#if 0
|
|
||||||
Renderer *renderer = &state->renderer;
|
Renderer *renderer = &state->renderer;
|
||||||
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
f32 yPos = CAST(f32)(rand() % CAST(i32)renderer->size.h);
|
||||||
f32 xModifier = 5.0f - CAST(f32)(rand() % 3);
|
f32 xModifier = 5.0f - CAST(f32)(rand() % 3);
|
||||||
@ -427,12 +482,6 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos);
|
v2 pos = V2(renderer->size.w - (renderer->size.w / xModifier), yPos);
|
||||||
entity_addGenericMob(&state->arena, &state->assetManager, world,
|
entity_addGenericMob(&state->arena, &state->assetManager, world,
|
||||||
pos);
|
pos);
|
||||||
#endif
|
|
||||||
spaceBarWasDown = TRUE;
|
|
||||||
}
|
|
||||||
else if (!state->input.keys[keycode_space])
|
|
||||||
{
|
|
||||||
spaceBarWasDown = FALSE;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,7 +504,7 @@ INTERNAL void parseInput(GameState *state, const f32 dt)
|
|||||||
}
|
}
|
||||||
|
|
||||||
f32 heroSpeed = 6.2f * METERS_TO_PIXEL;
|
f32 heroSpeed = 6.2f * METERS_TO_PIXEL;
|
||||||
if (state->input.keys[keycode_leftShift])
|
if (state->input.keys[keycode_leftShift].endedDown)
|
||||||
{
|
{
|
||||||
// TODO: Context sensitive command separation
|
// TODO: Context sensitive command separation
|
||||||
state->uiState.keyMod = keycode_leftShift;
|
state->uiState.keyMod = keycode_leftShift;
|
||||||
@ -898,7 +947,7 @@ INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
|
|||||||
if (math_pointInRect(rect, input.mouseP))
|
if (math_pointInRect(rect, input.mouseP))
|
||||||
{
|
{
|
||||||
uiState->hotItem = id;
|
uiState->hotItem = id;
|
||||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
|
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
||||||
uiState->activeItem = id;
|
uiState->activeItem = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -963,7 +1012,7 @@ INTERNAL i32 button(UiState *uiState, AssetManager *assetManager,
|
|||||||
|
|
||||||
uiState->lastWidget = id;
|
uiState->lastWidget = id;
|
||||||
|
|
||||||
if (!input.keys[keycode_mouseLeft] &&
|
if (!input.keys[keycode_mouseLeft].endedDown &&
|
||||||
uiState->hotItem == id &&
|
uiState->hotItem == id &&
|
||||||
uiState->activeItem == id)
|
uiState->activeItem == id)
|
||||||
{
|
{
|
||||||
@ -984,7 +1033,7 @@ INTERNAL i32 scrollBar(UiState *uiState, AssetManager *assetManager,
|
|||||||
if (math_pointInRect(scrollBarRect, input.mouseP))
|
if (math_pointInRect(scrollBarRect, input.mouseP))
|
||||||
{
|
{
|
||||||
uiState->hotItem = id;
|
uiState->hotItem = id;
|
||||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
|
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
||||||
uiState->activeItem = id;
|
uiState->activeItem = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,7 +1144,7 @@ INTERNAL i32 textField(UiState *const uiState, MemoryArena *arena,
|
|||||||
if (math_pointInRect(textRect, input.mouseP))
|
if (math_pointInRect(textRect, input.mouseP))
|
||||||
{
|
{
|
||||||
uiState->hotItem = id;
|
uiState->hotItem = id;
|
||||||
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft])
|
if (uiState->activeItem == 0 && input.keys[keycode_mouseLeft].endedDown)
|
||||||
{
|
{
|
||||||
uiState->activeItem = id;
|
uiState->activeItem = id;
|
||||||
}
|
}
|
||||||
@ -1158,15 +1207,15 @@ INTERNAL i32 textField(UiState *const uiState, MemoryArena *arena,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (uiState->keyChar >= keycode_space &&
|
if (uiState->keyChar >= keycode_space &&
|
||||||
uiState->keyChar <= keycode_Z && strLen < 30)
|
uiState->keyChar <= keycode_tilda && strLen < 30)
|
||||||
{
|
{
|
||||||
string[strLen++] = uiState->keyChar;
|
string[strLen++] = uiState->keyChar + ' ';
|
||||||
string[strLen] = 0;
|
string[strLen] = 0;
|
||||||
changed = TRUE;
|
changed = TRUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input.keys[keycode_mouseLeft] &&
|
if (!input.keys[keycode_mouseLeft].endedDown &&
|
||||||
uiState->hotItem == id &&
|
uiState->hotItem == id &&
|
||||||
uiState->activeItem == id)
|
uiState->activeItem == id)
|
||||||
{
|
{
|
||||||
@ -1449,7 +1498,7 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
state->input, 5, V2(1000, 500), fieldString);
|
state->input, 5, V2(1000, 500), fieldString);
|
||||||
|
|
||||||
// RESET IMGUI
|
// RESET IMGUI
|
||||||
if (!state->input.keys[keycode_mouseLeft])
|
if (!state->input.keys[keycode_mouseLeft].endedDown)
|
||||||
state->uiState.activeItem = 0;
|
state->uiState.activeItem = 0;
|
||||||
else if (state->uiState.activeItem == 0)
|
else if (state->uiState.activeItem == 0)
|
||||||
state->uiState.activeItem = -1;
|
state->uiState.activeItem = -1;
|
||||||
@ -1500,6 +1549,12 @@ void worldTraveller_gameUpdateAndRender(GameState *state, f32 dt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i32 i = 0; i < keycode_count; i++)
|
||||||
|
{
|
||||||
|
state->input.keys[i].oldHalfTransitionCount =
|
||||||
|
state->input.keys[i].newHalfTransitionCount;
|
||||||
|
}
|
||||||
|
|
||||||
sortWorldEntityList(world, numDeadEntities);
|
sortWorldEntityList(world, numDeadEntities);
|
||||||
|
|
||||||
#ifdef DENGINE_DEBUG
|
#ifdef DENGINE_DEBUG
|
||||||
|
@ -5,10 +5,13 @@
|
|||||||
#include "Dengine/OpenGL.h"
|
#include "Dengine/OpenGL.h"
|
||||||
#include "Dengine/WorldTraveller.h"
|
#include "Dengine/WorldTraveller.h"
|
||||||
|
|
||||||
INTERNAL inline void processKey(b32 *currState, int key, int action)
|
INTERNAL inline void processKey(KeyState *state, int action)
|
||||||
{
|
{
|
||||||
if (action == GLFW_PRESS) *currState = TRUE;
|
// TODO(doyle): Handle GLFW_REPEAT, and probably remove this function
|
||||||
else if (action == GLFW_RELEASE) *currState = FALSE;
|
if (action == GLFW_PRESS || action == GLFW_RELEASE)
|
||||||
|
{
|
||||||
|
state->newHalfTransitionCount++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
|
INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
|
||||||
@ -24,32 +27,38 @@ INTERNAL void keyCallback(GLFWwindow *window, int key, int scancode, int action,
|
|||||||
switch (key)
|
switch (key)
|
||||||
{
|
{
|
||||||
case GLFW_KEY_UP:
|
case GLFW_KEY_UP:
|
||||||
processKey(&game->input.keys[keycode_up], key, action);
|
processKey(&game->input.keys[keycode_up], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_DOWN:
|
case GLFW_KEY_DOWN:
|
||||||
processKey(&game->input.keys[keycode_down], key, action);
|
processKey(&game->input.keys[keycode_down], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_LEFT:
|
case GLFW_KEY_LEFT:
|
||||||
processKey(&game->input.keys[keycode_left], key, action);
|
processKey(&game->input.keys[keycode_left], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_RIGHT:
|
case GLFW_KEY_RIGHT:
|
||||||
processKey(&game->input.keys[keycode_right], key, action);
|
processKey(&game->input.keys[keycode_right], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_LEFT_SHIFT:
|
case GLFW_KEY_LEFT_SHIFT:
|
||||||
processKey(&game->input.keys[keycode_leftShift], key, action);
|
processKey(&game->input.keys[keycode_leftShift], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_ENTER:
|
case GLFW_KEY_ENTER:
|
||||||
processKey(&game->input.keys[keycode_enter], key, action);
|
processKey(&game->input.keys[keycode_enter], action);
|
||||||
break;
|
break;
|
||||||
case GLFW_KEY_BACKSPACE:
|
case GLFW_KEY_BACKSPACE:
|
||||||
processKey(&game->input.keys[keycode_backspace], key, action);
|
processKey(&game->input.keys[keycode_backspace], action);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (key >= ' ' && key <= '~')
|
if (key >= ' ' && key <= '~')
|
||||||
{
|
{
|
||||||
processKey(&game->input.keys[key - ' '], key, action);
|
i32 offset = 0;
|
||||||
// TODO(doyle): Temporary
|
if (key >= 'A' && key <= 'Z')
|
||||||
game->uiState.keyChar = key - ' ';
|
{
|
||||||
|
if (!game->input.keys[keycode_leftShift].endedDown)
|
||||||
|
offset = 'a' - 'A';
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 glfwCodeToPlatformCode = (key - ' ') + offset;
|
||||||
|
processKey(&game->input.keys[glfwCodeToPlatformCode], action);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -73,7 +82,7 @@ INTERNAL void mouseButtonCallback(GLFWwindow *window, int button, int action,
|
|||||||
switch(button)
|
switch(button)
|
||||||
{
|
{
|
||||||
case GLFW_MOUSE_BUTTON_LEFT:
|
case GLFW_MOUSE_BUTTON_LEFT:
|
||||||
processKey(&game->input.keys[keycode_mouseLeft], button, action);
|
processKey(&game->input.keys[keycode_mouseLeft], action);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -11,7 +11,7 @@ typedef struct MemoryArena MemoryArena;
|
|||||||
// have a mapping function to map it back to ascii?
|
// have a mapping function to map it back to ascii?
|
||||||
enum KeyCode
|
enum KeyCode
|
||||||
{
|
{
|
||||||
keycode_space = 0,
|
keycode_space,
|
||||||
keycode_exclamation,
|
keycode_exclamation,
|
||||||
keycode_dbl_quotes,
|
keycode_dbl_quotes,
|
||||||
keycode_hash,
|
keycode_hash,
|
||||||
@ -24,7 +24,6 @@ enum KeyCode
|
|||||||
keycode_star,
|
keycode_star,
|
||||||
keycode_plus,
|
keycode_plus,
|
||||||
keycode_comma,
|
keycode_comma,
|
||||||
keycode_minus,
|
|
||||||
keycode_hyphen,
|
keycode_hyphen,
|
||||||
keycode_dot,
|
keycode_dot,
|
||||||
keycode_forward_slash,
|
keycode_forward_slash,
|
||||||
@ -114,16 +113,22 @@ enum KeyCode
|
|||||||
keycode_leftShift,
|
keycode_leftShift,
|
||||||
keycode_mouseLeft,
|
keycode_mouseLeft,
|
||||||
keycode_enter,
|
keycode_enter,
|
||||||
keycode_count,
|
|
||||||
keycode_backspace,
|
keycode_backspace,
|
||||||
keycode_tab,
|
keycode_count,
|
||||||
keycode_null,
|
keycode_null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct KeyState
|
||||||
|
{
|
||||||
|
u32 oldHalfTransitionCount;
|
||||||
|
u32 newHalfTransitionCount;
|
||||||
|
b32 endedDown;
|
||||||
|
} KeyState;
|
||||||
|
|
||||||
typedef struct KeyInput
|
typedef struct KeyInput
|
||||||
{
|
{
|
||||||
v2 mouseP;
|
v2 mouseP;
|
||||||
b32 keys[keycode_count - 1];
|
KeyState keys[keycode_count];
|
||||||
} KeyInput;
|
} KeyInput;
|
||||||
|
|
||||||
typedef struct PlatformFileRead
|
typedef struct PlatformFileRead
|
||||||
|
Loading…
Reference in New Issue
Block a user