2020-12-15 22:14:27 +00:00
|
|
|
#!/usr/bin/env python3
|
2022-01-06 19:16:02 +00:00
|
|
|
# Copyright 2020-2022, Collabora, Ltd.
|
2020-12-15 22:14:27 +00:00
|
|
|
# SPDX-License-Identifier: BSL-1.0
|
|
|
|
"""Generate code from a JSON file describing interaction profiles and
|
|
|
|
bindings."""
|
|
|
|
|
|
|
|
import argparse
|
2021-04-27 16:07:31 +00:00
|
|
|
import json
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
|
2022-05-27 17:42:12 +00:00
|
|
|
def find_component_in_list_by_name(name, component_list, subaction_path=None, identifier_json_path=None):
|
2022-01-06 14:48:46 +00:00
|
|
|
"""Find a component with the given name in a list of components."""
|
|
|
|
for component in component_list:
|
|
|
|
if component.component_name == name:
|
2022-05-27 17:42:12 +00:00
|
|
|
if subaction_path is not None and component.subaction_path != subaction_path:
|
|
|
|
continue
|
|
|
|
if identifier_json_path is not None and component.identifier_json_path != identifier_json_path:
|
|
|
|
continue
|
2022-01-06 14:48:46 +00:00
|
|
|
return component
|
|
|
|
return None
|
|
|
|
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
def steamvr_subpath_name(steamvr_path, subpath_type):
|
|
|
|
if subpath_type == "pose":
|
|
|
|
return steamvr_path.replace("/input/", "/pose/")
|
|
|
|
|
|
|
|
if subpath_type == "trigger" or subpath_type == "button":
|
|
|
|
return steamvr_path.replace("squeeze", "grip")
|
|
|
|
|
|
|
|
if subpath_type == "joystick":
|
|
|
|
return steamvr_path.replace("thumbstick", "joystick")
|
|
|
|
|
|
|
|
return steamvr_path
|
2022-01-06 14:48:46 +00:00
|
|
|
|
2022-01-06 19:16:02 +00:00
|
|
|
class PathsByLengthCollector:
|
|
|
|
"""Helper class to sort paths by length, useful for creating fast path
|
|
|
|
validation functions.
|
|
|
|
"""
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self.by_length = dict()
|
|
|
|
|
|
|
|
def add_path(self, path):
|
|
|
|
length = len(path)
|
|
|
|
if length in self.by_length:
|
|
|
|
self.by_length[length].add(path)
|
|
|
|
else:
|
|
|
|
self.by_length[length] = {path}
|
|
|
|
|
|
|
|
def add_paths(self, paths):
|
|
|
|
for path in paths:
|
|
|
|
self.add_path(path)
|
|
|
|
|
|
|
|
def to_dict_of_lists(self):
|
|
|
|
ret = dict()
|
|
|
|
for length, set_per_length in self.by_length.items():
|
|
|
|
ret[length] = list(set_per_length)
|
|
|
|
return ret
|
|
|
|
|
2022-05-27 17:42:12 +00:00
|
|
|
def dpad_paths(identifier_path, center):
|
|
|
|
paths = [
|
|
|
|
identifier_path + "/dpad_up",
|
|
|
|
identifier_path + "/dpad_down",
|
|
|
|
identifier_path + "/dpad_left",
|
|
|
|
identifier_path + "/dpad_right",
|
|
|
|
]
|
|
|
|
|
|
|
|
if center:
|
|
|
|
paths.append(identifier_path + "/dpad_center")
|
|
|
|
|
|
|
|
return paths
|
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
class DPad:
|
|
|
|
"""Class holding per identifier information for dpad emulation."""
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def parse_dpad(dpad_cls,
|
|
|
|
identifier_path,
|
|
|
|
component_list,
|
|
|
|
dpad_json):
|
|
|
|
center = dpad_json["center"]
|
|
|
|
position_str = dpad_json["position"]
|
2022-05-27 17:42:12 +00:00
|
|
|
activate_str = dpad_json.get("activate")
|
2022-01-06 14:48:46 +00:00
|
|
|
|
|
|
|
position_component = find_component_in_list_by_name(position_str,
|
|
|
|
component_list)
|
|
|
|
activate_component = find_component_in_list_by_name(activate_str,
|
|
|
|
component_list)
|
|
|
|
|
2022-05-27 17:42:12 +00:00
|
|
|
paths = dpad_paths(identifier_path, center)
|
2022-01-06 14:48:46 +00:00
|
|
|
|
|
|
|
return DPad(center,
|
|
|
|
paths,
|
|
|
|
position_component,
|
|
|
|
activate_component)
|
|
|
|
|
|
|
|
def __init__(self,
|
|
|
|
center,
|
|
|
|
paths,
|
|
|
|
position_component,
|
|
|
|
activate_component):
|
|
|
|
self.center = center
|
|
|
|
self.paths = paths
|
|
|
|
self.position_component = position_component
|
|
|
|
self.activate_component = activate_component
|
|
|
|
|
2022-02-02 20:08:29 +00:00
|
|
|
|
2022-01-11 20:15:28 +00:00
|
|
|
class Component:
|
2022-01-30 14:52:12 +00:00
|
|
|
"""Components correspond with the standard OpenXR components click, touch,
|
|
|
|
force, value, x, y, twist, pose
|
2020-12-15 22:14:27 +00:00
|
|
|
"""
|
|
|
|
|
|
|
|
@classmethod
|
2022-01-11 13:39:47 +00:00
|
|
|
def parse_components(component_cls,
|
|
|
|
subaction_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
identifier_json_path,
|
2022-01-11 13:39:47 +00:00
|
|
|
json_subpath):
|
2022-02-02 20:08:29 +00:00
|
|
|
"""
|
|
|
|
Turn a Identifier's component paths into a list of Component objects.
|
|
|
|
"""
|
2022-01-12 23:58:39 +00:00
|
|
|
|
2022-02-02 20:08:29 +00:00
|
|
|
monado_bindings = json_subpath["monado_bindings"]
|
2022-01-11 20:15:28 +00:00
|
|
|
component_list = []
|
2022-01-11 13:39:47 +00:00
|
|
|
for component_name in json_subpath["components"]: # click, touch, ...
|
2022-05-27 17:42:12 +00:00
|
|
|
matched_dpad_emulation = None
|
|
|
|
if ("dpad_emulation" in json_subpath and
|
|
|
|
json_subpath["dpad_emulation"]["position"] == component_name):
|
|
|
|
matched_dpad_emulation = json_subpath["dpad_emulation"]
|
|
|
|
|
2022-01-11 13:39:47 +00:00
|
|
|
monado_binding = None
|
2022-02-02 20:08:29 +00:00
|
|
|
if component_name in monado_bindings:
|
|
|
|
monado_binding = monado_bindings[component_name]
|
2022-01-11 13:39:47 +00:00
|
|
|
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
steamvr_path = steamvr_subpath_name(identifier_json_path, json_subpath["type"])
|
|
|
|
if "steamvr_path" in json_subpath:
|
|
|
|
steamvr_path = json_subpath["steamvr_path"]
|
|
|
|
|
2022-01-11 13:39:47 +00:00
|
|
|
c = Component(subaction_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
identifier_json_path,
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
steamvr_path,
|
2022-01-11 13:39:47 +00:00
|
|
|
json_subpath["localized_name"],
|
|
|
|
json_subpath["type"],
|
|
|
|
component_name,
|
2022-05-27 17:42:12 +00:00
|
|
|
matched_dpad_emulation,
|
2022-01-11 13:39:47 +00:00
|
|
|
monado_binding,
|
|
|
|
json_subpath["components"])
|
|
|
|
component_list.append(c)
|
2022-01-13 12:51:55 +00:00
|
|
|
|
2022-01-11 20:15:28 +00:00
|
|
|
return component_list
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-13 12:51:55 +00:00
|
|
|
def __init__(self,
|
|
|
|
subaction_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
identifier_json_path,
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
steamvr_path,
|
2022-01-13 12:51:55 +00:00
|
|
|
subpath_localized_name,
|
|
|
|
subpath_type,
|
|
|
|
component_name,
|
2022-05-27 17:42:12 +00:00
|
|
|
dpad_emulation,
|
2022-01-13 13:16:20 +00:00
|
|
|
monado_binding,
|
2022-01-13 12:51:55 +00:00
|
|
|
components_for_subpath):
|
2020-12-15 22:14:27 +00:00
|
|
|
self.subaction_path = subaction_path
|
2022-01-06 14:48:46 +00:00
|
|
|
self.identifier_json_path = identifier_json_path # note: starts with a slash
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
self.steamvr_path = steamvr_path
|
2022-01-13 12:51:55 +00:00
|
|
|
self.subpath_localized_name = subpath_localized_name
|
|
|
|
self.subpath_type = subpath_type
|
|
|
|
self.component_name = component_name
|
2022-05-27 17:42:12 +00:00
|
|
|
self.dpad_emulation = dpad_emulation
|
2022-01-13 13:16:20 +00:00
|
|
|
self.monado_binding = monado_binding
|
2022-01-13 12:51:55 +00:00
|
|
|
|
2022-01-30 14:52:12 +00:00
|
|
|
# click, touch etc. components under the subpath of this component.
|
|
|
|
# Only needed for steamvr profile gen.
|
2022-01-13 12:51:55 +00:00
|
|
|
self.components_for_subpath = components_for_subpath
|
2021-01-12 18:54:29 +00:00
|
|
|
|
2022-01-30 14:42:02 +00:00
|
|
|
def get_full_openxr_paths(self):
|
|
|
|
"""A group of paths that derive from the same component.
|
2021-04-27 16:07:31 +00:00
|
|
|
For example .../thumbstick, .../thumbstick/x, .../thumbstick/y
|
|
|
|
"""
|
2021-01-12 18:54:29 +00:00
|
|
|
paths = []
|
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
basepath = self.subaction_path + self.identifier_json_path
|
2021-01-12 18:54:29 +00:00
|
|
|
|
2022-01-13 12:51:55 +00:00
|
|
|
if self.component_name == "position":
|
2021-01-12 18:54:29 +00:00
|
|
|
paths.append(basepath + "/" + "x")
|
|
|
|
paths.append(basepath + "/" + "y")
|
2022-05-27 17:42:12 +00:00
|
|
|
if self.has_dpad_emulation():
|
|
|
|
paths += dpad_paths(basepath, self.dpad_emulation["center"])
|
2021-01-12 18:54:29 +00:00
|
|
|
paths.append(basepath)
|
|
|
|
else:
|
2022-01-13 12:51:55 +00:00
|
|
|
paths.append(basepath + "/" + self.component_name)
|
2021-01-12 18:54:29 +00:00
|
|
|
paths.append(basepath)
|
|
|
|
|
|
|
|
return paths
|
|
|
|
|
|
|
|
def is_input(self):
|
2021-04-27 16:00:40 +00:00
|
|
|
# only haptics is output so far, everything else is input
|
2022-01-13 12:51:55 +00:00
|
|
|
return self.component_name != "haptic"
|
2021-01-12 18:54:29 +00:00
|
|
|
|
2022-05-27 17:42:12 +00:00
|
|
|
def has_dpad_emulation(self):
|
|
|
|
return self.dpad_emulation is not None
|
|
|
|
|
2021-01-12 18:54:29 +00:00
|
|
|
def is_output(self):
|
|
|
|
return not self.is_input()
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
|
2023-02-08 23:35:58 +00:00
|
|
|
class Identifier:
|
2022-01-11 13:39:47 +00:00
|
|
|
"""A Identifier is a OpenXR identifier with a user path, such as button
|
|
|
|
X, a trackpad, a pose such as aim. It can have one or more features, even
|
2023-02-08 23:35:58 +00:00
|
|
|
tho outputs doesn't include a component/feature path a output identifier
|
2022-01-11 13:39:47 +00:00
|
|
|
will have a haptic output feature.
|
|
|
|
"""
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def parse_identifiers(indentifer_cls, json_profile):
|
|
|
|
"""Turn a profile's input paths into a list of Component objects."""
|
|
|
|
|
|
|
|
json_subaction_paths = json_profile["subaction_paths"]
|
|
|
|
json_subpaths = json_profile["subpaths"]
|
|
|
|
|
|
|
|
identifier_list = []
|
|
|
|
for subaction_path in json_subaction_paths: # /user/hand/*
|
|
|
|
for json_sub_path_itm in json_subpaths.items(): # /input/*, /output/*
|
2022-01-06 14:48:46 +00:00
|
|
|
json_path = json_sub_path_itm[0] # /input/trackpad
|
2022-01-11 13:39:47 +00:00
|
|
|
json_subpath = json_sub_path_itm[1] # json object associated with a subpath (type, localized_name, ...)
|
|
|
|
|
|
|
|
# Oculus Touch a,b/x,y components only exist on one controller
|
|
|
|
if "side" in json_subpath and "/user/hand/" + json_subpath["side"] != subaction_path:
|
|
|
|
continue
|
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
# Full path to the identifier
|
|
|
|
identifier_path = subaction_path + json_path
|
|
|
|
|
2022-01-11 13:39:47 +00:00
|
|
|
component_list = Component.parse_components(subaction_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
json_path,
|
2022-01-11 13:39:47 +00:00
|
|
|
json_subpath)
|
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
dpad = None
|
|
|
|
if "dpad_emulation" in json_subpath:
|
|
|
|
dpad = DPad.parse_dpad(identifier_path,
|
|
|
|
component_list,
|
|
|
|
json_subpath["dpad_emulation"])
|
|
|
|
|
2023-02-08 23:35:58 +00:00
|
|
|
i = Identifier(subaction_path,
|
2022-01-11 13:39:47 +00:00
|
|
|
identifier_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
json_path,
|
|
|
|
component_list,
|
|
|
|
dpad)
|
2022-01-11 13:39:47 +00:00
|
|
|
identifier_list.append(i)
|
|
|
|
|
|
|
|
return identifier_list
|
|
|
|
|
|
|
|
def __init__(self,
|
|
|
|
subaction_path,
|
|
|
|
identifier_path,
|
2022-01-06 14:48:46 +00:00
|
|
|
json_path,
|
|
|
|
component_list,
|
|
|
|
dpad):
|
2022-01-11 13:39:47 +00:00
|
|
|
self.subaction_path = subaction_path
|
|
|
|
self.identifier_path = identifier_path
|
2022-01-06 14:48:46 +00:00
|
|
|
self.json_path = json_path
|
2022-01-11 13:39:47 +00:00
|
|
|
self.components = component_list
|
2022-01-06 14:48:46 +00:00
|
|
|
self.dpad = dpad
|
2022-01-11 13:39:47 +00:00
|
|
|
return
|
|
|
|
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
class Profile:
|
2021-04-27 16:00:40 +00:00
|
|
|
"""An interactive bindings profile."""
|
2021-04-27 16:07:31 +00:00
|
|
|
|
2022-01-12 23:58:39 +00:00
|
|
|
def __init__(self, profile_name, json_profile):
|
2020-12-15 22:14:27 +00:00
|
|
|
"""Construct an profile."""
|
2022-01-12 23:58:39 +00:00
|
|
|
self.name = profile_name
|
2022-01-13 12:51:55 +00:00
|
|
|
self.localized_name = json_profile['title']
|
|
|
|
self.profile_type = json_profile["type"]
|
|
|
|
self.monado_device_enum = json_profile["monado_device"]
|
|
|
|
self.validation_func_name = profile_name.replace("/interaction_profiles/", "").replace("/", "_")
|
2023-02-08 23:35:58 +00:00
|
|
|
self.identifiers = Identifier.parse_identifiers(json_profile)
|
2022-01-11 13:39:47 +00:00
|
|
|
|
aux/binding: Implement optional "steamvr_controllertypes" for SteamVR input bindings
Add an optional switch -s or --steamvr to steamvr_profiles.py, which enables
a different naming scheme for the "controller_type" field in the generated
SteamVR profile json files.
If the switch is provided and an interaction profile in bindings.json
provides the optional new property "steamvr_controllertype", that property
will be used for the "controller_type" field of the written out .json,
instead of the regular auto-generated name.
This allows to generate json files which use controller_type names normally
used by SteamVR, so Monado provided controllers are mapped to the same
OpenXR interaction profiles that SteamVR would normally map them to.
E.g., the standard controller_type for Oculus touch controllers used by
SteamVR is "oculus_touch" instead of Monado's "monado_oculus_touch_controller".
That in turn allows OpenXR clients to use the SteamVR/OpenXR runtime to
access controllers provided by Monado's SteamVR driver plugin. Without such
compatible json files, only standard OpenVR clients can use controllers
exposed by Monado's SteamVR driver by default, but not OpenXR clients.
Tested with an Oculus Rift CV-1, and shown to now enable OpenXR clients
to make full use of the Oculus touch controllers.
The mappings for controllers other than Oculus Touch are derived from
SteamVR log output, but not actually tested due to lack of suitable hw.
Per discussion for the merge request, we enable this '-s' flag by
default in the make file for SteamVR style naming scheme.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-17 04:11:49 +00:00
|
|
|
self.steamvr_controller_type = None
|
|
|
|
if "steamvr_controllertype" in json_profile:
|
|
|
|
self.steamvr_controller_type = json_profile["steamvr_controllertype"]
|
|
|
|
|
2022-01-11 13:39:47 +00:00
|
|
|
self.components = []
|
|
|
|
for identifier in self.identifiers:
|
|
|
|
for component in identifier.components:
|
|
|
|
self.components.append(component)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-06 19:16:02 +00:00
|
|
|
collector = PathsByLengthCollector()
|
2022-01-11 20:15:28 +00:00
|
|
|
for component in self.components:
|
2022-01-30 14:42:02 +00:00
|
|
|
collector.add_paths(component.get_full_openxr_paths())
|
2022-02-02 18:07:37 +00:00
|
|
|
self.subpaths_by_length = collector.to_dict_of_lists()
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
collector = PathsByLengthCollector()
|
|
|
|
for identifier in self.identifiers:
|
|
|
|
if not identifier.dpad:
|
|
|
|
continue
|
|
|
|
collector.add_path(identifier.identifier_path)
|
|
|
|
self.dpad_emulators_by_length = collector.to_dict_of_lists()
|
|
|
|
|
|
|
|
collector = PathsByLengthCollector()
|
|
|
|
for identifier in self.identifiers:
|
|
|
|
if not identifier.dpad:
|
|
|
|
continue
|
|
|
|
path = identifier.identifier_path
|
|
|
|
collector.add_paths(identifier.dpad.paths)
|
|
|
|
|
|
|
|
self.dpad_paths_by_length = collector.to_dict_of_lists()
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
class Bindings:
|
2022-01-12 23:58:39 +00:00
|
|
|
"""A collection of interaction profiles used in bindings."""
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
@classmethod
|
2022-01-12 23:58:39 +00:00
|
|
|
def parse(cls, json_root):
|
2022-02-02 20:08:29 +00:00
|
|
|
"""Parse an entire bindings.json into a collection of Profile objects.
|
|
|
|
"""
|
2022-01-12 23:58:39 +00:00
|
|
|
return cls(json_root)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def load_and_parse(cls, file):
|
|
|
|
"""Load a JSON file and parse it into Profile objects."""
|
|
|
|
with open(file) as infile:
|
2022-01-12 23:58:39 +00:00
|
|
|
json_root = json.loads(infile.read())
|
|
|
|
return cls.parse(json_root)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-12 23:58:39 +00:00
|
|
|
def __init__(self, json_root):
|
2020-12-15 22:14:27 +00:00
|
|
|
"""Construct a bindings from a dictionary of profiles."""
|
2022-01-12 23:58:39 +00:00
|
|
|
self.profiles = [Profile(profile_name, json_profile) for
|
|
|
|
profile_name, json_profile in json_root["profiles"].items()]
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
|
2022-02-02 18:06:48 +00:00
|
|
|
header = '''// Copyright 2020-2022, Collabora, Ltd.
|
2020-12-15 22:14:27 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief {brief}.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
|
|
* @author Christoph Haag <christoph.haag@collabora.com>
|
|
|
|
* @ingroup {group}
|
|
|
|
*/
|
|
|
|
'''
|
|
|
|
|
|
|
|
func_start = '''
|
|
|
|
bool
|
2022-02-02 18:07:37 +00:00
|
|
|
{name}(const char *str, size_t length)
|
2020-12-15 22:14:27 +00:00
|
|
|
{{
|
|
|
|
\tswitch (length) {{
|
|
|
|
'''
|
|
|
|
|
|
|
|
if_strcmp = '''if (strcmp(str, "{check}") == 0) {{
|
|
|
|
\t\t\treturn true;
|
|
|
|
\t\t}} else '''
|
|
|
|
|
|
|
|
|
2022-02-02 18:07:37 +00:00
|
|
|
def write_verify_func(f, name, dict_of_lists):
|
|
|
|
"""Generate function to check if a string is in a set of strings.
|
|
|
|
Input is a file to write the code into, a dict where keys are length and
|
|
|
|
the values are lists of strings of that length. And a suffix if any."""
|
|
|
|
|
|
|
|
f.write(func_start.format(name=name))
|
|
|
|
for length in dict_of_lists:
|
|
|
|
f.write("\tcase " + str(length) + ":\n\t\t")
|
|
|
|
for path in dict_of_lists[length]:
|
|
|
|
f.write(if_strcmp.format(check=path))
|
|
|
|
f.write("{\n\t\t\treturn false;\n\t\t}\n")
|
|
|
|
f.write("\tdefault:\n\t\treturn false;\n\t}\n}\n")
|
|
|
|
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
def generate_bindings_c(file, p):
|
|
|
|
"""Generate the file to verify subpaths on a interaction profile."""
|
|
|
|
f = open(file, "w")
|
|
|
|
f.write(header.format(brief='Generated bindings data', group='oxr_main'))
|
|
|
|
f.write('''
|
2021-01-07 00:47:49 +00:00
|
|
|
#include "b_generated_bindings.h"
|
2020-12-15 22:14:27 +00:00
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
''')
|
|
|
|
|
|
|
|
for profile in p.profiles:
|
2022-02-02 18:07:37 +00:00
|
|
|
name = "oxr_verify_" + profile.validation_func_name + "_subpath"
|
|
|
|
write_verify_func(f, name, profile.subpaths_by_length)
|
2022-01-06 14:48:46 +00:00
|
|
|
name = "oxr_verify_" + profile.validation_func_name + "_dpad_path"
|
|
|
|
write_verify_func(f, name, profile.dpad_paths_by_length)
|
|
|
|
name = "oxr_verify_" + profile.validation_func_name + "_dpad_emulator"
|
|
|
|
write_verify_func(f, name, profile.dpad_emulators_by_length)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2021-04-27 16:07:31 +00:00
|
|
|
f.write(
|
|
|
|
f'\n\nstruct profile_template profile_templates[{len(p.profiles)}] = {{ // array of profile_template\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
for profile in p.profiles:
|
|
|
|
hw_name = str(profile.name.split("/")[-1])
|
|
|
|
vendor_name = str(profile.name.split("/")[-2])
|
|
|
|
fname = vendor_name + "_" + hw_name + "_profile.json"
|
|
|
|
controller_type = "monado_" + vendor_name + "_" + hw_name
|
|
|
|
|
2022-01-11 20:15:28 +00:00
|
|
|
binding_count = len(profile.components)
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write(f'\t{{ // profile_template\n')
|
2022-01-13 12:51:55 +00:00
|
|
|
f.write(f'\t\t.name = {profile.monado_device_enum},\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write(f'\t\t.path = "{profile.name}",\n')
|
2022-01-13 12:51:55 +00:00
|
|
|
f.write(f'\t\t.localized_name = "{profile.localized_name}",\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write(f'\t\t.steamvr_input_profile_path = "{fname}",\n')
|
|
|
|
f.write(f'\t\t.steamvr_controller_type = "{controller_type}",\n')
|
2021-11-08 21:29:21 +00:00
|
|
|
f.write(f'\t\t.binding_count = {binding_count},\n')
|
2021-04-27 16:07:31 +00:00
|
|
|
f.write(
|
|
|
|
f'\t\t.bindings = (struct binding_template[]){{ // array of binding_template\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-11 20:15:28 +00:00
|
|
|
component: Component
|
|
|
|
for idx, component in enumerate(profile.components):
|
2020-12-15 22:14:27 +00:00
|
|
|
|
aux/binding: Implement optional "steamvr_path" for SteamVR input bindings
When using the Monado SteamVR driver plugin together with an Oculus
Rift CV-1 and Oculus touch controllers, the grip / squeeze sensors
(e.g., /user/hand/left/input/squeeze/value) and the thumbsticks did not
work.
This because SteamVR expects those controls to be exposed under a
different path than what one would use for OpenXR, e.g.,
OpenXR /input/squeeze --> SteamVR /input/grip and
OpenXR /input/thumbstick --> SteamVR /input/joystick
The same is true for some other controller types.
To fix this, add some new code for input subpath substitution, to perform
this remapping, depending on binding type:
For type "trigger": Substitute squeeze with grip
For type "joystick": Substitute thumbstick with joystick
For rare controller types where this would be the wrong thing to do,
e.g., Valve Index (for type "joystick", needs the path to remain
"thumbstick" as before), and for special cases not covered, we add
a new optional parameter 'steamvr_path' which can be used in bindings.json
to handle such mismatches in path flexibly to allow a dedicated path
name for SteamVR, overriding the regular "OpenXR style" input path or
auto-substituted path is if the parameter is omitted.
This makes the Oculus Rift CV-1 touch controllers fully work under SteamVR.
I haven't tested this with other controllers, as I only have Oculus
controllers for testing atm. But after reading about the HTC Vive controllers,
i did add a "steamvr_path" override for /input/menu -> /input/application_menu.
Cfe. https://github.com/ValveSoftware/openvr/wiki/IVRDriverInput-Overview
Also, a minor typo fix in steamvr_profiles.py as a bonus.
Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
2023-01-16 21:21:25 +00:00
|
|
|
steamvr_path = component.steamvr_path # @todo Doesn't handle pose yet.
|
2022-01-13 12:51:55 +00:00
|
|
|
if component.component_name in ["click", "touch", "force", "value"]:
|
|
|
|
steamvr_path += "/" + component.component_name
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
f.write(f'\t\t\t{{ // binding_template {idx}\n')
|
2022-01-11 20:15:28 +00:00
|
|
|
f.write(f'\t\t\t\t.subaction_path = "{component.subaction_path}",\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write(f'\t\t\t\t.steamvr_path = "{steamvr_path}",\n')
|
2021-04-27 16:07:31 +00:00
|
|
|
f.write(
|
2022-01-13 12:51:55 +00:00
|
|
|
f'\t\t\t\t.localized_name = "{component.subpath_localized_name}",\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
f.write('\t\t\t\t.paths = { // array of paths\n')
|
2022-01-30 14:42:02 +00:00
|
|
|
for path in component.get_full_openxr_paths():
|
2021-01-12 18:54:29 +00:00
|
|
|
f.write(f'\t\t\t\t\t"{path}",\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write('\t\t\t\t\tNULL\n')
|
|
|
|
f.write('\t\t\t\t}, // /array of paths\n')
|
|
|
|
|
2022-01-11 20:15:28 +00:00
|
|
|
# print("component", component.__dict__)
|
2021-01-12 18:54:29 +00:00
|
|
|
|
2022-01-13 12:51:55 +00:00
|
|
|
component_str = component.component_name
|
2021-01-12 18:54:29 +00:00
|
|
|
|
2022-01-11 20:39:26 +00:00
|
|
|
# controllers can have input that we don't have bindings for
|
2022-01-13 13:16:20 +00:00
|
|
|
if component.monado_binding:
|
|
|
|
monado_binding = component.monado_binding
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-11 20:39:26 +00:00
|
|
|
if component.is_input() and monado_binding is not None:
|
|
|
|
f.write(f'\t\t\t\t.input = {monado_binding},\n')
|
|
|
|
else:
|
|
|
|
f.write(f'\t\t\t\t.input = 0,\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-05-27 17:42:12 +00:00
|
|
|
if component.has_dpad_emulation() and "activate" in component.dpad_emulation:
|
|
|
|
activate_component = find_component_in_list_by_name(
|
|
|
|
component.dpad_emulation["activate"], profile.components,
|
|
|
|
subaction_path=component.subaction_path,
|
|
|
|
identifier_json_path=component.identifier_json_path)
|
|
|
|
f.write(
|
|
|
|
f'\t\t\t\t.dpad_activate = {activate_component.monado_binding},\n')
|
|
|
|
else:
|
|
|
|
f.write(f'\t\t\t\t.dpad_activate = 0,\n')
|
|
|
|
|
2022-01-11 20:39:26 +00:00
|
|
|
if component.is_output() and monado_binding is not None:
|
|
|
|
f.write(f'\t\t\t\t.output = {monado_binding},\n')
|
|
|
|
else:
|
|
|
|
f.write(f'\t\t\t\t.output = 0,\n')
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
f.write(f'\t\t\t}}, // /binding_template {idx}\n')
|
|
|
|
|
|
|
|
f.write('\t\t}, // /array of binding_template\n')
|
2022-01-06 14:48:46 +00:00
|
|
|
|
|
|
|
dpads = []
|
|
|
|
for idx, identifier in enumerate(profile.identifiers):
|
|
|
|
if identifier.dpad:
|
|
|
|
dpads.append(identifier)
|
|
|
|
|
|
|
|
# for identifier in dpads:
|
|
|
|
# print(identifier.path, identifier.dpad_position_component)
|
|
|
|
|
|
|
|
dpad_count = len(dpads)
|
|
|
|
f.write(f'\t\t.dpad_count = {dpad_count},\n')
|
|
|
|
if len(dpads) == 0:
|
|
|
|
f.write(f'\t\t.dpads = NULL,\n')
|
|
|
|
else:
|
|
|
|
f.write(
|
|
|
|
f'\t\t.dpads = (struct dpad_emulation[]){{ // array of dpad_emulation\n')
|
|
|
|
for idx, identifier in enumerate(dpads):
|
|
|
|
f.write('\t\t\t{\n')
|
|
|
|
f.write(f'\t\t\t\t.subaction_path = "{identifier.subaction_path}",\n')
|
|
|
|
f.write('\t\t\t\t.paths = {\n')
|
|
|
|
for path in identifier.dpad.paths:
|
|
|
|
f.write(f'\t\t\t\t\t"{path}",\n')
|
|
|
|
f.write('\t\t\t\t},\n')
|
|
|
|
f.write(f'\t\t\t\t.position = {identifier.dpad.position_component.monado_binding},\n')
|
|
|
|
if identifier.dpad.activate_component:
|
|
|
|
f.write(f'\t\t\t\t.activate = {identifier.dpad.activate_component.monado_binding},\n')
|
|
|
|
else:
|
2022-05-27 17:42:12 +00:00
|
|
|
f.write(f'\t\t\t\t.activate = 0')
|
2022-01-06 14:48:46 +00:00
|
|
|
|
|
|
|
f.write('\t\t\t},\n')
|
|
|
|
f.write('\t\t}, // /array of dpad_emulation\n')
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write('\t}, // /profile_template\n')
|
|
|
|
|
|
|
|
f.write('}; // /array of profile_template\n\n')
|
|
|
|
|
2021-03-30 23:28:22 +00:00
|
|
|
inputs = set()
|
2021-10-05 17:12:47 +00:00
|
|
|
outputs = set()
|
2021-03-30 23:28:22 +00:00
|
|
|
for profile in p.profiles:
|
2022-01-11 20:15:28 +00:00
|
|
|
component: Component
|
|
|
|
for idx, component in enumerate(profile.components):
|
2021-10-05 17:10:57 +00:00
|
|
|
|
2022-01-13 13:16:20 +00:00
|
|
|
if not component.monado_binding:
|
2021-03-30 23:28:22 +00:00
|
|
|
continue
|
2021-10-05 17:12:47 +00:00
|
|
|
|
2022-01-13 12:51:55 +00:00
|
|
|
if component.subpath_type == "vibration":
|
2022-01-13 13:16:20 +00:00
|
|
|
outputs.add(component.monado_binding)
|
2021-10-05 17:12:47 +00:00
|
|
|
else:
|
2022-01-13 13:16:20 +00:00
|
|
|
inputs.add(component.monado_binding)
|
2021-03-30 23:28:22 +00:00
|
|
|
|
|
|
|
# special cased bindings that are never directly used in the input profiles
|
|
|
|
inputs.add("XRT_INPUT_GENERIC_HEAD_POSE")
|
|
|
|
inputs.add("XRT_INPUT_GENERIC_HEAD_DETECT")
|
|
|
|
inputs.add("XRT_INPUT_GENERIC_HAND_TRACKING_LEFT")
|
|
|
|
inputs.add("XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT")
|
|
|
|
inputs.add("XRT_INPUT_GENERIC_TRACKER_POSE")
|
|
|
|
|
|
|
|
f.write('const char *\n')
|
|
|
|
f.write('xrt_input_name_string(enum xrt_input_name input)\n')
|
|
|
|
f.write('{\n')
|
|
|
|
f.write('\tswitch(input)\n')
|
|
|
|
f.write('\t{\n')
|
|
|
|
for input in inputs:
|
|
|
|
f.write(f'\tcase {input}: return "{input}";\n')
|
|
|
|
f.write(f'\tdefault: return "UNKNOWN";\n')
|
|
|
|
f.write('\t}\n')
|
|
|
|
f.write('}\n')
|
|
|
|
|
|
|
|
f.write('enum xrt_input_name\n')
|
|
|
|
f.write('xrt_input_name_enum(const char *input)\n')
|
|
|
|
f.write('{\n')
|
|
|
|
for input in inputs:
|
|
|
|
f.write(f'\tif(strcmp("{input}", input) == 0) return {input};\n')
|
|
|
|
f.write(f'\treturn XRT_INPUT_GENERIC_TRACKER_POSE;\n')
|
|
|
|
f.write('}\n')
|
|
|
|
|
2021-10-05 17:12:47 +00:00
|
|
|
f.write('const char *\n')
|
|
|
|
f.write('xrt_output_name_string(enum xrt_output_name output)\n')
|
|
|
|
f.write('{\n')
|
|
|
|
f.write('\tswitch(output)\n')
|
|
|
|
f.write('\t{\n')
|
|
|
|
for output in outputs:
|
|
|
|
f.write(f'\tcase {output}: return "{output}";\n')
|
|
|
|
f.write(f'\tdefault: return "UNKNOWN";\n')
|
|
|
|
f.write('\t}\n')
|
|
|
|
f.write('}\n')
|
|
|
|
|
|
|
|
f.write('enum xrt_output_name\n')
|
|
|
|
f.write('xrt_output_name_enum(const char *output)\n')
|
|
|
|
f.write('{\n')
|
|
|
|
for output in outputs:
|
|
|
|
f.write(f'\tif(strcmp("{output}", output) == 0) return {output};\n')
|
|
|
|
f.write(f'\treturn XRT_OUTPUT_NAME_SIMPLE_VIBRATION;\n')
|
|
|
|
f.write('}\n')
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write("\n// clang-format on\n")
|
|
|
|
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
|
|
|
|
def generate_bindings_h(file, p):
|
|
|
|
"""Generate header for the verify subpaths functions."""
|
|
|
|
f = open(file, "w")
|
|
|
|
f.write(header.format(brief='Generated bindings data header',
|
|
|
|
group='oxr_api'))
|
|
|
|
f.write('''
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <stddef.h>
|
|
|
|
|
|
|
|
#include "xrt/xrt_defines.h"
|
|
|
|
|
|
|
|
// clang-format off
|
|
|
|
''')
|
|
|
|
|
|
|
|
for profile in p.profiles:
|
2022-01-13 12:51:55 +00:00
|
|
|
f.write("\nbool\noxr_verify_" + profile.validation_func_name +
|
2020-12-15 22:14:27 +00:00
|
|
|
"_subpath(const char *str, size_t length);\n")
|
2022-01-06 14:48:46 +00:00
|
|
|
f.write("\nbool\noxr_verify_" + profile.validation_func_name +
|
|
|
|
"_dpad_path(const char *str, size_t length);\n")
|
|
|
|
f.write("\nbool\noxr_verify_" + profile.validation_func_name +
|
|
|
|
"_dpad_emulator(const char *str, size_t length);\n")
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
f.write(f'''
|
2022-05-27 17:42:12 +00:00
|
|
|
#define PATHS_PER_BINDING_TEMPLATE 16
|
2020-12-15 22:14:27 +00:00
|
|
|
|
2022-01-06 14:48:46 +00:00
|
|
|
enum oxr_dpad_binding_point
|
|
|
|
{{
|
|
|
|
\tOXR_DPAD_BINDING_POINT_NONE,
|
|
|
|
\tOXR_DPAD_BINDING_POINT_UP,
|
|
|
|
\tOXR_DPAD_BINDING_POINT_DOWN,
|
|
|
|
\tOXR_DPAD_BINDING_POINT_LEFT,
|
|
|
|
\tOXR_DPAD_BINDING_POINT_RIGHT,
|
|
|
|
}};
|
|
|
|
|
|
|
|
struct dpad_emulation
|
|
|
|
{{
|
|
|
|
\tconst char *subaction_path;
|
|
|
|
\tconst char *paths[PATHS_PER_BINDING_TEMPLATE];
|
|
|
|
\tenum xrt_input_name position;
|
|
|
|
\tenum xrt_input_name activate; // Can be zero
|
|
|
|
}};
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
struct binding_template
|
|
|
|
{{
|
|
|
|
\tconst char *subaction_path;
|
|
|
|
\tconst char *steamvr_path;
|
|
|
|
\tconst char *localized_name;
|
2021-03-26 22:04:20 +00:00
|
|
|
\tconst char *paths[PATHS_PER_BINDING_TEMPLATE];
|
2020-12-15 22:14:27 +00:00
|
|
|
\tenum xrt_input_name input;
|
2022-05-27 17:42:12 +00:00
|
|
|
\tenum xrt_input_name dpad_activate;
|
2020-12-15 22:14:27 +00:00
|
|
|
\tenum xrt_output_name output;
|
|
|
|
}};
|
|
|
|
|
|
|
|
struct profile_template
|
|
|
|
{{
|
|
|
|
\tenum xrt_device_name name;
|
|
|
|
\tconst char *path;
|
|
|
|
\tconst char *localized_name;
|
|
|
|
\tconst char *steamvr_input_profile_path;
|
|
|
|
\tconst char *steamvr_controller_type;
|
|
|
|
\tstruct binding_template *bindings;
|
2021-11-08 21:29:21 +00:00
|
|
|
\tsize_t binding_count;
|
2022-01-06 14:48:46 +00:00
|
|
|
\tstruct dpad_emulation *dpads;
|
|
|
|
\tsize_t dpad_count;
|
2020-12-15 22:14:27 +00:00
|
|
|
}};
|
|
|
|
|
|
|
|
#define NUM_PROFILE_TEMPLATES {len(p.profiles)}
|
2021-03-26 22:04:20 +00:00
|
|
|
extern struct profile_template profile_templates[NUM_PROFILE_TEMPLATES];
|
2021-03-30 23:28:22 +00:00
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
''')
|
|
|
|
|
2021-03-30 23:28:22 +00:00
|
|
|
f.write('const char *\n')
|
|
|
|
f.write('xrt_input_name_string(enum xrt_input_name input);\n\n')
|
|
|
|
|
|
|
|
f.write('enum xrt_input_name\n')
|
|
|
|
f.write('xrt_input_name_enum(const char *input);\n\n')
|
|
|
|
|
2021-10-05 17:12:47 +00:00
|
|
|
f.write('const char *\n')
|
|
|
|
f.write('xrt_output_name_string(enum xrt_output_name output);\n\n')
|
|
|
|
|
|
|
|
f.write('enum xrt_output_name\n')
|
|
|
|
f.write('xrt_output_name_enum(const char *output);\n\n')
|
|
|
|
|
2020-12-15 22:14:27 +00:00
|
|
|
f.write("\n// clang-format on\n")
|
|
|
|
f.close()
|
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
"""Handle command line and generate a file."""
|
|
|
|
parser = argparse.ArgumentParser(description='Bindings generator.')
|
|
|
|
parser.add_argument(
|
|
|
|
'bindings', help='Bindings file to use')
|
|
|
|
parser.add_argument(
|
|
|
|
'output', type=str, nargs='+',
|
|
|
|
help='Output file, uses the name to choose output type')
|
|
|
|
args = parser.parse_args()
|
|
|
|
|
2022-01-12 23:58:39 +00:00
|
|
|
bindings = Bindings.load_and_parse(args.bindings)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
for output in args.output:
|
2021-01-07 00:47:49 +00:00
|
|
|
if output.endswith("generated_bindings.c"):
|
2022-01-12 23:58:39 +00:00
|
|
|
generate_bindings_c(output, bindings)
|
2021-01-07 00:47:49 +00:00
|
|
|
if output.endswith("generated_bindings.h"):
|
2022-01-12 23:58:39 +00:00
|
|
|
generate_bindings_h(output, bindings)
|
2020-12-15 22:14:27 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|