From d54e3626d34672774817132f7bc15ccf338825ce Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Sat, 18 Apr 2026 13:02:15 +0100 Subject: [PATCH 1/2] MP3 player + NeoUI minor changes * Main root menu now responds to `neo_mp3` bind * `NeoUI::ProgressDrag` fix not immediately responding on click * New `NeoUI::Bind` for named keybinds --- src/game/client/neo/ui/neo_root.cpp | 2 +- src/game/client/neo/ui/neo_ui.cpp | 9 ++++++++- src/game/client/neo/ui/neo_ui.h | 1 + 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/game/client/neo/ui/neo_root.cpp b/src/game/client/neo/ui/neo_root.cpp index ff9a1a5c0..4bf162d1c 100644 --- a/src/game/client/neo/ui/neo_root.cpp +++ b/src/game/client/neo/ui/neo_root.cpp @@ -1270,7 +1270,7 @@ void CNeoRoot::MainLoopRoot(const MainLoopParam param) } // Play/Pause button - if (NeoUI::Button(mps->bPlaying ? L"II" : L"\u25B6").bPressed) + if (NeoUI::Button(mps->bPlaying ? L"II" : L"\u25B6").bPressed || NeoUI::Bind("neo_mp3")) { mps->flagsPlayStateNext = (mps->bPlaying) ? NeoMP3::PLAYSTATE_FLAG_PAUSED : NeoMP3::PLAYSTATE_FLAG_PLAY; diff --git a/src/game/client/neo/ui/neo_ui.cpp b/src/game/client/neo/ui/neo_ui.cpp index a06b4baf0..51bebdf3c 100644 --- a/src/game/client/neo/ui/neo_ui.cpp +++ b/src/game/client/neo/ui/neo_ui.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include "neo_misc.h" @@ -2217,7 +2218,7 @@ void Progress(const float flValue, const float flMin, const float flMax) void ProgressDrag(float *flValue, const float flMin, const float flMax) { - const auto wdgState = BeginWidget(WIDGETFLAG_MOUSE | WIDGETFLAG_MARKACTIVE); + auto wdgState = BeginWidget(WIDGETFLAG_MOUSE | WIDGETFLAG_MARKACTIVE); if (wdgState.bInView) { switch (c->eMode) @@ -2239,6 +2240,7 @@ void ProgressDrag(float *flValue, const float flMin, const float flMax) c->iActive = c->iWidget; c->iActiveSection = c->iSection; c->eMousePressedStart = MOUSESTART_SLIDER; + wdgState.bActive = true; } } [[fallthrough]]; case MODE_MOUSEMOVED: @@ -3528,6 +3530,11 @@ void EndIgnoreXOffset() c->bIgnoreXOffset = false; } +bool Bind(const char *pszBindName) +{ + return c->eMode == MODE_KEYPRESSED && c->eCode == gameuifuncs->GetButtonCodeForBind(pszBindName); +} + bool Bind(const ButtonCode_t eCode) { return c->eMode == MODE_KEYPRESSED && c->eCode == eCode; diff --git a/src/game/client/neo/ui/neo_ui.h b/src/game/client/neo/ui/neo_ui.h index caf6188a6..e1defdb59 100644 --- a/src/game/client/neo/ui/neo_ui.h +++ b/src/game/client/neo/ui/neo_ui.h @@ -645,6 +645,7 @@ bool Texture(const char *szTexturePath, const int x, const int y, const int widt void ResetTextures(); // Non-widgets/convenience functions +bool Bind(const char *pszBindName); bool Bind(const ButtonCode_t eCode); bool Bind(const ButtonCode_t *peCode, const int ieCodeSize); bool BindKeyEnter(); From a132708f6f935d3753e3b7c1fe7b6f90c846b9c7 Mon Sep 17 00:00:00 2001 From: nullsystem <15316579+nullsystem@users.noreply.github.com> Date: Sun, 26 Apr 2026 18:08:01 +0100 Subject: [PATCH 2/2] Root main menu multi keybindings fix neo_mp3 can now be handled by multiple binds. neo_toggleconsole also however it's limited to single due to keybind enforce workaround causing issue with console multi-keybinds and unable to figure out multi binds here somewhat. Settings button also updated to single key for console. --- src/game/client/neo/ui/neo_root.cpp | 42 ++++++++++++++--- src/game/client/neo/ui/neo_root.h | 12 +++++ src/game/client/neo/ui/neo_root_settings.cpp | 47 +++++++++++++------- src/game/client/neo/ui/neo_root_settings.h | 4 +- src/game/client/neo/ui/neo_ui.cpp | 5 --- src/game/client/neo/ui/neo_ui.h | 1 - 6 files changed, 81 insertions(+), 30 deletions(-) diff --git a/src/game/client/neo/ui/neo_root.cpp b/src/game/client/neo/ui/neo_root.cpp index 4bf162d1c..8c427a95a 100644 --- a/src/game/client/neo/ui/neo_root.cpp +++ b/src/game/client/neo/ui/neo_root.cpp @@ -349,6 +349,12 @@ constexpr const char *BTNS_LOCALIZE[MMBTN__TOTAL] = { "#GameUI_GameMenu_Quit", }; +static const char *BINDNAME_TO_ROOTBUTTONACTION_MAP[CNeoRoot::ROOTBUTTONACTION__TOTAL] = { + "", // ROOTBUTTONACTION_NIL (skip over in loop) + "neo_toggleconsole", // ROOTBUTTONACTION_TOGGLECONSOLE + "neo_mp3", // ROOTBUTTONACTION_MP3 +}; + CNeoRoot::CNeoRoot(VPANEL parent) : EditablePanel(nullptr, "NeoRootPanel") , m_panelCaptureInput(new CNeoRootInput(this)) @@ -632,12 +638,34 @@ void CNeoRoot::OnRelayedKeyCodeTyped(vgui::KeyCode code) return; } - // Refresh every time, because else if the user unbinds or rebinds the key, it will still incorrectly be mapped there. - // NEO FIXME (Rain): We do not currently support binding multiple buttons for the same command; - // if the user does: bind a foo; bind b foo; then only the latest bind will work. - m_ns.keys.bcConsole = gameuifuncs->GetButtonCodeForBind("neo_toggleconsole"); + // NEO NOTE (nullsystem): There doesn't seem to be callbacks to check on updated + // keybinds and neither would ClientModeShared::KeyInput pick up neo_mp3, + // so timed and only on typed so it doesn't go checking on all buttons everytime + if (m_flHtBtnCodeUpdate <= gpGlobals->realtime) + { + m_htButtonCodeToAction.RemoveAll(); + for (int iBc = KEY_FIRST; iBc <= BUTTON_CODE_LAST; ++iBc) + { + const ButtonCode_t bc = static_cast(iBc); + const char *pszBinding = gameuifuncs->GetBindingForButtonCode(bc); + // Only needed it for binds used for neo_root + if (pszBinding) + { + for (int i = (ROOTBUTTONACTION_NIL + 1); i < ROOTBUTTONACTION__TOTAL; ++i) + { + if (0 == V_strcmp(pszBinding, BINDNAME_TO_ROOTBUTTONACTION_MAP[i])) + { + m_htButtonCodeToAction.Insert(bc, static_cast(i)); + break; + } + } + } + } + m_flHtBtnCodeUpdate = gpGlobals->realtime + 1.0f; + } - if (code == m_ns.keys.bcConsole && code != KEY_BACKQUOTE) + if (KEY_BACKQUOTE != code + && ROOTBUTTONACTION_TOGGLECONSOLE == m_htButtonCodeToAction.Get(code, ROOTBUTTONACTION_NIL)) { // NEO JANK (nullsystem): Prevent toggle being handled twice causing it to not really open. // This can happen if using the default ` due to the engine enacting this all the time, however calling @@ -1270,7 +1298,9 @@ void CNeoRoot::MainLoopRoot(const MainLoopParam param) } // Play/Pause button - if (NeoUI::Button(mps->bPlaying ? L"II" : L"\u25B6").bPressed || NeoUI::Bind("neo_mp3")) + if (NeoUI::Button(mps->bPlaying ? L"II" : L"\u25B6").bPressed + || (NeoUI::MODE_KEYPRESSED == g_uiCtx.eMode + && ROOTBUTTONACTION_MP3 == m_htButtonCodeToAction.Get(g_uiCtx.eCode, ROOTBUTTONACTION_NIL))) { mps->flagsPlayStateNext = (mps->bPlaying) ? NeoMP3::PLAYSTATE_FLAG_PAUSED : NeoMP3::PLAYSTATE_FLAG_PLAY; diff --git a/src/game/client/neo/ui/neo_root.h b/src/game/client/neo/ui/neo_root.h index faa81859e..ff6931924 100644 --- a/src/game/client/neo/ui/neo_root.h +++ b/src/game/client/neo/ui/neo_root.h @@ -265,6 +265,18 @@ class CNeoRoot : public vgui::EditablePanel, public CGameEventListener float m_flAutoJoinLastAttempt = 0.0f; CNeoServerPing m_serverPingAutoJoin = {}; CNeoServerPing m_serverPingEnter = {}; + + enum ERootButtonAction + { + ROOTBUTTONACTION_NIL = 0, + ROOTBUTTONACTION_TOGGLECONSOLE, + ROOTBUTTONACTION_MP3, + + ROOTBUTTONACTION__TOTAL, + }; + + float m_flHtBtnCodeUpdate = 0.0f; + CUtlHashtable m_htButtonCodeToAction; }; extern CNeoRoot *g_pNeoRoot; diff --git a/src/game/client/neo/ui/neo_root_settings.cpp b/src/game/client/neo/ui/neo_root_settings.cpp index ff384a678..ad7c8c274 100644 --- a/src/game/client/neo/ui/neo_root_settings.cpp +++ b/src/game/client/neo/ui/neo_root_settings.cpp @@ -183,6 +183,7 @@ void NeoSettingsInit(NeoSettings *ns) auto *conbind = &keys->vBinds[keys->iBindsSize++]; V_strcpy_safe(conbind->szBindingCmd, "neo_toggleconsole"); V_wcscpy_safe(conbind->wszDisplayText, L"Developer console bind"); + conbind->bSkipSecondary = true; while (bufAct.IsValid() && keys->iBindsSize < ARRAYSIZE(keys->vBinds)) { @@ -222,6 +223,7 @@ void NeoSettingsInit(NeoSettings *ns) V_strcpy_safe(bind->szBindingCmd, szBindingCmd); V_wcscpy_safe(bind->wszDisplayText, wszDispText); bind->bcDefault = BUTTON_CODE_NONE; + bind->bSkipSecondary = false; } } AssertMsg(keys->iBindsSize < ARRAYSIZE(keys->vBinds), "Bump the size of the vBinds array"); @@ -490,15 +492,18 @@ void NeoSettingsRestore(NeoSettings *ns, const NeoSettings::Keys::Flags flagsKey auto hdl = htAllBinds.Find(bind->szBindingCmd); if (hdl != htAllBinds.InvalidHandle()) { - const auto &bcVal = htAllBinds.Element(hdl); - const int iMaxIdxBc = Min(bcVal.iSize, MAX_BCVAL); - for (int idxBc = 0; idxBc < iMaxIdxBc; ++idxBc) + if (false == bind->bSkipSecondary) { - const ButtonCode_t bc = bcVal.list[idxBc]; - if (bc != bind->bcCurrent) + const auto &bcVal = htAllBinds.Element(hdl); + const int iMaxIdxBc = Min(bcVal.iSize, MAX_BCVAL); + for (int idxBc = 0; idxBc < iMaxIdxBc; ++idxBc) { - bind->bcSecondaryNext = bind->bcSecondaryCurrent = bc; - break; + const ButtonCode_t bc = bcVal.list[idxBc]; + if (bc != bind->bcCurrent) + { + bind->bcSecondaryNext = bind->bcSecondaryCurrent = bc; + break; + } } } } @@ -727,6 +732,9 @@ void NeoSettingsRestore(NeoSettings *ns, const NeoSettings::Keys::Flags flagsKey } } +// NEO TODO (nullsystem): For now the settings UI only exposes consoles as a +// single keybind and this also deals with a single bind. Trying to enforce +// multiple neo_toggleconsole binds doesn't seem to work here? void NeoToggleConsoleEnforce() { // NEO JANK (nullsystem): Try to unbind toggleconsole when possible @@ -826,8 +834,6 @@ void NeoSettingsSave(const NeoSettings *ns) bind->bcCurrent = bind->bcNext; bind->bcSecondaryCurrent = bind->bcSecondaryNext; } - // Reset the cache to none so it'll refresh on next KeyCodeTyped - const_cast(pKeys)->bcConsole = KEY_NONE; } { const NeoSettings::Mouse *pMouse = &ns->mouse; @@ -1198,7 +1204,11 @@ void NeoSettings_Keys(NeoSettings *ns) } else { - NeoUI::BeginMultiWidgetHighlighter(3); + if (bind.bSkipSecondary) + { + NeoUI::SetPerRowLayout(2, NeoUI::ROWLAYOUT_TWOSPLIT); + } + NeoUI::BeginMultiWidgetHighlighter(bind.bSkipSecondary ? 2 : 3); NeoUI::Label(bind.wszDisplayText); wchar_t wszBindBtnName[64]; const char *szBindBtnName = g_pInputSystem->ButtonCodeToString(bind.bcNext); @@ -1208,14 +1218,21 @@ void NeoSettings_Keys(NeoSettings *ns) ns->iNextBinding = i; ns->bNextBindingSecondary = false; } - const char *szBindSecondaryBtnName = g_pInputSystem->ButtonCodeToString(bind.bcSecondaryNext); - g_pVGuiLocalize->ConvertANSIToUnicode(szBindSecondaryBtnName, wszBindBtnName, sizeof(wszBindBtnName)); - if (NeoUI::Button(wszBindBtnName).bPressed) + if (false == bind.bSkipSecondary) { - ns->iNextBinding = i; - ns->bNextBindingSecondary = true; + const char *szBindSecondaryBtnName = g_pInputSystem->ButtonCodeToString(bind.bcSecondaryNext); + g_pVGuiLocalize->ConvertANSIToUnicode(szBindSecondaryBtnName, wszBindBtnName, sizeof(wszBindBtnName)); + if (NeoUI::Button(wszBindBtnName).bPressed) + { + ns->iNextBinding = i; + ns->bNextBindingSecondary = true; + } } NeoUI::EndMultiWidgetHighlighter(); + if (bind.bSkipSecondary) + { + NeoUI::SetPerRowLayout(ARRAYSIZE(KEYS_LAYOUT), KEYS_LAYOUT); + } } } } diff --git a/src/game/client/neo/ui/neo_root_settings.h b/src/game/client/neo/ui/neo_root_settings.h index 577772a91..88ae91bfc 100644 --- a/src/game/client/neo/ui/neo_root_settings.h +++ b/src/game/client/neo/ui/neo_root_settings.h @@ -88,13 +88,11 @@ struct NeoSettings ButtonCode_t bcDefault; ButtonCode_t bcSecondaryNext; ButtonCode_t bcSecondaryCurrent; + bool bSkipSecondary = false; }; Bind vBinds[NEO_BINDS_TOTAL]; int iBindsSize = 0; - // Will be checked often so cached - ButtonCode_t bcConsole; - enum Flags { NONE = 0, diff --git a/src/game/client/neo/ui/neo_ui.cpp b/src/game/client/neo/ui/neo_ui.cpp index 51bebdf3c..7e9dfdb39 100644 --- a/src/game/client/neo/ui/neo_ui.cpp +++ b/src/game/client/neo/ui/neo_ui.cpp @@ -3530,11 +3530,6 @@ void EndIgnoreXOffset() c->bIgnoreXOffset = false; } -bool Bind(const char *pszBindName) -{ - return c->eMode == MODE_KEYPRESSED && c->eCode == gameuifuncs->GetButtonCodeForBind(pszBindName); -} - bool Bind(const ButtonCode_t eCode) { return c->eMode == MODE_KEYPRESSED && c->eCode == eCode; diff --git a/src/game/client/neo/ui/neo_ui.h b/src/game/client/neo/ui/neo_ui.h index e1defdb59..caf6188a6 100644 --- a/src/game/client/neo/ui/neo_ui.h +++ b/src/game/client/neo/ui/neo_ui.h @@ -645,7 +645,6 @@ bool Texture(const char *szTexturePath, const int x, const int y, const int widt void ResetTextures(); // Non-widgets/convenience functions -bool Bind(const char *pszBindName); bool Bind(const ButtonCode_t eCode); bool Bind(const ButtonCode_t *peCode, const int ieCodeSize); bool BindKeyEnter();