Source code for pyggui.input
"""
Module containing the input class which updates and handles keyboard / mouse input.
"""
from typing import Callable, List, Tuple, Dict
import pygame
from pyggui.gui.event_handler import EventHandler
[docs]def get_key_pressed_dict() -> dict:
"""
Method returns a dictionary of currently pressed keys (on current frame).
# TODO: Sort this out, make pretty
Returns:
dict: Dictionary containing button states.
"""
keys_pressed = pygame.key.get_pressed()
mouse = pygame.mouse.get_pressed()
return {
"left": keys_pressed[pygame.K_LEFT],
"right": keys_pressed[pygame.K_RIGHT],
"up": keys_pressed[pygame.K_UP],
"down": keys_pressed[pygame.K_DOWN],
"enter": keys_pressed[pygame.K_RETURN],
"space": keys_pressed[pygame.K_SPACE],
"backspace": keys_pressed[pygame.K_BACKSPACE],
"mouse": {
"left": mouse[0],
"rel": mouse[1],
"right": mouse[2]
},
"a": keys_pressed[pygame.K_a],
"b": keys_pressed[pygame.K_b],
"c": keys_pressed[pygame.K_c],
"d": keys_pressed[pygame.K_d],
"e": keys_pressed[pygame.K_e],
"f": keys_pressed[pygame.K_f],
"g": keys_pressed[pygame.K_g],
"h": keys_pressed[pygame.K_h],
"i": keys_pressed[pygame.K_i],
"j": keys_pressed[pygame.K_j],
"k": keys_pressed[pygame.K_k],
"l": keys_pressed[pygame.K_l],
"m": keys_pressed[pygame.K_m],
"n": keys_pressed[pygame.K_n],
"o": keys_pressed[pygame.K_o],
"p": keys_pressed[pygame.K_p],
"r": keys_pressed[pygame.K_r],
"s": keys_pressed[pygame.K_s],
"t": keys_pressed[pygame.K_t],
"u": keys_pressed[pygame.K_u],
"v": keys_pressed[pygame.K_v],
"z": keys_pressed[pygame.K_z],
"x": keys_pressed[pygame.K_x],
"y": keys_pressed[pygame.K_y],
}
[docs]class Input:
"""
Main class for handling keyboard and mouse input. TODO: Update this mess
"""
def __init__(self, game: 'Game'):
"""
Args:
game (Game): Main game object.
"""
self.game = game
# Internal attributes used in the gui
# Save as two consecutive mouse positions / clicks, accessible through properties
self.mouse_position: Tuple[int, int] = (0, 0) # Current mouse position
self.key_pressed: Dict = {} # Keys pressed dictionary
self._mouse_pressed: List[bool, bool] = [False, False] # Two consecutive mouse clicks, handled in properties
self.mouse_clicked: bool = False # Gets set by event, above is set every frame
self.mouse_movement: Tuple[int, int] = (0, 0) # Movement of mouse between two consecutive calls
self.mouse_scroll: int = 0 # Wheel on the mouse, 1 if up -1 if down roll
# Events
self.event_types: Dict[str, Callable] = {}
# Initial update
self.update()
@property
def mouse_pressed(self) -> bool:
"""
If mouse was clicked on current frame.
Returns:
bool: If clicked
"""
return self._mouse_pressed[-1] # Last click
@mouse_pressed.setter
def mouse_pressed(self, clicked: bool) -> None:
"""
Mouse pressed on current frame.
Args:
clicked (bool): If mouse pressed
"""
self._mouse_pressed.append(clicked)
self._mouse_pressed = self._mouse_pressed[-2:] # Save as only the last 2 recent clicks
@property
def previous_mouse_pressed(self) -> bool:
"""
If mouse was pressed on previous frame.
Returns:
bool: If pressed
"""
return self._mouse_pressed[0] # Left one is the previous one as we append clicks
[docs] def add_event_handler(self, event_handler: EventHandler) -> None:
"""
Method adds event handler object to self, its event types are added to the event types dictionary,
its handlers get triggered once the type appears in the main input loop.
Args:
event_handler (EventHandler): EventHandler object to add.
"""
for event_type in event_handler.types:
if event_type in self.event_types:
self.event_types[event_type].append(event_handler)
else:
self.event_types[event_type] = [event_handler]
[docs] def add_event_type_handler(self, event_type: int, handler: Callable) -> None:
"""
Method adds a single event type handler. The handler will get called once the event_type appears in the input
main loop.
Args:
event_type (int): Pygame event type integer number
handler (Callable): Callable function to get called once the event type appears in the input main loop.
"""
# Create an EventHandler object
event_handler = EventHandler(types=event_type, handlers=handler)
self.add_event_handler(event_handler)
[docs] def remove_event_handler(self, event_handler: EventHandler) -> None:
"""
Method removes passed EventHandler from self.
Args:
event_handler (EventHandler): EventHandler object to remove
"""
for event_type in event_handler.types:
if event_type in self.event_types:
# Create new list object, add only EventHandlers that are not the passed event_handler
self.event_types[event_type] = [eh for eh in self.event_types[event_type] if not (eh is event_handler)]
[docs] def remove_event_handlers(self, event_handlers: List[EventHandler]) -> None:
"""
Method removes all passed event handler objects from self.
EventHandlers therefor wont be triggered anymore.
Args:
event_handlers (List[EventHandler]): List of EventHandler objects to remove
"""
for event_handler in event_handlers:
self.remove_event_handler(event_handler)
def __process_event_type_handlers(self, event: 'Event') -> None:
"""
Method handles events set in event_types, these are added by users (pages and or items).
Args:
event (Event): Pygame Event object.
"""
if event.type in self.event_types: # Check if handler was added
for handler in self.event_types[event.type]:
handler.update(event=event) # Call EventHandlers update method, pass it the event
def __process_events(self, event: 'Event') -> None:
"""
Method handles events used internally by gui items and or controller.
Updates attributes.
Args:
event (Event): Pygame Event object.
"""
# Mouse events
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1:
self.mouse_clicked = True
else:
self.mouse_clicked = False
# Mouse wheel event
if event.type == pygame.MOUSEWHEEL:
self.mouse_scroll = event.y # This attribute has to be reset outside this event loop
[docs] def update(self) -> bool:
"""
Main loop for going over Pygame events.
Loop goes over user added events.
Returns:
bool: False if game was quit, True otherwise
"""
for event in pygame.event.get():
# Process user added events first
self.__process_event_type_handlers(event)
# Process own events
self.__process_events(event)
# Quit event
if event.type == pygame.QUIT:
pygame.quit()
return False
# Update data used by items and controller
# We do this at the end as mouse.get_pressed might not work as expected if called before pygame.event.get()
self.mouse_position = pygame.mouse.get_pos()
key_pressed = get_key_pressed_dict()
self.key_pressed = key_pressed
self.mouse_pressed = key_pressed["mouse"]["left"]
self.mouse_movement = pygame.mouse.get_rel() # Movement of mouse on two consecutive calls
return True