Files
VRCT/src-python/docs/details/clipboard.md

251 lines
8.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Clipboard 機能設計書
## 概要
VRCT のクリップボード機能は、VRChat 内でのテキスト送信効率を向上させるため、翻訳結果をクリップボードにコピーし、ペースト機能を提供します。
## 主要機能
### 1. テキストコピー
- 翻訳結果をシステムクリップボードにコピー
- 複数のバックエンド対応Windows clip、pyperclip、tkinter
- UTF-16LE BOM 対応でクロスプラットフォーム互換性を確保
### 2. テキストペースト
- `Ctrl+V` による自動ペースト
- VRChat ウィンドウの自動フォーカス
- カウントダウン機能で準備時間を確保
### 3. VR アプリ検出
- OpenVR を用いた VRChat アプリ名の自動検出
- バックグラウンドスレッドによる非同期監視
- SteamVR の起動を待機・検出
## クラス設計
### Clipboard クラス
```python
class Clipboard:
def __init__(self)
def enable(self) -> None
def disable(self) -> None
def copy(self, message: str) -> bool
def paste(self, window_name: str|None = None, countdown: int = 0) -> bool
```
#### メンバ変数
- `is_enabled`: クリップボード機能の有効/無効状態
- `app_name`: VRChat アプリケーション名(自動検出)
- `_vr_monitor_thread`: SteamVR 監視スレッド
- `_stop_monitoring`: スレッド停止フラグ
### 主要メソッド
#### `__init__()`
初期化処理:
1. VR 監視スレッドを起動
2. SteamVR の起動を待機10秒間隔で確認
#### `enable()`
クリップボード機能を有効化:
1. `is_enabled` フラグを True に設定
2. `_initialize()` を呼び出し VR 監視を再開
#### `disable()`
クリップボード機能を無効化:
1. `is_enabled` フラグを False に設定
2. `_stop_monitoring` フラグを設定しスレッド停止
3. スレッド終了を待機(タイムアウト 1秒
#### `copy(message: str) -> bool`
**パラメータ:**
- `message`: クリップボードにコピーするテキスト
**戻り値:**
- `True`: コピー成功
- `False`: コピー失敗または無効状態
**動作:**
1. `is_enabled` チェック
2. `copy_to_clipboard()` 関数を呼び出し
#### `paste(window_name: str|None = None, countdown: int = 0) -> bool`
**パラメータ:**
- `window_name`: フォーカス対象ウィンドウ(タイトル部分一致 or プロセス名)
- `countdown`: ペースト前の待機秒数
**戻り値:**
- `True`: ペースト送信成功
- `False`: ペースト失敗または無効状態
**動作:**
1. `is_enabled` チェック
2. `window_name` 未指定時は自動検出した VRChat アプリ名を使用
3. Windows 環境下でウィンドウをフォーカス(以下の順序)
- ウィンドウタイトルで部分一致検索
- マッチしない場合、プロセス名で検索
4. ウィンドウフォーカス成功時、`paste_via_pyautogui()` でペースト実行
### 内部メソッド
#### `_initialize()`
VR 監視スレッドの初期化:
1. `_stop_monitoring` を False に設定
2. デーモンスレッドで `_monitor_steamvr()` を起動
#### `_monitor_steamvr()`
バックグラウンドスレッド処理:
1. 10秒間隔で `checkSteamvrRunning()` を確認
2. SteamVR 検出時に `_setup_vr_app_name()` を呼び出し
3. `_stop_monitoring` が True になるまで監視
#### `_setup_vr_app_name()`
OpenVR を用いた VR アプリ名検出:
1. OpenVR 初期化(`VRApplication_Background` モード)
2. すべてのアプリケーション情報を取得
3. `steam.app` で始まるキーを検索し `app_name` に設定
4. 例外発生時は `app_name` を None に設定
## 支援関数
### `checkSteamvrRunning() -> bool`
SteamVR が起動しているかを確認
- プロセス名 `vrmonitor.exe`Windowsまたは `vrmonitor`(その他)を検索
### `copy_to_clipboard(text: str) -> bool`
複数バックエンド対応のコピー関数
1. Windows: `clip` コマンド + UTF-16LE BOM
2. 汎用: `pyperclip` ライブラリ
3. フォールバック: `tkinter` 使用
### `paste_via_pyautogui(countdown: int = 0) -> bool`
PyAutoGUI を用いたペースト
- `pyautogui.hotkey('ctrl', 'v')` で Ctrl+V を送信
- カウントダウン実行
### ウィンドウ検索関数Windows のみ)
#### `find_windows_by_title_substring(substring: str) -> list`
ウィンドウタイトルで部分一致検索
#### `find_windows_by_process_name(proc_name: str) -> list`
プロセス名でウィンドウを検索
#### `focus_window(hwnd) -> bool`
指定ウィンドウをアクティブ化
## 依存ライブラリ
| ライブラリ | 用途 | オプション |
|-----------|------|----------|
| pyautogui | キー入力シミュレーション | 必須(ペースト機能) |
| pyperclip | クリップボード操作 | オプション(フォールバック) |
| tkinter | クリップボード操作 | オプション(フォールバック) |
| openvr | VR アプリ名検出 | 必須 |
| psutil | プロセス検索 | 必須 |
## 動作フロー
### 初期化フロー
```
Clipboard.__init__()
└─ _initialize()
└─ スレッド起動: _monitor_steamvr()
└─ 10秒間隔で SteamVR 監視
└─ 検出時: _setup_vr_app_name()
└─ VRChat アプリ名を app_name に設定
```
### コピー・ペーストフロー
```
Model.setCopyToClipboard(text)
└─ clipboard.copy(text)
└─ copy_to_clipboard(text) [成功/失敗]
Model.setPasteFromClipboard()
└─ clipboard.paste(window_name=self.app_name)
└─ find_windows_by_title_substring() [Windows]
or find_windows_by_process_name()
└─ focus_window(hwnd)
└─ paste_via_pyautogui(countdown)
```
## 有効/無効制御
### コンフィグ設定
- `config.ENABLE_CLIPBOARD`: True/False でクリップボード機能を制御
- Controller 側で `config.ENABLE_CLIPBOARD` をチェックし、True の場合のみ `setCopyToClipboard()``setPasteFromClipboard()` を呼び出し
### 制御メソッドClipboard クラス内部)
```python
# 有効化内部API、通常は使用しない
clipboard.enable()
# 無効化内部API、通常は使用しない
clipboard.disable()
```
**注意**: 現在の実装では、Controller は `clipboard.enable()/disable()` を呼び出さず、`config.ENABLE_CLIPBOARD` フラグのみで制御します。Clipboard インスタンスは常に初期化されており、VR 監視スレッドも稼働し続けます。
### API エンドポイントController
```
/get/data/clipboard - 現在の有効/無効状態を取得
/set/enable/clipboard - config.ENABLE_CLIPBOARD を True に設定
/set/disable/clipboard - config.ENABLE_CLIPBOARD を False に設定
```
## エラーハンドリング
### 失敗時の動作
- コピー失敗: `False` を返却、リトライなし
- ペースト失敗: `False` を返却、リトライなし
- VR アプリ名検出失敗: `app_name` を None に設定、現在フォーカス中のウィンドウにペースト
### 例外処理
- OpenVR 初期化失敗時は `app_name = None` に設定
- プロセス検索例外も握りつぶし
- ウィンドウフォーカス失敗はログのみ出力
## パフォーマンス考慮
### スレッド設計
- VR 監視スレッドは **デーモンスレッド**(アプリ終了時の強制停止可能)
- 10秒間隔で監視CPU 負荷最小化)
### クリップボード操作
- コピー・ペースト操作はメインスレッド実行
- ウィンドウフォーカス後に 0.2秒スリープで安定性向上
## セキュリティ・プライバシー
### データ保護
- クリップボードデータは一切ログ出力されない
- VR アプリ名のみ app_name として保持
### OS 依存性
- Windows: `clip` コマンド、ctypes によるウィンドウ制御
- その他 OS: pyperclip/tkinter フォールバック、自動フォーカス機能なし
## 制限事項・既知の問題
1. **非 Windows 環境**
- ウィンドウフォーカス機能は Windows のみ対応
- その他 OS では現在フォーカス中のウィンドウにペースト
2. **VRChat アプリ名検出**
- OpenVR が利用可能で SteamVR が起動している必要がある
- `steam.app` 接頭辞のアプリのみ認識
3. **PyAutoGUI の制限**
- キー入力シミュレーションはOS依存
- 一部アプリケーションではセキュリティ制限により失敗する可能性あり
4. **クリップボードバッファ**
- Ctrl+V 送信のタイミングはユーザー判断(カウントダウン機能あり)
- クリップボード内容の永続化はしない
## 参考資料
- [PyAutoGUI 公式ドキュメント](https://pyautogui.readthedocs.io/)
- [OpenVR Python バインディング](https://github.com/ValvePython/openvr)
- [psutil ドキュメント](https://psutil.readthedocs.io/)