[{"data":1,"prerenderedAt":539},["ShallowReactive",2],{"content-/autohotkey-streamdeck-claude-code-pane-control":3,"all-pages-for-dir":537,"og-image-/autohotkey-streamdeck-claude-code-pane-control":538},{"id":4,"title":5,"body":6,"category":518,"description":519,"extension":520,"meta":521,"navigation":85,"ogImage":522,"path":523,"project_name":524,"published":525,"publishedAt":526,"seo":527,"stem":528,"tags":529,"todo":535,"unpublished":525,"updatedAt":522,"__hash__":536},"pages/2026-03/2026-03-26/autohotkey-streamdeck-claude-code-pane-control.md","AutoHotKey + Stream Deckで実現するClaude Codeマルチペイン制御",{"type":7,"value":8,"toc":503},"minimark",[9,14,18,23,39,134,137,174,178,189,194,205,209,216,220,231,234,238,241,244,248,251,371,374,413,417,420,442,445,448,469,473,479,485,488,491,499],[10,11,13],"h1",{"id":12},"autohotkey-stream-deckでclaude-codeマルチペイン制御","AutoHotKey + Stream DeckでClaude Codeマルチペイン制御",[15,16,17],"p",{},"Claude Codeを4ペインで並行実行していると、許可プロンプトが4つのペインから次々と飛んでくる。Chromeでドキュメントを読みながら、マウスを動かしてWindows Terminalに切り替え、正しいペインをクリックし、Enterを押し、またChromeに戻る。この往復を1日50回以上繰り返していた。Stream Deckのボタンを押すだけで済むようにした話。",[19,20,22],"h2",{"id":21},"_4ペイン起動の土台-launch-4paneps1","4ペイン起動の土台: launch-4pane.ps1",[15,24,25,26,30,31,34,35,38],{},"まず、Windows Terminalを4分割で立ち上げるスクリプトを作った。各ペインに",[27,28,29],"code",{},"PANE_POS","環境変数（",[27,32,33],{},"top-left","等）をセットし、タブタイトルを",[27,36,37],{},"CC:top-left","のように設定する。",[40,41,46],"pre",{"className":42,"code":43,"language":44,"meta":45,"style":45},"language-powershell shiki shiki-themes vitesse-light vitesse-light","# launch-4pane.ps1（核心部分のみ）\nfunction Encode-Command {\n    param([string]$Script)\n    [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Script))\n}\n\n$encTL = Encode-Command \"`$env:PANE_POS='top-left'; Set-Location '$TopLeft'\"\n\nwt -w 0 new-tab --title \"CC:top-left\" pwsh -NoExit -EncodedCommand $encTL `; `\n   split-pane --horizontal --title \"CC:bottom-left\" pwsh -NoExit -EncodedCommand $encBL `; `\n   move-focus up `; `\n   split-pane --vertical --title \"CC:top-right\" pwsh -NoExit -EncodedCommand $encTR `; `\n   move-focus down `; `\n   split-pane --vertical --title \"CC:bottom-right\" pwsh -NoExit -EncodedCommand $encBR\n","powershell","",[27,47,48,56,62,68,74,80,87,93,98,104,110,116,122,128],{"__ignoreMap":45},[49,50,53],"span",{"class":51,"line":52},"line",1,[49,54,55],{},"# launch-4pane.ps1（核心部分のみ）\n",[49,57,59],{"class":51,"line":58},2,[49,60,61],{},"function Encode-Command {\n",[49,63,65],{"class":51,"line":64},3,[49,66,67],{},"    param([string]$Script)\n",[49,69,71],{"class":51,"line":70},4,[49,72,73],{},"    [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($Script))\n",[49,75,77],{"class":51,"line":76},5,[49,78,79],{},"}\n",[49,81,83],{"class":51,"line":82},6,[49,84,86],{"emptyLinePlaceholder":85},true,"\n",[49,88,90],{"class":51,"line":89},7,[49,91,92],{},"$encTL = Encode-Command \"`$env:PANE_POS='top-left'; Set-Location '$TopLeft'\"\n",[49,94,96],{"class":51,"line":95},8,[49,97,86],{"emptyLinePlaceholder":85},[49,99,101],{"class":51,"line":100},9,[49,102,103],{},"wt -w 0 new-tab --title \"CC:top-left\" pwsh -NoExit -EncodedCommand $encTL `; `\n",[49,105,107],{"class":51,"line":106},10,[49,108,109],{},"   split-pane --horizontal --title \"CC:bottom-left\" pwsh -NoExit -EncodedCommand $encBL `; `\n",[49,111,113],{"class":51,"line":112},11,[49,114,115],{},"   move-focus up `; `\n",[49,117,119],{"class":51,"line":118},12,[49,120,121],{},"   split-pane --vertical --title \"CC:top-right\" pwsh -NoExit -EncodedCommand $encTR `; `\n",[49,123,125],{"class":51,"line":124},13,[49,126,127],{},"   move-focus down `; `\n",[49,129,131],{"class":51,"line":130},14,[49,132,133],{},"   split-pane --vertical --title \"CC:bottom-right\" pwsh -NoExit -EncodedCommand $encBR\n",[15,135,136],{},"ポイントが2つある。",[138,139,140,158],"ul",{},[141,142,143,150,151,154,155,157],"li",{},[144,145,146,149],"strong",{},[27,147,148],{},"-w 0","で既存WTにタブ追加",": ",[27,152,153],{},"wt new-tab","だけだと新しいウィンドウが開く。",[27,156,148],{},"を付けると既存のWindows Terminalにタブとして追加される",[141,159,160,150,166,169,170,173],{},[144,161,162,165],{},[27,163,164],{},"-EncodedCommand","でBase64エンコード",[27,167,168],{},"wt","コマンドのセミコロン区切りとPowerShellのセミコロンが衝突する。",[27,171,172],{},"-Command","方式ではエスケープが入れ子になって崩壊するため、Base64に逃がした",[19,175,177],{"id":176},"最初の試み-自動フォーカス方式","最初の試み: 自動フォーカス方式",[15,179,180,181,184,185,188],{},"最初に思いついたのは「許可プロンプトが出たら自動でそのペインにフォーカスを移す」という仕組みだった。Claude Codeの",[27,182,183],{},"Notification","フックからAHKスクリプトを呼び出し、",[27,186,187],{},"WinActivate","でWindows Terminalを最前面に持ってくる方式。",[190,191,193],"h3",{"id":192},"wt_sessionでペイン識別を試みる","WT_SESSIONでペイン識別を試みる",[15,195,196,197,200,201,204],{},"各ペインの",[27,198,199],{},"WT_SESSION","環境変数をキーにして、どのペインから通知が来たかを特定しようとした。しかし、WTウィンドウが2つ開いていると、両方が",[27,202,203],{},"ahk_exe WindowsTerminal.exe","にマッチしてフォーカスの奪い合いが起きた。",[190,206,208],{"id":207},"setforegroundwindowの壁","SetForegroundWindowの壁",[15,210,211,212,215],{},"Windowsには「バックグラウンドプロセスが勝手にフォアグラウンドを奪えない」というフォアグラウンドロック制約がある。",[27,213,214],{},"Alt","キーのシミュレートで回避するハックを試したが、動いたり動かなかったりで信頼性が低かった。",[190,217,219],{"id":218},"致命的だったのは別アプリ誤爆","致命的だったのは「別アプリ誤爆」",[15,221,222,223,226,227,230],{},"最も深刻な問題は、",[27,224,225],{},"SetForegroundWindow","が失敗したとき、",[27,228,229],{},"SendKeys","が意図しないウィンドウに飛ぶリスクがあること。Chromeの入力フォームにEnterが飛んでフォームが送信される、といった事故が想像できた。Codexにレビューを投げたところ、まさにこの点を「致命的」と指摘された。",[15,232,233],{},"ここで自動フォーカス方式を諦めた。",[19,235,237],{"id":236},"方針転換-stream-deck-ahk","方針転換: Stream Deck + AHK",[15,239,240],{},"考え直して、「自動」を捨てた。ユーザーが明示的にボタンを押して承認する。その代わり、マウスを動かさずChromeを見たまま操作できるようにする。",[15,242,243],{},"Stream Deck XLにはボタンが32個ある。4つ使うだけでいい。",[190,245,247],{"id":246},"claude-approve-paneahk","claude-approve-pane.ahk",[15,249,250],{},"核心のAHKスクリプト。Stream Deckから呼ばれ、指定ペインにEnterを送信して元のウィンドウに戻す。",[40,252,256],{"className":253,"code":254,"language":255,"meta":45,"style":45},"language-autohotkey shiki shiki-themes vitesse-light vitesse-light","; 元のウィンドウを記憶\noriginalHwnd := WinGetID(\"A\")\n\n; CC: タイトルの WT を特定（部分一致）\nSetTitleMatchMode 2\nif !WinExist(\"CC: ahk_exe WindowsTerminal.exe\") {\n    if !WinExist(\"ahk_exe WindowsTerminal.exe\") {\n        ExitApp\n    }\n}\ntargetHwnd := WinGetID()\nWinActivate \"ahk_id \" targetHwnd\n\n; 左上にリセットしてから目的のペインへ移動\nSend \"!{Left}\"  ; Alt+Left x2, Alt+Up x2 で左上到達\n; ... 目的ペインに Alt+矢印で移動 ...\n\nSend \"{Enter}\"  ; 承認\n\n; 元のウィンドウに戻す\nSleep 200\nWinActivate \"ahk_id \" originalHwnd\n","autohotkey",[27,257,258,263,268,272,277,282,287,292,297,302,306,311,316,320,325,331,337,342,348,353,359,365],{"__ignoreMap":45},[49,259,260],{"class":51,"line":52},[49,261,262],{},"; 元のウィンドウを記憶\n",[49,264,265],{"class":51,"line":58},[49,266,267],{},"originalHwnd := WinGetID(\"A\")\n",[49,269,270],{"class":51,"line":64},[49,271,86],{"emptyLinePlaceholder":85},[49,273,274],{"class":51,"line":70},[49,275,276],{},"; CC: タイトルの WT を特定（部分一致）\n",[49,278,279],{"class":51,"line":76},[49,280,281],{},"SetTitleMatchMode 2\n",[49,283,284],{"class":51,"line":82},[49,285,286],{},"if !WinExist(\"CC: ahk_exe WindowsTerminal.exe\") {\n",[49,288,289],{"class":51,"line":89},[49,290,291],{},"    if !WinExist(\"ahk_exe WindowsTerminal.exe\") {\n",[49,293,294],{"class":51,"line":95},[49,295,296],{},"        ExitApp\n",[49,298,299],{"class":51,"line":100},[49,300,301],{},"    }\n",[49,303,304],{"class":51,"line":106},[49,305,79],{},[49,307,308],{"class":51,"line":112},[49,309,310],{},"targetHwnd := WinGetID()\n",[49,312,313],{"class":51,"line":118},[49,314,315],{},"WinActivate \"ahk_id \" targetHwnd\n",[49,317,318],{"class":51,"line":124},[49,319,86],{"emptyLinePlaceholder":85},[49,321,322],{"class":51,"line":130},[49,323,324],{},"; 左上にリセットしてから目的のペインへ移動\n",[49,326,328],{"class":51,"line":327},15,[49,329,330],{},"Send \"!{Left}\"  ; Alt+Left x2, Alt+Up x2 で左上到達\n",[49,332,334],{"class":51,"line":333},16,[49,335,336],{},"; ... 目的ペインに Alt+矢印で移動 ...\n",[49,338,340],{"class":51,"line":339},17,[49,341,86],{"emptyLinePlaceholder":85},[49,343,345],{"class":51,"line":344},18,[49,346,347],{},"Send \"{Enter}\"  ; 承認\n",[49,349,351],{"class":51,"line":350},19,[49,352,86],{"emptyLinePlaceholder":85},[49,354,356],{"class":51,"line":355},20,[49,357,358],{},"; 元のウィンドウに戻す\n",[49,360,362],{"class":51,"line":361},21,[49,363,364],{},"Sleep 200\n",[49,366,368],{"class":51,"line":367},22,[49,369,370],{},"WinActivate \"ahk_id \" originalHwnd\n",[15,372,373],{},"設計で気を配った点:",[138,375,376,388,401,407],{},[141,377,378,150,384,387],{},[144,379,380,383],{},[27,381,382],{},"CC:","タイトルでWT識別",[27,385,386],{},"launch-4pane.ps1","で設定したタイトルに部分一致させる。複数WTが開いていても4ペインのWTだけをターゲットする",[141,389,390,150,393,396,397,400],{},[144,391,392],{},"ウィンドウハンドル固定",[27,394,395],{},"WinGetID()","でハンドルを取得し、以降は",[27,398,399],{},"ahk_id","で操作する。途中でフォーカスが移っても別ウィンドウにキーが飛ばない",[141,402,403,406],{},[144,404,405],{},"名前付きMutexで排他制御",": 4ボタン同時押しでもキーストロークが干渉しない",[141,408,409,412],{},[144,410,411],{},"元のウィンドウに自動復帰",": Chromeを見たまま操作が完結する",[190,414,416],{"id":415},"stream-deckの設定","Stream Deckの設定",[15,418,419],{},"4つのbatファイルを作り、Stream Deckの「システム > 開く」アクションに登録した。",[40,421,425],{"className":422,"code":423,"language":424,"meta":45,"style":45},"language-bat shiki shiki-themes vitesse-light vitesse-light","@echo off\n\"C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe\" ^\n  \"C:\\Users\\numbe\\Git_repo\\AutoHotkey\\claude-approve-pane.ahk\" top-left\n","bat",[27,426,427,432,437],{"__ignoreMap":45},[49,428,429],{"class":51,"line":52},[49,430,431],{},"@echo off\n",[49,433,434],{"class":51,"line":58},[49,435,436],{},"\"C:\\Program Files\\AutoHotkey\\v2\\AutoHotkey64.exe\" ^\n",[49,438,439],{"class":51,"line":64},[49,440,441],{},"  \"C:\\Users\\numbe\\Git_repo\\AutoHotkey\\claude-approve-pane.ahk\" top-left\n",[15,443,444],{},"ボタンをWTのペイン配置と同じ2x2に並べると、どのボタンがどのペインかを覚える必要がない。左上のボタンが左上のペイン。",[19,446,447],{"id":447},"運用フロー",[449,450,451,457,463,466],"ol",{},[141,452,453,456],{},[27,454,455],{},"pwsh -File launch-4pane.ps1","で4ペインを起動",[141,458,459,460],{},"各ペインで",[27,461,462],{},"claude --resume",[141,464,465],{},"Chromeでドキュメントを読みながら、許可プロンプトが出たらStream Deckの対応ボタンを押す",[141,467,468],{},"視線はChromeのまま、指だけが動く",[19,470,472],{"id":471},"自動フォーカス-stream-deckへの転換で学んだこと","自動フォーカス → Stream Deckへの転換で学んだこと",[15,474,475,476,478],{},"自動化の理想は「何もしなくても全部やってくれる」だが、Windowsのフォアグラウンドロックという制約がそれを阻んだ。",[27,477,225],{},"が失敗するケースを完全に潰すのは現実的でなく、失敗時のリスク（別ウィンドウへのキー誤送信）が大きすぎた。",[15,480,481,482,484],{},"「自動」を「半自動」に一段落とした瞬間、問題がすべて消えた。Stream Deckは物理ボタンなので、押し間違えても被害はEnterが1回空振りするだけ。フォアグラウンドの制御権もAHKが",[27,483,187],{},"で確実に取れる（ユーザー操作として扱われるため）。",[15,486,487],{},"全自動に固執して複雑な回避策を積み上げるより、「人間が1アクション担う」と割り切った方がシステム全体の信頼性が上がるケースがある。今回はまさにそれだった。",[19,489,490],{"id":490},"ファイル構成",[40,492,497],{"className":493,"code":495,"language":496},[494],"language-text","C:\\Users\\numbe\\Git_repo\\AutoHotkey\\\n├── claude-pane-control.md          # 運用ドキュメント\n├── claude-approve-pane.ahk         # メインスクリプト（Stream Deck用）\n├── claude-auto-focus.ahk           # 旧・自動フォーカス（未使用、参考用）\n├── launch-4pane.ps1                # 4ペイン一括起動\n├── sd-approve-top-left.bat         # Stream Deckラッパー x4\n├── sd-approve-top-right.bat\n├── sd-approve-bottom-left.bat\n└── sd-approve-bottom-right.bat\n","text",[27,498,495],{"__ignoreMap":45},[500,501,502],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":45,"searchDepth":58,"depth":58,"links":504},[505,506,511,515,516,517],{"id":21,"depth":58,"text":22},{"id":176,"depth":58,"text":177,"children":507},[508,509,510],{"id":192,"depth":64,"text":193},{"id":207,"depth":64,"text":208},{"id":218,"depth":64,"text":219},{"id":236,"depth":58,"text":237,"children":512},[513,514],{"id":246,"depth":64,"text":247},{"id":415,"depth":64,"text":416},{"id":447,"depth":58,"text":447},{"id":471,"depth":58,"text":472},{"id":490,"depth":58,"text":490},"dev","Windows Terminalの4ペイン分割でClaude Codeを並行実行し、Stream DeckからAHKスクリプト経由で許可プロンプトに応答する仕組みを構築した記録。自動フォーカス方式の挫折からStream Deck方式への方針転換まで","md",{},null,"/autohotkey-streamdeck-claude-code-pane-control","claude-code-tools",false,"2026-03-26T00:00:00.000Z",{"title":5,"description":519},"2026-03/2026-03-26/autohotkey-streamdeck-claude-code-pane-control",[530,531,532,533,534],"AutoHotKey","Stream Deck","Claude Code","Windows Terminal","AHK","memo","mXDBgeFzEok3kipSB69un1QgfXRqH4b9Lc0g9iN_0lg",[],"https://log.eurekapu.com/og/blog/autohotkey-streamdeck-claude-code-pane-control.png?v=2026-03-26T00%3A00%3A00.000Z&title=AutoHotKey%20%2B%20Stream%20Deck%E3%81%A7%E5%AE%9F%E7%8F%BE%E3%81%99%E3%82%8BClaude%20Code%E3%83%9E%E3%83%AB%E3%83%81%E3%83%9A%E3%82%A4%E3%83%B3%E5%88%B6%E5%BE%A1&author=Kei%20Komatsu&sig=4d7e7aaf34827ebf",1782528821008]