I have a function that detects if i press a key in pygame, but it only detects one key?

Question:

I have a function that detects key presses but, when i use the function and detect ‘a’ it detects but if i detect ‘d’ it doesnt detect it, but if i put the function that detects the key ‘d’ before the function that detects the key ‘a’ it detects ‘d’, why so?

here is my code:

keys = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','space','1','2','3','4','5','6','7','8','9','0']
pygame_keys = [pygame.K_a,pygame.K_b,pygame.K_c,pygame.K_d,pygame.K_e,pygame.K_f,pygame.K_g,pygame.K_h,pygame.K_i,pygame.K_j,pygame.K_k,pygame.K_l,pygame.K_m,pygame.K_n,pygame.K_o,pygame.K_p,pygame.K_q,pygame.K_r,pygame.K_s,pygame.K_t,pygame.K_u,pygame.K_v,pygame.K_w,pygame.K_x,pygame.K_y,pygame.K_z,pygame.K_SPACE,pygame.K_1,pygame.K_2,pygame.K_3,pygame.K_4,pygame.K_5,pygame.K_6,pygame.K_7,pygame.K_8,pygame.K_9,pygame.K_0]


def key_pressed(key_press,one_click =False):
    global key_function_run 
    if one_click:
        key_function_run = True
    if not one_click:
        if kb.is_pressed(key_press):
            return True
    if one_click:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            for i in range(len(keys)):
                if event.type == pygame.KEYDOWN:
                    if key_press == keys[i]:
                        if event.key == pygame_keys[i]:
                            print(i)
                            return True
    pass

And here is how i am using the function:

    if x == 205:
        player_lane = 2
    if x == 60:
        player_lane = 1
    if x == 347:
        player_lane = 3
    #player movement
    if peasy.key_pressed('a',True) and player_lane == 2:
        x = 60
    if peasy.key_pressed('a',True) and player_lane == 3:
        x = 205
    if peasy.key_pressed('d',True) and player_lane == 2:
        x = 347
    if peasy.key_pressed('d',True) and player_lane == 1:
        x = 205
Asked By: Morris

||

Answers:

Make a dictionary from your lists:

key_dict = dict(zip(keys, pygame_keys))

And use pygame.key.get_pressed:

def key_hold(keys, key):
    return keys[key_dict[key]]
keys = pygame.key.get_pressed()
is_a = key_hold(keys, 'a')
is_d = key_hold(keys, 'd')

If you want to use the KEYDOWN event, you have to be aware that pygame.event.get() get all the messages and remove them from the queue. See the documentation:

This will get all the messages and remove them from the queue. […]

So you can call pygame.event.get only once per frame. Also see Faster version of ‘pygame.event.get()’. Why are events being missed and why are the events delayed?. However you can use unicode property of the KEYDOWN event:

def key_down_event(event_list, c):
    return any(e for e in event_list if e.type == pygame.KEYDOWN and e.unicode == c)
event_list = pygame.event.get()
is_a = key_down_event(event_list, 'a')
is_d = key_down_event(event_list, 'd')

If you want a function that detects both whether a key is held down or has been pressed, you need to count the frames of how long a key is pressed, for each key. Return True if the count for a key is 1 when you want to determine if the key was just pressed:

import pygame

key_count = {}
def key_pressed(keys, key, one_click):
    pressed = keys[key]
    key_count[key] = (key_count.get(key, 0) + 1) if pressed else 0
    return key_count[key] == 1 if one_click else pressed
    
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

run = True
while run:
    clock.tick(100)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 

    keys = pygame.key.get_pressed()
    a_once = key_pressed(keys, pygame.K_a, True)
    d_hold = key_pressed(keys, pygame.K_d, False)
    if a_once:
        print(f'key event: {pygame.key.name(pygame.K_a)}')
    if d_hold:
        print(f'key pressed: {pygame.key.name(pygame.K_d)}')
    
    pygame.display.flip()

pygame.quit()
exit()
Answered By: Rabbid76

You shouldn’t need to make a custom function for input handling, you can use something like this:

running = True

def main():
    # Your normal game loop
    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()


        # Gets a list of the currently pressed keys,
        # this is updated because we put it in the while loop
        kbd = pygame.key.get_pressed()

        if kbd[pygame.K_a]:
            print("I just pressed the A button!") # You can run here whatever ya want

Edit: I realized OP wanted to use pygame.KEYDOWN instead of pygame.key.get_pressed(), so in that case, you can use something like this

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
           
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_d:
                    print("Pressed D!")

Hope I helped. If you have any questions, just leave a comment/reply/whatever!

Answered By: Markix
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.