使用SDL从键盘读取输入的最佳方法是什么?

时间:2012-07-28 07:30:24

标签: input keyboard sdl

我每秒运行一次update()方法来“更新”用户的键盘输入,以便稍后在程序的逻辑部分中读取它。所以我在SDL Docs中找到了两种实现方法,我不确定应该使用哪一种。

1;使用SDL_PollEvent循环搜索关键/关闭事件并将关键状态保存在地图中,以便我可以检查程序逻辑中的每个关键状态。

注意:或者,我也可以使用SDL_PeepEvents而不是SDL_PollEvent来仅采用重要的事件类型;所以,它不会“抛弃”队列中的事件。

std::map<int, bool> keyboard; // Saves the state(true=pressed; false=released) of each SDL_Key.

void update()
{
    SDL_Event event;
    while( SDL_PollEvent(&event))
    {
        switch(event.type)
        {
        case SDL_KEYDOWN:
            keyboard[event.key.keysym.sym] = false;
            break;
        case SDL_KEYUP:
            keyboard[event.key.keysym.sym] = true;
            break;
        }
    }
}

2;每帧从键盘拍摄快照,以便我可以轻松阅读。

Uint8* keyboard;

void update()
{
    SDL_PumpEvents();
    keyboard = SDL_GetKeyState(NULL);
}

通过上述任何实现,我可以像这样阅读keyboard

if (key_map[SDLK_Return]) printf("Return has been pressed.");

另外,还有另一种方法吗?

3 个答案:

答案 0 :(得分:9)

我更喜欢做1的变体,其中我填充三个数组,不仅指示当前状态,还指示哪些键刚刚关闭以及哪些键刚刚上升。这允许我在代码中轻松检查这些事件(不与之前的快照比较),但最重要的是,它不会错过持续少于一帧的事件。例如,如果您的游戏由于机器速度较慢而以10 fps运行,则用户可能会在两次更新例程调用之间按下并释放一个重要的键,然后您的系统将永远不会注册它。这非常令人沮丧。

SDL还会在按住按键时发送按键事件,这样您就可以为每个按键启用多个按键事件。我发现这在实现键盘滚动项目列表时特别有用,例如:键盘控制的菜单。

答案 1 :(得分:5)

您应该使用解决方案2.

为什么呢?正如SDL_GetKeyState()文档指出的那样,在使用它之前,您需要调用SDL_PumpEvents()来更新状态数组。

当您致电SDL_PollEvent()时,它会隐式调用SDL_PumpEvents()。所以,它基本上更新了SDL_GetKeyState()的数组。通过手动解析这些事件,您只需创建第二个数组(实际上是一个慢得多的映射),其中包含SDL已经为您收集的相同信息。

所以,我敢说第一个解决方案意味着两次做同样的事情。如果您决定支持诸如重复击键(SDL_EnableKeyRepeat())之类的事情,那么您将重新实现SDL的更大部分。

答案 2 :(得分:1)

我意识到这个问题已经很老了,但我的回答可能会使某些人受益。就个人而言,我使用两个SDL_GetKeyState数组。我存储一个保持当前帧键盘状态的数组,以及一个保存最后一帧键盘状态的数组。 (使用一些memcpy命令,它们很容易更新它们。)除了这两个数组,我还有一个转换字符串的地图,如&#34; A&#34;到SDL扫描码值,但这是可选的。

然后,当您需要检查某些内容是否被释放或按下时,您可以组合这两个数组进行检查。 (我把它变成了一个函数。)例如,如果你知道按键被按下了这一帧,但是最后一帧没有被按下,那么显然只是按下了这一帧。 if (currentFrame["A"] == true && lastFrame["A"] == false) {/*just pressed*/}

然后你会对发布的事情做相反的事情。我发现这种方法非常容易实现和使用。