Coverage for topdownengine/controls.py: 68%
40 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-24 02:27 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-24 02:27 +0000
1# Copyright (c) 2026 Shaurya Sharma
2# SPDX-License-Identifier: MIT
4import pygame as pg
5from pygame._sdl2.controller import Controller
7class KeyboardInputManager:
8 """Acts as a keyboard and mouse input reciever.
10 Attributes:
11 keybinds (dict[str,int|str]): Stores all keybind data.
12 non_hold_inputs (list[str]): List of which inputs can't be held.
13 keys (pg.key.ScancodeWrapper): Keys currently pressed.
14 just_pressed_keys (pg.key.ScancodeWrapper): Keys pressed in the current frame.
15 """
17 def __init__(self) -> None:
18 "Initialize KeyboardInputManager."
19 self.keybinds = {
20 "Move Right": pg.K_d,
21 "Move Left": pg.K_a,
22 "Move Up": pg.K_w,
23 "Move Down": pg.K_s,
24 "Jump": pg.K_SPACE
25 }
26 self.non_hold_inputs = []
28 def serialize(self) -> dict:
29 "Serialize the keybinds."
30 return {
31 k: pg.key.name(v) if type(v) == int else v
32 for k, v in self.keybinds.items()
33 }
35 def deserialize(self, data: dict) -> None:
36 "Deserialize the keybinds into this object."
37 for k, v in data.items():
38 try:
39 self.keybinds[k] = pg.key.key_code(v)
40 except ValueError:
41 self.keybinds[k] = v
43 def get_input(self) -> list[str]:
44 """Returns all inputs to execute logic for. MUST be called after pg.event.get().
46 Returns:
47 list[str]: The inputs to execute logic for.
48 """
49 self.keys = pg.key.get_pressed()
50 self.just_pressed_keys = pg.key.get_just_pressed()
51 inputs = []
53 for keybind in self.keybinds:
54 if self.keybinds[keybind] == "Button 1":
55 if pg.mouse.get_just_pressed()[0]:
56 inputs.append(keybind)
57 elif self.keybinds[keybind] == "Button 3":
58 if pg.mouse.get_just_pressed()[2]:
59 inputs.append(keybind)
60 else:
61 if self.keys[self.keybinds[keybind]]:
62 if keybind in self.non_hold_inputs:
63 if self.just_pressed_keys[self.keybinds[keybind]]:
64 inputs.append(keybind)
65 else:
66 inputs.append(keybind)
68 return inputs
70# TODO: Add controller support
71# class ControllerInputManager:
72# def __init__(self):
73# self.controller = Controller(0)
75# self.keybinds = {
76# # "Interact": pg.K_e,
77# # "Inventory": pg.K_i,
78# "Use Item": pg.CONTROLLER_BUTTON_RIGHTSHOULDER,
79# "Use Item Special": 5,
80# # "Use Ability 1": pg.K_v,
81# # "Use Ability 2": pg.K_b,
82# }
83# self.non_hold_inputs = ["Interact", "Inventory"]
85# def get_input(self) -> list[str]:
86# inputs = []
88# for keybind in self.keybinds:
89# print(self.controller.get_button(self.keybinds[keybind]))
90# if self.controller.get_button(self.keybinds[keybind]):
91# if keybind in self.non_hold_inputs and False:
92# if self.just_pressed_keys[self.keybinds[keybind]]:
93# inputs.append(keybind)
94# else:
95# inputs.append(keybind)
96# print("hello")
97# return inputs
99class NoKeysPressed:
100 "Emulates a pygame ScancodeWrapper where no keys are pressed."
101 def __getitem__(self, key: int) -> bool:
102 return False
104class MoreKeysPressed:
105 """Emulates a pygame ScancodeWrapper where given keys are always pressed.
107 Attributes:
108 wrapper: The base wrapper that keys were added to.
109 pressed_keys: The keys added to the wrapper.
110 """
112 def __init__(self, wrapper: pg.key.ScancodeWrapper, pressed_keys: set[int]) -> None:
113 """Initialize the MoreKeysPressed object.
115 Args:
116 wrapper: The wrapper to add keys to.
117 pressed_keys: The keys to add to the wrapper.
118 """
119 self.wrapper = wrapper
120 self.pressed_keys = pressed_keys
122 def __getitem__(self, key: int) -> bool:
123 return self.wrapper[key] or key in self.pressed_keys