Support of IsKeyPressed that only trigger for the frame it is pressed on.

This commit is contained in:
2026-08-09 11:23:56 -04:00
parent 681267f445
commit d52c77a017
16 changed files with 151 additions and 34 deletions
+18 -1
View File
@@ -5,13 +5,16 @@
#include <game.h> #include <game.h>
#include <Core/Common/EnumUtils.h>
#include <Core/HAL/Filesystem/Filesystem.h> #include <Core/HAL/Filesystem/Filesystem.h>
#include <Core/HAL/Keyboard/Keyboard.h>
#include <Core/JulietInit.h> #include <Core/JulietInit.h>
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
#include <Core/Memory/MemoryArena.h> #include <Core/Memory/MemoryArena.h>
#include <Entity/Entity.h> #include <Entity/Entity.h>
#include <Entity/EntityManager.h> #include <Entity/EntityManager.h>
#include <Graphics/Camera.h> #include <Graphics/Camera.h>
#include <imgui.h>
GameState* gGameState = nullptr; GameState* gGameState = nullptr;
GameState* GetGameState() GameState* GetGameState()
@@ -92,5 +95,19 @@ extern "C" JULIET_API void __cdecl GameUpdate(Juliet::GameData* params, [[maybe_
printf("Rock has %d health points\n", rock->Health); printf("Rock has %d health points\n", rock->Health);
} }
// printf("Updating game...\n"); if (IsKeyPressed(ScanCode::F1))
{
gGameState->Mode = static_cast<GameMode>((ToUnderlying(gGameState->Mode) + 1) % 2);
}
if (gGameState->Mode == GameMode::Play)
{
// update game
}
if (gGameState->Mode == GameMode::Debug)
{
ImGui::Begin("Debug");
ImGui::End();
}
} }
+8
View File
@@ -10,12 +10,20 @@ struct World
EntityManager* EntityManager; EntityManager* EntityManager;
}; };
enum class GameMode
{
Play,
Debug
};
struct GameState struct GameState
{ {
Juliet::Arena* TotalArena; Juliet::Arena* TotalArena;
World* World; World* World;
GameMode Mode = GameMode::Play;
float TotalTime; float TotalTime;
int Score; int Score;
}; };
@@ -17,7 +17,7 @@ namespace Juliet
virtual ~IApplication() = default; virtual ~IApplication() = default;
virtual void Init(NonNullPtr<Arena> arena) = 0; virtual void Init(NonNullPtr<Arena> arena) = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
virtual void Update() = 0; virtual void Update(float deltaTime) = 0;
virtual bool IsRunning() = 0; virtual bool IsRunning() = 0;
// Accessors for Engine Systems // Accessors for Engine Systems
@@ -118,4 +118,6 @@ namespace Juliet
// Add an event onto the event queue. // Add an event onto the event queue.
// TODO : support array of events // TODO : support array of events
extern JULIET_API bool AddEvent(SystemEvent& event); extern JULIET_API bool AddEvent(SystemEvent& event);
extern void Events_NewFrame(float deltaTime);
} // namespace Juliet } // namespace Juliet
+8 -1
View File
@@ -8,12 +8,18 @@ namespace Juliet
{ {
using KeyboardID = uint8; using KeyboardID = uint8;
enum class KeyState : bool enum class KeyPosition : bool
{ {
Up = false, Up = false,
Down = true Down = true
}; };
struct KeyState
{
KeyPosition Position;
float Time;
};
struct Key struct Key
{ {
ScanCode ScanCode; ScanCode ScanCode;
@@ -22,6 +28,7 @@ namespace Juliet
}; };
extern JULIET_API bool IsKeyDown(ScanCode scanCode); extern JULIET_API bool IsKeyDown(ScanCode scanCode);
extern JULIET_API bool IsKeyPressed(ScanCode scanCode);
extern JULIET_API KeyMod GetKeyModState(); extern JULIET_API KeyMod GetKeyModState();
extern JULIET_API KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState); extern JULIET_API KeyCode GetKeyCodeFromScanCode(ScanCode scanCode, KeyMod keyModState);
+5
View File
@@ -31,6 +31,11 @@ namespace Juliet
} // namespace Memory } // namespace Memory
namespace Time
{
uint64 Timestamp();
} // namespace Time
namespace Debug namespace Debug
{ {
JULIET_API bool IsDebuggerPresent(); JULIET_API bool IsDebuggerPresent();
@@ -12,6 +12,7 @@
#include <Core/Memory/Utils.h> #include <Core/Memory/Utils.h>
// For GET_X_LPARAM, GET_Y_LPARAM. // For GET_X_LPARAM, GET_Y_LPARAM.
#include <Core/HAL/OS/OS.h>
#include <windowsx.h> #include <windowsx.h>
#ifdef JULIET_ENABLE_IMGUI #ifdef JULIET_ENABLE_IMGUI
@@ -157,7 +158,7 @@ namespace Juliet::Win32
LRESULT returnCode = -1; LRESULT returnCode = -1;
// Wait until the window state is created before doing anything // Wait until the window state is created before doing anything
auto* windowState = GetWindowStateFromHandle(handle); Window32State* windowState = GetWindowStateFromHandle(handle);
if (!windowState) if (!windowState)
{ {
return CallWindowProcA(DefWindowProcA, handle, message, wParam, lParam); return CallWindowProcA(DefWindowProcA, handle, message, wParam, lParam);
@@ -188,7 +189,7 @@ namespace Juliet::Win32
SendWindowEvent(windowState->Window, EventType::Window_Close_Request); SendWindowEvent(windowState->Window, EventType::Window_Close_Request);
} }
SendKeyboardKey(1, kGlobalKeyboardID, key, KeyState::Down); SendKeyboardKey(Time::Timestamp(), kGlobalKeyboardID, key, KeyPosition::Down);
returnCode = 0; returnCode = 0;
break; break;
@@ -197,7 +198,7 @@ namespace Juliet::Win32
case WM_KEYUP: case WM_KEYUP:
{ {
Key key = GetScanScodeFromWinScanCode(wParam, lParam); Key key = GetScanScodeFromWinScanCode(wParam, lParam);
SendKeyboardKey(1, kGlobalKeyboardID, key, KeyState::Up); SendKeyboardKey(Time::Timestamp(), kGlobalKeyboardID, key, KeyPosition::Up);
returnCode = 0; returnCode = 0;
break; break;
+41 -13
View File
@@ -15,14 +15,14 @@ namespace Juliet
KeyMod KeyModState; KeyMod KeyModState;
} KeyboardState; } KeyboardState;
bool SendKeyboardKey_Internal(uint64 timestamp, KeyboardID /*ID*/, Key key, KeyState keyState) bool SendKeyboardKey_Internal(uint64 timestamp, KeyboardID /*ID*/, Key key, KeyPosition keyPosition)
{ {
Assert(key.KeyCode == KeyCode::Unknown); // At this point Keycode is not yet extracted Assert(key.KeyCode == KeyCode::Unknown); // At this point Keycode is not yet extracted
auto& keyboardState = KeyboardState; // Needed because MSVC debugger ignores variable in anonymouse namespace auto& keyboardState = KeyboardState; // Needed because MSVC debugger ignores variable in anonymouse namespace
auto type = EventType::None; auto type = EventType::None;
const bool isKeyDown = keyState == KeyState::Down; const bool isKeyDown = keyPosition == KeyPosition::Down;
if (isKeyDown) if (isKeyDown)
{ {
type = EventType::Key_Down; type = EventType::Key_Down;
@@ -40,21 +40,21 @@ namespace Juliet
// If state didn't change, this is a key repeat // If state didn't change, this is a key repeat
if (isKeyDown) if (isKeyDown)
{ {
if (currentKeyState == KeyState::Down) if (currentKeyState.Position == KeyPosition::Down)
{ {
isKeyRepeat = true; isKeyRepeat = true;
} }
} }
else else
{ {
if (currentKeyState == KeyState::Up) if (currentKeyState.Position == KeyPosition::Up)
{ {
return false; return false;
} }
} }
keyboardState.KeyState[ToUnderlying(key.ScanCode)] = keyState; currentKeyState.Position = keyPosition;
key.KeyCode = GetKeyCodeFromScanCode(key.ScanCode, keyboardState.KeyModState); key.KeyCode = GetKeyCodeFromScanCode(key.ScanCode, keyboardState.KeyModState);
} }
else if (key.Raw == 0) else if (key.Raw == 0)
{ {
@@ -99,7 +99,7 @@ namespace Juliet
evt.Type = type; evt.Type = type;
evt.Data.Keyboard.AssociatedKeyboardID = kGlobalKeyboardID; evt.Data.Keyboard.AssociatedKeyboardID = kGlobalKeyboardID;
evt.Data.Keyboard.Key = key; evt.Data.Keyboard.Key = key;
evt.Data.Keyboard.KeyState = keyState; evt.Data.Keyboard.KeyState = { keyPosition };
evt.Data.Keyboard.KeyModeState = keyboardState.KeyModState; evt.Data.Keyboard.KeyModeState = keyboardState.KeyModState;
bool evtPosted = AddEvent(evt); bool evtPosted = AddEvent(evt);
@@ -108,14 +108,42 @@ namespace Juliet
} }
} // namespace } // namespace
bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyState keyState) bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition)
{ {
return SendKeyboardKey_Internal(timestamp, ID, key, keyState); return SendKeyboardKey_Internal(timestamp, ID, key, keyPosition);
}
void UpdateKeyboardstate(float deltaTime)
{
for (KeyState& state : KeyboardState.KeyState)
{
if (state.Position == KeyPosition::Down)
{
if (state.Time < 0.0f)
{
state.Time = 0.0f;
}
else
{
state.Time += deltaTime;
}
}
else
{
state.Time = -1.0f;
}
}
} }
bool IsKeyDown(ScanCode scanCode) bool IsKeyDown(ScanCode scanCode)
{ {
return KeyboardState.KeyState[ToUnderlying(scanCode)] == KeyState::Down; return KeyboardState.KeyState[ToUnderlying(scanCode)].Position == KeyPosition::Down;
}
bool IsKeyPressed(ScanCode scanCode)
{
auto& keyState = KeyboardState.KeyState[ToUnderlying(scanCode)];
return keyState.Position == KeyPosition::Down && keyState.Time == 0.0f;
} }
KeyMod GetKeyModState() KeyMod GetKeyModState()
@@ -129,9 +157,9 @@ namespace Juliet
return GetKeyCodeFromDefaultMapping(scanCode, keyModState); return GetKeyCodeFromDefaultMapping(scanCode, keyModState);
} }
static_assert(sizeof(KeyState) == sizeof(bool)); static_assert(sizeof(KeyPosition) == sizeof(bool));
static_assert(ToUnderlying(KeyState::Down) == true); static_assert(ToUnderlying(KeyPosition::Down) == true);
static_assert(ToUnderlying(KeyState::Up) == false); static_assert(ToUnderlying(KeyPosition::Up) == false);
static_assert(sizeof(ScanCode) == sizeof(uint16)); static_assert(sizeof(ScanCode) == sizeof(uint16));
static_assert(ToUnderlying(ScanCode::Count) == 512); static_assert(ToUnderlying(ScanCode::Count) == 512);
} // namespace Juliet } // namespace Juliet
+2 -1
View File
@@ -5,7 +5,8 @@
namespace Juliet namespace Juliet
{ {
extern bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyState keyState); extern bool SendKeyboardKey(uint64 timestamp, KeyboardID ID, Key key, KeyPosition keyPosition);
extern void UpdateKeyboardstate(float deltaTime);
extern const KeyboardID kGlobalKeyboardID; extern const KeyboardID kGlobalKeyboardID;
} // namespace Juliet } // namespace Juliet
@@ -1,6 +1,8 @@
#include <Core/HAL/Display/DisplayDevice.h> #include <Core/HAL/Display/DisplayDevice.h>
#include <Core/HAL/Event/SystemEvent.h> #include <Core/HAL/Event/SystemEvent.h>
#include <Core/HAL/Event/Keyboard_Private.h>
#pragma push_macro("global") #pragma push_macro("global")
#undef global #undef global
@@ -87,4 +89,10 @@ namespace Juliet
return AddEvent_Internal(event); return AddEvent_Internal(event);
} }
void Events_NewFrame(float deltaTime)
{
UpdateKeyboardstate(deltaTime);
}
} // namespace Juliet } // namespace Juliet
+8
View File
@@ -21,6 +21,14 @@ namespace Juliet
} }
} // namespace Memory } // namespace Memory
namespace Time
{
uint64 Timestamp()
{
return Internal::OS_Timestamp();
}
} // namespace Time
namespace Debug namespace Debug
{ {
bool IsDebuggerPresent() bool IsDebuggerPresent()
+6
View File
@@ -13,6 +13,12 @@ namespace Juliet
{ {
bool IsDebuggerPresent(); bool IsDebuggerPresent();
} // namespace Debug::Internal } // namespace Debug::Internal
namespace Time::Internal
{
uint64 OS_Timestamp();
}
namespace Internal namespace Internal
{ {
int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv); int OS_Main(EntryPointFunc entryPointFunc, int argc, wchar_t** argv);
+11
View File
@@ -45,6 +45,17 @@ namespace Juliet
} }
} // namespace Memory::Internal } // namespace Memory::Internal
namespace Time::Internal
{
uint64 OS_Timestamp()
{
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
return (static_cast<uint64>(ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
}
} // namespace Time::Internal
namespace Debug::Internal namespace Debug::Internal
{ {
bool IsDebuggerPresent() bool IsDebuggerPresent()
+27 -1
View File
@@ -1,6 +1,7 @@
#include <Engine/Engine.h> #include <Engine/Engine.h>
#include <Core/Common/CoreUtils.h> #include <Core/Common/CoreUtils.h>
#include <Core/HAL/Event/SystemEvent.h>
#include <Core/HAL/Filesystem/Filesystem_Private.h> #include <Core/HAL/Filesystem/Filesystem_Private.h>
#include <Core/JulietInit.h> #include <Core/JulietInit.h>
#include <Core/Logging/LogManager.h> #include <Core/Logging/LogManager.h>
@@ -18,6 +19,14 @@
#include <imgui.h> #include <imgui.h>
#endif #endif
// TODO Move to os hal for query perf
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>
#endif
namespace Juliet namespace Juliet
{ {
#if JULIET_DEBUG #if JULIET_DEBUG
@@ -210,8 +219,25 @@ namespace Juliet
ImGuiRenderer_NewFrame(); ImGuiRenderer_NewFrame();
#endif #endif
// TODO : Move to os side as it is win32 only
static LARGE_INTEGER frequency = {};
static LARGE_INTEGER lastTime = {};
if (frequency.QuadPart == 0)
{
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&lastTime);
}
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
float deltaTime =
static_cast<float>(currentTime.QuadPart - lastTime.QuadPart) / static_cast<float>(frequency.QuadPart);
lastTime = currentTime;
Events_NewFrame(deltaTime);
// Logic tick // Logic tick
EngineInstance.Application->Update(); EngineInstance.Application->Update(deltaTime);
// Render tick // Render tick
RenderFrame(); RenderFrame();
+1 -12
View File
@@ -225,20 +225,9 @@ void JulietApplication::Shutdown()
Log(LogLevel::Message, LogCategory::Tool, "Juliet App shutdown Completed"); Log(LogLevel::Message, LogCategory::Tool, "Juliet App shutdown Completed");
} }
void JulietApplication::Update() void JulietApplication::Update(float deltaTime)
{ {
static LARGE_INTEGER frequency = {};
static LARGE_INTEGER lastTime = {};
if (frequency.QuadPart == 0)
{
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&lastTime);
}
LARGE_INTEGER currentTime;
QueryPerformanceCounter(&currentTime);
float deltaTime = static_cast<float>(currentTime.QuadPart - lastTime.QuadPart) / static_cast<float>(frequency.QuadPart);
lastTime = currentTime;
CameraTime += deltaTime; CameraTime += deltaTime;
+1 -1
View File
@@ -20,7 +20,7 @@ class JulietApplication : public Juliet::IApplication
protected: protected:
void Init(Juliet::NonNullPtr<Juliet::Arena> arena) override; void Init(Juliet::NonNullPtr<Juliet::Arena> arena) override;
void Shutdown() override; void Shutdown() override;
void Update() override; void Update(float deltaTime) override;
bool IsRunning() override; bool IsRunning() override;
Juliet::Window* GetPlatformWindow() override { return MainWindow; } Juliet::Window* GetPlatformWindow() override { return MainWindow; }