From 5d05ca30cac8f5fef0dbe88bc44edfb1488e404c Mon Sep 17 00:00:00 2001 From: Tommaso Bianchi Date: Mon, 27 Jul 2026 00:40:25 +0200 Subject: [PATCH] Sketch shortcuts: pick the key map by mode, not by whether a session exists All 17 single-letter sketch shortcuts were dead. The dispatch gate was circular: the sketch key map was consulted only when m_viewport->is_sketching() was already true, but is_sketching() is a whole-session flag whose only riser is begin_sketch(), called from select_tool() -- which is precisely what every sketch key closure calls. So the first letter after entering sketch mode fell through to the feature map, where the keys are Shift+letter, matched nothing, and did nothing. The mouse worked only because the toolbar flyout row reaches select_tool() directly, bypassing the gate. Which key MAP applies is a question about the mode. Split the flag: 'sketching' (live session) still drives undo/redo, Delete and the section-view branch, where a session genuinely has to exist; a new 'sketch_mode' (m_ui_mode == UiMode::Sketch alone) drives the map choice. Verified headless end to end, keyboard only: Shift+S, then R draws a 143.4 x 133.7 rectangle on XY reporting 4 degrees of freedom, then F and L arm Fillet and Line (artifacts/shots/0udb-01..03). Note the toolbar strip does NOT change when a tool is armed by keyboard -- the family buttons are flyouts and only show their own pressed state -- so the pixel diff on that strip, which is how this was originally measured, reads 0 for a tool that is live. The status line is the surface that actually reflects the armed tool. Also fixed, from snaporca-d9i's list: the plane-pick status line said "press Sketch to draw on it", naming a button that exists only in Feature mode. It is now mode-aware. Adds a SNAPORCA_KEYTRACE=1 trace in the CHAR_HOOK printing key, ui mode, is_sketching, in_text and the focused window's class. It is what separated "the fix does not work" from "the surface being measured never moves", and it costs a full GUI build to re-add, so it stays. snaporca-0ud, partial snaporca-d9i. --- src/slic3r/GUI/DesignPanel.cpp | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/src/slic3r/GUI/DesignPanel.cpp b/src/slic3r/GUI/DesignPanel.cpp index a658bfa37d..113f9b674c 100644 --- a/src/slic3r/GUI/DesignPanel.cpp +++ b/src/slic3r/GUI/DesignPanel.cpp @@ -3285,7 +3285,12 @@ DesignPanel::DesignPanel(wxWindow* parent) m_draw_plane->SetSelection(base); const char* nm = (base == 0) ? "XY" : (base == 1) ? "XZ" : (base == 2) ? "YZ" : "datum"; m_status->SetForegroundColour(wxColour(120, 210, 120)); - m_status->SetLabel(wxString::Format(_L("%s plane selected — press Sketch to draw on it"), nm)); + // The "press Sketch" half is only true in Feature mode, where that button exists. + // Inside sketch mode it told the user to press a button that isn't on screen; there + // the next step is arming a tool (toolbar flyout or its single-letter key). snaporca-d9i. + m_status->SetLabel(m_ui_mode == UiMode::Sketch + ? wxString::Format(_L("%s plane selected — pick a sketch tool to draw on it"), nm) + : wxString::Format(_L("%s plane selected — press Sketch to draw on it"), nm)); m_status->Refresh(); } }); @@ -3395,11 +3400,27 @@ DesignPanel::DesignPanel(wxWindow* parent) const int key = e.GetKeyCode(); const bool ctrl = e.ControlDown() || e.CmdDown(); const bool sketching = (m_ui_mode == UiMode::Sketch) && m_viewport && m_viewport->is_sketching(); + // Which key MAP applies is a question about the MODE, not about whether a session is + // already running. Gating the sketch map on is_sketching() made it unreachable by + // keyboard: is_sketching() only turns true inside select_tool()'s begin_sketch(), and + // select_tool() is what the sketch keys call — so the first letter after entering + // sketch mode fell through to the feature map, matched nothing (feature keys are + // Shift+letter), and did nothing. The mouse worked only because the toolbar flyout + // reaches select_tool() directly. That is why all 17 keys read as dead. snaporca-0ud. + const bool sketch_mode = (m_ui_mode == UiMode::Sketch); // Never steal editing keys from a focused text field or an open in-canvas value field — // Delete/Ctrl+Z there must edit the text, not the model. const bool in_text = (dynamic_cast(wxWindow::FindFocus()) != nullptr) || (m_viewport && m_viewport->inline_busy()); + if (getenv("SNAPORCA_KEYTRACE")) { + wxWindow* fw = wxWindow::FindFocus(); + fprintf(stderr, "[KEYTRACE] key=%d ui_mode=%d is_sketching=%d in_text=%d inline_busy=%d focus=%s\n", + key, int(m_ui_mode), (m_viewport && m_viewport->is_sketching()) ? 1 : 0, in_text ? 1 : 0, + (m_viewport && m_viewport->inline_busy()) ? 1 : 0, + fw ? (const char*) fw->GetClassInfo()->GetClassName() : "(none)"); + fflush(stderr); + } const bool dismissable = m_active != Tool::None || (m_viewport && m_viewport->moving_body()); if (key == WXK_ESCAPE && dismissable) { tool_cancel(); return; } @@ -3422,7 +3443,7 @@ DesignPanel::DesignPanel(wxWindow* parent) // Section view controls while it is on (Alt+Wheel is unreliable under remote desktops / is // grabbed by GLCanvas3D, so the keyboard drives it): PageUp/PageDown move the plane, F flips // which half is kept (so you can inspect the opposite part). - if (!in_text && !sketching && m_section_on) { + if (!in_text && !sketch_mode && m_section_on) { if (key == WXK_PAGEUP || key == WXK_PAGEDOWN) { m_section_cut_z += (key == WXK_PAGEUP ? 2.0 : -2.0); if (m_viewport) m_viewport->set_section_plane(true, m_section_cut_z, m_section_upper); @@ -3435,7 +3456,7 @@ DesignPanel::DesignPanel(wxWindow* parent) // toggles / section. Ctrl-combos and focused text fields are never intercepted. if (!in_text && !ctrl) { const int up = (key >= 'a' && key <= 'z') ? key - 'a' + 'A' : key; // normalise case - if (sketching) { + if (sketch_mode) { auto it = m_keys_sketch.find(up); if (it != m_keys_sketch.end()) { it->second(); return; } } else {