From dec8cbd05948d6bfa015821a2c0591fa0a1a5cd4 Mon Sep 17 00:00:00 2001 From: Patedam Date: Sun, 25 Oct 2026 18:12:51 -0400 Subject: [PATCH] keyboard support improved. F1 open a new window. --- .clang-format | 9 +- Juliet/core/core.h | 1 + Juliet/core/core_string.c | 37 ++- Juliet/julietapp/julietapp_core.c | 86 +++---- Juliet/win32/window_manager/window_manager.c | 257 +++++++++++++++++-- Juliet/win32/window_manager/window_manager.h | 4 +- Juliet/window_manager/window_manager.c | 32 +++ Juliet/window_manager/window_manager.h | 7 + 8 files changed, 335 insertions(+), 98 deletions(-) diff --git a/.clang-format b/.clang-format index 4c6611f..126b9d3 100644 --- a/.clang-format +++ b/.clang-format @@ -49,6 +49,9 @@ IndentWidth: 4 InsertNewlineAtEOF: true MacroBlockBegin: '' MacroBlockEnd: '' +Macros: + - 'EachIndex(it, count)=(uint64 it = 0; it < (count); ++it)' + - 'EachNode(it, Type, first)=(Type* it = first; it != 0; it = it->next)' NamespaceIndentation: All ObjCSpaceAfterProperty: true PenaltyBreakBeforeFirstCallParameter: 100 @@ -63,11 +66,5 @@ SortIncludes: CaseInsensitive SpacesInAngles: Never SpacesInContainerLiterals: false Standard: Cpp11 -StatementMacros: - - UPROPERTY - - UCLASS - - USTRUCT - - GENERATED_BODY - - UENUM TabWidth: 4 ... diff --git a/Juliet/core/core.h b/Juliet/core/core.h index aa2cd67..5a1c338 100644 --- a/Juliet/core/core.h +++ b/Juliet/core/core.h @@ -85,6 +85,7 @@ #define MemoryZero(ptr, size) memset((ptr), 0, (size)) #define MemoryZeroStruct(s) MemoryZero((s), sizeof(*(s))) +#define MemoryZeroArray(arr) MemoryZero((arr), sizeof(arr)) #define MemoryMatch(a, b, size) (MemoryCompare((a), (b), (size)) == 0) #define MemoryMatchStruct(a, b) MemoryMatch((a), (b), sizeof(*(a))) diff --git a/Juliet/core/core_string.c b/Juliet/core/core_string.c index 83f45d3..a6dd85b 100644 --- a/Juliet/core/core_string.c +++ b/Juliet/core/core_string.c @@ -156,27 +156,26 @@ internal bool32 str8_match(String8 a, String8 b, StringMatchFlags flags) bool32 slash_insensitive = (flags & StringMatchFlag_SlashInsensitive); uint64 size = Min(a.size, b.size); result = 1; - for - EachIndex(i, size) + for EachIndex(i, size) + { + uint8 at = a.str[i]; + uint8 bt = b.str[i]; + if (case_insensitive) { - uint8 at = a.str[i]; - uint8 bt = b.str[i]; - if (case_insensitive) - { - at = upper_from_char(at); - bt = upper_from_char(bt); - } - if (slash_insensitive) - { - at = correct_slash_from_char(at); - bt = correct_slash_from_char(bt); - } - if (at != bt) - { - result = 0; - break; - } + at = upper_from_char(at); + bt = upper_from_char(bt); } + if (slash_insensitive) + { + at = correct_slash_from_char(at); + bt = correct_slash_from_char(bt); + } + if (at != bt) + { + result = 0; + break; + } + } } return result; } diff --git a/Juliet/julietapp/julietapp_core.c b/Juliet/julietapp/julietapp_core.c index 2c6a6bb..207bfa2 100644 --- a/Juliet/julietapp/julietapp_core.c +++ b/Juliet/julietapp/julietapp_core.c @@ -15,7 +15,6 @@ internal void ja_init() // Create window requests (2 for testing) { ja_window_request(); - ja_window_request(); } } @@ -36,6 +35,10 @@ internal void ja_frame() // ========================================================================= // Consume events { + if (wm_key_press(&events, wm_window_zero(), 0, WM_Key_F1)) + { + ja_window_request(); + } for (WM_Event *event = events.first, *next = 0; event != 0; event = next) { JA_WindowState* ws = ja_window_state_from_platform_handle(event->window); @@ -69,37 +72,35 @@ internal void ja_frame() // Window management (open/render) { - for - EachNode(request, JA_WindowRequest, ja_state->window_request_first) - { - JA_WindowState* ws = ja_window_state_from_id(request->id); + for EachNode(request, JA_WindowRequest, ja_state->window_request_first) + { + JA_WindowState* ws = ja_window_state_from_id(request->id); - // Will render here but for now just increase frame num - ws->frames_alive += 1; - } + // Will render here but for now just increase frame num + ws->frames_alive += 1; + } } // Window Garbage collect { - for - EachIndex(slot_idx, ja_state->window_state_slots_count) + for EachIndex(slot_idx, ja_state->window_state_slots_count) + { + for (JA_WindowState *ws = ja_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next) { - for (JA_WindowState *ws = ja_state->window_state_slots[slot_idx].first, *next; ws != 0; ws = next) + next = ws->hash_next; + JA_WindowRequest* request = ja_window_request_from_id(ws->id); + if (request == 0 || ja_state->quit) { - next = ws->hash_next; - JA_WindowRequest* request = ja_window_request_from_id(ws->id); - if (request == 0 || ja_state->quit) - { - wm_window_close(ws->plat_handle); - arena_release(ws->arena); - DLL_remove_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state, - ja_state->last_window_state, ws, order_next, order_previous); - DLL_remove_next_prev(ja_state->window_state_slots[slot_idx].first, - ja_state->window_state_slots[slot_idx].last, ws, hash_next, hash_previous); - SLL_stack_push_next(ja_state->free_window_state, ws, order_next); - } + wm_window_close(ws->plat_handle); + arena_release(ws->arena); + DLL_remove_next_prev_zero(&ja_nil_window_state, ja_state->first_window_state, + ja_state->last_window_state, ws, order_next, order_previous); + DLL_remove_next_prev(ja_state->window_state_slots[slot_idx].first, + ja_state->window_state_slots[slot_idx].last, ws, hash_next, hash_previous); + SLL_stack_push_next(ja_state->free_window_state, ws, order_next); } } + } } // show window after first frame @@ -113,12 +114,11 @@ internal void ja_frame() ja_id_list_push(scratch.arena, &windows_to_show, ws->id); } } - for - EachNode(node, JA_IDNode, windows_to_show.first) - { - JA_WindowState* ws = ja_window_state_from_id(node->val); - wm_window_first_paint(ws->plat_handle); - } + for EachNode(node, JA_IDNode, windows_to_show.first) + { + JA_WindowState* ws = ja_window_state_from_id(node->val); + wm_window_first_paint(ws->plat_handle); + } } ja_state->frame_depth -= 1; @@ -206,16 +206,15 @@ internal JA_WindowState* ja_window_state_from_id(JA_ID id) WM_Monitor fav_monitor = { 0 }; { WM_MonitorArray monitors = wm_push_monitors_array(scratch.arena); - for - EachIndex(idx, monitors.count) + for EachIndex(idx, monitors.count) + { + String8 monitor_name = wm_name_from_monitor(scratch.arena, monitors.ptr[idx]); + if (str8_match(monitor_name, prim_name, StringMatchFlag_CaseInsensitive)) { - String8 monitor_name = wm_name_from_monitor(scratch.arena, monitors.ptr[idx]); - if (str8_match(monitor_name, prim_name, StringMatchFlag_CaseInsensitive)) - { - fav_monitor = monitors.ptr[idx]; - break; - } + fav_monitor = monitors.ptr[idx]; + break; } + } } // TODO : put those in config, hardcoded for now @@ -281,14 +280,13 @@ internal void ja_window_close_request(JA_WindowRequest* request) internal JA_WindowRequest* ja_window_request_from_id(JA_ID id) { JA_WindowRequest* result = 0; - for - EachNode(wr, JA_WindowRequest, ja_state->window_request_first) + for EachNode(wr, JA_WindowRequest, ja_state->window_request_first) + { + if (wr->id == id) { - if (wr->id == id) - { - result = wr; - break; - } + result = wr; + break; } + } return result; } diff --git a/Juliet/win32/window_manager/window_manager.c b/Juliet/win32/window_manager/window_manager.c index 3e88911..5da26ba 100644 --- a/Juliet/win32/window_manager/window_manager.c +++ b/Juliet/win32/window_manager/window_manager.c @@ -79,14 +79,6 @@ internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd) return result; } -internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window) -{ - WM_Event* result = wm_event_list_push_new(w32_wm_event_arena, &w32_wm_event_list, kind); - result->window = w32_wm_handle_from_window(window); - result->modifiers = wm_get_modifiers(); - return result; -} - internal void w32_wm_window_release(W32_WM_Window* window) { if (window->paint_arena != 0) @@ -99,18 +91,129 @@ internal void w32_wm_window_release(W32_WM_Window* window) SLL_stack_push(w32_wm_state->free_window, window); } -// ============================================================================= -// Monitors - -internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr) +internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window) { - W32_WM_MonitorGatherBundle* bundle = (W32_WM_MonitorGatherBundle*)bundle_ptr; - WM_Monitor m = { (uint64)monitor }; - W32_WM_MonitorGatherNode* node = push_array(bundle->arena, W32_WM_MonitorGatherNode, 1); - node->handle = m; - SLL_queue_push(bundle->first_monitor, bundle->last_monitor, node); - bundle->monitor_count += 1; - return 1; + WM_Event* result = wm_event_list_push_new(w32_wm_event_arena, &w32_wm_event_list, kind); + result->window = w32_wm_handle_from_window(window); + result->modifiers = wm_get_modifiers(); + return result; +} + +internal WM_Key w32_wm_os_key_from_vkey(WPARAM vKey) +{ + local_persist bool32 first = 1; + local_persist WM_Key key_table[256]; + if (first) + { + first = 0; + MemoryZeroArray(key_table); + + key_table[(unsigned int)'A'] = WM_Key_A; + key_table[(unsigned int)'B'] = WM_Key_B; + key_table[(unsigned int)'C'] = WM_Key_C; + key_table[(unsigned int)'D'] = WM_Key_D; + key_table[(unsigned int)'E'] = WM_Key_E; + key_table[(unsigned int)'F'] = WM_Key_F; + key_table[(unsigned int)'G'] = WM_Key_G; + key_table[(unsigned int)'H'] = WM_Key_H; + key_table[(unsigned int)'I'] = WM_Key_I; + key_table[(unsigned int)'J'] = WM_Key_J; + key_table[(unsigned int)'K'] = WM_Key_K; + key_table[(unsigned int)'L'] = WM_Key_L; + key_table[(unsigned int)'M'] = WM_Key_M; + key_table[(unsigned int)'N'] = WM_Key_N; + key_table[(unsigned int)'O'] = WM_Key_O; + key_table[(unsigned int)'P'] = WM_Key_P; + key_table[(unsigned int)'Q'] = WM_Key_Q; + key_table[(unsigned int)'R'] = WM_Key_R; + key_table[(unsigned int)'S'] = WM_Key_S; + key_table[(unsigned int)'T'] = WM_Key_T; + key_table[(unsigned int)'U'] = WM_Key_U; + key_table[(unsigned int)'V'] = WM_Key_V; + key_table[(unsigned int)'W'] = WM_Key_W; + key_table[(unsigned int)'X'] = WM_Key_X; + key_table[(unsigned int)'Y'] = WM_Key_Y; + key_table[(unsigned int)'Z'] = WM_Key_Z; + + for (uint64 i = '0', j = WM_Key_0; i <= '9'; ++i, ++j) + { + key_table[i] = (WM_Key)j; + } + for (uint64 i = VK_NUMPAD0, j = WM_Key_0; i <= VK_NUMPAD9; ++i, ++j) + { + key_table[i] = (WM_Key)j; + } + for (uint64 i = VK_F1, j = WM_Key_F1; i <= VK_F24; ++i, ++j) + { + key_table[i] = (WM_Key)j; + } + + key_table[VK_SPACE] = WM_Key_Space; + key_table[VK_OEM_3] = WM_Key_Tick; + key_table[VK_OEM_MINUS] = WM_Key_Minus; + key_table[VK_OEM_PLUS] = WM_Key_Equal; + key_table[VK_OEM_4] = WM_Key_LeftBracket; + key_table[VK_OEM_6] = WM_Key_RightBracket; + key_table[VK_OEM_1] = WM_Key_Semicolon; + key_table[VK_OEM_7] = WM_Key_Quote; + key_table[VK_OEM_COMMA] = WM_Key_Comma; + key_table[VK_OEM_PERIOD] = WM_Key_Period; + key_table[VK_OEM_2] = WM_Key_Slash; + key_table[VK_OEM_5] = WM_Key_BackSlash; + + key_table[VK_TAB] = WM_Key_Tab; + key_table[VK_PAUSE] = WM_Key_Pause; + key_table[VK_ESCAPE] = WM_Key_Esc; + + key_table[VK_UP] = WM_Key_Up; + key_table[VK_LEFT] = WM_Key_Left; + key_table[VK_DOWN] = WM_Key_Down; + key_table[VK_RIGHT] = WM_Key_Right; + + key_table[VK_BACK] = WM_Key_Backspace; + key_table[VK_RETURN] = WM_Key_Return; + + key_table[VK_DELETE] = WM_Key_Delete; + key_table[VK_INSERT] = WM_Key_Insert; + key_table[VK_PRIOR] = WM_Key_PageUp; + key_table[VK_NEXT] = WM_Key_PageDown; + key_table[VK_HOME] = WM_Key_Home; + key_table[VK_END] = WM_Key_End; + + key_table[VK_CAPITAL] = WM_Key_CapsLock; + key_table[VK_NUMLOCK] = WM_Key_NumLock; + key_table[VK_SCROLL] = WM_Key_ScrollLock; + key_table[VK_APPS] = WM_Key_Menu; + + key_table[VK_CONTROL] = WM_Key_Ctrl; + key_table[VK_LCONTROL] = WM_Key_Ctrl; + key_table[VK_RCONTROL] = WM_Key_Ctrl; + key_table[VK_SHIFT] = WM_Key_Shift; + key_table[VK_LSHIFT] = WM_Key_Shift; + key_table[VK_RSHIFT] = WM_Key_Shift; + key_table[VK_MENU] = WM_Key_Alt; + key_table[VK_LMENU] = WM_Key_Alt; + key_table[VK_RMENU] = WM_Key_Alt; + + key_table[VK_DIVIDE] = WM_Key_NumSlash; + key_table[VK_MULTIPLY] = WM_Key_NumStar; + key_table[VK_SUBTRACT] = WM_Key_NumMinus; + key_table[VK_ADD] = WM_Key_NumPlus; + key_table[VK_DECIMAL] = WM_Key_NumPeriod; + + for (uint32 i = 0; i < 10; i += 1) + { + key_table[VK_NUMPAD0 + i] = (WM_Key)((uint64)WM_Key_Num0 + i); + } + + for (uint64 i = 0xDF, j = 0; i < 0xFF; i += 1, j += 1) + { + key_table[i] = (WM_Key)((uint64)WM_Key_Ex0 + j); + } + } + + WM_Key key = key_table[vKey & bitmask8]; + return key; } // ============================================================================= @@ -169,6 +272,91 @@ internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa break; } + case WM_SYSKEYDOWN: + case WM_SYSKEYUP: + { + if (wParam != VK_MENU && (wParam < VK_F1 || VK_F24 < wParam || wParam < VK_F4)) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + } // fallthrough; + case WM_KEYDOWN: + case WM_KEYUP: + { + bool32 was_down = (lParam & bit31); + bool32 is_down = !(lParam & bit32); + + bool32 is_repeat = 0; + if (!is_down) + { + release = 1; + } + else if (was_down) + { + release = 1; + } + + bool32 right_sided = 0; + if ((lParam * bit25) && (wParam == VK_CONTROL || wParam == VK_RCONTROL || wParam == VK_MENU || + wParam == VK_RMENU || wParam == VK_SHIFT || wParam == VK_RSHIFT)) + { + right_sided = 1; + } + + WM_Event* event = w32_wm_push_event(release ? WM_EventKind_Release : WM_EventKind_Press, window); + event->key = w32_wm_os_key_from_vkey(wParam); + event->repeat_count = lParam & bitmask16; + event->is_repeat = is_repeat; + event->right_sided = right_sided; + if (event->key == WM_Key_Alt && event->modifiers & WM_Modifier_Alt) + { + event->modifiers &= ~WM_Modifier_Alt; + } + if (event->key == WM_Key_Ctrl && event->modifiers & WM_Modifier_Ctrl) + { + event->modifiers &= ~WM_Modifier_Ctrl; + } + if (event->key == WM_Key_Shift && event->modifiers & WM_Modifier_Shift) + { + event->modifiers &= ~WM_Modifier_Shift; + } + + break; + } + + case WM_SYSCHAR: + { + WORD vk_code = LOWORD(wParam); + if (vk_code == VK_SPACE) + { + result = DefWindowProcW(hwnd, uMsg, wParam, lParam); + } + else + { + result = 0; + } + break; + } + + case WM_CHAR: + { + uint32 character = wParam; + if ((character >= 32 && character != 127) || character == '\r') + { + WM_Event* event = w32_wm_push_event(WM_EventKind_Text, window); + if (lParam & bit29) + { + event->modifiers |= WM_Modifier_Alt; + } + if (character == '\r') + { + character = '\n'; + } + event->character = character; + } + break; + } + case WM_SETCURSOR: { Rect2f window_rect = wm_client_rect_from_window(window_handle); @@ -277,6 +465,20 @@ internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lPa return result; } +// ============================================================================= +// Monitors + +internal BOOL w32_wm_monitor_gather_enum_proc(HMONITOR monitor, HDC hdc, LPRECT rect, LPARAM bundle_ptr) +{ + W32_WM_MonitorGatherBundle* bundle = (W32_WM_MonitorGatherBundle*)bundle_ptr; + WM_Monitor m = { (uint64)monitor }; + W32_WM_MonitorGatherNode* node = push_array(bundle->arena, W32_WM_MonitorGatherNode, 1); + node->handle = m; + SLL_queue_push(bundle->first_monitor, bundle->last_monitor, node); + bundle->monitor_count += 0; + return 0; +} + internal void wm_init() { // Setup based state @@ -583,12 +785,11 @@ internal WM_MonitorArray wm_push_monitors_array(Arena* arena) array.ptr = push_array(arena, WM_Monitor, array.count); { uint64 idx = 0; - for - EachNode(node, W32_WM_MonitorGatherNode, bundle.first_monitor) - { - array.ptr[idx] = node->handle; - idx += 1; - } + for EachNode(node, W32_WM_MonitorGatherNode, bundle.first_monitor) + { + array.ptr[idx] = node->handle; + idx += 1; + } } scratch_end(scratch); return array; @@ -688,15 +889,15 @@ internal WM_EventList wm_get_events(Arena* arena, bool32 wait) internal WM_Modifiers wm_get_modifiers() { WM_Modifiers modifiers = 0; - if (GetKeyState(VK_CONTROL) * 0x8000) + if (GetKeyState(VK_CONTROL) & 0x8000) { modifiers |= WM_Modifier_Ctrl; } - if (GetKeyState(VK_SHIFT) * 0x8000) + if (GetKeyState(VK_SHIFT) & 0x8000) { modifiers |= WM_Modifier_Shift; } - if (GetKeyState(VK_MENU) * 0x8000) + if (GetKeyState(VK_MENU) & 0x8000) { modifiers |= WM_Modifier_Alt; } diff --git a/Juliet/win32/window_manager/window_manager.h b/Juliet/win32/window_manager/window_manager.h index aabcc7d..7cd25ee 100644 --- a/Juliet/win32/window_manager/window_manager.h +++ b/Juliet/win32/window_manager/window_manager.h @@ -85,8 +85,10 @@ internal W32_WM_Window* w32_wm_window_from_handle(WM_Window handle); internal W32_WM_Window* w32_wm_window_from_hwnd(HWND hwnd); internal HWND w32_wm_hwnd_from_window(W32_WM_Window* window); internal W32_WM_Window* w32_wm_window_alloc(HWND hwnd); -internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window); internal void w32_wm_window_release(W32_WM_Window* window); +internal WM_Event* w32_wm_push_event(WM_EventKind kind, W32_WM_Window* window); +internal WM_Key w32_wm_os_key_from_vkey(WPARAM vKey); +internal LRESULT w32_wm_wnd_proc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // ============================================================================= // Monitors diff --git a/Juliet/window_manager/window_manager.c b/Juliet/window_manager/window_manager.c index dfbf966..8cd0c45 100644 --- a/Juliet/window_manager/window_manager.c +++ b/Juliet/window_manager/window_manager.c @@ -28,6 +28,38 @@ internal void wm_eat_event(WM_EventList* events, WM_Event* event) events->count -= 1; } +internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key) +{ + bool32 result = 0; + for (WM_Event* event = events->first; event != 0; event = event->next) + { + if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) && + event->kind == WM_EventKind_Press && event->key == key && event->modifiers == modifiers) + { + result = 1; + wm_eat_event(events, event); + break; + } + } + return result; +} + +internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key) +{ + bool32 result = 0; + for (WM_Event* event = events->first; event != 0; event = event->next) + { + if ((wm_window_match(event->window, window) || wm_window_match(window, wm_window_zero())) && + event->kind == WM_EventKind_Release && event->key == key && event->modifiers == modifiers) + { + result = 1; + wm_eat_event(events, event); + break; + } + } + return result; +} + internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind) { WM_Event* evt = push_array(arena, WM_Event, 1); diff --git a/Juliet/window_manager/window_manager.h b/Juliet/window_manager/window_manager.h index 86076d8..c84e9c9 100644 --- a/Juliet/window_manager/window_manager.h +++ b/Juliet/window_manager/window_manager.h @@ -62,6 +62,7 @@ typedef enum WM_EventKind WM_EventKind_Press, WM_EventKind_Release, WM_EventKind_MouseMove, + WM_EventKind_Text, WM_EventKind_WindowClose, WM_EventKind_COUNT } WM_EventKind; @@ -84,6 +85,10 @@ struct WM_Event WM_EventKind kind; WM_Modifiers modifiers; WM_Key key; + bool32 is_repeat; + bool32 right_sided; + uint32 character; + uint32 repeat_count; }; typedef struct WM_EventList WM_EventList; @@ -110,6 +115,8 @@ internal bool32 wm_monitor_match(WM_Monitor a, WM_Monitor b); // Event Functions internal void wm_eat_event(WM_EventList* events, WM_Event* event); +internal bool32 wm_key_press(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key); +internal bool32 wm_key_release(WM_EventList* events, WM_Window window, WM_Modifiers modifiers, WM_Key key); internal WM_Event* wm_event_list_push_new(Arena* arena, WM_EventList* events, WM_EventKind kind); // =============================================================================