Fixed input handling for events that need to be held. Added support for events that only get called on a button release

This commit is contained in:
Peter Slattery 2019-11-01 09:09:05 -07:00
parent 10cc9a4e95
commit 22e15858e5
8 changed files with 103 additions and 76 deletions

View File

@ -350,18 +350,18 @@ RELOAD_STATIC_DATA(ReloadStaticData)
if (State->InputCommandRegistry.Size > 0) if (State->InputCommandRegistry.Size > 0)
{ {
RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_MouseLeftButton, true, KeyCode_Invalid, RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_MouseLeftButton, Command_Began | Command_Held | Command_Ended, KeyCode_Invalid,
CameraMouseControl); CameraMouseControl);
RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_U, false, KeyCode_Invalid, OpenUniverseView); RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_U, Command_Began, KeyCode_Invalid, OpenUniverseView);
RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_A, false, KeyCode_Invalid, OpenNodeLister); RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_A, Command_Began, KeyCode_Invalid, OpenNodeLister);
RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_Tab, false, KeyCode_Invalid, OpenNodeView); RegisterKeyPressCommand(&State->InputCommandRegistry, KeyCode_Tab, Command_Began, KeyCode_Invalid, OpenNodeView);
// Node Lister // Node Lister
RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_DownArrow, false, KeyCode_Invalid, NodeListerNextItem); RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_DownArrow, Command_Began, KeyCode_Invalid, NodeListerNextItem);
RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_UpArrow, false, KeyCode_Invalid, NodeListerPrevItem); RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_UpArrow, Command_Began, KeyCode_Invalid, NodeListerPrevItem);
RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_Enter, false, KeyCode_Invalid, SelectAndCloseNodeLister); RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_Enter, Command_Began, KeyCode_Invalid, SelectAndCloseNodeLister);
RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_MouseLeftButton, false, KeyCode_Invalid, CloseNodeLister); RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_MouseLeftButton, Command_Began, KeyCode_Invalid, CloseNodeLister);
RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_Esc, false, KeyCode_Invalid, CloseNodeLister); RegisterKeyPressCommand(&State->NodeListerCommandRegistry, KeyCode_Esc, Command_Began, KeyCode_Invalid, CloseNodeLister);
InitializeTextInputCommands(&State->NodeListerCommandRegistry, State->Permanent); InitializeTextInputCommands(&State->NodeListerCommandRegistry, State->Permanent);
} }
} }
@ -511,12 +511,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
ActivateQueuedCommandRegistry(State); ActivateQueuedCommandRegistry(State);
// CommandQueue holds the list of commands, generated from the current InputCommandRegistry
// Every command entry in the queue should be executed.
// For every Input Event, attempt to add an entry to the CommandQueue if an appropriate command
// exists in ActiveCommands
RemoveNonPersistantCommandsFromQueueAndUpdatePersistentEvents(&State->CommandQueue);
for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++)
{ {
input_entry Event = InputQueue.Entries[EventIdx]; input_entry Event = InputQueue.Entries[EventIdx];
@ -524,13 +518,23 @@ UPDATE_AND_RENDER(UpdateAndRender)
input_command* Command = FindExistingCommand(ActiveCommands, Event.Key, (key_code)0); input_command* Command = FindExistingCommand(ActiveCommands, Event.Key, (key_code)0);
if (Command) if (Command)
{ {
if (KeyTransitionedDown(Event)) if ((KeyTransitionedDown(Event) && ((Command->Flags & Command_Began) > 0)))
{ {
PushCommandOnQueue(&State->CommandQueue, *Command, Event); PushCommandOnQueue(&State->CommandQueue,
*Command,
Event,
(Command->Flags & Command_Held) == 0);
} }
else if (Command->PersistsUntilReleased && KeyTransitionedUp(Event)) else if (KeyTransitionedUp(Event) && ((Command->Flags & Command_Ended) > 0))
{ {
RemoveCommandFromQueue(&State->CommandQueue, *Command, Event); if ((Command->Flags & Command_Held) == 0)
{
PushCommandOnQueue(&State->CommandQueue, *Command, Event, true);
}
else
{
FlagCommandForRemoval(&State->CommandQueue, *Command, Event);
}
} }
} }
@ -552,11 +556,13 @@ UPDATE_AND_RENDER(UpdateAndRender)
} }
// Execute all commands in CommandQueue // Execute all commands in CommandQueue
for (s32 CommandIdx = 0; CommandIdx < State->CommandQueue.Used; CommandIdx++) for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--)
{ {
command_queue_entry Entry = State->CommandQueue.Commands[CommandIdx]; command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx];
Entry.Command.Proc(State, Entry.Event, Mouse); Entry->Command.Proc(State, Entry->Event, Mouse);
} }
RemoveNonPersistantCommandsFromQueueAndUpdatePersistentEvents(&State->CommandQueue);
} }
if (State->LEDBufferList) if (State->LEDBufferList)
@ -746,9 +752,6 @@ UPDATE_AND_RENDER(UpdateAndRender)
// Figuring Out Nodes // Figuring Out Nodes
////////////////////////////////////// //////////////////////////////////////
//NodeViewMousePickNode(State, {}, Mouse);
//RenderNodeView(State, RenderBuffer, {}, Mouse);
for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) for (s32 m = 0; m < State->Modes.ActiveModesCount; m++)
{ {
operation_mode OperationMode = State->Modes.ActiveModes[m]; operation_mode OperationMode = State->Modes.ActiveModes[m];

View File

@ -29,7 +29,7 @@ FindExistingCommand (input_command_registry* CommandRegistry, key_code Key, key_
internal void internal void
RegisterKeyPressCommand (input_command_registry* CommandRegistry, RegisterKeyPressCommand (input_command_registry* CommandRegistry,
key_code Key, key_code Key,
b32 PersistsUntilReleased, b32 Flags,
key_code Mdfr, key_code Mdfr,
input_command_proc* Proc) input_command_proc* Proc)
{ {
@ -44,7 +44,7 @@ RegisterKeyPressCommand (input_command_registry* CommandRegistry,
} }
Command->Key = Key; Command->Key = Key;
Command->PersistsUntilReleased = PersistsUntilReleased; Command->Flags = Flags;
Command->Mdfr = Mdfr; Command->Mdfr = Mdfr;
Command->Proc = Proc; Command->Proc = Proc;
} }
@ -56,6 +56,22 @@ RegisterMouseWheelCommand (input_command_registry* CommandRegistry,
CommandRegistry->MouseWheelCommand = Proc; CommandRegistry->MouseWheelCommand = Proc;
} }
internal s32
GetCommandIndexInQueue(input_command_queue* Queue, input_command Command, input_entry Event)
{
s32 Result = -1;
for (s32 CommandIndex = 0; CommandIndex < Queue->Used; CommandIndex++)
{
command_queue_entry* Entry = Queue->Commands + CommandIndex;
if(Entry->Event.Key == Event.Key)
{
Result = CommandIndex;
break;
}
}
return Result;
}
internal input_command_queue internal input_command_queue
InitializeCommandQueue(command_queue_entry* Memory, s32 MemorySize) InitializeCommandQueue(command_queue_entry* Memory, s32 MemorySize)
{ {
@ -73,7 +89,7 @@ RemoveNonPersistantCommandsFromQueueAndUpdatePersistentEvents(input_command_queu
for (s32 i = 0; i < Queue->Used; i++) for (s32 i = 0; i < Queue->Used; i++)
{ {
command_queue_entry* Entry = Queue->Commands + i; command_queue_entry* Entry = Queue->Commands + i;
if (Entry->Command.PersistsUntilReleased) if (!Entry->RemoveOnExecute)
{ {
Entry->Event.State |= KeyState_WasDown; Entry->Event.State |= KeyState_WasDown;
// NOTE(Peter): If i == PersistantCommandsCount, then we don't need to copy the // NOTE(Peter): If i == PersistantCommandsCount, then we don't need to copy the
@ -89,27 +105,42 @@ RemoveNonPersistantCommandsFromQueueAndUpdatePersistentEvents(input_command_queu
} }
internal void internal void
PushCommandOnQueue(input_command_queue* Queue, input_command Command, input_entry Event) PushCommandOnQueue(input_command_queue* Queue, input_command Command, input_entry Event, b32 RemoveOnExecute)
{ {
Assert(Queue->Used < Queue->Size); Assert(Queue->Used < Queue->Size);
command_queue_entry Entry = {}; command_queue_entry Entry = {};
Entry.Command = Command; Entry.Command = Command;
Entry.Event = Event; Entry.Event = Event;
Entry.RemoveOnExecute = RemoveOnExecute;
Queue->Commands[Queue->Used++] = Entry; Queue->Commands[Queue->Used++] = Entry;
} }
internal void
FlagCommandForRemoval(input_command_queue* Queue, input_command Command, input_entry Event)
{
s32 CommandIndex = GetCommandIndexInQueue(Queue, Command, Event);
Queue->Commands[CommandIndex].RemoveOnExecute = true;
}
internal void
RemoveCommandFromQueue(input_command_queue* Queue, s32 Index)
{
s32 CommandIndex = Index;
if (CommandIndex < Queue->Used)
{
Queue->Used -= 1;
for (; CommandIndex < Queue->Used; CommandIndex++)
{
Queue->Commands[CommandIndex] = Queue->Commands[CommandIndex + 1];
}
}
}
internal void internal void
RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_entry Event) RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_entry Event)
{ {
s32 CommandIndex = 0; s32 CommandIndex = GetCommandIndexInQueue(Queue, Command, Event);
for (CommandIndex = 0; CommandIndex < Queue->Used; CommandIndex++)
{
command_queue_entry* Entry = Queue->Commands + CommandIndex;
if(Entry->Event.Key == Event.Key)
{
break;
}
}
// NOTE(Peter): If we made it through the queue without finding an event, there wasn't one // NOTE(Peter): If we made it through the queue without finding an event, there wasn't one
// to remove. This happens when we've changed command registries as a result of an input command, // to remove. This happens when we've changed command registries as a result of an input command,
@ -121,15 +152,7 @@ RemoveCommandFromQueue(input_command_queue* Queue, input_command Command, input_
// For this reason, I'm allowing the case where we try and remove a command where non exists // For this reason, I'm allowing the case where we try and remove a command where non exists
// I don't think this is a great solution but Im not super familiar with the codebase right now // I don't think this is a great solution but Im not super familiar with the codebase right now
// so leaving it as is. revisit if it becomes a problem. // so leaving it as is. revisit if it becomes a problem.
if (CommandIndex < Queue->Used) RemoveCommandFromQueue(Queue, CommandIndex);
{
Queue->Used -= 1;
for (; CommandIndex < Queue->Used; CommandIndex++)
{
Queue->Commands[CommandIndex] = Queue->Commands[CommandIndex + 1];
}
}
} }
internal void internal void

View File

@ -1,21 +1,19 @@
#if USAGE_CODE
RegisterInputCommand(KeyCode_UpArrow, SACNView_DrawNextUniverse, Context);
RegisterInputCommand(KeyCode_MouseLeftButton, PanCamera, Context);
ExecuteRegisteredCommands(Context, Input);
#endif // USAGE_CODE
#define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse) #define FOLDHAUS_INPUT_COMMAND_PROC(name) void name(app_state* State, input_entry Event, mouse_state Mouse)
typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc); typedef FOLDHAUS_INPUT_COMMAND_PROC(input_command_proc);
enum input_command_flags
{
Command_Began = 1 << 0,
Command_Held = 1 << 1,
Command_Ended = 1 << 2,
};
// TODO(Peter): At the moment these are all key press commands. Need a way to differentiate between // TODO(Peter): At the moment these are all key press commands. Need a way to differentiate between
// press and hold. Probably add a second array to input_command_Registry // press and hold. Probably add a second array to input_command_Registry
struct input_command struct input_command
{ {
key_code Key; key_code Key;
b32 PersistsUntilReleased; b32 Flags;
key_code Mdfr; key_code Mdfr;
input_command_proc* Proc; input_command_proc* Proc;
}; };
@ -33,6 +31,7 @@ struct command_queue_entry
{ {
input_command Command; input_command Command;
input_entry Event; input_entry Event;
b32 RemoveOnExecute;
}; };
struct input_command_queue struct input_command_queue

View File

@ -20,12 +20,13 @@ DrawDebugInterface (render_command_buffer* RenderBuffer, r32 StartX, interface_c
r32 FramesPerSecond = 1.0f / DeltaTime; r32 FramesPerSecond = 1.0f / DeltaTime;
PrintF(&DebugString, "Framerate: %.*f s %d fps | Modes: %d Memory Used: %d / %d", PrintF(&DebugString, "Framerate: %.*f s %d fps | Modes: %d Memory Used: %d / %d | Commands: %d",
5, DeltaTime, 5, DeltaTime,
(u32)FramesPerSecond, (u32)FramesPerSecond,
State->Modes.ActiveModesCount, State->Modes.ActiveModesCount,
State->Modes.Arena.CurrentRegion->Used, State->Modes.Arena.CurrentRegion->Used,
State->Modes.Arena.CurrentRegion->Size); State->Modes.Arena.CurrentRegion->Size,
State->CommandQueue.Used);
DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize, TopOfScreenLinePos, WhiteV4); DrawString(RenderBuffer, DebugString, Interface.Font, Interface.FontSize, TopOfScreenLinePos, WhiteV4);
v2 ButtonDim = v2{200, (r32)NewLineYOffset(*Interface.Font) + 10}; v2 ButtonDim = v2{200, (r32)NewLineYOffset(*Interface.Font) + 10};

View File

@ -109,8 +109,8 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenUniverseView)
{ // Mode Commands { // Mode Commands
InitializeInputCommandRegistry(&UniverseViewMode->Commands, 3, &State->Modes.Arena); InitializeInputCommandRegistry(&UniverseViewMode->Commands, 3, &State->Modes.Arena);
RegisterKeyPressCommand(&UniverseViewMode->Commands, KeyCode_MouseLeftButton, true, KeyCode_Invalid, UniverseViewPan); RegisterKeyPressCommand(&UniverseViewMode->Commands, KeyCode_MouseLeftButton, Command_Began | Command_Ended, KeyCode_Invalid, UniverseViewPan);
RegisterKeyPressCommand(&UniverseViewMode->Commands, KeyCode_U, false, KeyCode_Invalid, CloseUniverseView); RegisterKeyPressCommand(&UniverseViewMode->Commands, KeyCode_U, Command_Began, KeyCode_Invalid, CloseUniverseView);
RegisterMouseWheelCommand(&UniverseViewMode->Commands, UniverseZoom); RegisterMouseWheelCommand(&UniverseViewMode->Commands, UniverseZoom);
} }
@ -198,11 +198,11 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeLister)
{ // Mode Commands { // Mode Commands
InitializeInputCommandRegistry(&AddNodeOperation->Commands, 128, &State->Modes.Arena); InitializeInputCommandRegistry(&AddNodeOperation->Commands, 128, &State->Modes.Arena);
RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_DownArrow, false, KeyCode_Invalid, NodeListerNextItem); RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_DownArrow, Command_Began, KeyCode_Invalid, NodeListerNextItem);
RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_UpArrow, false, KeyCode_Invalid, NodeListerPrevItem); RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_UpArrow, Command_Began, KeyCode_Invalid, NodeListerPrevItem);
RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_Enter, false, KeyCode_Invalid, SelectAndCloseNodeLister); RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_Enter, Command_Began, KeyCode_Invalid, SelectAndCloseNodeLister);
RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_MouseLeftButton, false, KeyCode_Invalid, CloseNodeLister); RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_MouseLeftButton, Command_Began, KeyCode_Invalid, CloseNodeLister);
RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_Esc, false, KeyCode_Invalid, CloseNodeLister); RegisterKeyPressCommand(&AddNodeOperation->Commands, KeyCode_Esc, Command_Began, KeyCode_Invalid, CloseNodeLister);
InitializeTextInputCommands(&AddNodeOperation->Commands, &State->Modes.Arena); InitializeTextInputCommands(&AddNodeOperation->Commands, &State->Modes.Arena);
} }
@ -373,9 +373,9 @@ FOLDHAUS_INPUT_COMMAND_PROC(OpenNodeView)
{ // Mode Commands { // Mode Commands
InitializeInputCommandRegistry(&NodeViewMode->Commands, 3, &State->Modes.Arena); InitializeInputCommandRegistry(&NodeViewMode->Commands, 3, &State->Modes.Arena);
RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_Tab, false, KeyCode_Invalid, CloseNodeView); RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_Tab, Command_Began, KeyCode_Invalid, CloseNodeView);
RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_A, false, KeyCode_Invalid, OpenNodeLister); RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_A, Command_Began, KeyCode_Invalid, OpenNodeLister);
RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_MouseLeftButton, true, KeyCode_Invalid, RegisterKeyPressCommand(&NodeViewMode->Commands, KeyCode_MouseLeftButton, Command_Began | Command_Ended, KeyCode_Invalid,
NodeViewMousePickNode); NodeViewMousePickNode);
} }

