Skip to content

Custom hotkey remapping for unit/building production keys in Options#2589

Open
wahidkurdo wants to merge 4 commits intoTheSuperHackers:mainfrom
wahidkurdo:feat/custom-hotkey-remapping
Open

Custom hotkey remapping for unit/building production keys in Options#2589
wahidkurdo wants to merge 4 commits intoTheSuperHackers:mainfrom
wahidkurdo:feat/custom-hotkey-remapping

Conversation

@wahidkurdo
Copy link
Copy Markdown

You can now set Custom Hotkeys in game Options

Test Done its working without crashes

…n keys

- Add per-faction (USA/China/GLA) hotkey categories to KeyboardOptionsMenu

- Override-Map in HotKeyManager for persistent key rebinding

- Manual overlay layout management (no Shell push/pop conflicts)

- ComboBox category selector, ListBox command list, TextEntry key input

- Assign/ResetAll buttons with full MetaMap + CommandButton support

- Includes .wnd UI layout files under Patch/Window/Menus/
@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 12, 2026

Greptile Summary

This PR adds per-faction (USA/China/GLA) CommandButton hotkey remapping accessible from the Options menu, backed by a new HotKeyManager override map persisted to HotKeyOverrides.ini via UserPreferences. The three issues flagged in the previous review cycle (missing override methods, unnotified conflict, null-dereference on EntryData) are all resolved.

  • loadOverrides() (HotKey.cpp:280) is missing an strncmp prefix guard — any INI key longer than 7 chars that doesn't start with HotKey_ is silently accepted and loaded under a garbage command-button name. saveOverrides() already performs this check correctly.
  • OptionsMenu.cpp contains unrelated #if defined(ENABLE_VOICE_CHAT) dead-code comment blocks that appear out of scope for this PR.

Confidence Score: 4/5

Safe to merge after fixing the missing prefix check in loadOverrides(); all prior blocking issues are resolved.

All three P1 issues from the previous review cycle are addressed. One new P1 remains: loadOverrides() skips the strncmp prefix guard that saveOverrides() already uses, meaning a corrupted or manually edited INI can silently populate the override map with garbage entries. The NULL/nullptr and unrelated dead-code items are P2 and do not block merge.

HotKey.cpp — the loadOverrides() function at line 280 needs a strncmp prefix check to match the guard already present in saveOverrides().

Important Files Changed

Filename Overview
GeneralsMD/Code/GameEngine/Include/GameClient/HotKey.h Adds setOverride, removeOverride, getOverride, clearAllOverrides, loadOverrides, saveOverrides, and OverrideMap typedef to HotKeyManager; backing storage m_hotKeyOverrides added correctly.
GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp Implements override methods; loadOverrides() is missing an strncmp prefix guard, allowing any key longer than 7 chars in the INI to be silently misinterpreted as a command-button override.
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/KeyboardOptionsMenu.cpp Major rework: adds faction-based CommandButton hotkey UI, manual overlay open/close helpers, and conflict warning; previous null-check and missing-method issues are resolved; NULL should be nullptr in the fallback MessageBoxA call.
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp Routes Keyboard Options button to OpenKeyboardOptionsMenu(); also adds unrelated #if defined(ENABLE_VOICE_CHAT) dead-code blocks that appear out of scope for this PR.
GeneralsMD/Code/GameEngine/Include/GameClient/GUICallbacks.h Adds extern declarations for OpenKeyboardOptionsMenu and CloseKeyboardOptionsMenu; straightforward and correct.
GeneralsMD/Code/GameEngine/Source/Common/System/FunctionLexicon.cpp Registers KeyboardOptionsMenuUpdate in the layout update table so the new .wnd file can resolve its callback; correct and minimal change.

Sequence Diagram

sequenceDiagram
    participant OM as OptionsMenu
    participant KOM as KeyboardOptionsMenu
    participant HKM as HotKeyManager
    participant INI as HotKeyOverrides.ini

    Note over HKM: init() on startup
    HKM->>INI: loadOverrides()
    INI-->>HKM: HotKey_* entries to m_hotKeyOverrides

    OM->>KOM: OpenKeyboardOptionsMenu()
    KOM->>KOM: winCreateLayout(KeyboardOptionsMenu.wnd)
    KOM->>OM: hide OptionsMenu overlay

    KOM->>HKM: getOverride(cmdButtonName)
    HKM-->>KOM: current override key (or empty)

    Note over KOM: User selects entry, types new key, clicks Assign
    KOM->>HKM: setOverride(cmdButtonName, newKey)
    KOM->>HKM: saveOverrides()
    HKM->>INI: write HotKey_* entries

    KOM->>OM: CloseKeyboardOptionsMenu()
    KOM->>KOM: destroyWindows() + deleteInstance()
    KOM->>OM: show OptionsMenu overlay
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/HotKey.cpp
Line: 280-283

