{"id":"events-keys","slug":"key-presses","title":"Events and key presses","text":"So far the main loops have handled one kind of event, `pygame.QUIT`. But `pygame.event.get()` hands the program every event: each key pressed or let go, each mouse click, each move of the mouse. Printing them shows what they look like:\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        print(event)\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/f8919e417f3af6aa.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":20,\"log\":\"fill (0, 0, 0)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        print(event)\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.fill((0, 0, 0))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":20,\"events\":[{\"at\":5,\"type\":\"keydown\",\"key\":\"K_a\"},{\"at\":8,\"type\":\"keyup\",\"key\":\"K_a\"},{\"at\":12,\"type\":\"mousedown\",\"pos\":[100,60],\"button\":1},{\"at\":13,\"type\":\"mouseup\",\"pos\":[100,60],\"button\":1},{\"at\":15,\"type\":\"keydown\",\"key\":\"K_LEFT\"}]}}\n```\n\n```output\n<Event(768-KeyDown {'key': 97, 'mod': 0, 'scancode': 0, 'unicode': 'a'})>\n<Event(769-KeyUp {'key': 97, 'mod': 0, 'scancode': 0})>\n<Event(1025-MouseButtonDown {'pos': (100, 60), 'button': 1, 'touch': False})>\n<Event(1026-MouseButtonUp {'pos': (100, 60), 'button': 1, 'touch': False})>\n<Event(768-KeyDown {'key': 1073741904, 'mod': 0, 'scancode': 0, 'unicode': ''})>\n<Event(256-Quit {})>\n```\n\nEvery event is an object with a **type**, and each type has attributes of its own. A key event's `key` is a number for the key: 97 is the A key, and 1073741904 the left arrow. Nobody remembers such numbers, so pygame has a name for each one: `pygame.K_a`, `pygame.K_LEFT`, `pygame.K_RIGHT`, `pygame.K_UP`, `pygame.K_DOWN`, `pygame.K_SPACE`, `pygame.K_RETURN` and so on. A mouse button event has the point where it happened in `pos` and the button in `button`. (On your own computer, the events have a few more details, and there are more of them: one for every move of the mouse over the window, for example.)\n\nThe event types have names too:\n\n| Type | When |\n|---|---|\n| `pygame.KEYDOWN` | a key is pressed down |\n| `pygame.KEYUP` | a key is let go |\n| `pygame.MOUSEBUTTONDOWN` | a mouse button is pressed |\n| `pygame.MOUSEBUTTONUP` | a mouse button is let go |\n| `pygame.MOUSEMOTION` | the mouse moves |\n| `pygame.QUIT` | the window is closed |\n\n### Reacting to keys\n\nTo react to a key, check the event's type first and then its key:\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_LEFT:\n                print(\"left\")\n            if event.key == pygame.K_RIGHT:\n                print(\"right\")\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/f8919e417f3af6aa.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":20,\"log\":\"fill (0, 0, 0)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        if event.type == pygame.KEYDOWN:\\n            if event.key == pygame.K_LEFT:\\n                print(\\\"left\\\")\\n            if event.key == pygame.K_RIGHT:\\n                print(\\\"right\\\")\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.fill((0, 0, 0))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":20,\"events\":[{\"at\":3,\"type\":\"keydown\",\"key\":\"K_RIGHT\"},{\"at\":4,\"type\":\"keyup\",\"key\":\"K_RIGHT\"},{\"at\":8,\"type\":\"keydown\",\"key\":\"K_LEFT\"},{\"at\":9,\"type\":\"keyup\",\"key\":\"K_LEFT\"},{\"at\":12,\"type\":\"keydown\",\"key\":\"K_RIGHT\"},{\"at\":13,\"type\":\"keyup\",\"key\":\"K_RIGHT\"}]}}\n```\n\n```output\nright\nleft\nright\n```\n\nOnly a `KEYDOWN` event has a key that this program cares about, so the `KEYUP` events pass by without printing anything.\n\nOn this site you can try it yourself: run the program, click in its window and press keys. A test gives the events itself, and the task card lists them, such as \"After 3 frames: the right arrow is pressed and let go.\"\n\n### Moving with the keys\n\nNow the key presses can move the robot. Each press of an arrow moves it 10 pixels:\n\n```asset robot.png\n40x40\n```\n\n```python\nimport pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 140\ny = 200\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_LEFT:\n                x -= 10\n            if event.key == pygame.K_RIGHT:\n                x += 10\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n```\n\n```window-shot\n{\"image\":\"lessons/windows/1fda5b17f25a1b09.png\",\"size\":[320,240],\"title\":\"pygame window\",\"frames\":30,\"log\":\"fill (0, 0, 0)\\nblit robot.png at (160, 200)\",\"ended\":\"closed\",\"code\":\"import pygame\\n\\npygame.init()\\nwindow = pygame.display.set_mode((320, 240))\\nrobot = pygame.image.load(\\\"robot.png\\\")\\n\\nx = 140\\ny = 200\\n\\nwhile True:\\n    for event in pygame.event.get():\\n        if event.type == pygame.KEYDOWN:\\n            if event.key == pygame.K_LEFT:\\n                x -= 10\\n            if event.key == pygame.K_RIGHT:\\n                x += 10\\n        if event.type == pygame.QUIT:\\n            exit()\\n\\n    window.fill((0, 0, 0))\\n    window.blit(robot, (x, y))\\n    pygame.display.flip()\\n\",\"window\":{\"frames\":30,\"events\":[{\"at\":5,\"type\":\"keydown\",\"key\":\"K_RIGHT\"},{\"at\":6,\"type\":\"keyup\",\"key\":\"K_RIGHT\"},{\"at\":10,\"type\":\"keydown\",\"key\":\"K_RIGHT\"},{\"at\":11,\"type\":\"keyup\",\"key\":\"K_RIGHT\"},{\"at\":15,\"type\":\"keydown\",\"key\":\"K_RIGHT\"},{\"at\":16,\"type\":\"keyup\",\"key\":\"K_RIGHT\"},{\"at\":20,\"type\":\"keydown\",\"key\":\"K_LEFT\"},{\"at\":21,\"type\":\"keyup\",\"key\":\"K_LEFT\"}]},\"assets\":[\"robot.png\"]}\n```\n\nThree steps right and one left: the robot ends 20 pixels right of where it started, at (160, 200). The events are handled at the start of each round, before the drawing, so a press shows in the very next frame.\n","task":"Fill in the blanks so that each press of the up arrow moves the robot 20 pixels up. (The down arrow already moves it down.)\n","kind":"fill","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 140\ny = 100\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.[[KEYDOWN]]:\n            if event.key == pygame.[[K_UP]]:\n                y -= 20\n            if event.key == pygame.K_DOWN:\n                y += 20\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 140\ny = 100\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_UP:\n                y -= 20\n            if event.key == pygame.K_DOWN:\n                y += 20\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n","hints":["The first blank is the type of event that comes when a key is pressed down. The second is pygame's name for the up arrow.","The type is `pygame.KEYDOWN`, and the up arrow is `pygame.K_UP`."],"tests":[{"name":"Up, up and down","stdin":"","window":{"frames":20,"events":[{"at":3,"type":"keydown","key":"K_UP"},{"at":4,"type":"keyup","key":"K_UP"},{"at":8,"type":"keydown","key":"K_UP"},{"at":9,"type":"keyup","key":"K_UP"},{"at":13,"type":"keydown","key":"K_DOWN"},{"at":14,"type":"keyup","key":"K_DOWN"}]},"expectWindow":{"frames":20,"log":"fill (0, 0, 0)\nblit robot.png at (140, 80)","size":[320,240],"title":"pygame window","image":"lessons/windows/3ba1c54c8411aeb1.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":25,"events":[{"at":2,"type":"keydown","key":"K_UP"},{"at":3,"type":"keyup","key":"K_UP"},{"at":6,"type":"keydown","key":"K_UP"},{"at":7,"type":"keyup","key":"K_UP"},{"at":10,"type":"keydown","key":"K_UP"},{"at":11,"type":"keyup","key":"K_UP"}]},"expectWindow":{"frames":25,"log":"fill (0, 0, 0)\nblit robot.png at (140, 40)","size":[320,240],"title":"pygame window","image":"lessons/windows/37afca9606f53d30.png"},"expect":"","hidden":true},{"name":"Held down, and still down at the end","stdin":"","window":{"frames":20,"events":[{"at":3,"type":"keydown","key":"K_UP"},{"at":9,"type":"keyup","key":"K_UP"},{"at":14,"type":"keydown","key":"K_UP"}]},"expectWindow":{"frames":20,"log":"fill (0, 0, 0)\nblit robot.png at (140, 60)","size":[320,240],"title":"pygame window","image":"lessons/windows/d544e355277b3672.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["robot.png"],"more":[{"task":"Write a program that counts jumps. Each press of the space bar prints `Jump!`, and other keys do nothing. When the window is closed, the program prints how many jumps there were and ends: in the `pygame.QUIT` branch, print the count and then call `exit()`. (Do it there, not after the main loop. Here a closed window can't show another frame, so a program that draws again after `pygame.QUIT` is stopped at its next `pygame.display.flip()`, and code after its loop never runs.) With three presses of the space bar, it prints:\n\n```\nJump!\nJump!\nJump!\nJumps: 3\n```\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\njumps = 0\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_SPACE:\n                print(\"Jump!\")\n                jumps += 1\n        if event.type == pygame.QUIT:\n            print(\"Jumps:\", jumps)\n            exit()\n\n    window.fill((0, 0, 0))\n    pygame.display.flip()\n","hints":["Keep the count in a variable that starts at 0 before the main loop.","When an event is a `pygame.KEYDOWN` and its key is `pygame.K_SPACE`, print `Jump!` and add one to the count.","Print the count in the `pygame.QUIT` branch, before `exit()`: after `exit()` nothing runs any more."],"tests":[{"name":"Three jumps","stdin":"","window":{"frames":15,"events":[{"at":2,"type":"keydown","key":"K_SPACE"},{"at":3,"type":"keyup","key":"K_SPACE"},{"at":6,"type":"keydown","key":"K_SPACE"},{"at":7,"type":"keyup","key":"K_SPACE"},{"at":10,"type":"keydown","key":"K_SPACE"},{"at":11,"type":"keyup","key":"K_SPACE"}]},"expectWindow":{"frames":15,"log":"fill (0, 0, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/f8919e417f3af6aa.png"},"expect":"Jump!\nJump!\nJump!\nJumps: 3","hidden":false},{"name":"Other keys too","stdin":"","window":{"frames":20,"events":[{"at":1,"type":"keydown","key":"K_SPACE"},{"at":2,"type":"keyup","key":"K_SPACE"},{"at":4,"type":"keydown","key":"K_RETURN"},{"at":5,"type":"keyup","key":"K_RETURN"},{"at":7,"type":"keydown","key":"K_SPACE"},{"at":8,"type":"keyup","key":"K_SPACE"},{"at":12,"type":"keydown","key":"K_a"},{"at":13,"type":"keyup","key":"K_a"}]},"expectWindow":{"frames":20,"log":"fill (0, 0, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/f8919e417f3af6aa.png"},"expect":"Jump!\nJump!\nJumps: 2","hidden":true},{"name":"No jumps","stdin":"","window":{"frames":8,"events":[]},"expectWindow":{"frames":8,"log":"fill (0, 0, 0)","size":[320,240],"title":"pygame window","image":"lessons/windows/f8919e417f3af6aa.png"},"expect":"Jumps: 0","hidden":true}],"require":[],"forbid":[],"assets":["robot.png"]},{"task":"The robot moves on a grid of 40-pixel tiles. It starts at (140, 100), and each press of an arrow key moves it one tile, 40 pixels, in the arrow's direction: left, right, up or down. It moves when the key goes down, and only once, however long the key is held.\n","kind":"code","seed":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 140\ny = 100\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n","solution":"import pygame\n\npygame.init()\nwindow = pygame.display.set_mode((320, 240))\nrobot = pygame.image.load(\"robot.png\")\n\nx = 140\ny = 100\n\nwhile True:\n    for event in pygame.event.get():\n        if event.type == pygame.KEYDOWN:\n            if event.key == pygame.K_LEFT:\n                x -= 40\n            if event.key == pygame.K_RIGHT:\n                x += 40\n            if event.key == pygame.K_UP:\n                y -= 40\n            if event.key == pygame.K_DOWN:\n                y += 40\n        if event.type == pygame.QUIT:\n            exit()\n\n    window.fill((0, 0, 0))\n    window.blit(robot, (x, y))\n    pygame.display.flip()\n","hints":["In the event loop, check for a `pygame.KEYDOWN` event, then which arrow its key is.","Four arrows: `pygame.K_LEFT`, `pygame.K_RIGHT`, `pygame.K_UP` and `pygame.K_DOWN`. Left and right change x, up and down change y.","Up is a smaller y: `y -= 40`."],"tests":[{"name":"Right, right, down, left","stdin":"","window":{"frames":25,"events":[{"at":3,"type":"keydown","key":"K_RIGHT"},{"at":4,"type":"keyup","key":"K_RIGHT"},{"at":7,"type":"keydown","key":"K_RIGHT"},{"at":8,"type":"keyup","key":"K_RIGHT"},{"at":11,"type":"keydown","key":"K_DOWN"},{"at":12,"type":"keyup","key":"K_DOWN"},{"at":15,"type":"keydown","key":"K_LEFT"},{"at":16,"type":"keyup","key":"K_LEFT"}]},"expectWindow":{"frames":25,"log":"fill (0, 0, 0)\nblit robot.png at (180, 140)","size":[320,240],"title":"pygame window","image":"lessons/windows/a7b68ecd200b2cae.png"},"expect":"","hidden":false},{"name":"Test 2","stdin":"","window":{"frames":30,"events":[{"at":2,"type":"keydown","key":"K_UP"},{"at":3,"type":"keyup","key":"K_UP"},{"at":5,"type":"keydown","key":"K_UP"},{"at":6,"type":"keyup","key":"K_UP"},{"at":9,"type":"keydown","key":"K_LEFT"},{"at":10,"type":"keyup","key":"K_LEFT"},{"at":13,"type":"keydown","key":"K_LEFT"},{"at":14,"type":"keyup","key":"K_LEFT"},{"at":17,"type":"keydown","key":"K_LEFT"},{"at":18,"type":"keyup","key":"K_LEFT"}]},"expectWindow":{"frames":30,"log":"fill (0, 0, 0)\nblit robot.png at (20, 20)","size":[320,240],"title":"pygame window","image":"lessons/windows/d96be968c170de8a.png"},"expect":"","hidden":true},{"name":"Keys held down","stdin":"","window":{"frames":20,"events":[{"at":3,"type":"keydown","key":"K_RIGHT"},{"at":10,"type":"keyup","key":"K_RIGHT"},{"at":15,"type":"keydown","key":"K_UP"}]},"expectWindow":{"frames":20,"log":"fill (0, 0, 0)\nblit robot.png at (180, 60)","size":[320,240],"title":"pygame window","image":"lessons/windows/4282dcfcb74484be.png"},"expect":"","hidden":true}],"require":[],"forbid":[],"assets":["robot.png"]}]}