ElfDeckAI について
ElfDeckAIは、LinuxやSteam Deckで使える仮想キーボード、ゲームパッド、マウスを提供し、AIが画面を見ながら操作できるようにします。Gaming ModeとDesktop Modeの両方で仮想デバイスを利用できます。
主な機能
- 01キーボード・Xbox 360クラスのパッド・マウスを再現
- 02画面をPNGでキャプチャ
- 03スクリーンショット座標でマウスを配置
- 04SSH経由でPCからSteam Deckに接続
- 05入力を検証し押下時間を制限
- 06終了時にすべての入力を解除
活用シーン
- 01AIにSteam Deckのゲームを見て操作させる
- 02Linuxデスクトップのマウス・キーボード操作を自動化する
- 03スクリーンショットの座標で画面要素をクリックする
MCP 対応
stdioのMCPサーバーが、キーボード、ゲームパッド、マウス、スクリーンショット用の21個のツールを提供します。MCPクライアントからローカルで起動するほか、SSH経由でSteam Deck上に起動して呼び出せます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
ElfDeckAI
AI に Steam Deck でゲームをプレイさせましょう。
ElfDeckAI を使うと、Claude などの AI アシスタントが、Steam Deck 上で仮想コントローラー、キーボード、マウスを操作し、画面を見ることもできます。 AI はゲームを見て、次に何をするかを判断し、自分でボタンを押します。ゲーミングモードとデスクトップモードの両方で動作し、ほかの Linux マシンでも使えます。
まずはこちら:Steam Deck(約 5 分)
Steam Deck と、MCP に対応した AI アプリ(Claude Desktop など)をインストールした、同じ Wi-Fi に接続された PC が必要です。
1. Deck にインストールします。 Deck をデスクトップモードに切り替え(Steam ボタン → 電源 → デスクトップに切り替え)、Konsole を開いて、次の内容を貼り付けます。
curl -fsSL https://raw.githubusercontent.com/Garthnesss/ElfDeckAI/main/install-on-deck.sh | sh
最後に Deck の IP アドレスが表示されます。手順 3 で使うので控えておいてください。
2. Deck で SSH を有効にします(一度だけ)。PC から Deck に接続できるようにするため、同じ Konsole ウィンドウで次を実行します。
passwd # choose a password for the Deck, if you haven't
sudo systemctl enable --now sshd
3. PC を接続します。 PC で 1 行貼り付けます。Deck の IP アドレスとパスワードを一度入力すると、Claude Desktop を含めてすべて設定されます。
- Windows(PowerShell で実行):
irm https://raw.githubusercontent.com/Garthnesss/ElfDeckAI/main/setup-pc.ps1 | iex - Mac または Linux(ターミナルで実行):
curl -fsSL https://raw.githubusercontent.com/Garthnesss/ElfDeckAI/main/setup-pc.sh | sh
4. 試してみましょう。 Claude Desktop を再起動して、*「Steam Deck のスクリーンショットを撮って」*と頼みます。Deck の画面が表示されたら、ゲームを起動して AI にプレイを頼んでみてください。
ヒント
- ターン制ゲーム、RPG、パズル、メニューの操作が最適です。AI の手には 1 秒以上かかるため、動きの速いアクションゲームには対応できません。
- ゲーミングモードでゲームが AI のコントローラーを認識しない場合は、AI にコントローラーをプレイヤー 1にするよう頼んでください。ゲームの実行中に Steam のコントローラーの並べ替えメニューを使う方法を AI は把握しています。
- うまく動作しませんか?AI_SETUP_GUIDE.md を AI に渡して、サポートを頼んでください。セットアップとトラブルシューティングを順を追って説明しています。
仕組み
Deck 上の 3 つの小さなプログラムが、Linux カーネルの /dev/uinput を通じて仮想入力デバイスを作成するため、ゲームや Steam から実際のハードウェアとして認識されます。
- ElfKey:仮想キーボード
- ElfPad:仮想 Xbox 360 クラスのゲームパッド(ボタン、アナログトリガー、2 本のスティック、十字キー)
- ElfMouse:仮想マウス。画面上の正確な位置をクリックすることもできます
4 つ目のプログラムである MCP サーバーは、これらのデバイスとスクリーンショットツールを、あらゆる MCP クライアントが呼び出せるツールとして公開します。PC 上の AI アプリが SSH 経由で Deck 上のサーバーを起動します。特定のゲームやエミュレーターに依存しません。ElfDeckAI は、物理 Steam Deck 上の RetroArch で Pokémon FireRed をプレイし、エージェントがスクリーンショットだけを見ながら、オープニングから最初のライバル戦まで進めました。学んだことについてはnotes/driving.mdをご覧ください。
すべて標準ライブラリのみを使った単一ファイルの Python で実装されており、Deck へのインストールに sudo は不要です。
ほかの Linux マシン
pip install elfdeckai
elfkey &
elfpad &
elfmouse &
echo "key x 150" > /tmp/elfkey.fifo # tap X for 150 ms
echo "press a" > /tmp/elfpad.fifo # tap A
echo "move 300 -100" > /tmp/elfmouse.fifo # move the pointer
echo "click left" > /tmp/elfmouse.fifo # left click
grep -E "ElfKey|ElfPad|ElfMouse" /proc/bus/input/devices # confirm the devices exist
pip を使わない場合は、リポジトリをクローンして python3 elfkey.py などを直接実行してください。実行時の状態は /tmp に保存され、再起動時に消去されます。
Steam Deck では、標準で /dev/uinput にユーザーが書き込めます。ほかのディストリビューションでは、まず udev ルールをインストールしてください(インストールを参照)。
MCP サーバー
elfdeckai-mcp は、21 個のツールを公開する Model Context Protocol サーバー(stdio トランスポート)です。
| グループ | ツール |
|---|---|
| キーボード | key_tap、key_down、key_up、key_release |
| ゲームパッド | pad_press、pad_down、pad_up、pad_stick、pad_trigger、pad_center、pad_reset |
| マウス | mouse_click_at、mouse_move_to、mouse_move、mouse_click、mouse_down、mouse_up、mouse_scroll、mouse_hscroll、mouse_release |
| ビジョン | screenshot |
screenshot はサーバーが動作しているマシンの画面をキャプチャして PNG を返すため、エージェントは別途ビデオストリームを用意せずに「見て、操作し、もう一度見る」ループで作業できます。Steam Deck の Gaming Mode(gamescope 経由)と Desktop Mode(KDE Plasma)、wlroots コンポジター、X11 に対応しています。長辺が 1280 ピクセルを超える画面は送信前に縮小されます(上限を変更するには ELFDECKAI_SCREENSHOT_MAX を設定し、無効にするには 0 を設定してください)。結果には画像サイズも含まれます。
mouse_click_at と mouse_move_to は、直近のスクリーンショット上のピクセル座標を受け取るため、画面の実際の解像度や適用された拡大縮小にかかわらず、エージェントは見えているものを正確にクリックできます。ディスプレイは 1 台のみを想定しています。
デーモンと同じマシン上で実行する場合:
{"mcpServers": {"elfdeckai": {"command": "elfdeckai-mcp"}}}
PC 上の AI クライアントから SSH 経由で Steam Deck 上で実行する場合(まずはこちらにある setup-pc スクリプトが設定を行います):
{"mcpServers": {"elfdeckai": {
"command": "ssh",
"args": ["-i", "~/.ssh/elfdeckai_ed25519", "-o", "IdentitiesOnly=yes",
"-o", "BatchMode=yes", "deck@DECK-IP-ADDRESS", ".local/bin/elfdeckai-mcp"]}}}
MCP クライアントはパスワード入力プロンプトに応答できないため、SSH キーを使ってログインします。pip がない場合は、"command": "python3", "args": ["/path/to/elfdeckai_mcp.py"] を使用してください。
すべてのツール呼び出しは、FIFO に書き込まれる前に、ツールのスキーマとデーモン独自のパーサーの両方で検証されます。デーモンが実行されていない場合、呼び出しはブロックせず、すぐにエラーを返します。
コマンドリファレンス
ElfKey(/tmp/elfkey.fifo)
| コマンド | 動作 |
|---|---|
key <name> [ms] | キーをタップします(デフォルトは 120 ms) |
down <name> / up <name> | キーを押し続ける/離します |
release | 押し続けているすべてのキーを離します |
quit | すべてを解除して終了します |
キー:a~z、0~9、矢印キー、enter、esc、space、tab、backspace、shift、rshift、ctrl、rctrl、alt、ralt、capslock、f1~f10、home、end、pageup、pagedown、insert、delete、および一般的な句読点。完全な一覧は elfkey.py の KEYS にあります。
ElfPad(/tmp/elfpad.fifo)
| コマンド | 動作 |
|---|---|
press <btn> [ms] | ボタンまたは D パッドの方向をタップします(デフォルトは 120 ms) |
down <btn> / up <btn> | 押し続ける/離します |
stick left|right <x> <y> [ms] | アナログスティックを設定します。各軸は −100~100 です。ms を指定すると、その後に中央へ戻します |
trigger left|right <0..100> [ms] | アナログトリガーを設定します。ms を指定すると、その後に解除します |
center | スティック、トリガー、D パッドをニュートラル位置に戻します |
reset | すべてを解除します |
quit | すべてを解除して終了します |
ボタン:a b x y lb rb l2 r2 select start guide l3 r3 と、D パッドの方向 up down left right。
ElfPad は Xbox 360 コントローラーとして認識されるため、SDL、Steam Input、RetroArch は設定なしでマッピングできます。l2 と r2 は実際のコントローラーと同様にアナログトリガー軸を操作します。デジタルトリガーボタンは意図的にありません。これらを宣言すると、Select、Start、Guide が標準のボタンインデックスからずれてしまうためです。
ElfMouse (/tmp/elfmouse.fifo)
| コマンド | 動作 |
|---|---|
move <dx> <dy> [glide_ms] | ポインターを相対移動します。glide_ms を指定すると、その時間をかけて移動します |
moveto <x> <y> [<width> <height>] | ポインターを絶対位置に移動します。width×height のフレーム内のピクセル位置(x, y)、またはフレームを指定しない場合は画面全体にわたるデバイス単位の 0~32767 で指定します |
click <btn> [ms] | left、right、middle をクリックします(既定は 100 ms) |
down <btn> / up <btn> | ボタンを押し続ける/離します(ドラッグの場合は down、move、up) |
scroll <ticks> / hscroll <ticks> | 縦/横スクロールホイール(正の値は上/右) |
release | 押されているすべてのボタンを離します |
quit | すべての入力を解除して終了します |
move は相対移動です。負の dy は上方向に移動します。単位は移動カウントであり、ポインターアクセラレーションが適用されるため、画面上のピクセル数と一致するとは限りません。各コマンドの上限は ±10,000 カウント、±120 ホイールティックです。
moveto は 2 つ目の仮想デバイス、ElfMouse Absolute を使用します。コンポジターはこれを仮想マシンのタブレットポインターのように扱うため、位置を正確に指定できます。ボタンは最後に移動したデバイス上で押されます。
安全性モデル
呼び出し元が言語モデルである可能性を考慮し、不正な入力によってマシンが危険な状態に陥らないよう、デーモンを構築しています。
- 不正な入力は拒否され、致命的なエラーにはなりません。 すべての行を厳密なパーサーで処理します。不正なコマンドはログに記録され、無視されます。
- タップには上限があります。 時間指定の押下は最大 5 秒です。それより長く押し続ける場合は
down/upを使用します。 - 入力が押されたままになることはありません。 時間指定の操作は
finallyブロックで元に戻され、押し続けている入力は追跡されます。また、quit、SIGTERM、SIGINT の受信時には、デバイスを削除する前にすべての入力が解除されます。key_release、mouse_release、pad_resetを使えば、いつでもすべての入力を解除できます。 - アクセスできるのは所有者のみです。 各 FIFO はモード 0600 で作成されます。
- 監査ログがあります。 受け付けたすべてのコマンドは stderr(サービスとして実行した場合はジャーナル)に書き込まれます。
- プロトコル処理は堅牢です。 MCP サーバーは、不正またはサイズ超過のリクエストに対して適切な JSON-RPC エラーを返し、停止中のデーモンによってブロックされることはありません。
範囲: これらは OS レベルの実際の入力デバイスです。ターミナルやブラウザーを含め、フォーカスされているウィンドウに入力します。ElfDeckAI は入力に上限を設けて検証し、解除できるようにしますが、エージェントが操作できる場所を決めるのはオペレーターです。信頼できるエージェントのみを、監視できるセッションで実行してください。
他のアプローチとの比較
| アプローチ | 制限 |
|---|---|
| エミュレーター API(PyBoy、mGBA スクリプティング) | 特定のエミュレーター内でしか動作しません。 |
| Moonlight などのストリーミングクライアント経由でキーを送信 | マウスクリックは転送されますが、合成キーボードイベントは転送されません。 |
| xdotool | ネイティブの Wayland クライアントにはアクセスできません。 |
| ydotool、dotool | キーボードとマウスには同じ uinput 方式を使用しますが、ゲームパッド、raw キーコード、エージェント向けのインターフェース(MCP、入力上限、解除コマンド)はありません。 |
| ハードウェア入力エミュレーター(KVM ガジェット、コントローラーアダプター) | 動作しますが、追加のハードウェアが必要です。 |
インストール
要件: /dev/uinput を備えた 64 ビット Linux と Python 3.9 以降。
/dev/uinput にユーザーが書き込めない場合は、udev ルールを一度インストールしてください。
sudo cp 70-elfdeckai-uinput.rules /etc/udev/rules.d/
sudo udevadm control --reload-rules && sudo udevadm trigger
getfacl /dev/uinput # your user should appear in the ACL
pip install --user elfdeckai の実行後、デーモンを systemd ユーザーサービスとして実行するには、次のコマンドを使います(ユニットファイルはコマンドが ~/.local/bin にあることを想定しています)。
mkdir -p ~/.config/systemd/user
cp systemd/*.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now elfkey.service elfpad.service elfmouse.service
開発
pip install -e ".[test]"
python3 -m pytest
テストスイートでは、各デーモンの入力パーサー、偽の uinput デバイスを使ったデバイス動作、実際の JSON-RPC を使った MCP サーバーをテストします。テストの実行に /dev/uinput は必要ありません。
ロードマップ
ROADMAP.md を参照してください。
変更履歴
CHANGELOG.md を参照してください。
ライセンス
MIT。LICENSE を参照してください。
作者
Garth Elfstrom(@Garthnesss)が作成・保守しています。 イシューやプルリクエストを歓迎します。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。