pygame - Getting name of pressed key [duplicate] - python

Game I'm working on currently needs to let people time in their name for highscore board. I'm slightly familiar with how to deal with key presses, but I've only dealt with looking for specific ones. Is there an easy way to get the letter of any key pressed without having to do something like this:
for event in pygame.event.get():
if event.type == KEYUP:
if event.key == K_a:
newLetter = 'a'
elif event.key == K_b:
newLetter = 'b'
...
elif event.key == K_z:
newLetter = 'z'
While that would work, I have a feeling there is a more efficient way to go about it. I just can't figure it out or find any guides on it.

There a basically two ways:
Option 1: use pygame.key.name().
It's as simple as
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print(pygame.key.name(event.key))
The advantage over using chr is that chr works only if the value of event.key is between 0 and 255 (inclusive).
If you press menu, Alt Gr, Tab or LShift, pygame.key.name will happily return menu, alt gr, tab and left shift, while chr will crash, crash, return whitespace, and crash.
Option 2: use the unicode attribute of the pygame.KEYDOWN event
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
print(event.unicode)
It will get you the letter/number or an empty string when using a function key, and it will also take modifiers into account, e.g. if you hold Shift while pressing a it will return A instead of just a.
The pygame.KEYDOWN event has additional attributes unicode and
scancode. unicode represents a single character string that is the
fully translated character entered. This takes into account the shift
and composition keys. scancode represents the platform-specific key
code.

if you look K_a is just 97 thats the ascii code for 'a' , I will extrapolate to K_? is the ascii code for whatever the question mark represents
if event.type == KEYUP:
print chr(event.key) #convert ascii code to a character
maybe?
as pointed out this will not work with ascii over 255 (no longer ascii really)
you can use the method outlined below or just use unichr(event.key) instead of chr

Related

PyGame doesn´t detect Button 6 press? [duplicate]

I've seen other solutions to this problem say that you either need to call the pygame.event.pump() or initialize the joystick outside of the while loop. However, even with these solutions, I'm getting 0's for the joystick axes values.
If I uncomment just the pygame.display.set_mode((1, 1)), then the code works as expected, and the values are output to the console.
Is there a way to still get the axes values without having to create the extra window?
Also, I am running python 3.6 on Windows 10.
import pygame
FRAMES_PER_SECOND = 20
pygame.init()
pygame.joystick.init()
# pygame.display.set_mode((1,1))
# Used to manage how fast the screen updates.
clock = pygame.time.Clock()
xboxController = pygame.joystick.Joystick(0)
xboxController.init()
# Loop until the user presses menu button
done = False
print('Found controller\nStarting loop...')
while not done:
pygame.event.pump()
for event in pygame.event.get():
if event.type == pygame.JOYBUTTONDOWN and event.button == 7:
print(f'Exiting controller loop')
done = True
for i in range(xboxController.get_numaxes()):
print(f'Axis {i}: {xboxController.get_axis(i)}')
# pygame.display.flip()
clock.tick(FRAMES_PER_SECOND)
Output:
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
Found controller
Starting loop...
Axis 0: 0.0
Axis 1: 0.0
Axis 2: 0.0
Axis 3: 0.0
Axis 4: 0.0
.
.
.
I would probably move away from Pygame unless you need the whole underlaying GL features, as the library is meant for 2D/3D game development. Although it might be possible to use it for these purposes, issues down the line is more or less unavoidable. A perhaps simpler approach would be to go with python's input library, which can handle gamepads (joysticks).
from inputs import get_gamepad
while True:
events = get_gamepad()
for event in events:
if event.ev_type == 'Absolute':
if event.code == 'ABS_X':
print(f'Left joystick x: {event.state}')
elif event.code == 'ABS_Y':
print(f'Left joystick y: {event.state}')
elif event.code == 'ABS_RX':
print(f'Right joystick x: {event.state}')
elif event.code == 'ABS_RY':
print(f'Right joystick y: {event.state}')
Alright found the answer 5 minutes after I posted this. The problem was that I was using pygame 1.9.6 instead of 2.0.0.dev8. After updating, I'm getting the console output without the display window.

python using ord() with getch() to get unicode

i am learning python at the moment and i tried to get keyboard input, without the need to press the enter key with getch() and ord() in order to work with the (at least for me) gibberish that returns from getch().
in my understanding getch() returns a byte stream, and ord does translate that byte data into unicode. and if iam not wrong there are keys like the arrow keys (this is my intention, to build a cmd "ui" to navigate) that are seperated into different unicode values.
so far, after trying myself and searching the web i come up with a soultion, provided by a person on the internet(information only for not claimig someone elses code as mine)
import msvcrt
while True:
key = ord(msvcrt.getch())
if key == 27: #ESC
break
elif key == 13: #Enter
print("select")
elif key == 224: #thing i do not understand
key = ord(msvcrt.getch()) #thing i do not understand
if key == 80: #Down arrow
print("moveDown")
elif key == 72: #Up arrow
print("moveUp")
elif key == 77: #Right arrow
print("moveRight")
elif key == 75: #Left arrow
print("moveLeft")
this works fine, but the thing that i do not understand is, why it is necessary to make the second variable assignment. in my understanding getch() should return the value instantly, so i do not understand where the second key = ord... statement gets the data to assign it to the key variable.
I would appreciate an explanation.
From the documentation for msvcrt.getch:
msvcrt.getch()
Read a keypress and return the resulting character as a byte string.
Nothing is echoed to the console. This call will block if a keypress
is not already available, but will not wait for Enter to be pressed.
If the pressed key was a special function key, this will return '\000'
or '\xe0'; the next call will return the keycode. The Control-C keypress
cannot be read with this function.
So, if a special function key (e.g. an arrow key) was pressed, we have to test for 0xE0 (224) and then read the next value.

