Injection panel UX: reachable auto re-attach + explain disabled controls
- The "Auto re-attach this game on relaunch" checkbox (and the Vulkan-layer checkbox) lived inside the connected-only block, so after a disconnect the control vanished while auto_reattach_ could stay enabled -- an active, invisible flag. Move both to render whenever a target is selected, connected or not, so they can be set up pre-launch and toggled off after disconnect. - Explain why controls are greyed out: an inline hint under the subsystem toggles when no live game is connected, and a hover tooltip (AllowWhenDisabled) on the disabled "Inject & Connect" button telling the operator to pick a target. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -113,11 +113,6 @@ default** and covers anything the hooked path doesn't.
|
|||||||
From an in-depth review pass. Each item is fixed test-first (a failing test, then the fix) and lands
|
From an in-depth review pass. Each item is fixed test-first (a failing test, then the fix) and lands
|
||||||
as its own commit; "verify" items are confirmed real before any change, and dropped if not.
|
as its own commit; "verify" items are confirmed real before any change, and dropped if not.
|
||||||
|
|
||||||
UX:
|
|
||||||
- **Auto re-attach control** — keep it visible/controllable when not connected (today it can be
|
|
||||||
enabled-but-invisible).
|
|
||||||
- **Tooltips on disabled controls** — explain *why* Inject/subsystem controls are disabled.
|
|
||||||
|
|
||||||
Code quality:
|
Code quality:
|
||||||
- **Stale comments** — `hook_guard.hpp` top block (still the old destroy-on-remove model),
|
- **Stale comments** — `hook_guard.hpp` top block (still the old destroy-on-remove model),
|
||||||
`input_source.hpp` ("future" Steam source), `audio_ring.hpp` (v1/reserved), `shared_memory.hpp` /
|
`input_source.hpp` ("future" Steam source), `audio_ring.hpp` (v1/reserved), `shared_memory.hpp` /
|
||||||
|
|||||||
@@ -561,6 +561,10 @@ void InjectionPanel::draw_hook_status(bool debug_details)
|
|||||||
ImGui::BeginDisabled(target_state_ != TargetState::Alive);
|
ImGui::BeginDisabled(target_state_ != TargetState::Alive);
|
||||||
draw_subsystem_controls(status);
|
draw_subsystem_controls(status);
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
if (target_state_ != TargetState::Alive)
|
||||||
|
{
|
||||||
|
ImGui::TextDisabled("(connect to a live game to change these)"); // why the toggles are locked
|
||||||
|
}
|
||||||
ImGui::TextDisabled("Controller poll rates are in the Controllers panel.");
|
ImGui::TextDisabled("Controller poll rates are in the Controllers panel.");
|
||||||
|
|
||||||
draw_hook_list(status);
|
draw_hook_list(status);
|
||||||
@@ -636,40 +640,41 @@ void InjectionPanel::draw(bool debug_details)
|
|||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::TextDisabled("(relaunched %s)", narrow(selected_name_).c_str());
|
ImGui::TextDisabled("(relaunched %s)", narrow(selected_name_).c_str());
|
||||||
}
|
}
|
||||||
// Session-only auto re-attach: tick it (while attached or terminated), then kill +
|
ImGui::Separator();
|
||||||
// relaunch the game and it re-injects itself early -- the kill+relaunch fix for a
|
}
|
||||||
// wrong audio format, without picking a target again.
|
|
||||||
if (!selected_name_.empty())
|
// Session options for the selected game, shown whether or not we're connected -- so they can be set
|
||||||
|
// up before launching the game, and an enabled auto re-attach is never hidden after a disconnect.
|
||||||
|
if (!selected_name_.empty())
|
||||||
|
{
|
||||||
|
// Session-only auto re-attach: tick it, then kill + relaunch the game and it re-injects itself
|
||||||
|
// early -- the kill+relaunch fix for a wrong audio format, without picking a target again.
|
||||||
|
ImGui::Checkbox("Auto re-attach this game on relaunch", &auto_reattach_);
|
||||||
|
if (auto_reattach_ && target_state_ == TargetState::Terminated)
|
||||||
{
|
{
|
||||||
ImGui::Checkbox("Auto re-attach this game on relaunch", &auto_reattach_);
|
ImGui::SameLine();
|
||||||
if (auto_reattach_ && target_state_ == TargetState::Terminated)
|
ImGui::TextColored(kGrey, "(watching for %s...)", narrow(selected_name_).c_str());
|
||||||
|
}
|
||||||
|
// Opt-in Vulkan capture layer: for Vulkan games that initialize Vulkan immediately (where even
|
||||||
|
// auto-attach injects too late -- see the red banner), register a per-user implicit layer scoped
|
||||||
|
// to this game so the next launch is captured from the first frame. Removed when unticked / exit.
|
||||||
|
if (ImGui::Checkbox("Set up Vulkan layer (for immediate-init Vulkan games)", &vk_layer_enabled_))
|
||||||
|
{
|
||||||
|
if (vk_layer_enabled_)
|
||||||
{
|
{
|
||||||
ImGui::SameLine();
|
vk_layer_enabled_ = register_vk_layer(selected_name_);
|
||||||
ImGui::TextColored(kGrey, "(watching for %s...)", narrow(selected_name_).c_str());
|
|
||||||
}
|
}
|
||||||
// Opt-in Vulkan capture layer: for Vulkan games that initialize Vulkan immediately
|
else
|
||||||
// (where even auto-attach injects too late -- see the red banner), register a per-user
|
|
||||||
// implicit layer scoped to this game so the next launch is captured from the first frame.
|
|
||||||
// Removed when unticked or the host exits.
|
|
||||||
if (ImGui::Checkbox("Set up Vulkan layer (for immediate-init Vulkan games)", &vk_layer_enabled_))
|
|
||||||
{
|
{
|
||||||
if (vk_layer_enabled_)
|
unregister_vk_layer();
|
||||||
{
|
|
||||||
vk_layer_enabled_ = register_vk_layer(selected_name_);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
unregister_vk_layer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ImGui::IsItemHovered())
|
|
||||||
{
|
|
||||||
ImGui::SetTooltip("Registers a per-user (HKCU, no admin) implicit Vulkan layer scoped to\n"
|
|
||||||
"this game, so a relaunch is captured before Vulkan init. Pair with\n"
|
|
||||||
"Auto re-attach. Removed when you untick it or close the tool.");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
if (ImGui::IsItemHovered())
|
||||||
|
{
|
||||||
|
ImGui::SetTooltip("Registers a per-user (HKCU, no admin) implicit Vulkan layer scoped to\n"
|
||||||
|
"this game, so a relaunch is captured before Vulkan init. Pair with\n"
|
||||||
|
"Auto re-attach. Removed when you untick it or close the tool.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::TextUnformatted("Target window");
|
ImGui::TextUnformatted("Target window");
|
||||||
@@ -737,6 +742,12 @@ void InjectionPanel::draw(bool debug_details)
|
|||||||
inject_selected();
|
inject_selected();
|
||||||
}
|
}
|
||||||
ImGui::EndDisabled();
|
ImGui::EndDisabled();
|
||||||
|
// Explain the disabled state on hover (AllowWhenDisabled, since the button is greyed out).
|
||||||
|
if (!can_inject && ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled))
|
||||||
|
{
|
||||||
|
ImGui::SetTooltip("Pick a target window or process above first.\n"
|
||||||
|
"If the game already has the DLL (e.g. after a reconnect), this reuses it.");
|
||||||
|
}
|
||||||
|
|
||||||
if (!status_.empty())
|
if (!status_.empty())
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user