Skip to content

Commit

Permalink
add normal dualsense variant, refactor output code, switch dualsense …
Browse files Browse the repository at this point in the history
…name to default
  • Loading branch information
antheas committed Jan 3, 2024
1 parent 542cbad commit 4818d3d
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 99 deletions.
2 changes: 0 additions & 2 deletions src/hhd/controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
TouchpadCorrection,
correct_touchpad,
)
from .outputs import get_outputs
from .const import Axis, Button, Configuration

__all__ = [
Expand All @@ -21,5 +20,4 @@
"TouchpadCorrectionType",
"TouchpadCorrection",
"correct_touchpad",
"get_outputs",
]
18 changes: 12 additions & 6 deletions src/hhd/controller/virtual/dualsense/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,20 @@
DS5_EDGE_MAX_REPORT_FREQ,
DS5_EDGE_MIN_REPORT_FREQ,
DS5_EDGE_NAME,
DS5_NAME,
DS5_EDGE_PRODUCT,
DS5_EDGE_STOCK_REPORTS,
DS5_EDGE_TOUCH_HEIGHT,
DS5_EDGE_TOUCH_WIDTH,
DS5_EDGE_VENDOR,
DS5_EDGE_VERSION,
DS5_FEATURE_CRC32_SEED,
DS5_INPUT_CRC32_SEED,
DS5_INPUT_REPORT_BT_OFS,
DS5_INPUT_REPORT_USB_OFS,
DS5_PRODUCT,
DS5_USB_AXIS_MAP,
DS5_USB_BTN_MAP,
DS5_VENDOR,
patch_dpad_val,
prefill_ds5_report,
sign_crc32_append,
Expand All @@ -48,10 +50,11 @@
logger = logging.getLogger(__name__)


