Skip to content

Fix windowevent and key repeat in sdl2-compat #3470

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions src_c/_pygame.h
Original file line number Diff line number Diff line change
Expand Up @@ -403,8 +403,6 @@ typedef enum {

PGE_MIDIIN,
PGE_MIDIOUT,
PGE_KEYREPEAT, /* Special internal pygame event, for managing key-presses
*/

/* DO NOT CHANGE THE ORDER OF EVENTS HERE */
PGE_WINDOWSHOWN,
Expand Down
69 changes: 46 additions & 23 deletions src_c/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,15 +152,21 @@ _pg_repeat_callback(Uint32 interval, void *param)
int repeat_interval_copy = pg_key_repeat_interval;
PG_UNLOCK_EVFILTER_MUTEX

repeat_event_copy.type = PGE_KEYREPEAT;
repeat_event_copy.type = SDL_KEYDOWN;
#if SDL_VERSION_ATLEAST(3, 0, 0)
repeat_event_copy.key.down = true;
repeat_event_copy.key.repeat = true;
#else
repeat_event_copy.key.state = SDL_PRESSED;
repeat_event_copy.key.repeat = 1;
#endif
SDL_PushEvent(&repeat_event_copy);
/* Use SDL_PeepEvents and not SDL_PushEvent because we don't want
* this to go through our event filter.
* Because this doesn't go through our filter we have to check event
* blocking beforehand. */
if (PG_EventEnabled(_pg_pgevent_proxify(repeat_event_copy.type))) {
SDL_PeepEvents(&repeat_event_copy, 1, SDL_ADDEVENT, 0, 0);
}
return repeat_interval_copy;
}

Expand Down Expand Up @@ -470,19 +476,40 @@ _pg_pgevent_deproxify(Uint32 type)
return _pg_pgevent_proxify_helper(type, 0);
}

/* Get type of an event, handling WINDOWEVENT translation on SDL2.
* On SDL3 this function is trivial */
static Uint32
_pg_pgevent_type(SDL_Event *event)
{
#if !SDL_VERSION_ATLEAST(3, 0, 0)
/* We don't need to do window event translation because in SDL3 each window
* event is its own thing anyways */
static int
_pg_translate_windowevent(void *_, SDL_Event *event)
if (event->type == SDL_WINDOWEVENT) {
return PGE_WINDOWSHOWN + event->window.event - 1;
}
#endif
return event->type;
}

/* Handle blocking of pseudo-blocked events.
* Currently this only includes WINDOWEVENT, but can be expanded in the
* future.
*/
#if SDL_VERSION_ATLEAST(3, 0, 0)
static bool SDLCALL
#else
static int SDLCALL
#endif
_pg_filter_blocked_events(void *_, SDL_Event *event)
{
#if SDL_VERSION_ATLEAST(3, 0, 0)
if (event->type >= SDL_EVENT_WINDOW_FIRST &&
event->type <= SDL_EVENT_WINDOW_LAST) {
#else
if (event->type == SDL_WINDOWEVENT) {
event->type = PGE_WINDOWSHOWN + event->window.event - 1;
return PG_EventEnabled(_pg_pgevent_proxify(event->type));
#endif
return PG_EventEnabled(_pg_pgevent_proxify(_pg_pgevent_type(event)));
}
return 1;
}
#endif

#if SDL_VERSION_ATLEAST(3, 0, 0)
static bool SDLCALL
Expand Down Expand Up @@ -613,10 +640,6 @@ pg_event_filter(void *_, SDL_Event *event)
PG_UNLOCK_EVFILTER_MUTEX
}

else if (event->type == PGE_KEYREPEAT) {
event->type = SDL_KEYDOWN;
}

else if (event->type == SDL_KEYUP) {
PG_LOCK_EVFILTER_MUTEX
/* Actual keyup is blocked, so clear unneeded cache if it exists */
Expand Down Expand Up @@ -709,6 +732,14 @@ pg_event_filter(void *_, SDL_Event *event)
return RAISE(pgExc_SDLError, SDL_GetError()), 0;
*/
}
/* TODO:
* Any event that gets blocked here will not be visible to the event
* watchers. So things like WINDOWEVENT should never be blocked here.
* This is taken care of in SDL2 codepaths already but needs to also
* be verified in SDL3 porting.
* If the user requests a block on WINDOWEVENTs we are going to handle
* it specially and call it a "pseudo-block", where the filtering will
* happen in a _pg_filter_blocked_events call. */
return PG_EventEnabled(_pg_pgevent_proxify(event->type));
}

Expand Down Expand Up @@ -1747,6 +1778,7 @@ pgEvent_New(SDL_Event *event)
}

if (event) {
event->type = _pg_pgevent_type(event);
e->type = _pg_pgevent_deproxify(event->type);
e->dict = dict_from_event(event);
}
Expand Down Expand Up @@ -1846,14 +1878,7 @@ _pg_event_pump(int dopump)
SDL_PumpEvents();
}

/* WINDOWEVENT translation needed only on SDL2 */
#if !SDL_VERSION_ATLEAST(3, 0, 0)
/* We need to translate WINDOWEVENTS. But if we do that from the
* from event filter, internal SDL stuff that rely on WINDOWEVENT
* might break. So after every event pump, we translate events from
* here */
SDL_FilterEvents(_pg_translate_windowevent, NULL);
#endif
SDL_FilterEvents(_pg_filter_blocked_events, NULL);
}

static int
Expand Down Expand Up @@ -2458,8 +2483,6 @@ pg_event_set_blocked(PyObject *self, PyObject *obj)
/* Never block SDL_WINDOWEVENT on SDL2, we need them for translation */
PG_SetEventEnabled(SDL_WINDOWEVENT, SDL_TRUE);
#endif
/* Never block PGE_KEYREPEAT too, its needed for pygame internal use */
PG_SetEventEnabled(PGE_KEYREPEAT, SDL_TRUE);
Py_RETURN_NONE;
}

Expand Down
Loading