Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 10 additions & 10 deletions arcade/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -680,7 +680,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> EVENT_H

modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
pass

Expand All @@ -705,7 +705,7 @@ def on_mouse_drag(
Which button is pressed
modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return self.on_mouse_motion(x, y, dx, dy)

Expand All @@ -730,7 +730,7 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> EVENT
- ``arcade.MOUSE_BUTTON_MIDDLE``
modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return EVENT_UNHANDLED

Expand Down Expand Up @@ -831,7 +831,7 @@ def on_key_press(self, symbol: int, modifiers: int) -> EVENT_HANDLE_STATE:
Key that was just pushed down
modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return EVENT_UNHANDLED

Expand All @@ -853,7 +853,7 @@ def on_key_release(self, symbol: int, modifiers: int) -> EVENT_HANDLE_STATE:
symbol (int): Key that was released
modifiers (int): Bitwise 'and' of all modifiers (shift,
ctrl, num lock) active during this event.
See :ref:`keyboard_modifiers`.
See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return EVENT_UNHANDLED

Expand Down Expand Up @@ -1440,7 +1440,7 @@ def on_mouse_press(self, x: int, y: int, button: int, modifiers: int) -> bool |

modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
pass

Expand All @@ -1465,7 +1465,7 @@ def on_mouse_drag(
Which button is pressed
_modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
self.on_mouse_motion(x, y, dx, dy)
return False
Expand All @@ -1492,7 +1492,7 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> bool

modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock)
active during this event. See :ref:`keyboard_modifiers`.
active during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
pass

Expand Down Expand Up @@ -1547,7 +1547,7 @@ def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
Key that was just pushed down
modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock) active
during this event. See :ref:`keyboard_modifiers`.
during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return False

