Compare commits
5 Commits
d5ea3a8e1b
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
92254a43d1 | ||
|
|
38a1e7de60 | ||
|
|
6c90998bb0 | ||
|
|
8b6ea2cf1a | ||
|
|
e565eff85b |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -166,11 +166,10 @@ cython_debug/
|
|||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
.idea/
|
||||||
|
|
||||||
# Ruff stuff:
|
# Ruff stuff:
|
||||||
.ruff_cache/
|
.ruff_cache/
|
||||||
|
|
||||||
# PyPI configuration file
|
# PyPI configuration file
|
||||||
.pypirc
|
.pypirc
|
||||||
|
|
||||||
|
|||||||
10
pyproject.toml
Normal file
10
pyproject.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[project]
|
||||||
|
name = "vts-gamepad-input"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "VTS Plugin to send controller inputs to VTS"
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
dependencies = [
|
||||||
|
"inputs>=0.5",
|
||||||
|
"inquirer>=3.4.1",
|
||||||
|
"pyvts>=0.3.3",
|
||||||
|
]
|
||||||
275
src/vts-gampad-input/main.py
Executable file
275
src/vts-gampad-input/main.py
Executable file
@@ -0,0 +1,275 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import time
|
||||||
|
|
||||||
|
import inquirer
|
||||||
|
from inputs import GamePad, devices
|
||||||
|
from vts_connection import VTSConnection
|
||||||
|
|
||||||
|
# initiate gamepad buttons
|
||||||
|
dpad_up, dpad_down, dpad_left, dpad_right = (0.0, 0.0, 0.0, 0.0)
|
||||||
|
action_up, action_down, action_left, action_right = (0.0, 0.0, 0.0, 0.0)
|
||||||
|
button_start, button_select = (0.0, 0.0)
|
||||||
|
button_l1, button_l2, button_l3 = (0.0, 0.0, 0.0)
|
||||||
|
button_r1, button_r2, button_r3 = (0.0, 0.0, 0.0)
|
||||||
|
left_stick_x_axis, left_stick_y_axis, right_stick_x_axis, right_stick_y_axis = (
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
left_button_pressed, right_button_pressed, left_button_hold, right_button_hold = (
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
)
|
||||||
|
left_thumb_stick, right_thumb_stick = (0.0, 0.0)
|
||||||
|
left_thumb_X, right_thumb_X, left_thumb_Y, right_thumb_Y = (0.0, 0.0, 0.0, 0.0)
|
||||||
|
left_index, right_index = (0.0, 0.0)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_gamepads() -> list[GamePad]:
|
||||||
|
"""Get list of connected gamepad"""
|
||||||
|
gamepads = []
|
||||||
|
|
||||||
|
for device in devices.gamepads:
|
||||||
|
gamepads.append(device)
|
||||||
|
|
||||||
|
return gamepads
|
||||||
|
|
||||||
|
|
||||||
|
def select_gamepad() -> GamePad | None:
|
||||||
|
"""Select gamepad to use with VTS"""
|
||||||
|
gamepads = _get_gamepads()
|
||||||
|
|
||||||
|
if len(gamepads) > 1:
|
||||||
|
selection = inquirer.prompt(
|
||||||
|
questions=[
|
||||||
|
inquirer.List(
|
||||||
|
name="gamepad",
|
||||||
|
message="Select gamepad to use for VTS",
|
||||||
|
choices=gamepads,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
if selection:
|
||||||
|
gamepad = selection["gamepad"]
|
||||||
|
return gamepad
|
||||||
|
else:
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
return gamepads[0]
|
||||||
|
|
||||||
|
|
||||||
|
def _deadzone(analog_value: float, deadzone: float = 0.1) -> float:
|
||||||
|
return 0 if abs(analog_value) < deadzone else analog_value
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_analog_sticks(analog_value: float) -> float:
|
||||||
|
"""Normalize analog value to -1 - 1 range to comply with Nyarupad"""
|
||||||
|
minimum: int = 0
|
||||||
|
maximum: int = 255
|
||||||
|
formula = 2 * ((analog_value - minimum) / (maximum - minimum)) - 1
|
||||||
|
return formula
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_analog_trigger(analog_value: float) -> float:
|
||||||
|
minimum: int = 0
|
||||||
|
maximum: int = 255
|
||||||
|
formula = (analog_value - minimum) / (maximum - minimum)
|
||||||
|
return formula
|
||||||
|
|
||||||
|
|
||||||
|
def set_inputs(code: str, state: float) -> None:
|
||||||
|
global dpad_up, dpad_down, dpad_left, dpad_right
|
||||||
|
global action_up, action_down, action_left, action_right
|
||||||
|
global left_stick_x_axis, left_stick_y_axis, right_stick_x_axis, right_stick_y_axis
|
||||||
|
global button_start, button_l1, button_l2, button_l3
|
||||||
|
global button_select, button_r1, button_r2, button_r3
|
||||||
|
global left_thumb_stick, right_thumb_stick
|
||||||
|
global left_thumb_X, right_thumb_X, left_thumb_Y, right_thumb_Y
|
||||||
|
global left_index, right_index
|
||||||
|
global \
|
||||||
|
left_button_pressed, \
|
||||||
|
right_button_pressed, \
|
||||||
|
left_button_hold, \
|
||||||
|
right_button_hold
|
||||||
|
|
||||||
|
if code == "ABS_HAT0Y":
|
||||||
|
dpad_up = state * -1 if state < 0 else 0
|
||||||
|
dpad_down = state if state > 0 else 0
|
||||||
|
|
||||||
|
elif code == "ABS_HAT0X":
|
||||||
|
dpad_left = state * -1 if state < 0 else 0
|
||||||
|
dpad_right = state if state > 0 else 0
|
||||||
|
|
||||||
|
elif code == "ABS_X":
|
||||||
|
left_stick_x_axis = state
|
||||||
|
|
||||||
|
elif code == "ABS_Y":
|
||||||
|
left_stick_y_axis = state * -1
|
||||||
|
|
||||||
|
elif code == "ABS_RX":
|
||||||
|
right_stick_x_axis = state
|
||||||
|
|
||||||
|
elif code == "ABS_RY":
|
||||||
|
right_stick_y_axis = state * -1
|
||||||
|
|
||||||
|
elif code == "ABS_Z":
|
||||||
|
button_l2 = state
|
||||||
|
|
||||||
|
elif code == "ABS_RZ":
|
||||||
|
button_r2 = state
|
||||||
|
|
||||||
|
elif code == "BTN_TL":
|
||||||
|
button_l1 = state
|
||||||
|
|
||||||
|
elif code == "BTN_TR":
|
||||||
|
button_r1 = state
|
||||||
|
|
||||||
|
elif code == "BTN_SOUTH":
|
||||||
|
action_down = state
|
||||||
|
|
||||||
|
elif code == "BTN_WEST":
|
||||||
|
action_left = state
|
||||||
|
|
||||||
|
elif code == "BTN_EAST":
|
||||||
|
action_right = state
|
||||||
|
|
||||||
|
elif code == "BTN_NORTH":
|
||||||
|
action_up = state
|
||||||
|
|
||||||
|
elif code == "BTN_THUMBL":
|
||||||
|
button_l3 = state
|
||||||
|
|
||||||
|
elif code == "BTN_THUMBR":
|
||||||
|
button_r3 = state
|
||||||
|
|
||||||
|
elif code == "BTN_START":
|
||||||
|
button_start = state
|
||||||
|
|
||||||
|
elif code == "BTN_SELECT":
|
||||||
|
button_select = state
|
||||||
|
|
||||||
|
left_button_pressed = dpad_left + dpad_up + dpad_down + dpad_right
|
||||||
|
right_button_pressed = action_left + action_right + action_up + action_down
|
||||||
|
|
||||||
|
left_thumb_X = dpad_right - dpad_left if left_button_pressed >= 1 else 0
|
||||||
|
left_thumb_Y = dpad_up - dpad_down if left_button_pressed >= 1 else 0
|
||||||
|
right_thumb_X = action_right - action_left if right_button_pressed >= 1 else 0
|
||||||
|
right_thumb_Y = action_up - action_down if right_button_pressed >= 1 else 0
|
||||||
|
|
||||||
|
left_thumb_stick = (
|
||||||
|
1
|
||||||
|
if dpad_down == dpad_up == dpad_left == dpad_right == 0 or button_l3 == 1
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
right_thumb_stick = (
|
||||||
|
1
|
||||||
|
if action_up == action_down == action_left == action_right == 0
|
||||||
|
or button_r3 == 1
|
||||||
|
else 0
|
||||||
|
)
|
||||||
|
|
||||||
|
left_index = 1 if button_l1 == 0 else 0
|
||||||
|
right_index = 1 if button_r1 == 0 else 0
|
||||||
|
|
||||||
|
|
||||||
|
def create_vts_input_request() -> list[dict]:
|
||||||
|
params = [
|
||||||
|
{"id": "NP_ON", "value": 1.0, "weight": 1.0},
|
||||||
|
{"id": "NP_DPadDown", "value": dpad_down, "weight": 1.0},
|
||||||
|
{"id": "NP_DPadUp", "value": dpad_up, "weight": 1.0},
|
||||||
|
{"id": "NP_DPadLeft", "value": dpad_left, "weight": 1.0},
|
||||||
|
{"id": "NP_DPadRight", "value": dpad_right, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonA", "value": action_down, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonB", "value": action_right, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonX", "value": action_left, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonY", "value": action_up, "weight": 1.0},
|
||||||
|
{"id": "NP_StartDown", "value": button_start, "weight": 1.0},
|
||||||
|
{"id": "NP_SelectDown", "value": button_select, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonLS", "value": button_l3, "weight": 1.0},
|
||||||
|
{"id": "NP_ButtonRS", "value": button_r3, "weight": 1.0},
|
||||||
|
{"id": "NP_L1", "value": button_l1, "weight": 1.0},
|
||||||
|
{"id": "NP_R1", "value": button_r1, "weight": 1.0},
|
||||||
|
{"id": "NP_L2", "value": button_l2, "weight": 1.0},
|
||||||
|
{"id": "NP_R2", "value": button_r2, "weight": 1.0},
|
||||||
|
{"id": "NP_LStickX", "value": left_stick_x_axis, "weight": 1.0},
|
||||||
|
{"id": "NP_LStickY", "value": left_stick_y_axis, "weight": 1.0},
|
||||||
|
{"id": "NP_RStickX", "value": right_stick_x_axis, "weight": 1.0},
|
||||||
|
{"id": "NP_RStickY", "value": right_stick_y_axis, "weight": 1.0},
|
||||||
|
{"id": "NP_LButtonDown", "value": left_button_pressed, "weight": 1.0},
|
||||||
|
{"id": "NP_RButtonDown", "value": right_button_pressed, "weight": 1.0},
|
||||||
|
{"id": "NP_LButtonPress", "value": left_button_pressed, "weight": 1.0},
|
||||||
|
{"id": "NP_RButtonPress", "value": right_button_pressed, "weight": 1.0},
|
||||||
|
{"id": "NP_LThumbX", "value": left_thumb_X, "weight": 1.0},
|
||||||
|
{"id": "NP_LThumbY", "value": left_thumb_Y, "weight": 1.0},
|
||||||
|
{"id": "NP_RThumbX", "value": right_thumb_X, "weight": 1.0},
|
||||||
|
{"id": "NP_RThumbY", "value": right_thumb_Y, "weight": 1.0},
|
||||||
|
{"id": "NP_LOnStick", "value": left_thumb_stick, "weight": 1.0},
|
||||||
|
{"id": "NP_ROnStick", "value": right_thumb_stick, "weight": 1.0},
|
||||||
|
{"id": "NP_LIndexPos", "value": left_index, "weight": 1.0},
|
||||||
|
{"id": "NP_RIndexPos", "value": right_index, "weight": 1.0},
|
||||||
|
]
|
||||||
|
|
||||||
|
return params
|
||||||
|
|
||||||
|
|
||||||
|
async def main() -> None:
|
||||||
|
gamepad = select_gamepad()
|
||||||
|
vts = VTSConnection()
|
||||||
|
try:
|
||||||
|
await vts.connect()
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
await vts.close()
|
||||||
|
|
||||||
|
axis_states = {
|
||||||
|
"ABS_X": 0.0,
|
||||||
|
"ABS_Y": 0.0,
|
||||||
|
"ABS_RX": 0.0,
|
||||||
|
"ABS_RY": 0.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
trigger_states = {
|
||||||
|
"ABS_Z": 0.0,
|
||||||
|
"ABS_RZ": 0.0,
|
||||||
|
}
|
||||||
|
|
||||||
|
last_time = time.monotonic()
|
||||||
|
frequency = 1 / 30
|
||||||
|
|
||||||
|
while True:
|
||||||
|
for event in gamepad.read():
|
||||||
|
if event.code != "SYN_REPORT":
|
||||||
|
# Add some deadzone of about 10% to analog stick
|
||||||
|
if event.code in ["ABS_X", "ABS_Y", "ABS_RX", "ABS_RY"]:
|
||||||
|
axis_states[event.code] = _deadzone(
|
||||||
|
_normalize_analog_sticks(event.state)
|
||||||
|
)
|
||||||
|
elif event.code in ["ABS_Z", "ABS_RZ"]:
|
||||||
|
trigger_states[event.code] = _normalize_analog_trigger(event.state)
|
||||||
|
else:
|
||||||
|
set_inputs(event.code, event.state)
|
||||||
|
|
||||||
|
now = time.monotonic()
|
||||||
|
if now - last_time >= frequency:
|
||||||
|
last_time = now
|
||||||
|
|
||||||
|
for key in trigger_states:
|
||||||
|
set_inputs(key, trigger_states[key])
|
||||||
|
for key in axis_states:
|
||||||
|
set_inputs(key, axis_states[key])
|
||||||
|
|
||||||
|
input_data = create_vts_input_request()
|
||||||
|
await vts.update_parameters(input_data)
|
||||||
|
|
||||||
|
await asyncio.sleep(0.001)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
asyncio.run(main())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
exit(0)
|
||||||
405
src/vts-gampad-input/vts_connection.py
Executable file
405
src/vts-gampad-input/vts_connection.py
Executable file
@@ -0,0 +1,405 @@
|
|||||||
|
#! /usr/bin/env python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import pyvts
|
||||||
|
|
||||||
|
AUTHOR = "Melody LaFae"
|
||||||
|
PLUGIN_NAME = "VTS Gamepad Input"
|
||||||
|
|
||||||
|
token_path = f"{os.environ['HOME']}/.vts-gamepad-input-token"
|
||||||
|
ip_path = f"{os.environ['HOME']}/.vts-gamepad-input-ip"
|
||||||
|
|
||||||
|
plugin_info = {
|
||||||
|
"plugin_name": PLUGIN_NAME,
|
||||||
|
"developer": AUTHOR,
|
||||||
|
"authentication_token_path": token_path,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VTSConnection:
|
||||||
|
def __init__(self):
|
||||||
|
self.vts = pyvts.vts(
|
||||||
|
plugin_info=plugin_info, vts_api_info=self._get_vts_api_info()
|
||||||
|
)
|
||||||
|
self.request = pyvts.VTSRequest(plugin_info=plugin_info)
|
||||||
|
|
||||||
|
async def connect(self):
|
||||||
|
conn_success = await self._connect_to_api()
|
||||||
|
if conn_success:
|
||||||
|
await self._create_vts_params()
|
||||||
|
await self.close()
|
||||||
|
|
||||||
|
async def close(self):
|
||||||
|
await self.vts.close()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _get_vts_api_info() -> dict[str, str]:
|
||||||
|
host_uri = "ws://localhost:8001"
|
||||||
|
vts_api_info: dict[str, str] = {}
|
||||||
|
|
||||||
|
if os.path.exists(ip_path) and os.path.isfile(ip_path):
|
||||||
|
with open(ip_path, "r") as file:
|
||||||
|
host_uri = file.read()
|
||||||
|
else:
|
||||||
|
with open(ip_path, "w") as file:
|
||||||
|
file.write(host_uri)
|
||||||
|
|
||||||
|
host_url = host_uri.split(":")[1].replace("//", "")
|
||||||
|
host_port = host_uri.split(":")[2]
|
||||||
|
vts_api_info["host"] = host_url
|
||||||
|
vts_api_info["port"] = host_port
|
||||||
|
vts_api_info["name"] = "VTubeStudioPublicAPI"
|
||||||
|
vts_api_info["version"] = "1.0"
|
||||||
|
|
||||||
|
return vts_api_info
|
||||||
|
|
||||||
|
async def _connect_to_api(self) -> bool:
|
||||||
|
try:
|
||||||
|
await self.vts.connect()
|
||||||
|
except OSError:
|
||||||
|
print("Error: Make sure the VTS API is running")
|
||||||
|
exit(1)
|
||||||
|
await self.vts.request_authenticate_token()
|
||||||
|
await self.vts.request_authenticate()
|
||||||
|
|
||||||
|
if not self.vts.get_connection_status():
|
||||||
|
raise ConnectionError("Connection failed")
|
||||||
|
else:
|
||||||
|
return True
|
||||||
|
|
||||||
|
async def _create_vts_params(self) -> None:
|
||||||
|
# Param to enable or disable inputs
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ON",
|
||||||
|
info="VTS Gamepad Input Enabled",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# DPad params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_DPadDown",
|
||||||
|
info="DPad Down pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_DPadLeft",
|
||||||
|
info="DPad Left pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_DPadUp",
|
||||||
|
info="DPad Up pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_DPadRight",
|
||||||
|
info="DPad Right pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Action Buttons params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonA",
|
||||||
|
info="Down Action button pressed (XBox A, PS Cross)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonB",
|
||||||
|
info="Right Action button pressed (XBox B, PS Circle)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonY",
|
||||||
|
info="Up Action button pressed (XBox Y, PS Triangle)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonX",
|
||||||
|
info="Left Action button pressed (XBox X, PS Square)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Shoulder buttons params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_L1",
|
||||||
|
info="Left front shoulder button pressed (XBox LB, PS L1, Switch L)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_L2",
|
||||||
|
info="Left back shoulder button pressed (XBox LT, PS L2, Switch ZL)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_R1",
|
||||||
|
info="Right front shoulder button pressed (XBox RB, PS R1, Switch R)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_R2",
|
||||||
|
info="Right back shoulder button pressed (XBox RT, PS R2, Switch ZR)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Start and select params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_StartDown",
|
||||||
|
info="Start button pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_SelectDown",
|
||||||
|
info="Select button pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Left Analog stick param
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LStickX",
|
||||||
|
info="Left stick moved on X axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LStickY",
|
||||||
|
info="Left stick moved on Y axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonLS",
|
||||||
|
info="Left analog stick pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Right Analog stick params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RStickX",
|
||||||
|
info="Right stick moved on X axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RStickY",
|
||||||
|
info="Right stick moved on Y axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ButtonRS",
|
||||||
|
info="Right analog stick pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
## Rigging Logic params
|
||||||
|
# Thumb on sticks if no buttons are pressed
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LOnStick",
|
||||||
|
info="Left thumb on left analog stick",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_ROnStick",
|
||||||
|
info="Right thumb on right analog stick",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Thumb locations
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LThumbX",
|
||||||
|
info="Left thumb movement on X axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LThumbY",
|
||||||
|
info="Left thumb movement on Y axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RThumbX",
|
||||||
|
info="Right thumb movement on X axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RThumbY",
|
||||||
|
info="Right thumb movement on Y axis",
|
||||||
|
min=-1.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Index finger location
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LIndexPos",
|
||||||
|
info="Left index finger position (on L2/LT/ZL if L1 not pressed)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RIndexPos",
|
||||||
|
info="Right index finger position (on R2/RT/ZR if R1 not pressed)",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
# Button pressed or hold params
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LButtonPress",
|
||||||
|
info="Left button pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RButtonPress",
|
||||||
|
info="Right button pressed",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_LButtonDown",
|
||||||
|
info="Left button hold",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
await self.vts.request(
|
||||||
|
self.request.requestCustomParameter(
|
||||||
|
parameter="NP_RButtonDown",
|
||||||
|
info="Right button hold",
|
||||||
|
min=0.0,
|
||||||
|
max=1.0,
|
||||||
|
default_value=0.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def update_parameters(self, parameters: list[dict]) -> None:
|
||||||
|
await self._connect_to_api()
|
||||||
|
request = self.request.BaseRequest(
|
||||||
|
data={
|
||||||
|
"faceFound": False,
|
||||||
|
"mode": "set",
|
||||||
|
"parameterValues": parameters,
|
||||||
|
},
|
||||||
|
message_type="InjectParameterDataRequest",
|
||||||
|
)
|
||||||
|
await self.vts.request(request)
|
||||||
|
await self.close()
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
vts_conn = VTSConnection()
|
||||||
|
await vts_conn.vts.connect()
|
||||||
|
await vts_conn.vts.request_authenticate_token()
|
||||||
|
# await vts_conn.vts.request_authenticate()
|
||||||
|
# await vts_conn.connect()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
181
uv.lock
generated
Normal file
181
uv.lock
generated
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 3
|
||||||
|
requires-python = ">=3.14"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "aiofiles"
|
||||||
|
version = "25.1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/41/c3/534eac40372d8ee36ef40df62ec129bee4fdb5ad9706e58a29be53b2c970/aiofiles-25.1.0.tar.gz", hash = "sha256:a8d728f0a29de45dc521f18f07297428d56992a742f0cd2701ba86e44d23d5b2", size = 46354, upload-time = "2025-10-09T20:51:04.358Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/8a/340a1555ae33d7354dbca4faa54948d76d89a27ceef032c8c3bc661d003e/aiofiles-25.1.0-py3-none-any.whl", hash = "sha256:abe311e527c862958650f9438e859c1fa7568a141b22abcd015e120e86a85695", size = 14668, upload-time = "2025-10-09T20:51:03.174Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ansicon"
|
||||||
|
version = "1.89.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b6/e2/1c866404ddbd280efedff4a9f15abfe943cb83cde6e895022370f3a61f85/ansicon-1.89.0.tar.gz", hash = "sha256:e4d039def5768a47e4afec8e89e83ec3ae5a26bf00ad851f914d1240b444d2b1", size = 67312, upload-time = "2019-04-29T20:23:57.314Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/f9/f1c10e223c7b56a38109a3f2eb4e7fe9a757ea3ed3a166754fb30f65e466/ansicon-1.89.0-py2.py3-none-any.whl", hash = "sha256:f1def52d17f65c2c9682cf8370c03f541f410c1752d6a14029f97318e4b9dfec", size = 63675, upload-time = "2019-04-29T20:23:53.83Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blessed"
|
||||||
|
version = "1.25.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "jinxed", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "wcwidth" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/33/cd/eed8b82f1fabcb817d84b24d0780b86600b5c3df7ec4f890bcbb2371b0ad/blessed-1.25.0.tar.gz", hash = "sha256:606aebfea69f85915c7ca6a96eb028e0031d30feccc5688e13fd5cec8277b28d", size = 6746381, upload-time = "2025-11-18T18:43:52.71Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7c/2c/e9b6dd824fb6e76dbd39a308fc6f497320afd455373aac8518ca3eba7948/blessed-1.25.0-py3-none-any.whl", hash = "sha256:e52b9f778b9e10c30b3f17f6b5f5d2208d1e9b53b270f1d94fc61a243fc4708f", size = 95646, upload-time = "2025-11-18T18:43:50.924Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "editor"
|
||||||
|
version = "1.6.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "runs" },
|
||||||
|
{ name = "xmod" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/2a/92/734a4ab345914259cb6146fd36512608ea42be16195375c379046f33283d/editor-1.6.6.tar.gz", hash = "sha256:bb6989e872638cd119db9a4fce284cd8e13c553886a1c044c6b8d8a160c871f8", size = 3197, upload-time = "2024-01-25T10:44:59.909Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1b/c2/4bc8cd09b14e28ce3f406a8b05761bed0d785d1ca8c2a5c6684d884c66a2/editor-1.6.6-py3-none-any.whl", hash = "sha256:e818e6913f26c2a81eadef503a2741d7cca7f235d20e217274a009ecd5a74abf", size = 4017, upload-time = "2024-01-25T10:44:58.66Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inputs"
|
||||||
|
version = "0.5"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/cd/5f434220920f76eb73d19bb7aab8d857445f40aa642718e6e51e850cd663/inputs-0.5.tar.gz", hash = "sha256:a31d5b96a3525f1232f326be9e7ce8ccaf873c6b1fb84d9f3c9bc3d79b23eae4", size = 33393, upload-time = "2018-10-05T22:38:14.206Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d0/94/040a0d9c81f018c39bd887b7b825013b024deb0a6c795f9524797e2cd41b/inputs-0.5-py2.py3-none-any.whl", hash = "sha256:13f894564e52134cf1e3862b1811da034875eb1f2b62e6021e3776e9669a96ec", size = 33630, upload-time = "2018-10-05T22:38:28.28Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "inquirer"
|
||||||
|
version = "3.4.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "blessed" },
|
||||||
|
{ name = "editor" },
|
||||||
|
{ name = "readchar" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/c1/79/165579fdcd3c2439503732ae76394bf77f5542f3dd18135b60e808e4813c/inquirer-3.4.1.tar.gz", hash = "sha256:60d169fddffe297e2f8ad54ab33698249ccfc3fc377dafb1e5cf01a0efb9cbe5", size = 14069, upload-time = "2025-08-02T18:36:27.901Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f0/fd/7c404169a3e04a908df0644893a331f253a7f221961f2b6c0cf44430ae5a/inquirer-3.4.1-py3-none-any.whl", hash = "sha256:717bf146d547b595d2495e7285fd55545cff85e5ce01decc7487d2ec6a605412", size = 18152, upload-time = "2025-08-02T18:36:26.753Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "jinxed"
|
||||||
|
version = "1.3.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "ansicon", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/20/d0/59b2b80e7a52d255f9e0ad040d2e826342d05580c4b1d7d7747cfb8db731/jinxed-1.3.0.tar.gz", hash = "sha256:1593124b18a41b7a3da3b078471442e51dbad3d77b4d4f2b0c26ab6f7d660dbf", size = 80981, upload-time = "2024-07-31T22:39:18.854Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/27/e3/0e0014d6ab159d48189e92044ace13b1e1fe9aa3024ba9f4e8cf172aa7c2/jinxed-1.3.0-py2.py3-none-any.whl", hash = "sha256:b993189f39dc2d7504d802152671535b06d380b26d78070559551cbf92df4fc5", size = 33085, upload-time = "2024-07-31T22:39:17.426Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "numpy"
|
||||||
|
version = "2.2.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/76/21/7d2a95e4bba9dc13d043ee156a356c0a8f0c6309dff6b21b4d71a073b8a8/numpy-2.2.6.tar.gz", hash = "sha256:e29554e2bef54a90aa5cc07da6ce955accb83f21ab5de01a62c8478897b264fd", size = 20276440, upload-time = "2025-05-17T22:38:04.611Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "opencv-python"
|
||||||
|
version = "4.12.0.88"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "numpy" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/ac/71/25c98e634b6bdeca4727c7f6d6927b056080668c5008ad3c8fc9e7f8f6ec/opencv-python-4.12.0.88.tar.gz", hash = "sha256:8b738389cede219405f6f3880b851efa3415ccd674752219377353f017d2994d", size = 95373294, upload-time = "2025-07-07T09:20:52.389Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/85/68/3da40142e7c21e9b1d4e7ddd6c58738feb013203e6e4b803d62cdd9eb96b/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:f9a1f08883257b95a5764bf517a32d75aec325319c8ed0f89739a57fae9e92a5", size = 37877727, upload-time = "2025-07-07T09:13:31.47Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/7c/042abe49f58d6ee7e1028eefc3334d98ca69b030e3b567fe245a2b28ea6f/opencv_python-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:812eb116ad2b4de43ee116fcd8991c3a687f099ada0b04e68f64899c09448e81", size = 57326471, upload-time = "2025-07-07T09:13:41.26Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/3a/440bd64736cf8116f01f3b7f9f2e111afb2e02beb2ccc08a6458114a6b5d/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:51fd981c7df6af3e8f70b1556696b05224c4e6b6777bdd2a46b3d4fb09de1a92", size = 45887139, upload-time = "2025-07-07T09:13:50.761Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/68/1f/795e7f4aa2eacc59afa4fb61a2e35e510d06414dd5a802b51a012d691b37/opencv_python-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:092c16da4c5a163a818f120c22c5e4a2f96e0db4f24e659c701f1fe629a690f9", size = 67041680, upload-time = "2025-07-07T09:14:01.995Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/02/96/213fea371d3cb2f1d537612a105792aa0a6659fb2665b22cad709a75bd94/opencv_python-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:ff554d3f725b39878ac6a2e1fa232ec509c36130927afc18a1719ebf4fbf4357", size = 30284131, upload-time = "2025-07-07T09:14:08.819Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/80/eb88edc2e2b11cd2dd2e56f1c80b5784d11d6e6b7f04a1145df64df40065/opencv_python-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:d98edb20aa932fd8ebd276a72627dad9dc097695b3d435a4257557bbb49a79d2", size = 39000307, upload-time = "2025-07-07T09:14:16.641Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pyvts"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "aiofiles" },
|
||||||
|
{ name = "opencv-python" },
|
||||||
|
{ name = "websockets" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/0c/c7/be53a7964c0d5e108c416bfdea432a4451fd4d8e03f18b5877376548f016/pyvts-0.3.3.tar.gz", hash = "sha256:decf3299a391ce2e38ffcc3fb2caf71f06b27b9ca2b7581dc5a97e62620da2c4", size = 11655, upload-time = "2024-09-10T08:16:27.494Z" }
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "readchar"
|
||||||
|
version = "4.2.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/dd/f8/8657b8cbb4ebeabfbdf991ac40eca8a1d1bd012011bd44ad1ed10f5cb494/readchar-4.2.1.tar.gz", hash = "sha256:91ce3faf07688de14d800592951e5575e9c7a3213738ed01d394dcc949b79adb", size = 9685, upload-time = "2024-11-04T18:28:07.757Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a9/10/e4b1e0e5b6b6745c8098c275b69bc9d73e9542d5c7da4f137542b499ed44/readchar-4.2.1-py3-none-any.whl", hash = "sha256:a769305cd3994bb5fa2764aa4073452dc105a4ec39068ffe6efd3c20c60acc77", size = 9350, upload-time = "2024-11-04T18:28:02.859Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "runs"
|
||||||
|
version = "1.2.2"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "xmod" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/26/6d/b9aace390f62db5d7d2c77eafce3d42774f27f1829d24fa9b6f598b3ef71/runs-1.2.2.tar.gz", hash = "sha256:9dc1815e2895cfb3a48317b173b9f1eac9ba5549b36a847b5cc60c3bf82ecef1", size = 5474, upload-time = "2024-01-25T14:44:01.563Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/d6/17caf2e4af1dec288477a0cbbe4a96fbc9b8a28457dce3f1f452630ce216/runs-1.2.2-py3-none-any.whl", hash = "sha256:0980dcbc25aba1505f307ac4f0e9e92cbd0be2a15a1e983ee86c24c87b839dfd", size = 7033, upload-time = "2024-01-25T14:43:59.959Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "vts-gamepad-input"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { virtual = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "inputs" },
|
||||||
|
{ name = "inquirer" },
|
||||||
|
{ name = "pyvts" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "inputs", specifier = ">=0.5" },
|
||||||
|
{ name = "inquirer", specifier = ">=3.4.1" },
|
||||||
|
{ name = "pyvts", specifier = ">=0.3.3" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wcwidth"
|
||||||
|
version = "0.2.14"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/24/30/6b0809f4510673dc723187aeaf24c7f5459922d01e2f794277a3dfb90345/wcwidth-0.2.14.tar.gz", hash = "sha256:4d478375d31bc5395a3c55c40ccdf3354688364cd61c4f6adacaa9215d0b3605", size = 102293, upload-time = "2025-09-22T16:29:53.023Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/af/b5/123f13c975e9f27ab9c0770f514345bd406d0e8d3b7a0723af9d43f710af/wcwidth-0.2.14-py2.py3-none-any.whl", hash = "sha256:a7bb560c8aee30f9957e5f9895805edd20602f2d7f720186dfd906e82b4982e1", size = 37286, upload-time = "2025-09-22T16:29:51.641Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websockets"
|
||||||
|
version = "15.0.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "xmod"
|
||||||
|
version = "1.8.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/72/b2/e3edc608823348e628a919e1d7129e641997afadd946febdd704aecc5881/xmod-1.8.1.tar.gz", hash = "sha256:38c76486b9d672c546d57d8035df0beb7f4a9b088bc3fb2de5431ae821444377", size = 3988, upload-time = "2024-01-04T18:03:17.663Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/6b/0dc75b64a764ea1cb8e4c32d1fb273c147304d4e5483cd58be482dc62e45/xmod-1.8.1-py3-none-any.whl", hash = "sha256:a24e9458a4853489042522bdca9e50ee2eac5ab75c809a91150a8a7f40670d48", size = 4610, upload-time = "2024-01-04T18:03:16.078Z" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user