fix(gui): keyboard shortcuts cleanup after #15706 (#15862)

This commit is contained in:
Kris Austin
2026-09-25 21:51:19 -03:00
committed by GitHub
parent 6be6fdd7c7
commit 93b58a2034
8 changed files with 48 additions and 11 deletions
-2
View File
@@ -1088,8 +1088,6 @@ wxDEFINE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_MOVE_SLIDERS, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDEFINE_EVENT(EVT_GLCANVAS_SWITCH_TO_OBJECT, SimpleEvent);
-2
View File
@@ -185,8 +185,6 @@ wxDECLARE_EVENT(EVT_GLCANVAS_MOUSE_DRAGGING_FINISHED, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UPDATE_BED_SHAPE, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_TAB, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_RESETGIZMOS, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_MOVE_SLIDERS, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_JUMP_TO, wxKeyEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_UNDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_REDO, SimpleEvent);
wxDECLARE_EVENT(EVT_GLCANVAS_SWITCH_TO_OBJECT, SimpleEvent);
+13 -4
View File
@@ -159,8 +159,12 @@ void KBShortcutsDialog::fill_pages()
if (wxGetApp().is_editor()) {
page(_L("Global"), _L("Available anywhere in the window, even while typing in a text field."), ShortcutContext::Global, {
fixed(Section::Application, { alt, "1-9, 0" }, L("Run a speed dial favorite while the dial is open")),
fixed(Section::SpeedDial, { alt, "1-9, 0" }, L("Run favorite 1 to 10")),
fixed(Section::SpeedDial, { ctrl, "B" }, L("Pin or unpin the selected action")),
// wx cycles notebook pages on Ctrl+Tab, which is Cmd+Tab on macOS and never arrives there.
#ifndef __APPLE__
fixed(Section::Application, { ctrl, key(L_CONTEXT("Tab", "Keyboard Shortcut")) }, L("Switch to the next main tab")),
#endif
});
page(_L("Prepare"), _L("Available while the 3D view on the Prepare tab has focus."), ShortcutContext::Plater, {
@@ -454,7 +458,10 @@ ShortcutCaptureDialog::ShortcutCaptureDialog(wxWindow* parent, Shortcut shortcut
capture_sizer->Add(m_chord_label, 0, wxALIGN_CENTER);
capture_sizer->AddStretchSpacer();
capture->SetSizer(capture_sizer);
capture->Bind(wxEVT_KEY_DOWN, &ShortcutCaptureDialog::on_key, this);
capture->Layout(); // the box is created at its final size, so nothing resizes it into laying the sizer out
// The hook runs before the window procedure, so Windows does not open its window menu
// over the dialog on Alt+Space.
Bind(wxEVT_CHAR_HOOK, &ShortcutCaptureDialog::on_key, this);
capture->Bind(wxEVT_CHAR, &ShortcutCaptureDialog::on_char, this);
capture->Bind(wxEVT_LEFT_DOWN, [capture](wxMouseEvent&) { capture->SetFocus(); });
sizer->Add(capture, 0, wxLEFT | wxRIGHT | wxEXPAND, FromDIP(20));
@@ -531,10 +538,12 @@ void ShortcutCaptureDialog::record(const KeyChord& chord)
m_ok->Enable(false);
};
const bool global = (shortcut_info(m_shortcut).contexts & context_bit(ShortcutContext::Global)) != 0;
if (global && !chord.is_menu_accelerator()) {
if (chord.is_system_shortcut()) {
reject(_L("The system uses this shortcut, so it cannot be assigned."));
} else if (global && !chord.is_menu_accelerator()) {
reject(m_rejection);
} else if (const std::optional<Shortcut> owner = wxGetApp().shortcuts().step_owner(m_shortcut, chord); owner.has_value()) {
reject(wxString::Format(_L("Already used as a step of %s."), _(shortcut_info(*owner).name)));
reject(wxString::Format(_L("Shift and Ctrl with this key belong to %s and cannot be assigned."), _(shortcut_info(*owner).name)));
} else {
m_conflicts = wxGetApp().shortcuts().conflicts(m_shortcut, chord);
m_status->SetForegroundColour(m_status_colour);
+10
View File
@@ -182,6 +182,16 @@ bool KeyChord::is_menu_accelerator() const
return valid() && ((modifiers & (wxMOD_CONTROL | wxMOD_ALT | wxMOD_RAW_CONTROL)) != 0 || (!is_printable(key) && key != WXK_SPACE));
}
// Only a chord the desktop acts on while still delivering it to the app belongs here.
bool KeyChord::is_system_shortcut() const
{
#ifdef _WIN32
return modifiers == wxMOD_ALT && (key == WXK_F4 || key == WXK_SPACE);
#else
return false;
#endif
}
std::string KeyChord::to_string() const
{
if (!valid())
+3
View File
@@ -34,6 +34,9 @@ struct KeyChord
// True when Ctrl or Alt is held or the key is non-printable, the chords a menu can own without
// swallowing typing in text fields.
bool is_menu_accelerator() const;
// True for a chord the desktop acts on although the app receives it, so a binding would
// take it from the system.
bool is_system_shortcut() const;
// Platform-neutral text ("Ctrl+Shift+S") for persistence and wx accelerator strings.
std::string to_string() const;
+4 -1
View File
@@ -147,9 +147,11 @@ constexpr std::array<ShortcutInfo, size_t(Shortcut::Count)> shortcut_table = {{
SHORTCUT(Search, "search", L("Search"), GLOBAL, { 'F', CTRL }),
SHORTCUT(SwitchView, "switch_view", L("Switch between Prepare/Preview"), CANVAS, { WXK_TAB }),
SHORTCUT(CollapseSidebar, "collapse_sidebar", L("Collapse/Expand the sidebar"), CANVAS, { WXK_TAB, SHIFT }),
SHORTCUT(SpeedDial, "speed_dial", L("Open the speed dial"), GLOBAL, { WXK_SPACE }),
SHORTCUT(ReloadDevicePage, "reload_device_page", L("Reload the device page"), CANVAS, { WXK_F5 }),
SHORTCUT(KeyboardShortcuts, "keyboard_shortcuts", L("Show keyboard shortcuts list"), CANVAS, { '?' }),
// Speed Dial
SHORTCUT(SpeedDial, "speed_dial", L("Open the Speed Dial"), GLOBAL, { WXK_SPACE }),
}};
#undef SHORTCUT
@@ -177,6 +179,7 @@ constexpr std::array<SectionInfo, size_t(ShortcutSection::Count)> section_table
{ Shortcut::ViewDefault, L("Camera") },
{ Shortcut::ShowLabels, L("Display") },
{ Shortcut::Preferences, L("Application") },
{ Shortcut::SpeedDial, L("Speed Dial") },
}};
constexpr bool sections_follow_table_order()
+4 -2
View File
@@ -47,7 +47,9 @@ enum class Shortcut : uint8_t {
// Display
ShowLabels, ShowWireframe, ToggleGcodeWindow, ToggleOneLayerMode,
// Application
Preferences, Search, SwitchView, CollapseSidebar, SpeedDial, ReloadDevicePage, KeyboardShortcuts,
Preferences, Search, SwitchView, CollapseSidebar, ReloadDevicePage, KeyboardShortcuts,
// Speed Dial
SpeedDial,
Count
};
@@ -66,7 +68,7 @@ struct ShortcutInfo
// Headings of the shortcuts dialog, in listing order.
enum class ShortcutSection : uint8_t {
Project, SlicingAndPrinting, Selection, Editing, Objects, Placement, Gizmos, Sliders, PaintingTools, Camera, Display, Application,
Project, SlicingAndPrinting, Selection, Editing, Objects, Placement, Gizmos, Sliders, PaintingTools, Camera, Display, Application, SpeedDial,
Count
};
+14
View File
@@ -120,6 +120,20 @@ TEST_CASE("Only modified or non-printable chords qualify as menu accelerators",
CHECK(registry.accelerator(Shortcut::KeyboardShortcuts).empty());
}
TEST_CASE("Chords the desktop keeps for itself are recognized", "[Shortcuts]")
{
#ifdef _WIN32
CHECK(KeyChord{ WXK_F4, wxMOD_ALT }.is_system_shortcut());
CHECK(KeyChord{ WXK_SPACE, wxMOD_ALT }.is_system_shortcut());
#else
CHECK_FALSE(KeyChord{ WXK_F4, wxMOD_ALT }.is_system_shortcut());
CHECK_FALSE(KeyChord{ WXK_SPACE, wxMOD_ALT }.is_system_shortcut());
#endif
CHECK_FALSE(KeyChord{ WXK_F4, wxMOD_ALT | wxMOD_SHIFT }.is_system_shortcut());
CHECK_FALSE(KeyChord{ WXK_F4, wxMOD_CONTROL }.is_system_shortcut());
CHECK_FALSE(KeyChord{ WXK_SPACE }.is_system_shortcut());
}
TEST_CASE("Chords convert to wx accelerator entries", "[Shortcuts]")
{
const wxAcceleratorEntry entry = KeyChord{ 'S', wxMOD_CONTROL | wxMOD_SHIFT }.to_accelerator_entry(42);