class DualsenseEdge(Producer, Consumer):
class Dualsense(Producer, Consumer):
def __init__(
self,
touchpad_method: TouchpadCorrectionType = "crop_end",
edge_mode: bool = True,
use_bluetooth: bool = True,
fake_timestamps: bool = False,
enable_touchpad: bool = True,
Expand All @@ -62,6 +65,7 @@ def __init__(
self.dev = None
self.start = 0
self.use_bluetooth = use_bluetooth
self.edge_mode = edge_mode
self.fake_timestamps = fake_timestamps
self.touchpad_method: TouchpadCorrectionType = touchpad_method
self.enable_touchpad = enable_touchpad
Expand All @@ -77,12 +81,12 @@ def open(self) -> Sequence[int]:
self.available = False
self.report = bytearray(prefill_ds5_report(self.use_bluetooth))
self.dev = UhidDevice(
vid=DS5_EDGE_VENDOR,
pid=DS5_EDGE_PRODUCT,
vid=DS5_VENDOR,
pid=DS5_EDGE_PRODUCT if self.edge_mode else DS5_PRODUCT,
bus=BUS_BLUETOOTH if self.use_bluetooth else BUS_USB,
version=DS5_EDGE_VERSION,
country=DS5_EDGE_COUNTRY,
name=DS5_EDGE_NAME,
name=DS5_EDGE_NAME if self.edge_mode else DS5_NAME,
report_descriptor=DS5_EDGE_DESCRIPTOR_BT
if self.use_bluetooth
else DS5_EDGE_DESCRIPTOR_USB,
Expand All @@ -99,7 +103,9 @@ def open(self) -> Sequence[int]:
self.start = time.perf_counter_ns()
self.fd = self.dev.open()

logger.info(f"Starting '{DS5_EDGE_NAME.decode()}'.")
logger.info(
f"Starting '{(DS5_EDGE_NAME if self.edge_mode else DS5_NAME).decode()}'."
)
return [self.fd]

def close(self, exit: bool) -> bool:
Expand Down
6 changes: 4 additions & 2 deletions src/hhd/controller/virtual/dualsense/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

from hhd.controller.lib.common import AM, BM

DS5_EDGE_VENDOR = 0x054C
DS5_VENDOR = 0x054C
DS5_PRODUCT = 0x0CE6
DS5_EDGE_PRODUCT = 0x0DF2
DS5_EDGE_VERSION = 256
DS5_EDGE_COUNTRY = 0
DS5_EDGE_NAME = b"Emulated Sony DS5 Edge Controller"
DS5_NAME = b"Sony Interactive Entertainment DualSense Wireless Controller"
DS5_EDGE_NAME = b"Sony Interactive Entertainment DualSense Edge Wireless Controller"

DS5_EDGE_MIN_REPORT_FREQ = 25
DS5_EDGE_MAX_REPORT_FREQ = 1000
Expand Down
15 changes: 13 additions & 2 deletions src/hhd/device/legion_go/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
from threading import Event, Thread
from typing import Any, Sequence

from hhd.plugins import Config, Context, Emitter, HHDPlugin, load_relative_yaml
from hhd.plugins import (
Config,
Context,
Emitter,
HHDPlugin,
load_relative_yaml,
get_outputs_config,
)
from hhd.plugins.settings import HHDSettings


Expand All @@ -24,7 +31,11 @@ def open(
self.prev = None

def settings(self) -> HHDSettings:
return {"controllers": {"legion_go": load_relative_yaml("controllers.yaml")}}
base = {"controllers": {"legion_go": load_relative_yaml("controllers.yaml")}}
base["controllers"]["legion_go"]["children"]["xinput"].update(
get_outputs_config()
)
return base

def update(self, conf: Config):
if conf["controllers.legion_go"] == self.prev:
Expand Down
11 changes: 4 additions & 7 deletions src/hhd/device/legion_go/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,17 @@
import sys
import time
from threading import Event as TEvent
from typing import Sequence, Literal
from typing import Literal, Sequence

from hhd.controller import Button, Consumer, Event, Producer, get_outputs
from hhd.controller import Button, Consumer, Event, Producer
from hhd.controller.base import Multiplexer, TouchpadAction
from hhd.controller.lib.hid import enumerate_unique
from hhd.controller.physical.evdev import B as EC
from hhd.controller.physical.evdev import GenericGamepadEvdev
from hhd.controller.physical.hidraw import GenericGamepadHidraw
from hhd.controller.physical.imu import AccelImu, GyroImu
from hhd.controller.virtual.uinput import (
UInputDevice,
HHD_PID_VENDOR,
)
from hhd.plugins import Config, Context, Emitter
from hhd.controller.virtual.uinput import HHD_PID_VENDOR, UInputDevice
from hhd.plugins import Config, Context, Emitter, get_outputs

from .const import (
LGO_RAW_INTERFACE_AXIS_MAP,
Expand Down
54 changes: 0 additions & 54 deletions src/hhd/device/legion_go/controllers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,6 @@ children:
hint: >-
Emulate different controller types when the Legion Controllers are in X-Input mode.
default: dualsense
modes:
#
# No emulation
#
disabled:
type: container
tags: [lgc_emulation_disabled]
title: Disabled
hint: >-
Does not modify the default controller.
#
# evdev through uinput
#
uinput:
type: container
tags: [lgc_emulation_uinput, uinput]
title: Virtual Controller
hint: >-
Creates a virtual `Handheld Daemon Controller` that can be used normally
in apps. Back buttons are supported but steam will not detect them.
If Gyroscope or Accelerometer are enabled, a Motion device will be
created as well (experimental; works in Dolphin).
#
# Dual Sense 5
#
dualsense:
type: container
tags: [lgc_emulation_dualsense, dualsense]
title: Dualsense Edge
hint: >-
Emulates the expensive Dualsense Edge Sony controller that maps 1-1 to
the legion go.
children:
led_support:
type: bool
title: LED Support
hint: >-
Passes through the LEDs to the controller, which allows games
to control them.
default: True

bluetooth_mode:
type: bool
title: Use
hint: >-
Emulates the controller in bluetooth mode instead of USB mode.
This is the default as it causes less issues with how apps
interact with the controller.
However, using USB mode can improve LED support (?) in some games.
Test and report back!
default: True

#
# Common settings
#
Expand Down
26 changes: 4 additions & 22 deletions src/hhd/plugins/__init__.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,8 @@
from .conf import Config
from .plugin import HHDAutodetect, HHDPlugin, Context, Emitter, Event
from .settings import HHDSettings


def get_relative_fn(fn: str):
"""Returns the directory of a file relative to the script calling this function."""
import inspect
import os

script_fn = inspect.currentframe().f_back.f_globals["__file__"] # type: ignore
dirname = os.path.dirname(script_fn)
return os.path.join(dirname, fn)


def load_relative_yaml(fn: str):
"""Returns the yaml data of a file in the relative dir provided."""
import inspect
import os
import yaml

script_fn = inspect.currentframe().f_back.f_globals["__file__"] # type: ignore
dirname = os.path.dirname(script_fn)
with open(os.path.join(dirname, fn), "r") as f:
return yaml.safe_load(f)
from .utils import get_relative_fn, load_relative_yaml
from .outputs import get_outputs_config, get_outputs


__all__ = [
Expand All @@ -35,4 +15,6 @@ def load_relative_yaml(fn: str):
"Emitter",
"Event",
"Context",
"get_outputs_config",
"get_outputs",
]
14 changes: 10 additions & 4 deletions src/hhd/controller/outputs.py → src/hhd/plugins/outputs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
from typing import Any, Mapping, Sequence

from .base import Consumer, Producer
from .virtual.dualsense import DualsenseEdge, TouchpadCorrectionType
from .virtual.uinput import (
from .utils import load_relative_yaml
from ..controller.base import Consumer, Producer
from ..controller.virtual.dualsense import Dualsense, TouchpadCorrectionType
from ..controller.virtual.uinput import (
HHD_PID_MOTION,
HHD_PID_TOUCHPAD,
MOTION_AXIS_MAP,
Expand All @@ -26,10 +27,11 @@ def get_outputs(
match controller:
case "dualsense":
uses_touch = touchpad == "controller"
d = DualsenseEdge(
d = Dualsense(
touchpad_method=touch_conf["controller.correction"].to(
TouchpadCorrectionType
),
edge_mode=conf["dualsense.edge_mode"].to(bool),
use_bluetooth=conf["dualsense.bluetooth_mode"].to(bool),
enable_touchpad=uses_touch,
enable_rgb=conf["dualsense.led_support"].to(bool),
Expand Down Expand Up @@ -71,3 +73,7 @@ def get_outputs(
uses_touch = True

return producers, consumers, {"uses_touch": uses_touch, "is_dual": False}


def get_outputs_config():
return load_relative_yaml("outputs.yml")
63 changes: 63 additions & 0 deletions src/hhd/plugins/outputs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
default: dualsense
modes:
#
# No emulation
#
disabled:
type: container
tags: [lgc_emulation_disabled]
title: Disabled
hint: >-
Does not modify the default controller.
#
# evdev through uinput
#
uinput:
type: container
tags: [lgc_emulation_uinput, uinput]
title: Virtual Controller
hint: >-
Creates a virtual `Handheld Daemon Controller` that can be used normally
in apps. Back buttons are supported but steam will not detect them.
If Gyroscope or Accelerometer are enabled, a Motion device will be
created as well (experimental; works in Dolphin).
#
# Dual Sense 5
#
dualsense:
type: container
tags: [lgc_emulation_dualsense, dualsense]
title: Dualsense
hint: >-
Emulates the expensive Dualsense Sony controller, both Edge and non-edge
variants.
children:
led_support:
type: bool
title: LED Support
hint: >-
Passes through the LEDs to the controller, which allows games
to control them.
default: True

bluetooth_mode:
type: bool
title: Bluetooth Mode
hint: >-
Emulates the controller in bluetooth mode instead of USB mode.
This is the default as it causes less issues with how apps
interact with the controller.
However, using USB mode can improve LED support (?) in some games.
Test and report back!
default: True

edge_mode:
type: bool
title: Edge Mode
hint: >-
Uses the edge product ID which enables paddle support.
The edge controller is a bit obscure, so some games might not
support it correctly.
You can disable this to use normal Dualsense (no paddle support).
default: True
20 changes: 20 additions & 0 deletions src/hhd/plugins/utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
def get_relative_fn(fn: str):
"""Returns the directory of a file relative to the script calling this function."""
import inspect
import os

script_fn = inspect.currentframe().f_back.f_globals["__file__"] # type: ignore
dirname = os.path.dirname(script_fn)
return os.path.join(dirname, fn)


def load_relative_yaml(fn: str):
"""Returns the yaml data of a file in the relative dir provided."""
import inspect
import os
import yaml

script_fn = inspect.currentframe().f_back.f_globals["__file__"] # type: ignore
dirname = os.path.dirname(script_fn)
with open(os.path.join(dirname, fn), "r") as f:
return yaml.safe_load(f)
4 changes: 4 additions & 0 deletions usr/lib/udev/rules.d/83-hhd.rules
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ KERNELS=="0020:1022:*", SUBSYSTEM=="iio", TEST=="in_accel_x_raw", TEST=="in_acce
# Allow steam to access the raw controllers
#

# Sony DualSense Wireless-Controller; Bluetooth; USB
KERNEL=="hidraw*", KERNELS=="*054C:0CE6*", MODE="0660", TAG+="uaccess"
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0ce6", MODE="0660", TAG+="uaccess"

# Sony DualSense Edge Wireless-Controller; Bluetooth; USB
KERNEL=="hidraw*", KERNELS=="*054C:0DF2*", MODE="0666", TAG+="uaccess"
KERNEL=="hidraw*", ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0df2", MODE="0666", TAG+="uaccess"
Expand Down

0 comments on commit 4818d3d

Please sign in to comment.