每当我调用 GetAnalogActionData 时,Steam 输入都会导致 SEGFAULT

Steam Input causes SEGFAULT whenever I call GetAnalogActionData

提问人:addiment 提问时间:6/6/2023 最后编辑:addiment 更新时间:8/5/2023 访问量:87

问:

我正在使用 SDL2 制作游戏,并通过 Steamworks 提供控制器支持,每当调用 GetAnalogActionData 时,我的程序 SEGFAULTs 都会出现。 我正在通过 MSYS2 使用 MinGW g++ 进行编译,使用 Steamworks API 版本 157。

我知道我应该存储一次句柄,但由于它在我尝试从数据中读取的第二次出现段错误,因此它永远不会再次被读取。我只是想弄清楚为什么这不起作用。

#include <SDL2/SDL.h>
#include <steam/steam_api.h>

SDL_Window *window;
SDL_Renderer *renderer;
bool isRunning = true;
using namespace std;

int init() {

    // Initialize Steam API
    if (!SteamAPI_Init()) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize Steam API!");
        return 1;
    }
    // Initialize Steam Input
    if (!SteamInput()->Init(false)) {
        SDL_LogCritical(SDL_LOG_CATEGORY_INPUT, "Failed to initialize Steam Input!");
        return 1;
    }

    {
        int res = SDL_Init(SDL_INIT_EVERYTHING);
        if (res < 0) {
            SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize SDL: %s", SDL_GetError());
            return res;
        }
    }

    window = SDL_CreateWindow(">:(", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 640, SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);
    if (window == nullptr) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to create window: %s", SDL_GetError());
        return 1;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
    if (renderer == nullptr) {
        SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to create renderer: %s", SDL_GetError());
        return 1;
    }

    SDL_Log("initialized");

    return 0;
}

void shutdown() {
    SDL_Log("shutting down");
    SDL_Quit();
    SteamAPI_Shutdown();
    SDL_Log("goodnight");
}

void tick() {
    SDL_Event ev;
    while (SDL_PollEvent(&ev)) {
        switch (ev.type) {
            case SDL_WINDOWEVENT:
                // fallthrough if event is closing the window
                if (ev.window.event != SDL_WINDOWEVENT_CLOSE) { break; }
            case SDL_QUIT: {
                isRunning = false;
                return;
                break;
            }
            case SDL_JOYBUTTONDOWN:
            case SDL_JOYBUTTONUP: {
                const char* buttonName = SDL_GameControllerGetStringForButton((SDL_GameControllerButton)ev.cbutton.button);
                printf("Button %s %s\n", buttonName, (ev.cbutton.state ? "DOWN" : "UP"));
                break;
            }
        }
    }
    SteamAPI_RunCallbacks();

    SDL_SetRenderDrawColor(renderer, 0.f, 0.f, 0.f, 0.f);
    SDL_RenderClear(renderer);
    SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);

#ifdef USE_STEAM
    SteamAPI_RunCallbacks();
#endif // USE_STEAM

    // render
    SDL_Rect rect = {100, 100, 480, 480 };
    InputAnalogActionHandle_t AnalogControls = SteamInput()->GetAnalogActionHandle ("AnalogControls");
    InputActionSetHandle_t GameControls = SteamInput()->GetActionSetHandle("GameControls");
    InputHandle_t controllers[STEAM_INPUT_MAX_COUNT]{};
    SteamInput()->GetConnectedControllers(controllers);
    SteamInput()->ActivateActionSet(controllers[0], GameControls);
    InputAnalogActionData_t data = SteamInput()->GetAnalogActionData(controllers[0], AnalogControls);
    printf("data: { %f, %f }\n", data.x, data.y);
    SDL_SetRenderDrawColor(renderer, uint8_t(data.x * float(0xFF)), uint8_t(data.y * float(0xFF)), 0, SDL_ALPHA_OPAQUE);
    SDL_RenderFillRect(renderer, &rect);

    SDL_RenderPresent(renderer);
#ifdef NDEBUG
    GLenum err = glGetError();
    if (err != 0) SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "%x %s", err, glewGetErrorString(err));
