Controller model

controller type は単なる文字列ではなく、domain object として扱う。設定値や CLI option は文字列だが、SwbtControllerConfig に入る時点で SwbtControllerTypeSwbtControllerModel に変換する。

実装 module は nyxpy.framework.core.hardware.swbt.config とする。models.py を分けるほどの独立した layer は作らない。

永続化値

表示名 既定 pairing profile
pro-controller Pro Controller pro-controller-profile.json
joy-con-l Joy-Con L joy-con-l-profile.json
joy-con-r Joy-Con R joy-con-r-profile.json

TOML 例:

[controller.swbt]
controller_type = "pro-controller"

CLI 例:

nyxpy run sample_macro --controller swbt --swbt-controller-type pro-controller

内部型

from dataclasses import dataclass
from enum import Enum
from pathlib import Path

from nyxpy.framework.core.constants import Button


class SwbtControllerType(str, Enum):
    PRO_CONTROLLER = "pro-controller"
    JOY_CON_L = "joy-con-l"
    JOY_CON_R = "joy-con-r"


@dataclass(frozen=True)
class SwbtInputCapabilities:
    buttons: frozenset[Button]
    left_stick: bool
    right_stick: bool
    imu: bool


@dataclass(frozen=True)
class SwbtControllerModel:
    controller_type: SwbtControllerType
    display_name: str
    default_profile_name: str
    capabilities: SwbtInputCapabilities

    @property
    def settings_value(self) -> str:
        return self.controller_type.value

    def default_profile_path(self, base_dir: Path = Path(".nyxpy/swbt")) -> Path:
        return base_dir / self.default_profile_name

SwbtControllerModel は Project_NyX 側の controller 定義である。swbt の ProControllerJoyConLJoyConR などの runtime class は保持しない。session 作成時に controller_type から swbt controller class を解決する。

capabilities は NyX 側の入力可否の正本である。swbt runtime の UnsupportedInputError は防御的に map するが、通常の入力拒否は mapper の事前検証で行う。

registry

SUPPORTED_CONTROLLER_MODELS: dict[SwbtControllerType, SwbtControllerModel] = {
    SwbtControllerType.PRO_CONTROLLER: SwbtControllerModel(...),
    SwbtControllerType.JOY_CON_L: SwbtControllerModel(...),
    SwbtControllerType.JOY_CON_R: SwbtControllerModel(...),
}


def supported_controller_models() -> tuple[SwbtControllerModel, ...]:
    return tuple(SUPPORTED_CONTROLLER_MODELS.values())


def parse_controller_type(value: str | SwbtControllerType) -> SwbtControllerType:
    if isinstance(value, SwbtControllerType):
        return value
    try:
        return SwbtControllerType(value)
    except ValueError as exc:
        raise ConfigurationError(
            f"unsupported swbt controller type: {value}",
            code="NYX_SWBT_CONTROLLER_TYPE_UNSUPPORTED",
            component="SwbtControllerConfig",
        ) from exc


def resolve_controller_model(value: str | SwbtControllerType) -> SwbtControllerModel:
    return SUPPORTED_CONTROLLER_MODELS[parse_controller_type(value)]

GUI choices と CLI choices は supported_controller_models() から作る。

config

@dataclass(frozen=True)
class SwbtControllerConfig:
    model: SwbtControllerModel
    adapter: str | None = None
    profile_path: Path
    connect_timeout_sec: float = 30.0
    report_period_us: int | None = 8000

SwbtControllerConfigcontroller_type: str を持たない。設定 parser が model へ正規化する。

adapter は settings 上では空を許容する。pair / reconnect / run の直前に空なら NYX_SWBT_ADAPTER_NOT_SELECTED にする。

profile_pathNone の場合は、model.default_profile_path().nyxpy/swbt/<controller>-profile.json を補う。

capability validation

Joy-Con L/R では存在しない input がある。mapper は SwbtControllerModel.capabilities を参照し、非対応 input を silent no-op にしない。

input Pro Controller Joy-Con L Joy-Con R
A/B/X/Y yes subset subset
L/ZL yes yes no
R/ZR yes no yes
left stick yes yes no
right stick yes no yes
IMU yes yes yes

具体的な対応 button は Project_NyX 側の capabilities を正とする。swbt profile から UnsupportedInputError が返った場合も NYX_SWBT_INPUT_UNSUPPORTED に map する。