I have a fairly typical pygame project with a game loop that processes events, updates game state and data, and then draws the next frame. That's all working.
For various reasons, this is Windows only at the moment. So I thought I would add an "About..." screen to the Windows System Menu (A.K.A. Window Menu / Control Menu).
Near the initialization of my program, I insert the menu (which works):
WM_COMMAND = 0x0111
ABOUT_MENU_ID = 1001
hwnd = pygame.display.get_wm_info()["window"]
menu = ctypes.windll.user32.GetSystemMenu(hwnd, False)
ctypes.windll.user32.AppendMenuW(menu, 0, ABOUT_MENU_ID, "About...")
I understand that pygame does not get system messages, so I need to use pygame.event.pump() to bring them in. My full game loop is:
running = True
while running:
# Include system events.
pygame.event.pump()
if game.state == "playing":
if pygame.key.get_pressed()[pygame.K_a] or pygame.key.get_pressed()[pygame.K_LEFT]:
game.players[-1].move([-4, 0])
elif pygame.key.get_pressed()[pygame.K_d] or pygame.key.get_pressed()[pygame.K_RIGHT]:
game.players[-1].move([4, 0])
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
elif event.key == pygame.K_SPACE:
game.players[-1].fire()
elif event.type == pygame.QUIT:
running = False
elif event.type == WM_COMMAND and event.wparam == ABOUT_MENU_ID:
handle_about_screen()
game.handleFrame()
elif game.state == "splash":
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_p:
game.__init__()
elif event.type == pygame.QUIT:
running = False
elif event.type == WM_COMMAND and event.wparam == ABOUT_MENU_ID:
handle_about_screen()
elif game.state == "about":
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
running = False
if event.key == pygame.K_p:
if(game.lastState == "splash"):
handle_splash_screen()
elif event.type == pygame.QUIT:
running = False
pygame.display.update()
clock.tick(game.frame_rate)
handle_about_screen() is never called, so if the event message is making it to pygame, it isn't identified correctly.
I also tried a different strategy, involving more directly accessing the System message queue. But you can see the infinite loop in the code below... I haven't been able to find a way to get at my about screen menu item event, without either having an obvious infinite loop, or without throwing out potentially important messages that I'm not handling, or withotu scrambling the order of events as I re-insert the ones I'm not handling:
while True:
msg = ctypes.windll.user32.PeekMessageW(None, None, 0, 0, 1) # Check without removing (to avoid deleting other events)
if not msg:
break # No events found
if msg[0] == WM_COMMAND and msg[1] == ABOUT_MENU_ID:
handle_about_screen() # It's ours...
ctypes.windll.user32.PeekMessageW(None, None, 0, 0, 0) # Remove the "About" menu message from the queue
else:
break # It's an event we don't handle... But now we're
# infinite looping because we will find this one again.
This seems like it should be simple... Am I missing some obvious API, pygame or python functionality?
Thanks in advance for any help.