Expand All @@ -1570,7 +1570,7 @@ def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
Key that was released
modifiers:
Bitwise 'and' of all modifiers (shift, ctrl, num lock) active
during this event. See :ref:`keyboard_modifiers`.
during this event. See :ref:`pg_simple_input_keyboard_modifiers`.
"""
return False

Expand Down
100 changes: 97 additions & 3 deletions arcade/input/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,28 @@ class InputDevice(Enum):


class InputManager:
"""
The InputManager is responsible for managing input for a given device, this can be the keyboard/mouse or a controller.
In general, you can share one InputManager for one controller and the keyboard/mouse, there are even utilities to handle
automatically switching between them as the active device. However if you intend to have multiple controllers connected
to your game, each controller should have it's own InputManager.
For runnable examples of how to use this, please see Arcdade's
:ref:`built-in InputManager examples <input_manager_examples>`.
Args:
controller:
Either a Pyglet Controller object or None if you only want to use the keyboard/mouse.
allow_keyboard:
Whether to allow keyboard input, defaults to True, can be changed safely after initialization.
action_handlers:
Either one or a collection of functions that will be called for every action that is triggered.
:py:meth:`InputManager.subscribe_to_action` may be preferred to subscribe to individual actions instead.
controller_deadzone:
The deadzone for controller input, defaults to 0.1. If changes to axis values are within this
range from the underlying hardware, they will be ignored.
"""
def __init__(
self,
controller: Controller | None = None,
Expand Down Expand Up @@ -127,6 +149,20 @@ def __init__(
self.active_device = InputDevice.CONTROLLER

def serialize(self) -> RawInputManager:
"""
Serializes the current state of the InputManager into a RawInputManager dictionary which can easily be saved to JSON.
This does not include current values of inputs, but rather the structure of the InputManager. Including:
- Actions: All registered actions
- Axes: All registered axis inputs
- Current Mappings: All current mappings of underlying inputs to actions/axis
The output dictionary of this function can be passed to :meth:`arcade.InputManager.parse` to create a new InputManager
from a serialized one.
Returns:
A RawInputManager dictionary representing the current state of the InputManager.
"""
raw_actions = []
for action in self.actions.values():
raw_actions.append(serialize_action(action))
Expand All @@ -141,6 +177,13 @@ def serialize(self) -> RawInputManager:

@classmethod
def parse(cls, raw: RawInputManager) -> InputManager:
"""
Create a new InputManager from a serialized dictionary. Can be used in combination with the :meth:`arcade.InputManager.serialize` to
save/load input configurations.
Returns:
A new InputManager with the state defined in the provided RawInputManager dictionary.
"""
final = cls(controller_deadzone=raw["controller_deadzone"])

for raw_action in raw["actions"]:
Expand Down Expand Up @@ -169,6 +212,16 @@ def parse(cls, raw: RawInputManager) -> InputManager:
return final

def copy_existing(self, existing: InputManager):
"""
Copies the state of another InputManager into this one. Note that this does not create a new InputManager, but modifies the one on which it is called.
This does not copy current input values, just the structure/mappings of the InputManager.
If you want to create a new InputManager from an existing one, use :meth:`arcade.InputManager.from_existing`
Args:
existing: The InputManager to copy from.
"""
self.actions = existing.actions.copy()
self.keys_to_actions = existing.keys_to_actions.copy()
self.controller_buttons_to_actions = existing.controller_buttons_to_actions.copy()
Expand All @@ -185,19 +238,38 @@ def from_existing(
existing: InputManager,
controller: pyglet.input.Controller | None = None,
) -> InputManager:
"""
Create a new InputManager from an existing one. This does not copy current input values, just the structure/mappings of the InputManager.
If you want to create a new InputManager from a serialized dictionary, use :meth:`arcade.InputManager.parse`
Args:
existing: The InputManager to copy from.
controller: The controller to use for this InputManager. If None, no Controller will be bound.
Returns:
A new InputManager with the state defined in the provided existing InputManager.
"""
new = cls(
allow_keyboard=existing.allow_keyboard,
controller=controller,
controller_deadzone=existing.controller_deadzone,
)
new.copy_existing(existing)
new.actions = existing.actions.copy()

return new

def bind_controller(self, controller: Controller):
"""
Bind a controller to this InputManager. If a controller is already bound, it will be unbound first.
Upon binding a controller it will be set as the active device.
Args:
controller: The controller to bind to this InputManager.
"""
if self.controller:
self.controller.remove_handlers()
self.unbind_controller()

self.controller = controller
self.controller.open()
Expand All @@ -211,6 +283,9 @@ def bind_controller(self, controller: Controller):
self.active_device = InputDevice.CONTROLLER

def unbind_controller(self):
"""
Unbind the currently bound controller from this InputManager.
"""
if not self.controller:
return

Expand All @@ -229,6 +304,11 @@ def unbind_controller(self):

@property
def allow_keyboard(self):
"""
Whether the keyboard is allowed for this InputManager. This also effects mouse input.
If this is false then all keyboard and mouse input will be ignored regardless of if there are mappings for them.
"""
return self._allow_keyboard

@allow_keyboard.setter
Expand All @@ -251,14 +331,28 @@ def new_action(
self,
name: str,
):
"""
Create a new action with the given name. If an action with the same name already exists, this will do nothing.
Args:
name: The name of the action to create.
"""
if name in self.actions:
return

action = Action(name)
self.actions[name] = action

def remove_action(self, name: str):
self.clear_action_input(name)
"""
Remove the specified action. If the action does not exist, this will do nothing.
Args:
name: The name of the action to remove.
"""
to_remove = self.actions.get(name, None)
if to_remove:
self.clear_action_input(name)
del self.actions[name]

def add_action_input(
Expand Down
2 changes: 1 addition & 1 deletion doc/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ help improve Arcade.
:caption: Manual

programming_guide/sprites/index
programming_guide/keyboard
programming_guide/input/index
programming_guide/sound
programming_guide/textures
programming_guide/event_loop
Expand Down
Loading
Loading