Skip to content

Commit

Permalink
Attempt to clean up new experimental controllers a bit (#2133)
Browse files Browse the repository at this point in the history
* Remove file-wide type: ignore from input/inputs.py

* Remove type ignore line

* Ugly oneliner fix for mypy redefinition error

* Convert input.mapping types to class-based TypedDict

* Convert RawInputManager to class-based TypedDict

* Turn O(N) elif ladder into O(1) type hash

* Move INPUT_TYPE_TOCLASS and stop local clobber of input builtin

* Compact another O(N) builder into an O(1) map lookup

* Collapse instance parsing into a function

* Simplify Mapping's monster O(N) x isinstance elif chain

* Add CLASS_TO_INPUT_TYPE dict

* Use new table tot simplify Mapping's isinstance elif ladder

* Move extracted parse_instance func into inputs where it belongs

* Replace O(N) elif block with O(1) type hash parse_instance call

* Clean up unused import

* WIP notes

* Restore file-wide type ignores for the moment

* Newline at EOF

* Add some temp comments

* Fix random 1 typo
  • Loading branch information
pushfoo authored Jun 25, 2024
1 parent d9e8331 commit 04dfafb
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 85 deletions.
41 changes: 36 additions & 5 deletions arcade/experimental/input/inputs.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# type: ignore

#type: ignore
"""
Enums used to map different input types to their common counterparts.
Expand Down Expand Up @@ -90,9 +89,7 @@ class Keys(InputEnum):
MOD_SCROLLLOCK = 256

# Platform-specific base hotkey modifier
MOD_ACCEL = MOD_CTRL
if platform == "darwin":
MOD_ACCEL = MOD_COMMAND
MOD_ACCEL = MOD_COMMAND if platform == "darwin" else MOD_CTRL

# Keys
BACKSPACE = 65288
Expand Down Expand Up @@ -319,3 +316,37 @@ class MouseButtons(InputEnum):

MOUSE_4 = 1 << 3
MOUSE_5 = 1 << 4


#.This is safe since:
# 1. Enum types with members are final
#.2. Types are hashable
# Hoever, we can probably make this much cleaner to set up since
# we have repeated if ladders elsewhere which can be replaced with
# smaller dicts.
CLASS_TO_INPUT_TYPE = {
Keys: InputType.KEYBOARD,
MouseButtons: InputType.MOUSE_BUTTON,
MouseAxes: InputType.MOUSE_AXIS,
ControllerButtons: InputType.CONTROLLER_BUTTON,
ControllerAxes: InputType.CONTROLLER_AXIS,
}

INPUT_TYPE_TO_CLASS = {
InputType.KEYBOARD: Keys,
InputType.MOUSE_BUTTON: MouseButtons,
InputType.MOUSE_AXIS: MouseAxes,
InputType.CONTROLLER_BUTTON: ControllerButtons,
InputType.CONTROLLER_AXIS: ControllerAxes,
}


# WIP cleanup, will be documented and named better and actually annotated later
def parse_instance(_mapping):
_raw_input = _mapping['input']
_input_type = InputType(_mapping["input_type"])

if not (_input_class := INPUT_TYPE_TO_CLASS.get(_input_type, None)):
raise AttributeError("Tried to parse an unknown input type")
return _input_class(_raw_input)

52 changes: 15 additions & 37 deletions arcade/experimental/input/manager.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# type: ignore

# type: ignore
from __future__ import annotations

from enum import Enum
Expand All @@ -24,10 +23,12 @@
serialize_axis,
)

RawInputManager = TypedDict(
"RawInputManager",
{"actions": List[RawAction], "axes": List[RawAxis], "controller_deadzone": float},
)


class RawInputManager(TypedDict):
actions: List[RawAction]
axes: List[RawAxis]
controller_deadzone: float


def _set_discard(set: Set, element: Any) -> Set:
Expand Down Expand Up @@ -125,24 +126,13 @@ def parse(cls, raw: RawInputManager) -> InputManager:
for raw_action in raw["actions"]:
name = raw_action["name"]
final.new_action(name)

for raw_mapping in raw_action["mappings"]:
raw_input = raw_mapping["input"]
input_type = inputs.InputType(raw_mapping["input_type"])
if input_type == inputs.InputType.KEYBOARD:
input = inputs.Keys(raw_input)
elif input_type == inputs.InputType.MOUSE_BUTTON:
input = inputs.MouseButtons(raw_input)
elif input_type == inputs.InputType.MOUSE_AXIS:
input = inputs.MouseAxes(raw_input)
elif input_type == inputs.InputType.CONTROLLER_BUTTON:
input = inputs.ControllerButtons(raw_input)
elif input_type == inputs.InputType.CONTROLLER_AXIS:
input = inputs.ControllerAxes(raw_input)
else:
raise AttributeError("Tried to parse an unknown input type")
input_instance = inputs.parse_instance(raw_mapping)

final.add_action_input(
name,
input,
input_instance,
raw_mapping["mod_shift"],
raw_mapping["mod_ctrl"],
raw_mapping["mod_alt"],
Expand All @@ -152,21 +142,9 @@ def parse(cls, raw: RawInputManager) -> InputManager:
name = raw_axis["name"]
final.new_axis(name)
for raw_mapping in raw_axis["mappings"]:
raw_input = raw_mapping["input"]
input_type = inputs.InputType(raw_mapping["input_type"])
if input_type == inputs.InputType.KEYBOARD:
input = inputs.Keys(raw_input)
elif input_type == inputs.InputType.MOUSE_BUTTON:
input = inputs.MouseButtons(raw_input)
elif input_type == inputs.InputType.MOUSE_AXIS:
input = inputs.MouseAxes(raw_input)
elif input_type == inputs.InputType.CONTROLLER_BUTTON:
input = inputs.ControllerButtons(raw_input)
elif input_type == inputs.InputType.CONTROLLER_AXIS:
input = inputs.ControllerAxes(raw_input)
else:
raise AttributeError("Tried to parse an unknown input type")
final.add_axis_input(name, input, raw_mapping["scale"])
input_instance = inputs.parse_instance(raw_mapping)

final.add_axis_input(name, input_instance, raw_mapping["scale"])

return final

Expand Down Expand Up @@ -484,7 +462,7 @@ def on_mouse_release(self, x: int, y: int, button: int, modifiers: int) -> None:
def on_key_release(self, key: int, modifiers) -> None:
if not self._allow_keyboard:
return

# What, why are we doing any of this repeat tuple conversion in here?
keys_to_actions = tuple(self.keys_to_actions.get(key, set()))
for action_name in keys_to_actions:
action = self.actions[action_name]
Expand Down
71 changes: 28 additions & 43 deletions arcade/experimental/input/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,29 @@

from arcade.experimental.input import inputs

RawActionMapping = TypedDict(
"RawActionMapping",
{
"input_type": int,
"input": Union[str, int],
"mod_shift": bool,
"mod_ctrl": bool,
"mod_alt": bool,
},
)
RawAxisMapping = TypedDict(
"RawAxisMapping", {"input_type": int, "input": Union[str, int], "scale": float}
)

RawAction = TypedDict("RawAction", {"name": str, "mappings": List[RawActionMapping]})
RawAxis = TypedDict("RawAxis", {"name": str, "mappings": List[RawAxisMapping]})

class RawActionMapping(TypedDict):
input_type: int
input: Union[str, int]
mod_shift: bool
mod_ctrl: bool
mod_alt: bool


class RawAxisMapping(TypedDict):
input_type: int
input: Union[str, int]
scale: float


class RawAction(TypedDict):
name: str
mappings: List[RawActionMapping]


class RawAxis(TypedDict):
name: str
mappings: List[RawAxisMapping]


class Action:
Expand Down Expand Up @@ -61,21 +68,12 @@ def remove_mapping(self, mapping: AxisMapping) -> None:
class Mapping:

def __init__(self, input: inputs.InputEnum):
if isinstance(input, inputs.Keys):
self._input_type = inputs.InputType.KEYBOARD
elif isinstance(input, inputs.MouseButtons):
self._input_type = inputs.InputType.MOUSE_BUTTON
elif isinstance(input, inputs.MouseAxes):
self._input_type = inputs.InputType.MOUSE_AXIS
elif isinstance(input, inputs.ControllerButtons):
self._input_type = inputs.InputType.CONTROLLER_BUTTON
elif isinstance(input, inputs.ControllerAxes):
self._input_type = inputs.InputType.CONTROLLER_AXIS
else:
try:
self._input_type = inputs.CLASS_TO_INPUT_TYPE[input]
except KeyError:
raise TypeError(
"Input specified for ActionMapping must inherit from InputEnum"
)

self._input = input


Expand Down Expand Up @@ -127,23 +125,10 @@ def serialize_action(action: Action) -> RawAction:
def parse_raw_axis(raw_axis: RawAxis) -> Axis:
axis = Axis(raw_axis["name"])
for raw_mapping in raw_axis["mappings"]:
raw_input = raw_mapping["input"]
input_type = inputs.InputType(raw_mapping["input_type"])
if input_type == inputs.InputType.KEYBOARD:
input = inputs.Keys(raw_input)
elif input_type == inputs.InputType.MOUSE_BUTTON:
input = inputs.MouseButtons(raw_input)
elif input_type == inputs.InputType.MOUSE_AXIS:
input = inputs.MouseAxes(raw_input)
elif input_type == inputs.InputType.CONTROLLER_BUTTON:
input = inputs.ControllerButtons(raw_input)
elif input_type == inputs.InputType.CONTROLLER_AXIS:
input = inputs.ControllerAxes(raw_input)
else:
raise AttributeError("Tried to parse an unknown input type")
instance = inputs.parse_instance(raw_mapping)
axis.add_mapping(
AxisMapping(
input,
instance,
raw_mapping["scale"],
)
)
Expand Down

0 comments on commit 04dfafb

Please sign in to comment.