2021-03-09 04:39:43

If I'm using something like Pygame, or more likely pySDL, what would be the best way of designing a keyboard/input handler that supports assigning callbacks for keys being pressed, held, or released? For determining whether keys are being held versus pressed, I was thinking about storing the current and previous state of the keyboard and querying them for various key states, but I'd appreciate any feedback. I'm looking to create a system that would allow for certain inputs to be held down to trigger over and over again while others only occur once. I'm struggling mainlly with determining when certain inputs need to fire. Should I get all keys that are down and determine what inputs need to be triggered? Do I loop through all of the inputs and query the keys for each one? How should I store valid inputs in the first place?

Trying to free my mind before the end of the world.

2021-03-09 04:50:37

Input handling can be structured in a number of ways, though it can depend on the library. I tend to structure my code so there's a main loop, with the input being captured and passed on to each class in the loop. So, for example:

import pygame
import sys

class main(object):
    def __init__(self):
    #initialize pygame
        pygame.init()
    #create display
        self.window = pygame.display.set_mode([640,480])
    #current menu state
        self.state = 'title'
    #list of menu/game classes
        self.menus = {'title':titlescreen(), 'game':game()}

    #primary update loop
        while True:
        #check for key press events
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN:
                    key = event
                else:
                    key = None

        #update and pass key presses and menu state to active menu
            self.state = self.menus[self.state].update(key,self.state)

        #update window
            pygame.display.update()


#titlescreen menu class
class titlescreen(object):
    def __init__(self):
    #menu option
        self.option = 0

    def update(self,event,state):
    #if a key has been pressed
        if event != None:
        #move up in the menu
            if event.key == pygame.K_UP:
                if self.option > 0:
                    print(self.option)
                    self.option -= 1

        #move down in the menu
            elif event.key == pygame.K_DOWN:
                if self.option < 1:
                    print(self.option)
                    self.option += 1

        #select a menu option
            elif event.key == pygame.K_RETURN:
            #if option is 0 return game state and play tone
                if self.option == 0:
                    print('game menu')
                    return 'game'
            #quit game
                elif self.option == 1:
                    print('quit')
                    pygame.quit()
                    sys.exit(0)

    #return current state if no changes
        return state


#main game class
class game(object):
    def __init__(self):
        pass

#DEMO: return to titlescreen
    def update(self,key,state):
        return 'title'


a = main()

In this case, the class you pass it to checks what the value is, or in the case of multiple key presses whether your key press is in a passed list, and then performs your chosen action. The key here is that the main class gathers the input and manages the other classes of the program, it doesn't perform any program specific actions itself. So you can switch between menus or game states universally and keep your input flow.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2021-03-09 05:28:46

For me, I tend to have a GameState object that holds both variable user data (e.g.: what we'redoing at any one moment in time, such as a menu object) and a GameState enumeration which check. Then, if I'm in C++, I cast the game state user data to the actual object I expect, then call a method on it like processEvents() which handles all incoming events.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-03-19 20:51:42

PyGame's keyboard support is very bad.
If you want to be able to handle more keyboard events, you should use something like Allegro5.

2021-03-19 21:00:04

Why is pygame bad?  This is the first I've heard anyone making this claim, and it's backed by sdl which is quite stable and quite capable, certainly more so than allegro.

This thread was about structuring code in any case.

My Blog
Twitter: @ajhicks1992

2021-03-19 21:30:31

#5

I have tried many things with PyGame. And he's really not talented.
For example, you want to get unicode characters from key events. It's a real nightmare.
Or you need the keyboard refresh rate of Windows (for characters, menus, etc...).

2021-03-19 21:31:20 (edited by magurp244 2021-03-19 21:31:39)

@4
As mentioned, for most intents and purposes [Pygames keyboard handling] is much the same as [Allegro5's]. There do seem to be a few differences for some non-essential things though, like detecting if a keyboard is installed, or setting keyboard LEDs, etc.

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer

2021-03-19 21:35:30 (edited by Ethin 2021-03-19 21:36:21)

Why would you use Allegro5 of all things? Why not just use sDL in that case? Plus, you still haven't provided evidence to prove that Pygame's key handling is bad.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2021-03-19 22:58:50

Could have sworn Pygame supports getting unicode keyvalues, but if you need unicode keyvalues then you actually need a proper IME provider because many unicode "characters" (e.g. Chinese) are actually multiple keypresses and/or mouse clicks.  While you might be able to extract the value in some cases, this is broken in the sense that you don't actually support Chinese or Japanese if you do it, and the only way to do it right from the screen reader perspective is to open an accessible textbox.

My Blog
Twitter: @ajhicks1992

2021-03-20 00:51:42

Pygame does seem to handle unicode, well in a fashion:

The pygame.KEYDOWN event has the additional attributes unicode and scancode.

        unicode: a single character string that is the fully translated character entered, this takes into account the shift and composition keys
        scancode: the platform-specific key code, which could be different from keyboard to keyboard, but is useful for key selection of weird keys like the multimedia keys

-BrushTone v1.3.3: Accessible Paint Tool
-AudiMesh3D v1.0.0: Accessible 3D Model Viewer