Handling None as position in pygame

The built in pygame function: pygame.mouse.get_pos() returns the X and Y coordinates in a tuple when I am moving the mouse, but if I stop moving the mouse, the function returns None.
But, I want the computer to keep returning the current coordinates over and over again.
How do I do that?
What I am trying to do is write a function that makes it easier to get the mouse coordinates.
I want to be able to do following:
Xpos, Ypos = mouse_pos()
What I have right now is:
def mouse_pos():
for event in pygame.event.get():
pos = pygame.mouse.get_pos()
if pos != None:
x=a[0]
y=a[1]
return x, y
else:
#here I want code that says: if pos is NoneType, x=(latest x-value) and y=(latest y-value)
So, how can i get pygame to not return None (and return current coordinates) even if mouse is stationary?
Thanks in advance!
You are using the API wrong, the fact that there are events doesn't mean any of them is a mouse event, and pygame fills the mouse position on mouse events.
The function get_pos shouldn't be calle to find out where the mouse is but rather to update your knowledge when it is changed.
The correct way to keep track of mouse position will be to have the following in you main game loop:
mouse_position = (0, 0) # initial value
while game_is_running: # your main game loop
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
mouse_position = pygame.mouse.get_pos()
Remove your function. Just use pygame.mouse.get_pos().
It's not pygame.mouse.get_pos() that returns None, it's your own function.
It will only set pos if there's an event in the event queue. If not, pos will be None.
But even worse is that every time you call your mouse_pos function, the event queue will be cleared. That will lead to events getting lost.

Keyboard layout aware combinations in pygame

Pygame has a constant for example for the exclamation mark, !. The constant is called pygame.K_EXCLAIM. However, in my standard US keyboard layout, the exclamation mark is produced by pressing shift and the key 1. Consider the following two snippets:
# snippet 1
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_EXCLAIM:
print('!')
elif event.key == pygame.K_1:
print('1')
# snippet 2
pressed = pygame.key.get_pressed()
if pressed[pygame.K_EXCLAIM]:
print('!')
if pressed[pygame.K_1]:
print('1')
In both cases, when I press Shift+1, which would produce a exclamation mark, pygame does not recognize the combination and simply says the shift key and the 1 key are pressed, printing the value "1". This concerns me a little bit because while I can hardcode such combinations, they are dependent of the keyboard's layout.
Can I make pygame produce combinations constants (such as K_EXCLAIM or K_AMPERSAND) in a keyboard layout-aware manner?
What you want is the event.unicode attribute:
if event.unicode == "!":
print("!")

How to append items to a list one time each in python

Lets say I have a list called my_list and a function called my_function and my_function appends items to my_list based on which portion of the surface gameDisplay was clicked on. However whenever you hold down the mouse for more than one frame, it appends more than one of that item to my_list. This is not the result I am going for. I was wondering if there was a way you could do this without appending more than one of each item to my_list
Thanks for your help
You didn't show code but I guess you use pygame.mouse.get_pressed() which gives True all the time when you keep button pressed. And this can be your problem.
You can do one of two things:
use event.MOUSEBUTTONDOWN which is created only once - when button change state from not-pressed into pressed.
Or:
use extra variable which will remeber pygame.mouse.get_pressed() from previous frame. And then compare if now button is pressed but in previous frame was not-pressed then add element to list.
EDIT: old code from different question which use event.MOUSEBUTTONDOWN to change color.
#!/usr/bin/env python
# http://stackoverflow.com/questions/33856739/how-to-cycle-3-images-on-a-rect-button
import pygame
# - init -
pygame.init()
screen = pygame.display.set_mode((300,200))
# - objects -
# create three images with different colors
images = [
pygame.Surface((100,100)),
pygame.Surface((100,100)),
pygame.Surface((100,100)),
]
images[0].fill((255,0,0))
images[1].fill((0,255,0))
images[2].fill((0,0,255))
images_rect = images[0].get_rect()
# choose first image
index = 0
# - mainloop -
running = True
while running:
# - events -
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and images_rect.collidepoint(event.pos):
# cycle index
index = (index+1) % 3
# - draws -
screen.blit(images[index], images_rect)
pygame.display.flip()
# - end -
pygame.quit()
GitHub: furas/python-examples/pygame/button-click-cycle-color

Categories