Comment:
**Missing prefix validation corrupts override map**

`key.getLength() > (Int)prefixLen` only checks that the key is longer than 7 characters; it does not verify the key actually starts with `"HotKey_"`. Any entry in `HotKeyOverrides.ini` whose key is longer than 7 chars but does *not* start with `HotKey_` (e.g. from a manual edit or future migration) will have its first 7 bytes stripped and inserted into `m_hotKeyOverrides` with a garbage command-button name. `saveOverrides()` already uses `strncmp` to guard against this — `loadOverrides()` should do the same.

```suggestion
		if (key.getLength() > (Int)prefixLen
			&& strncmp(key.str(), HOTKEY_OVERRIDE_PREFIX, prefixLen) == 0)
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/KeyboardOptionsMenu.cpp
Line: 667

Comment:
**`NULL``nullptr` for pointer argument**

`MessageBoxA` takes an `HWND` (pointer) as its first argument; per the project's style rules, pointer literals should use `nullptr` rather than `NULL`.

```suggestion
		MessageBoxA( nullptr,
```

**Rule Used:** Use nullptr instead of NULL for null pointer liter... ([source](https://app.greptile.com/review/custom-context?memory=c69cf1a9-c69a-4330-a013-69bb5d6701da))

**Learnt From**
[TheSuperHackers/GeneralsGameCode#2067](https://github.com/TheSuperHackers/GeneralsGameCode/pull/2067#discussion_r2703746722)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp
Line: 74-77

Comment:
**Unrelated dead-code block**

This `#if defined(ENABLE_VOICE_CHAT)` block — and the similar comments added in `OptionsMenuInit`, `OptionsMenuShutdown`, and `OptionsMenuSystem` — appear unrelated to the hotkey remapping feature. Since `ENABLE_VOICE_CHAT` is never defined these blocks compile away entirely, but they add confusing noise. Were these voice-chat removals intended to be part of this PR?

How can I resolve this? If you propose a fix, please make it concise.

Reviews (4): Last reviewed commit: "fix: address code review feedback" | Re-trigger Greptile

@wahidkurdo wahidkurdo force-pushed the feat/custom-hotkey-remapping branch from 375b7c7 to 66fca53 Compare April 12, 2026 13:59
- Show conflict warning in description text when duplicate hotkey detected

- Replace NULL with nullptr in runInit call

- Include HotKey.h and HotKey.cpp with override methods
- Show conflict warning in description text when duplicate hotkey detected

- Replace NULL with nullptr in runInit call

- Include HotKey.h and HotKey.cpp with override methods
Copy link
Copy Markdown

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this AI generated code?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do not add game data files to this repository. You will need to document the data changes that are required to use the new code.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Hotkey option was already in the game but hidden during EA never finished. The code consists of AI prompts; no one is going to write hundreds of lines of code without help from Claude.

i already pushed the README.md for how to use it. The Only Problem is that you need the Window-Menus files in game Folder

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code consists of AI prompts; no one is going to write hundreds of lines of code without help from Claude.

Do you think that EA had AI when they wrote hunderds of thousands of line of code for the generals and zero hour games?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code consists of AI prompts; no one is going to write hundreds of lines of code without help from Claude.

Do you think that EA had AI when they wrote hunderds of thousands of line of code for the generals and zero hour games?

They got paid for it and we dont

}
else if (controlID == buttonAccept )
{
// VoiceOptionsUI::Save() removed — /voice slash commands persist directly.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't make sense

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't make sense

i sent a pull request before for generalsOnline voice chat this was for it

GameWindow *control = (GameWindow *)mData1;
Int controlID = control->winGetWindowId();

// VoiceOptionsUI event routing removed — /voice-only configuration.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't make sense

//-------------------------------------------------------------------------------------------------
void OptionsMenuShutdown( WindowLayout *layout, void *userData )
{
// VoiceOptionsUI::Teardown() removed with /voice-only configuration.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't make sense

}


// Voice-chat options panel disabled — use /voice slash commands instead.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't make sense

#include "GameNetwork/GameSpy/PeerDefs.h"
#include "GameLogic/GameLogic.h"
#include "GameLogic/ScriptEngine.h"
#if defined(ENABLE_VOICE_CHAT)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unused code and out of scope for this PR.

UnicodeString str;
GadgetComboBoxReset(comboBoxCategoryList);

// Built-in MetaMap categories (global hotkeys)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment not needed

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code consists of AI prompts; no one is going to write hundreds of lines of code without help from Claude.

Do you think that EA had AI when they wrote hunderds of thousands of line of code for the generals and zero hour games?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants