ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
60.9k stars 10.28k forks source link

Erratic window movement #8122

Closed malloc2k closed 5 hours ago

malloc2k commented 6 hours ago

Version/Branch of Dear ImGui:

Version 1.91.4, Branch: master

Back-ends:

imgui_impl_win32.cpp + imgui_impl_dx11.cpp

Compiler, OS:

Windows 11 + minGW

Full config/build information:

Unable

Details:

My Issue/Question:

The problem I have can be seen in the video (the quality is not the best but the window moves erratically for some reason). What I've done is hide the Window that WIN32 creates making the imgui window look like a standalone (just for looks). I suspect of a DPI problem but I'm unsure on how to fix it, any help would be appreciated!

Screenshots/Video:

https://github.com/user-attachments/assets/630b239b-5573-490c-adb9-5292043fee27

Minimal, Complete and Verifiable Example code:

void RenderInjectorPage() {
    ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar |
                                    ImGuiWindowFlags_NoResize |
                                    ImGuiWindowFlags_NoMove |
                                    ImGuiWindowFlags_NoScrollbar |
                                    ImGuiWindowFlags_NoScrollWithMouse;

    ImGui::SetNextWindowPos(ImVec2(0, 0));
    ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
    ImGui::Begin("Injector", nullptr, window_flags);

    static bool isDragging = false;
    static ImVec2 initialMousePos = ImVec2(0, 0);
    static POINT initialWindowPos = {0, 0};

    const float dragAreaHeight = 30.0f;

    ImGui::InvisibleButton("DragZone", ImVec2(ImGui::GetWindowWidth(), dragAreaHeight));
    bool isDragZoneActive = ImGui::IsItemActive();

    ImGui::SetCursorPosY(ImGui::GetCursorPosY() - dragAreaHeight + 5);
    ImGui::Text("Funi");

    ImGui::SameLine(ImGui::GetWindowWidth() - 30);
    if (ImGui::Button("X")) {
        PostQuitMessage(0);
    }

    ImGuiIO& io = ImGui::GetIO();
    if (isDragZoneActive && ImGui::IsMouseDragging(0)) {
        if (!isDragging) {
            isDragging = true;
            RECT rect;
            GetWindowRect(Win32Init::hwnd, &rect);
            initialWindowPos.x = rect.left;
            initialWindowPos.y = rect.top;
        }

        float deltaX = io.MouseDelta.x;
        float deltaY = io.MouseDelta.y;

        SetWindowPos(Win32Init::hwnd, nullptr,
                     initialWindowPos.x + static_cast<int>(deltaX),
                     initialWindowPos.y + static_cast<int>(deltaY),
                     0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);

        initialWindowPos.x += static_cast<int>(deltaX);
        initialWindowPos.y += static_cast<int>(deltaY);
    }

    if (!ImGui::IsMouseDown(0)) {
        isDragging = false;
    }

    static char dllPath[MAX_PATH] = "";
    static int injectionMethod = 0;
    static DWORD selectedPID = 0;
    static std::vector<ProcessUtils::ProcessInfo> processList;

    ImGui::Spacing();
    ImGui::Spacing();

    ImGui::InputText(" Path", dllPath, MAX_PATH);
    ImGui::SameLine();
    if (ImGui::Button("Browse...")) {
        OPENFILENAME ofn;
        ZeroMemory(&ofn, sizeof(ofn));
        char fileName[MAX_PATH] = "";
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = Win32Init::hwnd;
        ofn.lpstrFile = fileName;
        ofn.nMaxFile = MAX_PATH;
        ofn.lpstrFilter = "DLL Files\0*.dll\0All Files\0*.*\0";
        ofn.nFilterIndex = 1;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

        if (GetOpenFileName(&ofn)) {
            strcpy_s(dllPath, fileName);
        }
    }

    ImGui::Text("11");
    ImGui::RadioButton("test1", &test, 0);
    ImGui::SameLine();
    ImGui::RadioButton("test2mm", &test, 1);
    ImGui::SameLine();
    ImGui::RadioButton("test3", &test, 2);

    if (ImGui::Button("Refresh Process List")) {
        ProcessUtils::FreeProcessIcons(processList);
        processList = ProcessUtils::GetProcessList();
    }

    ImGui::Text("Select a process:");
    ImGui::BeginChild("ProcessList", ImVec2(0, 300), true);

    for (const auto& process : processList) {
        ImGui::PushID(process.pid);

        if (process.texture) {
            ImGui::Image(reinterpret_cast<ImTextureID>(process.texture), ImVec2(16, 16));
            ImGui::SameLine();
        }

        char label[256];
        snprintf(label, 256, "%s [%d]", process.name.c_str(), process.pid);
        if (ImGui::Selectable(label, selectedPID == process.pid)) {
            selectedPID = process.pid;
        }
        ImGui::PopID();
    }

    ImGui::EndChild();

    if (ImGui::Button("Inject")) {
        if (selectedPID == 0 || strlen(dllPath) == 0) {
            MessageBox(Win32Init::hwnd, "Please select a process and DLL", "Error", MB_OK | MB_ICONERROR);
        } else {
            MessageBox(Win32Init::hwnd, "implementing later", "Info", MB_OK | MB_ICONINFORMATION);
        }
    }

    ImGui::End();
}                                
malloc2k commented 6 hours ago

Disclaimer: I'm not trying to make this to sell later or whatever, this is an injector that I've challenged myself to make in order to improve my C++ skills and WINAPI knowledge. Thanks

ocornut commented 5 hours ago

Sorry for as per issue opening guidelines you are outside the scope of supported users. Your issue is however likely that you have a lag or feedback loop between relying on local mousedelta and how moving the platform window alter imgui coordinates. You should probably only rely on global mouse positions for this.