Pygame keyboard layouts mixed up
Asked Answered
B

2

7

I'm on Mac OS X 10.6, and I have Dvorak, US Extended, and Norwegian in my keyboard input selector menu, and US Extended is the one I use.

When I run Pygame programs with keyboard input, pygame seems to think I'm using dvorak regardless of what is actually selected.

This is the part of the code that takes the keyboard input:

    # Check for events
for event in pygame.event.get():
    if event.type == KEYDOWN:
        # Change the keyboard variables
        if event.key == K_LEFT or event.key == ord('a'):
            moveRight = False
            moveLeft = True
        if event.key == K_RIGHT or event.key == ord('d'):
            moveLeft = False
            moveRight = True
        if event.key == K_UP or event.key == ord('w'):
            moveDown = False
            moveUp = True
        if event.key == K_DOWN or event.key == ord('s'):
            moveUp = False
            moveDown = True
    if event.type == KEYUP:
        if event.key == K_ESCAPE:
            pygame.quit()
            sys.exit()
        if event.key == K_LEFT or event.key == ord('a'):
            moveLeft = False
        if event.key == K_RIGHT or event.key == ord('d'):
            moveRight = False
        if event.key == K_UP or event.key == ord('w'):
            moveUp = False
        if event.key == K_DOWN or event.key == ord('s'):
            moveDown = False
        if event.key == ord('x'):
            player.top = random.randint(0, WINDOWHEIGHT - player.height)
            player.left = random.randint(0, WINDOWWIDTH - player.width)

The arrow keys work as they should, but the WASD keys are spread over the keyboard in a way consistent with Dvorak. So, "A" is in the same place on both layouts, "W" is on QWERTY's comma key, and so on. If I change the code to look for the a, e, , and o keys instead, things work as expected.

How can I make Pygame use the correct layout?

Bouchard answered 23/11, 2012 at 12:13 Comment(3)
Why are you using ord() instead of the KEYS given by pygame?Ontiveros
The code is from the Invent Your Own Computer Games with Python book. (inventwithpython.com) I don't know why the author chose ord() over KEYS. I might learn about that in the next chapter, or the sequel, Invent [...] with Pygame.Bouchard
Excuse me, the sequel is actually called "Making Games with Python & Pygame"Bouchard
M
3

Ok I had to do some acrobatics to get this working. So first I recommend you use the key scancode which you can get from event.scancode. Each key has a unique code that refers to the physical key on the keyboard and this is the same scancode regardless of your keyboard layout dvorak or us. Then on the keydown event you will have an attribute called unicode which is the character pressed that respects the current keyboard layout in use. So pressing the d key on a us layout gets you unicode d, on dvorak that physical key would get you the e character and this gets reflected correctly in event.unicode. Here's where it gets a little annoying. It seems the unicode attribute is only available on the keydown event and not the keyup event. So I simply created a dictionary called keymap that keeps track of this information as a mapping of scancode to unicode character. The example code below will print out the character you pressed taking into account the keyboard layout. You can try it out, even if you switch the keyboard layout during program execution it still picks up the right key. The output you see below is a session where I pressed the d key in us layout switched to dvorak pressed the same key and correctly got e. And hats off to you for using dvorak its way better then qwerty, I use it too :)

code

import pygame, os
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((640, 480))
keymap = {}

while True:
    event = pygame.event.wait()
    if event.type == KEYDOWN:
        keymap[event.scancode] = event.unicode
        print 'keydown %s pressed' % event.unicode
        if (event.key == K_ESCAPE):
            os._exit(0)

    if event.type == KEYUP:
        print 'keyup %s pressed' % keymap[event.scancode]

output

keydown d pressed
keyup d pressed
keydown e pressed
keyup e pressed
Margitmargo answered 23/11, 2012 at 15:27 Comment(2)
Thanks! This solution works great! I still wonder why pygame doesn't read the current keyboard layout by default, though.Bouchard
Well in a way it does, it provides you with both the physical key press as well as the layout character. It was probably a design decision to implement it that way. It is very confusing though.Margitmargo
L
0

The accepted answer is correct, but for the sake of brevity, here is the solution:

if event.type == pygame.KEYDOWN:
   print(event.unicode)
Latticework answered 26/5, 2020 at 17:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.