Skip to content

Commit

Permalink
Updates to gremlin parser (WIP) virtual hats/pov_containers
Browse files Browse the repository at this point in the history
  • Loading branch information
Rexeh committed Mar 20, 2024
1 parent 8c63350 commit 22b8441
Show file tree
Hide file tree
Showing 6 changed files with 188 additions and 392 deletions.
162 changes: 133 additions & 29 deletions joystick_diagrams/plugins/joystick_gremlin_plugin/joystick_gremlin.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
"""
import logging
from pathlib import Path
from typing import Union
from xml.dom import minidom

from joystick_diagrams.exceptions import JoystickDiagramsError
Expand All @@ -25,15 +24,27 @@
8: "UL",
}

VIRTUAL_HAT_POSITIONS = {
"north": HAT_POSITIONS[1],
"north-east": HAT_POSITIONS[2],
"east": HAT_POSITIONS[3],
"south-east": HAT_POSITIONS[4],
"south": HAT_POSITIONS[5],
"south-west": HAT_POSITIONS[6],
"west": HAT_POSITIONS[7],
"north-west": HAT_POSITIONS[8],
}


class JoystickGremlinParser:
def __init__(self, filepath: Path):
self.file = self.parse_xml_file(filepath)
import os

def parse_xml_file(self, xml_file: Path) -> minidom.Document:
file_path = str(xml_file)
parsed_xml = minidom.parse(file_path)
_logger.debug(os.access(Path(filepath), os.R_OK))
self.file = self.parse_xml_file(Path(filepath))

def parse_xml_file(self, xml_file: Path) -> minidom.Document:
parsed_xml = minidom.parse(str(xml_file))
valid = self.validate_xml(parsed_xml)

if valid:
Expand Down Expand Up @@ -102,7 +113,7 @@ def create_dictionary(self) -> ProfileCollection:

return profile_collection

def extract_hats(self, hat_node) -> list[Union[str, str] | None]:
def extract_hats(self, hat_node: minidom.Element) -> list[tuple[Hat, str]]:
"""Extract the hat positions for a given HAT node.
Each HAT node may contain a CONTAINER, which may contain N number of action-set nodes
Expand All @@ -114,47 +125,140 @@ def extract_hats(self, hat_node) -> list[Union[str, str] | None]:
hat_description: str = hat_node.getAttribute("description") or ""
hat_mappings: list = []

_logger.debug("Hat ID: {hat_id}")
_logger.debug("Hat has description: {hat_description}")
_logger.debug(f"Hat ID: {hat_id}")
_logger.debug(f"Hat has description: {hat_description}")

# Get the containers
hat_container = hat_node.getElementsByTagName("container")
hat_containers = hat_node.getElementsByTagName("container")

if not hat_container:
if not hat_containers:
return hat_mappings

_logger.debug("Has containers: {hat_containers.length}")
# Gather container types
basic_containers = [
x for x in hat_containers if x.getAttribute("type") == "basic"
]
filtered_hat_containers = [
x for x in hat_containers if x.getAttribute("type") == "hat_buttons"
]

_logger.debug(f"Basic Containers: {len(basic_containers)}")
_logger.debug(f"Hat Containers: {len(filtered_hat_containers)}")

if filtered_hat_containers:
hat_mappings = self.handle_hat_button_container(
hat_id, filtered_hat_containers
)

if basic_containers:
hat_mappings = self.handle_virtual_button_container(hat_id, hat_containers)

hat_positions = hat_container[0].getElementsByTagName("action-set")
return hat_mappings

def handle_virtual_button_container(
self, hat_id, containers: minidom.NodeList[minidom.Element]
):
hat_mappings = []
for container in containers:
# Check if we have a top level description
container_description = (
container.getAttribute("description")
if container.getAttribute("description") != ""
else None
)

