Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 26 additions & 41 deletions src/Menu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ void Menu::ProcessInputEventQueue()
};
KeyAction keyActions[] = {
{ settings.ToggleKey, [this]() { if (!HomePageRenderer::ShouldShowFirstTimeSetup()) IsEnabled = !IsEnabled; } },
{ settings.SkipCompilationKey, [shaderCache]() { shaderCache->backgroundCompilation = true; } },
{ settings.SkipCompilationKey, [this, shaderCache]() { if (!ShouldSwallowInput() && shaderCache->IsCompiling()) shaderCache->backgroundCompilation = true; } },
{ settings.EffectToggleKey, [shaderCache]() { shaderCache->SetEnabled(!shaderCache->IsEnabled()); } },
{ settings.ShaderBlockPrevKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(); } },
{ settings.ShaderBlockNextKey, [this, shaderCache]() { if (settings.EnableShaderBlocking) shaderCache->IterateShaderBlock(false); } },
Expand All @@ -1027,36 +1027,9 @@ void Menu::ProcessInputEventQueue()
} },
};
for (const auto& ka : keyActions) {
// Check if key matches last key in combo and all modifiers are held (exact match)
if (!ka.settingKey.empty() &&
ka.settingKey.back().GetKey() == key &&
ka.settingKey.back().GetDevice() == InputDeviceType::Keyboard) {
// Build set of required modifiers from combo
bool requiresCtrl = false, requiresShift = false, requiresAlt = false;
for (size_t i = 0; i < ka.settingKey.size() - 1; ++i) {
uint32_t modKey = ka.settingKey[i].GetKey();
if (modKey == VK_CONTROL || modKey == VK_LCONTROL || modKey == VK_RCONTROL)
requiresCtrl = true;
else if (modKey == VK_SHIFT || modKey == VK_LSHIFT || modKey == VK_RSHIFT)
requiresShift = true;
else if (modKey == VK_MENU || modKey == VK_LMENU || modKey == VK_RMENU)
requiresAlt = true;
}

// Check current modifier state
bool ctrlHeld = (GetAsyncKeyState(VK_CONTROL) & Constants::KEY_PRESSED_MASK) != 0;
bool shiftHeld = (GetAsyncKeyState(VK_SHIFT) & Constants::KEY_PRESSED_MASK) != 0;
bool altHeld = (GetAsyncKeyState(VK_MENU) & Constants::KEY_PRESSED_MASK) != 0;

// Exact match: required modifiers must be held, and no extra modifiers
bool exactMatch = (requiresCtrl == ctrlHeld) &&
(requiresShift == shiftHeld) &&
(requiresAlt == altHeld);

if (exactMatch) {
ka.action();
break;
}
if (InputCombo::MatchesKeyboardCombo(ka.settingKey, key)) {
ka.action();
break;
}
}
}
Expand All @@ -1074,16 +1047,28 @@ void Menu::ProcessInputEventQueue()
}
}

// DirectInput loses key-up events after alt-tab; validate against OS state.
bool pressed = event.IsPressed() && (GetAsyncKeyState(key) & Constants::KEY_PRESSED_MASK);
io.AddKeyEvent(Util::Input::VirtualKeyToImGuiKey(key), pressed);

if (key == VK_LCONTROL || key == VK_RCONTROL)
io.AddKeyEvent(ImGuiMod_Ctrl, pressed);
else if (key == VK_LSHIFT || key == VK_RSHIFT)
io.AddKeyEvent(ImGuiMod_Shift, pressed);
else if (key == VK_LMENU || key == VK_RMENU)
io.AddKeyEvent(ImGuiMod_Alt, pressed);
// Don't forward hotkey events to ImGui when input is captured (prevents e.g. End key scrolling the feature list)
// SkipCompilationKey (ESC) is excluded — ESC must reach ImGui for menu/dialog close.
const std::vector<InputCombo>* hotkeys[] = {
&settings.ToggleKey, &settings.EffectToggleKey,
&settings.OverlayToggleKey, &settings.ShaderBlockPrevKey, &settings.ShaderBlockNextKey,
&settings.WeatherEditorToggleKey
};
bool isHotkey = ShouldSwallowInput() && std::any_of(std::begin(hotkeys), std::end(hotkeys),
[key](const auto* combo) { return InputCombo::MatchesKeyboardCombo(*combo, key); });

if (!isHotkey) {
// DirectInput loses key-up events after alt-tab; validate against OS state.
bool pressed = event.IsPressed() && (GetAsyncKeyState(key) & Constants::KEY_PRESSED_MASK);
io.AddKeyEvent(Util::Input::VirtualKeyToImGuiKey(key), pressed);

if (key == VK_LCONTROL || key == VK_RCONTROL)
io.AddKeyEvent(ImGuiMod_Ctrl, pressed);
else if (key == VK_LSHIFT || key == VK_RSHIFT)
io.AddKeyEvent(ImGuiMod_Shift, pressed);
else if (key == VK_LMENU || key == VK_RMENU)
io.AddKeyEvent(ImGuiMod_Alt, pressed);
}
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/Utils/Input.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,31 @@ struct InputCombo
return IsValidDevice(GetDevice()) && GetKey() != 0;
}

/// Checks if a VK key code with current modifier state exactly matches a keyboard combo.
static bool MatchesKeyboardCombo(const std::vector<InputCombo>& combo, uint32_t vkKey)
{
if (combo.empty() || combo.back().GetKey() != vkKey || combo.back().GetDevice() != InputDeviceType::Keyboard)
return false;

bool requiresCtrl = false, requiresShift = false, requiresAlt = false;
for (size_t i = 0; i < combo.size() - 1; ++i) {
uint32_t modKey = combo[i].GetKey();
if (modKey == VK_CONTROL || modKey == VK_LCONTROL || modKey == VK_RCONTROL)
requiresCtrl = true;
else if (modKey == VK_SHIFT || modKey == VK_LSHIFT || modKey == VK_RSHIFT)
requiresShift = true;
else if (modKey == VK_MENU || modKey == VK_LMENU || modKey == VK_RMENU)
requiresAlt = true;
}

constexpr uint16_t KEY_PRESSED = 0x8000;
bool ctrlHeld = (GetAsyncKeyState(VK_CONTROL) & KEY_PRESSED) != 0;
bool shiftHeld = (GetAsyncKeyState(VK_SHIFT) & KEY_PRESSED) != 0;
bool altHeld = (GetAsyncKeyState(VK_MENU) & KEY_PRESSED) != 0;

return (requiresCtrl == ctrlHeld) && (requiresShift == shiftHeld) && (requiresAlt == altHeld);
}

/**
* @brief Equality comparison operator for container usage
* @param other The InputCombo to compare with
Expand Down
Loading