GUI 仮想コントローラー manual input
GUI の仮想コントローラー manual input は、既存の VirtualControllerPane / VirtualControllerModel を使う。swbt 対応のために GUI 専用の SwbtManualInputSession は追加しない。
現行経路を維持する
ControllerButton / AnalogStick / DPad
-> Qt signal
-> VirtualControllerPane
-> VirtualControllerModel
-> ControllerOutputPort
backend は ControllerOutputPort の下で差し替える。
VirtualControllerModel
-> ControllerOutputPort
├─ SerialControllerOutputPort
└─ SwbtControllerOutputPort
この構造により、GUI model は serial / swbt / dummy を知らない。
入力対象
manual input で扱うもの:
- button down / up
- D-pad direction
- left stick
- right stick
- release all
manual input で扱わないもの:
- IMU preset gesture
- IMU pose editor
- IMU raw frame editor
- IMU recorder / replay
- CLI command 生成
- clipboard copy
- diagnostics editor
- controller color editor
port 注入
settings apply または reconnect 成功後、GUI app service は runtime builder から GUI lifetime controller を取得し、model に差し込む。
GuiAppServices.apply_settings(...)
-> builder.controller_output_for_manual_input()
-> MainWindow._apply_runtime_ports(...)
-> VirtualControllerModel.set_controller(port)
swbt backend の場合、その port は SwbtControllerOutputPort である。GUI は具象型を見ない。
失敗時は None を入れる。
virtual_controller.model.set_controller(None)
controller が None の間、GUI 操作は送信されず、入力 widget も無効にする。model の有効状態は controller is not None、macro 実行状態、lifecycle worker 実行状態から決める。
操作 mapping
| GUI 操作 | VirtualControllerModel |
ControllerOutputPort |
|---|---|---|
| button press | button_press(button) |
press((button,)) |
| button release | button_release(button) |
release((button,)) |
| D-pad direction | set_hat_direction(hat) |
previous release + new press |
| left stick | set_left_stick(angle, strength) |
press((LStick(...),)) or release previous |
| right stick | set_right_stick(angle, strength) |
press((RStick(...),)) or release previous |
| release all | GUI action | release() |
swbt backend は ControllerOutputPort の下で InputState を再構築する。
connection state
GUI manual input は connected controller port がある時だけ有効にする。
| 状態 | GUI manual input |
|---|---|
| no adapter selected | disabled |
| adapter listed only | disabled |
| pairing in progress | disabled |
| reconnect in progress | disabled |
| connected / port available | enabled |
| macro running | disabled |
| disconnected / error | disabled |
macro runtime との排他
macro start 前に GUI lifetime port を閉じる。
macro start requested
-> virtual_controller.model.set_controller(None)
-> virtual_controller.model.reset_state()
-> builder.discard_manual_controller(previous port)
-> previous manual port.release()
-> previous manual port.close()
-> macro runtime start
runtime 終了後、自動で再接続しない。利用者が reconnect を押した場合だけ GUI lifetime port を再作成する。
backend factory も同じ排他を守る。swbt backend では、同じ session key に対して新しい SwbtControllerOutputPort を作る前に旧 active port を close する。GUI 上位層の macro start sequence だけに依存せず、backend 内にも「有効な入力 port は 1 つだけ」という制約を置く。
IMU の扱い
GUI manual input には IMU 操作 UI を置かない。
IMU は programmatic command として扱う。
Command.imu(...)
-> ControllerOutputPort.imu(...)
-> SwbtControllerOutputPort.imu(...)
GUI manual input から IMU を変更しないため、VirtualControllerModel に IMU state を持たせない。
error handling
| case | 動作 |
|---|---|
controller is None |
no-op |
| port operation fails | user-visible error と technical log を出し、失敗した controller を model から外して reconnect を促す |
| unsupported input | user-visible error + technical log |
| macro running | input widgets disabled |
| reconnect lost | input widgets disabled |
silent no-op は controller 未設定時だけ許容する。接続済み port が error を返した場合は明示的に表示する。
入力状態は port 操作が成功してから model へ反映する。送信失敗時に押下済み button や stick state を成功扱いで残さない。