View File

@ -107,13 +107,13 @@ InitializeTextInputCommands (input_command_registry* Commands, memory_arena* Per
{ {
if (Commands->Size > 0) if (Commands->Size > 0)
{ {
RegisterKeyPressCommand(Commands, KeyCode_Backspace, false, KeyCode_Invalid, RemoveCharacterFromEntryString); RegisterKeyPressCommand(Commands, KeyCode_Backspace, Command_Began, KeyCode_Invalid, RemoveCharacterFromEntryString);
RegisterKeyPressCommand(Commands, KeyCode_LeftArrow, false, KeyCode_Invalid, TextEntryMoveCursorLeft); RegisterKeyPressCommand(Commands, KeyCode_LeftArrow, Command_Began, KeyCode_Invalid, TextEntryMoveCursorLeft);
RegisterKeyPressCommand(Commands, KeyCode_RightArrow, false, KeyCode_Invalid, TextEntryMoveCursorRight); RegisterKeyPressCommand(Commands, KeyCode_RightArrow, Command_Began, KeyCode_Invalid, TextEntryMoveCursorRight);
for (s32 i = KeyCode_a; i < KeyCode_UpArrow; i++) for (s32 i = KeyCode_a; i < KeyCode_UpArrow; i++)
{ {
RegisterKeyPressCommand(Commands, (key_code)i, false, KeyCode_Invalid, TextEntryInsertChar); RegisterKeyPressCommand(Commands, (key_code)i, Command_Began, KeyCode_Invalid, TextEntryInsertChar);
} }
} }

View File

@ -379,6 +379,7 @@ HandleWindowMessage (MSG Message, window* Window, input_queue* InputQueue, mouse
AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true, AddInputEventEntry(InputQueue, KeyCode_MouseLeftButton, false, true,
ShiftDown, AltDown, CtrlDown, false); ShiftDown, AltDown, CtrlDown, false);
Mouse->DownPos = Mouse->Pos; Mouse->DownPos = Mouse->Pos;
}break; }break;

View File

@ -8,9 +8,9 @@ x Allow one operation at a time at first
x Push/pop operations on a list? x Push/pop operations on a list?
- Current Operations: - Current Operations:
- - View Sculpture (this might be an exception since its so central) - - View Sculpture (this might be an exception since its so central)
- - View/Edit Nodes x - View/Edit Nodes
- x Add Node (needs nesting) - x Add Node (needs nesting)
- x View SACN - x View SACN
- Why does backspacing in text entry not save when you close and reopen the node lister? - Why does backspacing in text entry not save when you close and reopen the node lister?
- Typing a period into a float value doesn't register - Typing a period into a float value doesn't register