#endif
}

int main(int argc, char* argv[]) {
    SDL_Log("running");
#ifdef NDEBUG
    SDL_LogSetAllPriority(SDL_LOG_PRIORITY_DEBUG);
#endif
    {
        int i = init();
        if (i) return i;
    }

    while (isRunning) tick();

    shutdown();
    return 0;
}

调试器为我提供了我的值:

  • controllers[0]319124578728929405
  • AnalogControls1
  • GameControls1

我正在使用默认的 Spacewar appid 进行开发,这是我的 IGA 文件():game_actions_480.vdf

"In Game Actions"
{
    "actions"
    {
        "GameControls"
        {
            "title"                 "#Set_GameControls"
            "StickPadGyro"
            {
                "AnalogControls"
                {
                    "title"         "#Action_AnalogControls"
                    "input_mode"    "joystick_move"
                }
            }
            "Button"
            {
                "jump"  "#Action_Jump"
            }
        }
        "MenuControls"
        {
            "title"                 "#Set_MenuControls"
            "Button"
            {
                "menu_up"       "#Action_MenuUp"
                "menu_down"     "#Action_MenuDown"
                "menu_left"     "#Action_MenuLeft"
                "menu_right"    "#Action_MenuRight"
                "menu_select"   "#Action_MenuSelect"
                "menu_cancel"   "#Action_MenuCancel"
            }
        }
    }
    "localization"
    {
        "english"
        {
            "Title_Config1"     "Officially Configurated Configuration"
            "Description_Config1"   "sdalskdjaksjda."

            "Set_GameControls"          "In-Game Controls"
            "Set_MenuControls"          "Menu Controls"

            "Action_AnalogControls"     "Analog Controls"

            "Action_Jump"               "Jump"

            "Action_MenuUp"             "Menu Up"
            "Action_MenuDown"           "Menu Down"
            "Action_MenuLeft"           "Menu Left"
            "Action_MenuRight"          "Menu Right"
            "Action_MenuSelect"         "Menu Select"
            "Action_MenuCancel"         "Menu Cancel"
        }
    }
}
C++ 输入 SDL-2 Steam Steamworks-API

评论

2赞 Ted Lyngmo 6/6/2023
原因出在您没有向我们展示的代码中。请显示重现该问题的最短代码片段。
1赞 user4581301 6/6/2023
片段是一个冒险的词。你最好有一个尽可能小的完整程序。这里的人们可以直接放入他们的工具中,构建和试验,前提是他们拥有所有必需的库。使用最小可重复示例 (MRE) 作为灵感。制作 MRE 的真正美妙之处在于,在制作这个微程序时,您会发现出了什么问题并自己修复它。
0赞 addiment 6/6/2023
这是一个 1 个文件的 MRE。更新了原帖。
0赞 paddy 6/6/2023
您不使用 中的返回值。它告诉您有多少个句柄写入了数组。虽然这可能不是问题所在,但它肯定是对 API 的错误使用。GetConnectedControllers
0赞 Pepijn Kramer 6/6/2023
您是否附加了调试器,如果没有,请这样做并检查返回指针的函数的返回值。例如。.如果其中任何一个是 nullptr,则不要取消引用它们。SDL_GameControllerGetStringForButton

答:

0赞 addiment 6/6/2023 #1

这真的很不幸;我能够通过使用 Clang++(MSVC 后端)而不是 g++ 来解决这个问题。我需要进一步研究这个问题,但就目前而言,使用 MSVC“解决”了这个问题。我真的需要使用 g++,所以任何建议都值得赞赏。

0赞 addiment 8/5/2023 #2

这有点晚了,但我最终想通了,忘了回答我自己的问题!

事实证明(我通过阅读文档弄清楚了这一点)Steamworks 提供了一个替代标头,称为 ,提供了一个用于其他编译器/语言的 C API。我的代码如下所示:steam_api_flat.h

InputDigitalActionData_t data = SteamAPI_ISteamInput_GetDigitalActionData(SteamAPI_SteamInput(), activeSteamControllerHandle, h);

希望这对某人有所帮助。