【问题标题】:How do I empty the SDL event queue?如何清空 SDL 事件队列?
【发布时间】:2014-11-25 14:29:49
【问题描述】:

在我的 SDL 1.2 程序中,我有一个函数 KeyPressed 需要检查是否已按下某个键。如果鼠标指针没有移动到窗口前面,则程序会在按下键时按预期停止。另一方面,如果鼠标指针移动到窗口前面,事件队列似乎已满,然后程序不再响应按键。当事件队列中没有键盘事件时,有没有办法清空事件队列?

#include <SDL/SDL.h>
#include <stdio.h>

static void Init(int *error)
{
    SDL_Surface *display;

    *error = SDL_Init(SDL_INIT_VIDEO);
    if (! *error) {
        display = SDL_SetVideoMode(640, 480, 8, 0);
        if (display != NULL) {
            *error = 0;
        } else {
            fprintf(stderr, "SDL_SetVideoMode: %s\n", SDL_GetError());
            *error = 1;
        }
    } else {
        fprintf(stderr, "SDL_Init: %s\n", SDL_GetError());
        *error = 1;
    }   
}


static int KeyPressed(void)
{
    SDL_Event event;
    int count, result;

    result = 0;
    SDL_PumpEvents();
    count = SDL_PeepEvents(&event, 1, SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
    switch (count) {
        case -1:
            fprintf(stderr, "SDL_PeepEvents: %s\n", SDL_GetError());
            break;
        case 0:
            break;
        case 1:
            result = 1;
            break;
    }
    return result;
}


int main(void)
{
    int error;

    Init(&error);
    if (! error) {
        do {
            /*nothing*/
        } while (! KeyPressed());
    }
    return error;
}

【问题讨论】:

  • 您必须从某处的事件队列中删除事件,您是否尝试过使用 SDL_GETEVENT 而不是 SDL_PEEKEVENT ?
  • @nos 好的,但是我应该删除多少事件?据我所知,没有办法获得事件队列的长度。
  • 您将执行一个循环,首先执行 SDL_PEEKEVENT,如果返回非零,则执行 SDL_GETEVENT。如果它确实返回零,则您已经清空了事件队列。不过,尚不清楚此代码是否只是真实应用程序的一部分——其中控制流和检查关键事件通常会有很大不同——并且通常按此处所示stackoverflow.com/questions/3741055/… 进行处理
  • @nos 我的理由是,由于我过滤了事件,鼠标事件不会被 SDL_GETEVENT 删除。 (在我正在处理函数的实际代码中,KeyPressed 是无法更改的 API 的一部分。)

标签: c sdl sdl-1.2


【解决方案1】:

您应该使用轮询在 while 循环中检查事件,这将在处理事件时从队列中弹出事件。使用多个if/then 语句或swicth 块来处理事件。我推荐这种方法,因为您在使用SDL_PeepEvent时很容易错过SDL_QUIT等重要事件

基本示例:

SDL_Event e;
while (SDL_PollEvent(&e))
{
    if (e.type == SDL_QUIT)
    {
        // do something here
    }
}

【讨论】:

  • 感谢您的意见。但是,在我正在处理函数 KeyPressed 的实际代码中,它是无法更改的 API 的一部分。否则我会听从你的建议。
  • 在这种情况下,您应该使用代码中的事件掩码检查事件队列,以查看是否没有按键事件。如果没有,还要检查是否没有重要的事件需要以相同的方式处理,即 SDL_QUIT。然后使用SDL_PeepEvent 删除所有带有SDL_GETEVENT 的事件。见这里 - wiki.libsdl.org/SDL_PeepEvents
【解决方案2】:

受 Zammalad 评论启发的以下解决方案似乎有效。当没有找到按键事件时,我们从队列中删除一个事件(通常是鼠标事件),以便为新事件腾出空间。为了使代码更健壮,我还用数组 events 替换了标量 event

#define LEN(a) ((int) (sizeof (a) / sizeof (a)[0]))

static int KeyPressed(void)
{
    SDL_Event events[1];
    int count, result;

    result = 0;
    SDL_PumpEvents();
    /*search the event queue for key down events*/
    count = SDL_PeepEvents(events, LEN(events), SDL_PEEKEVENT, SDL_EVENTMASK(SDL_KEYDOWN));
    switch (count) {
        case -1:
            fprintf(stderr, "SDL_PeepEvents: %s\n", SDL_GetError());
            break;
        case 0:
            /*make room for new events by removing (non-key down) event from the queue*/
            count = SDL_PeepEvents(events, LEN(events), SDL_GETEVENT, -1);
            if ((count > 0) && (events[0].type == SDL_QUIT)) {
                exit(EXIT_SUCCESS);
            }
            break;
        case 1:
            result = 1;
            break;
    }
    return result;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-28
    • 2012-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多