Mercurial
diff infinite_canvas/main.c @ 282:6bd4a3990696 default tip
Add cross-platform canvas orchestration and typed composer
Enable native ARM dependencies, macOS Copilot orchestration, portable service supervision, CPU dictation, and a shared N-key speak-or-type composer.
Co-authored-by: Copilot <[email protected]>
Copilot-Session: f68442b1-fa8f-46a0-9689-81710613bbd4
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 20 Aug 2026 20:45:25 -0700 |
| parents | c57149ad216e |
| children |
line wrap: on
line diff
--- a/infinite_canvas/main.c Tue Aug 18 22:18:15 2026 -0700 +++ b/infinite_canvas/main.c Thu Aug 20 20:45:25 2026 -0700 @@ -40,6 +40,8 @@ boolean dictation_overlay_visible; boolean dictation_listening; boolean dictation_requested_active; + boolean dictation_typing; + boolean dictation_refocus_pending; boolean dictation_send_pending; char dictation_status[128]; char dictation_partial[CANVAS_ENTITY_TEXT_CAPACITY]; @@ -252,6 +254,21 @@ return p_entity; } +static void Canvas_App_Focus_Dictation_Entity(void) +{ + Canvas_Entity *p_entity = Canvas_App_Ensure_Dictation_Entity(); + if (!p_entity) return; + for (size_t index = 0; + index < Dowa_Array_Length(g_app->scene.p_entities); + index++) { + if (g_app->scene.p_entities[index].id == p_entity->id) { + g_app->scene.selected_index = (int32)index; + break; + } + } + Canvas_Text_Area_Focus_End(p_entity, g_app->font); +} + static void Canvas_App_Sync_Dictation_Entity(void) { Canvas_Entity *p_entity = @@ -283,6 +300,7 @@ g_app->dictation_overlay_visible = TRUE; g_app->dictation_requested_active = active; g_app->dictation_listening = FALSE; + g_app->dictation_typing = FALSE; g_app->dictation_send_pending = FALSE; if (active) { Canvas_App_Ensure_Dictation_Entity(); @@ -298,6 +316,45 @@ active); } +static void Canvas_App_Start_Dictation_Typing(void) +{ + if (g_app->dictation_requested_active || + g_app->dictation_listening) { + Canvas_Web_Surface_Set_Dictation_Active( + &g_app->web_surface, + FALSE); + } + g_app->dictation_requested_active = FALSE; + g_app->dictation_listening = FALSE; + g_app->dictation_typing = TRUE; + g_app->dictation_refocus_pending = FALSE; + g_app->dictation_send_pending = FALSE; + g_app->dictation_partial[0] = '\0'; + g_app->dictation_overlay_visible = TRUE; + Canvas_App_Sync_Dictation_Entity(); + Canvas_App_Focus_Dictation_Entity(); + snprintf( + g_app->dictation_status, + sizeof(g_app->dictation_status), + "Type a thought"); + + while (GetCharPressed() > 0) { + } +} + +static void Canvas_App_Sync_Typed_Dictation(void) +{ + if (!g_app->dictation_typing) return; + Canvas_Entity *p_entity = + Canvas_App_Find_Entity(g_app->dictation_entity_id); + if (!p_entity) return; + snprintf( + g_app->dictation_transcript, + sizeof(g_app->dictation_transcript), + "%s", + p_entity->text); +} + static boolean Canvas_App_Submit_Dictation(void) { if (!g_app->dictation_transcript[0]) return FALSE; @@ -311,11 +368,16 @@ } Canvas_Entity *p_entity = Canvas_App_Find_Entity(g_app->dictation_entity_id); - if (p_entity) p_entity->text_muted = FALSE; + if (p_entity) { + p_entity->text_muted = FALSE; + if (g_app->dictation_typing) p_entity->active = FALSE; + } g_app->dictation_transcript[0] = '\0'; g_app->dictation_partial[0] = '\0'; Canvas_App_Sync_Dictation_Entity(); g_app->dictation_send_pending = FALSE; + g_app->dictation_typing = FALSE; + g_app->dictation_refocus_pending = FALSE; g_app->dictation_overlay_visible = g_app->dictation_listening; return TRUE; @@ -360,15 +422,32 @@ g_app->dictation_listening = FALSE; } g_app->dictation_send_pending = FALSE; + g_app->dictation_typing = FALSE; g_app->dictation_partial[0] = '\0'; g_app->dictation_transcript[0] = '\0'; + Canvas_Entity *p_entity = + Canvas_App_Find_Entity(g_app->dictation_entity_id); + if (p_entity) p_entity->active = FALSE; Canvas_App_Sync_Dictation_Entity(); g_app->dictation_overlay_visible = FALSE; return; } if (!IsKeyPressed(KEY_ENTER)) return; + if (g_app->dictation_typing && + (IsKeyDown(KEY_LEFT_SHIFT) || + IsKeyDown(KEY_RIGHT_SHIFT))) { + return; + } - if (g_app->dictation_partial[0]) { + if (g_app->dictation_typing) { + Canvas_Entity *p_entity = + Canvas_App_Find_Entity(g_app->dictation_entity_id); + if (p_entity) p_entity->active = FALSE; + Canvas_App_Sync_Typed_Dictation(); + if (!Canvas_App_Submit_Dictation()) { + g_app->dictation_refocus_pending = TRUE; + } + } else if (g_app->dictation_partial[0]) { g_app->dictation_send_pending = TRUE; snprintf( g_app->dictation_status, @@ -620,9 +699,16 @@ !Canvas_Scene_Is_Text_Editing(&g_app->scene) && !Canvas_Web_Chrome_Is_Editing(&g_app->scene) && IsKeyPressed(KEY_M); + boolean typing_hotkey = + !dev_ui_editing && + !Canvas_Scene_Is_Text_Editing(&g_app->scene) && + !Canvas_Web_Chrome_Is_Editing(&g_app->scene) && + IsKeyPressed(KEY_N); if (dictation_hotkey) { Canvas_App_Set_Dictation_Active( g_app->dictation_requested_active ? FALSE : TRUE); + } else if (typing_hotkey) { + Canvas_App_Start_Dictation_Typing(); } Canvas_App_Update_Dictation_Overlay_Input(); Canvas_Web_Chrome_Action chrome_action = CANVAS_WEB_CHROME_NONE; @@ -660,6 +746,7 @@ boolean web_input = FALSE; if (!block_pointer_input && !dictation_hotkey && + !typing_hotkey && chrome_action == CANVAS_WEB_CHROME_NONE) { web_input = Canvas_Web_Surface_Update_Input( &g_app->web_surface, @@ -675,6 +762,11 @@ &g_app->camera, g_app->font, block_pointer_input); + if (g_app->dictation_refocus_pending) { + Canvas_App_Focus_Dictation_Entity(); + g_app->dictation_refocus_pending = FALSE; + } + Canvas_App_Sync_Typed_Dictation(); boolean keyboard_focus = Canvas_Scene_Is_Text_Editing(&g_app->scene) || Canvas_Web_Chrome_Is_Editing(&g_app->scene) || @@ -717,7 +809,8 @@ } Canvas_App_Submit_Dictation(); } else if (!g_app->dictation_transcript[0] && - !g_app->dictation_partial[0]) { + !g_app->dictation_partial[0] && + !g_app->dictation_typing) { g_app->dictation_overlay_visible = FALSE; } } else if (strcmp(dictation_text, "Listening") == 0 ||