for position in hat_positions:
# Get REMAP of node (assumes 1)
hat_position_id = int(
position.getElementsByTagName("remap")[0].getAttribute("button")
# Try source description from inner block
if not container_description:
container_description = " - ".join(
{
x.getAttribute("description")
for x in container.getElementsByTagName("description")
}
)

# Skip processing if we have no descriptions
if not container_description:
print("No point continuing")
continue

virtual_buttons: minidom.Element = container.getElementsByTagName(
"virtual-button"
)

# Get the description node if exists
hat_description_check = position.getElementsByTagName("description")
if not virtual_buttons:
# If we don't have virtual buttons we have no hats to process
continue

# If no node then continue
if not hat_description_check:
if len(virtual_buttons) != 1:
print("Not expected number of virtual button elements")
continue

hat_description = hat_description_check[0].getAttribute("description")
attributes = [x for x in virtual_buttons[0].attributes.keys()]

if not hat_description:
# If we don't have a description then no point using the item
continue
for attribute in attributes:
hat_mappings.append(
(
Hat(hat_id, HatDirection[VIRTUAL_HAT_POSITIONS[attribute]]),
container_description,
)
)

hat_position_to_string = HAT_POSITIONS[hat_position_id]
hat_mappings.append(
[Hat(hat_id, HatDirection[hat_position_to_string]), hat_description]
)
return hat_mappings

def handle_hat_button_container(
self, hat_id, hat_containers: minidom.NodeList[minidom.Element]
):
four_way_hat = 4

for container in hat_containers:
button_count = int(container.getAttribute("button-count"))

hat_positions = container.getElementsByTagName("action-set")

hat_mappings = []

# Iterate each ACTION_SET, for the HAT_BUTTONS
for hat_direction_no, position in enumerate(hat_positions, 1):
# Get the description node if exists
hat_description_node = position.getElementsByTagName("description")

hat_direction = hat_direction_no

if button_count == four_way_hat:
hat_direction = hat_direction_no + (hat_direction_no - 1)

# If no node then continue
if not hat_description_node:
continue

# What if multiple hat_description_nodes

hat_description = hat_description_node[0].getAttribute("description")

if not hat_description:
# If we don't have a description then no point using the item
continue

hat_position_to_string = HAT_POSITIONS[hat_direction]
hat_mappings.append(
(Hat(hat_id, HatDirection[hat_position_to_string]), hat_description)
)

return hat_mappings


if __name__ == "__main__":
pass
pars = JoystickGremlinParser(
Path(
r"D:\Git Repos\joystick-diagrams\tests\data\joystick_gremlin\gremlin_pov_container_hat_buttons.xml"
)
)
# pars = JoystickGremlinParser(
# Path(
# r"D:\Git Repos\joystick-diagrams\tests\data\joystick_gremlin\gremlin_hat_virtual_buttons.xml"
# )
# )

_logger.setLevel(logging.DEBUG)
data = pars.create_dictionary()
print(data)
40 changes: 40 additions & 0 deletions tests/data/joystick_gremlin/gremlin_hat_virtual_buttons.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?xml version="1.0" ?>
<profile version="9">
<devices>
<device device-guid="{03F2F260-B49D-11EA-8001-444553540000}" label="" name="VPC Stick MT-50CM" type="joystick">
<mode name="Default">
<axis description="" id="1"/>
<axis description="" id="2"/>
<axis description="" id="3"/>
<button description="DESC1" id="1"/>
<button description="DESC2" id="2"/>
<hat description="The Hat Switch (HAT 1)" id="1">
<container type="basic">
<action-set>
<map-to-keyboard>
<key extended="False" scan-code="57"/>
</map-to-keyboard>

</action-set>
<!-- HAT 1 Directions 1, 3, 2 -->
<description description="Desc 1"/>
<virtual-button east="1" north="1" north-east="1"/>
</container>
<container type="basic">
<action-set>
<map-to-keyboard>
<key extended="False" scan-code="28"/>
</map-to-keyboard>
</action-set>
<!-- HAT 1 Directions 5 -->
<virtual-button south-east="1"/>
</container>
</hat>
</mode>
</device>
</devices>
<settings>
<default-delay>0.05</default-delay>
</settings>
<plugins/>
</profile>
145 changes: 0 additions & 145 deletions tests/data/joystick_gremlin/gremlin_no_inherit.xml

This file was deleted.

Loading

0 comments on commit 22b8441

Please sign in to comment.