You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Add environment variable to pygame module docs with the other environment variables
Add note about current behaviour (defaults to no joystick events for apps without focus) to joystick module introduction somewhere.
Nice to have: open a new issue about adding SetSDLHint() & GetSDLHint() (names not final) to new context module.
Windows Python 3.10 PyGame 2.1.2
I had to go back to version 2.1.0 and it works again : my pygame window that captures all joystick events doesn't capture anything anymore when I switch to another window
Current behavior:
No joystick events catched
Expected behavior:
joystick events catched (wirks on pygame 2.1.0)
code
# Extract from my 2.1.0 working code
pygame.init()
screen = pygame.display.set_mode((200, 200), pygame.NOFRAME)
hwnd = pygame.display.get_wm_info()["window"]
win32gui.SetWindowPos(hwnd, win32con.HWND_TOPMOST, 600, 300, 0, 0, win32con.SWP_NOSIZE)
...
joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())]
for joy in joysticks:
print(joy.get_name(), joy.get_id(), joy.get_guid(), joy.get_instance_id())
if joy.get_name() == 'My joystick 1':
MyJoysticks['My joystick 1']={}
MyJoysticks['My joystick 1']['joy'] = joy
MyJoysticks['My joystick 1']['joy'].init()
...
while 1==1:
...
PosJoy1 = MyJoysticks['My joystick 1']['joy'].get_axis(0)
...
@KingOfIce77 This seems like it's an issue with SDL 2.0.16 -> 2.0.18.
In the pygame info prompt, you should see pygame 2.1 running on SDL 2.0.16, and pygame 2.1.2 running on SDL 2.0.18.
@zoldalma999 Do you have the time and stuff to handle this one?
It looks like we need to report upstream to SDL, but I feel bad doing it without a C minimum reproducible example, and I don't have the hardware for this on my end.
Thanks for the bug report. have two more questions to ask you:
What controller are you using?
So the problem is that while the window is inactive (for example switched to another window), there are no joystick events, right? And when switching back to the pygame window, everything works as it should (ie get_axis returns the correct value).
@zoldalma999
1- my controller is a steering wheel + pedal (Fanatec)
2- Yes
I'm just pointing out that it works in version 2.1.0 and not in 2.1.2. Personally, I need this.
We can discuss about the notion of "active" window... When I stream a game with OBS Studio, I play my game and OBS Studio is then an "inactive" window: fortunately it still captures ;-D Same thing for getting information from my computer, AIDA64, CPU-Z and others don't stop the collection as soon as I switch to another window.
I'm doing simracing and I need a lot of additional information when I'm piloting, my pygame window is displayed as an overlay (so it's active for me and looked at even if the game is technically the active window).
Don't hesitate if you have other questions or if you want I perform specifical tests.
Isn't joystick events not being passed to an inactive window an improvement?
Yes, it would be new to pygame. That is why I asked if this is the issue - it should not work this way on either versions. However, there is an SDL hint for it, SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, which allows you to toggle that. We might want to expose this trough something like pygame.joystick.allow_background_events.
It's personal so it's selfish but as long as I still have the functionality, I'm fine with it!
(for information if not too long to explain, since it's possible why is it annoying to leave by default ? penalizing in performance ?)
I think having it on by default is a bit counterintuitive. Users normally expect only the active application to receive input style events like mouse clicks - joystick/controller events would be in that class for me. In practice it doesn't likely come up that much because who plays two games simultaneously on PC without closing one down? Then again with modern consoles having freeze and resume features for games maybe we'll get a new generation who will do this...
Anyway, I think exposing the SDL_HINT is a fine solution for those that are using this behaviour, but I think the default should follow SDL's logic.
importos# needs to be set before importing pygame, or can also be set from shell# while calling the scriptos.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] ="1"importpygame
[othercodehere]
You can do something like this to set the SDL hint to get it behave the way you want. zoldalma has confirmed this works for him, so it should work for you as well. Oh well, this looks a bit inelegant from code quality POV, but until pygame exposes more of SDL hint get/set API, this is the only way to set SDL hints from pygame
And unfrotunately I won't be back at that computer to test for probably a week, but will post how it works then. For now I reverted to 1.9.6.
I think having it on by default is a bit counterintuitive. Users normally expect only the active application to receive input style events like mouse clicks - joystick/controller events would be in that class for me.
For whatever it's worth joystick input seems to be an exception to that rule. Every other Python library that works with joysticks, such as the inputs library, has the joystick input as global. And on Windows for example the joystick config utility in the control panel doens't need focus to catch joystick events. Same goes for every linux joystick testing utility I've tried. I can't think of any joystick utilities or games that need focus.
I currently have the exact same problem - I need to capture joystick events even when the pygame window is not in focus. I tried including os.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = "1", however, this does not work.
I am using Python 3.9 and pygame 2.1.2 on Windows 10.
I can also confirm that the environment variable doesn't work on it's own on Windows.
The SDL hint does work if you add it directly to the pygame code base before SDL_Init and recompile pygame.
I guess that SetHint() doesn't get called before SDLinit() based on environment variables. Or maybe at all? Not sure how zoldama had it working, different platform perhaps?
We could add a patch like:
if (strcmp(SDL_getenv("SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"), "1") == 0){
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,"1");
}
to pg_init in base.c before SDL_Init - but perhaps a more generic solution would be better to allow setting more SDL hints than just this one?
I can also confirm that the environment variable doesn't work on it's own on Windows.
Are you sure you are setting it before importing pygame and calling pygame.init()?
Yes. This was the test code I used:
import os
# needs to be set before importing pygame, or can also be set from shell
# while calling the script
os.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = "1"
import pygame
# Define some colors.
BLACK = pygame.Color('black')
WHITE = pygame.Color('white')
# This is a simple class that will help us print to the screen.
# It has nothing to do with the joysticks, just outputting the
# information.
class TextPrint(object):
def __init__(self):
self.reset()
self.font = pygame.font.Font(None, 20)
def tprint(self, screen, textString):
textBitmap = self.font.render(textString, True, BLACK)
screen.blit(textBitmap, (self.x, self.y))
self.y += self.line_height
def reset(self):
self.x = 10
self.y = 10
self.line_height = 15
def indent(self):
self.x += 10
def unindent(self):
self.x -= 10
pygame.init()
# Set the width and height of the screen (width, height).
screen = pygame.display.set_mode((500, 700))
pygame.display.set_caption("My Game")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates.
clock = pygame.time.Clock()
# Initialize the joysticks.
pygame.joystick.init()
# Get ready to print.
textPrint = TextPrint()
# -------- Main Program Loop -----------
while not done:
#
# EVENT PROCESSING STEP
#
# Possible joystick actions: JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN,
# JOYBUTTONUP, JOYHATMOTION
for event in pygame.event.get(): # User did something.
if event.type == pygame.QUIT: # If user clicked close.
done = True # Flag that we are done so we exit this loop.
elif event.type == pygame.JOYBUTTONDOWN:
print("Joystick button pressed.")
elif event.type == pygame.JOYBUTTONUP:
print("Joystick button released.")
#
# DRAWING STEP
#
# First, clear the screen to white. Don't put other drawing commands
# above this, or they will be erased with this command.
screen.fill(WHITE)
textPrint.reset()
# Get count of joysticks.
joystick_count = pygame.joystick.get_count()
textPrint.tprint(screen, "Number of joysticks: {}".format(joystick_count))
textPrint.indent()
# For each joystick:
for i in range(joystick_count):
joystick = pygame.joystick.Joystick(i)
joystick.init()
try:
jid = joystick.get_instance_id()
except AttributeError:
# get_instance_id() is an SDL2 method
jid = joystick.get_id()
textPrint.tprint(screen, "Joystick {}".format(jid))
textPrint.indent()
# Get the name from the OS for the controller/joystick.
name = joystick.get_name()
textPrint.tprint(screen, "Joystick name: {}".format(name))
try:
guid = joystick.get_guid()
except AttributeError:
# get_guid() is an SDL2 method
pass
else:
textPrint.tprint(screen, "GUID: {}".format(guid))
# Usually axis run in pairs, up/down for one, and left/right for
# the other.
axes = joystick.get_numaxes()
textPrint.tprint(screen, "Number of axes: {}".format(axes))
textPrint.indent()
for i in range(axes):
axis = joystick.get_axis(i)
textPrint.tprint(screen, "Axis {} value: {:>6.3f}".format(i, axis))
textPrint.unindent()
buttons = joystick.get_numbuttons()
textPrint.tprint(screen, "Number of buttons: {}".format(buttons))
textPrint.indent()
for i in range(buttons):
button = joystick.get_button(i)
textPrint.tprint(screen,
"Button {:>2} value: {}".format(i, button))
textPrint.unindent()
hats = joystick.get_numhats()
textPrint.tprint(screen, "Number of hats: {}".format(hats))
textPrint.indent()
# Hat position. All or nothing for direction, not a float like
# get_axis(). Position is a tuple of int values (x, y).
for i in range(hats):
hat = joystick.get_hat(i)
textPrint.tprint(screen, "Hat {} value: {}".format(i, str(hat)))
textPrint.unindent()
textPrint.unindent()
#
# ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
#
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Limit to 20 frames per second.
clock.tick(20)
# Close the window and quit.
# If you forget this line, the program will 'hang'
# on exit if running from IDLE.
pygame.quit()
Which is the joystick module test code from the docs plus your snippet above.
Perhaps the environment variables in os.environ don't get turned into SDL environment variables/Hints quick enough?
Seems like when using environment variables, SDL hints do not work with the "HINT_" part in the name. SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS works for me, while SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS does not. Also, this specific hint works after importing pygame, but before calling pygame.init, so you don't need to violate PEP 8 either.
I still support the idea of either exposing set/get_hint (maybe the new context module would be a nice place for it), with documenting the important hints and linking to all SDL hints, or adding a function to joystick, like allow_background_events, as I mentioned above. But at the very least there should be something added to the joystick docs about this.
Seems like when using environment variables, SDL hints do not work with the "HINT_" part in the name. SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS works for me, while SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS does not.
Yes, SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTS did work.
Hi! I'd like to work on this issue as a beginner-friendly documentation contribution. I see the environment variable is already mentioned, but some checklist items look incomplete. I'd be happy to clean it up and submit a final PR.
Activity
Starbuck5 commentedon Dec 28, 2021
@KingOfIce77 This seems like it's an issue with SDL 2.0.16 -> 2.0.18.
In the pygame info prompt, you should see pygame 2.1 running on SDL 2.0.16, and pygame 2.1.2 running on SDL 2.0.18.
I've built a wheel of pygame 2.1.2 for Windows and Python 3.10, but using SDL 2.0.16:
pygame-2.1.2.dev1-cp310-cp310-win_amd64.zip
Unzip that and pip install directly from the file, and then say here whether the problem persists.
KingOfIce77 commentedon Dec 28, 2021
Hello ! Thanks for the quick answer. It seems to be ok with your package 2.1.2.dev1 using SDL 2.0.16
It works in the quick test I just did.
Starbuck5 commentedon Dec 28, 2021
@zoldalma999 Do you have the time and stuff to handle this one?
It looks like we need to report upstream to SDL, but I feel bad doing it without a C minimum reproducible example, and I don't have the hardware for this on my end.
zoldalma999 commentedon Dec 30, 2021
Thanks for the bug report. have two more questions to ask you:
get_axisreturns the correct value).MyreMylar commentedon Dec 30, 2021
Isn't joystick events not being passed to an inactive window an improvement?
KingOfIce77 commentedon Dec 30, 2021
@zoldalma999
1- my controller is a steering wheel + pedal (Fanatec)
2- Yes
I'm just pointing out that it works in version 2.1.0 and not in 2.1.2. Personally, I need this.
We can discuss about the notion of "active" window... When I stream a game with OBS Studio, I play my game and OBS Studio is then an "inactive" window: fortunately it still captures ;-D Same thing for getting information from my computer, AIDA64, CPU-Z and others don't stop the collection as soon as I switch to another window.
I'm doing simracing and I need a lot of additional information when I'm piloting, my pygame window is displayed as an overlay (so it's active for me and looked at even if the game is technically the active window).
Don't hesitate if you have other questions or if you want I perform specifical tests.
zoldalma999 commentedon Dec 30, 2021
Yes, it would be new to pygame. That is why I asked if this is the issue - it should not work this way on either versions. However, there is an SDL hint for it,
SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, which allows you to toggle that. We might want to expose this trough something likepygame.joystick.allow_background_events.KingOfIce77 commentedon Dec 30, 2021
It's personal so it's selfish but as long as I still have the functionality, I'm fine with it!
(for information if not too long to explain, since it's possible why is it annoying to leave by default ? penalizing in performance ?)
MyreMylar commentedon Dec 30, 2021
I think having it on by default is a bit counterintuitive. Users normally expect only the active application to receive input style events like mouse clicks - joystick/controller events would be in that class for me. In practice it doesn't likely come up that much because who plays two games simultaneously on PC without closing one down? Then again with modern consoles having freeze and resume features for games maybe we'll get a new generation who will do this...
Anyway, I think exposing the SDL_HINT is a fine solution for those that are using this behaviour, but I think the default should follow SDL's logic.
ankith26 commentedon Dec 31, 2021
You can do something like this to set the SDL hint to get it behave the way you want. zoldalma has confirmed this works for him, so it should work for you as well. Oh well, this looks a bit inelegant from code quality POV, but until pygame exposes more of SDL hint get/set API, this is the only way to set SDL hints from pygame
Starbuck5 commentedon Jan 11, 2022
Reopening because I just directed someone here from the pygame mailing list.
Which means (anecdotally) that people care about this functionality. So we should probably document it somehow, at least.
wrybread commentedon Jan 11, 2022
os.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = "1"Thanks for that!
And does it really require a numerical string, or is this more correct?
os.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = TrueAnd unfrotunately I won't be back at that computer to test for probably a week, but will post how it works then. For now I reverted to 1.9.6.
For whatever it's worth joystick input seems to be an exception to that rule. Every other Python library that works with joysticks, such as the inputs library, has the joystick input as global. And on Windows for example the joystick config utility in the control panel doens't need focus to catch joystick events. Same goes for every linux joystick testing utility I've tried. I can't think of any joystick utilities or games that need focus.
HeliPylot commentedon Jun 9, 2022
Hi,
I currently have the exact same problem - I need to capture joystick events even when the pygame window is not in focus. I tried including
os.environ["SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS"] = "1", however, this does not work.I am using Python 3.9 and pygame 2.1.2 on Windows 10.
MyreMylar commentedon Jun 9, 2022
I can also confirm that the environment variable doesn't work on it's own on Windows.
The SDL hint does work if you add it directly to the pygame code base before SDL_Init and recompile pygame.
I guess that SetHint() doesn't get called before SDLinit() based on environment variables. Or maybe at all? Not sure how zoldama had it working, different platform perhaps?
We could add a patch like:
to
pg_initinbase.cbefore SDL_Init - but perhaps a more generic solution would be better to allow setting more SDL hints than just this one?ankith26 commentedon Jun 10, 2022
Are you sure you are setting it before importing pygame and calling
pygame.init()?MyreMylar commentedon Jun 10, 2022
Yes. This was the test code I used:
Which is the joystick module test code from the docs plus your snippet above.
Perhaps the environment variables in os.environ don't get turned into SDL environment variables/Hints quick enough?
zoldalma999 commentedon Jun 11, 2022
Seems like when using environment variables, SDL hints do not work with the "HINT_" part in the name.
SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTSworks for me, whileSDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTSdoes not. Also, this specific hint works after importing pygame, but before callingpygame.init, so you don't need to violate PEP 8 either.I still support the idea of either exposing set/get_hint (maybe the new
contextmodule would be a nice place for it), with documenting the important hints and linking to all SDL hints, or adding a function to joystick, likeallow_background_events, as I mentioned above. But at the very least there should be something added to the joystick docs about this.wsyxbcl commentedon Jul 5, 2022
Yes,
SDL_JOYSTICK_ALLOW_BACKGROUND_EVENTSdid work.ivandev-81 commentedon Aug 8, 2022
Hello, Is this issue still open ?
MyreMylar commentedon Aug 8, 2022
Yes. there are three tasks in the first post in this thread that still need doing to tie it off.
VebjornRiiser commentedon Nov 12, 2023
Hey, it seem like the two first tasks are fixed, but not yet marked as completed:
https://www.pygame.org/docs/ref/pygame.html

https://www.pygame.org/docs/ref/joystick.html

glarerena commentedon Jun 7, 2025
Hi! I'd like to work on this issue as a beginner-friendly documentation contribution. I see the environment variable is already mentioned, but some checklist items look incomplete. I'd be happy to clean it up and submit a final PR.