一個使用者口述的多視窗痛點,在同一場約 8 小時的 Claude Code session 裡,走完「構想 → 撞死路 → 繞路 → 對抗式審查 → 聖杯」的完整旅程。這是那趟旅程的完整記錄。
2026-08-12 10:14 → 18:36(台灣時間),單一 Claude Code session。從「我常常⋯迷失第一個 app 在哪」的口述,走到使用者親口說出「一起拿到聖杯,很開心」。
出處:session 逐字稿首末 timestamp 實測(00be7b8c-...jsonl,UTC 02:14:56 → 10:36:22)
使用者一開場就把痛點講得很具體——不是不會切換視窗,是「切過去之後,起點在哪裡」的空間記憶問題。
我在mac多視窗切患有個煩惱 我常常想跨windows把兩個app拉在一起 當我找到第一個我想要的app 然後切換到第二個app的時候 我就會找不到(迷失)第一個app在哪一個window 讓我效率很滴下
使用者最初的構想是「畫面遮罩高亮顯示」,並主動先問一句「我想先確認你懂不懂我的需求?」——這場 session 從一開始就是雙向確認,不是單向下指令。
使用者同一則訊息附上了背景,兩件事都已經做好:
常用 app 都已設定快捷鍵,可以快速切換焦點。
已有快速視窗位置調整軟體,並設定好快捷鍵。
但這兩者都只在「同一個桌面(Space)」裡有效。缺口精準落在同一件事上:跨桌面把兩個視窗湊在一起時,人一移動、視覺參照就斷了,起點瞬間消失。
方案定案之前,Claude 先逐項實測「跨桌面搬視窗」的每一條看起來可行的程式路徑——結果三條全部封死。
回報 true(成功),但視窗完全不動——silent no-op,不能依賴回傳值。
用兩種手法重測(含正確的 mouseDown→連續拖曳→mouseUp),WindowServer 完全拒收,視窗紋風不動。
只看得到「目前」桌面(含目前桌面 app 的最小化視窗),別的桌面一律回傳 nil。
出處:本機 2026-08-12,macOS 26.5.2 / Hammerspoon 1.1.1 逐項實測;記憶檔 macos26-spaces-api-dead.md
三條死路撞完之後,方向反過來:既然舊視窗搬不動,就先標記它、彈過去確認、能重開內容的就在眼前直接開一份新的。
解決的問題:想把兩個不同桌面(Space)的視窗湊在一起對照, 切到第二個app就迷失第一個在哪。
這一步定了整支工具的骨架:兩個標記 🅰🅱、一個熱鍵 ⌥Z 貫穿標記與拉攏、一個 ⌥⇧Z 隨時清除重來。
整支 pairwin.lua 只掛兩個熱鍵:⌥Z 一鍵包辦「標記→拉攏→重試」,⌥⇧Z 隨時清除。狀態機只有四個節點——快樂路徑走一圈就完成拉攏並自動清空。
方案剛定型,Claude 沒有直接交卷,而是先發動一個對抗式審查 workflow:三個視角並行檢查程式碼,每一項發現都要再被「懷疑者」驗證過一次才算數。
activate 放在 make new 之前,新視窗開錯桌面,使用者還會被硬拉走。
重開流程還沒完成前連按 ⌥Z,會再開一個孤兒視窗,前一輪結果被靜默丟棄。
⌥⇧Z 清除時沒取消未完成的計時器,非同步回呼事後把標記寫回來,變成看不見的幽靈配對。
視窗最小化+app 不在當前桌面時,會被誤判成「已關閉」而清掉還活著的標記。
出處:review-pairwin workflow(agentCount=15,logic/lua 三視角交叉審查+懷疑者驗證,2026-08-12 10:44–10:56);9 項全數修復並裝機驗證
我試著用⌥Z第一次鎖定 Claude 時沒問題,第二次鎖定 Codex 時沒問題,但我按第三次⌥Z 並沒有把這兩個視窗拉在同一個 Window 裡面 但另外一個情況,像我第二張貼圖,配合的是 Office Word 和 Safari 瀏覽器,它們就被拉到同一個Window裡面 幫我排解測試一下,為什麼有時候可以,有時候不行
使用者同時附上兩張截圖佐證,並在同一則訊息裡主動把權限交出來:「我授權你螢幕操作等最高權限,全部授權給你,請幫我嘗試把功能完整」。
Claude 排查後指出:這不是隨機的,是設計上早就存在的邊界,只是使用者剛好踩到了。
要讓兩種 app 都做到「拉到眼前併排」,唯一的路是把「已經判死刑」的真搬窗救回來。
我授權你螢幕操作等最高權限,全部授權給你,請幫我嘗試把功能完整
你再試試,剛剛系統有跳出來跟我要 Hammerspoon 的授權,我剛剛授權了。
這把權限表面上解鎖的是螢幕錄製(給即時鏡像用),但真正打開的是重新挑戰「已經判死刑」的模擬拖曳的機會。過程中 Claude 用 screencapture 自己截圖(mc.png/state.png)驗證畫面狀態,不是憑感覺猜測。
桌面上直接拖視窗確實被 macOS 26 封死(合成游標會動、就是抓不住窗), 但 Mission Control 裡拖縮圖這條通道還活著。
用更正確的手法重測合成拖曳:桌面上直接拖依舊死透;但在 Mission Control 裡拖曳縮圖到空間列——這條 WindowServer 通道還活著。程式讓自己開 MC、用輔助功能讀出縮圖與「桌面 1~11」按鈕的精準座標,合成拖曳把縮圖丟過去。中途踩到一個坑:拖曳懸停時空間列會展開、座標整個位移,解法是「先懸停展開、抄下座標、再拖放」。
整個真搬窗是一段阻塞式流程,天然把 Hammerspoon 鎖住,期間使用者的實體滑鼠會跟合成拖曳打架,所以介面上會先跳出「請先別動滑鼠」的警告——這是全程靜默設計裡唯一保留的非錯誤提示。
gotoSpace(),動畫約 1.2 秒
toggleMissionControl()
抓縮圖與「桌面N」按鈕座標
懸停展開空間列、抄下位移後座標,合成拖曳縮圖過去
收合 MC,切回原桌面——併排完成
出處:pairwin.lua mcMoveHere()(L466-538);空間列按鈕用「桌面N」文字辨識,系統改英文語系需同步改 pattern
真搬窗跑通、全流程實測 PASS 之後,使用者提出最後一個要求:把「標記→確認→拉攏」精簡成「按兩下 ⌥Z」,並且成功後自動清除,不用再按 ⌥⇧Z。Claude 收尾時回了一句:「一起拿到聖杯,與有榮焉。」
按下第 2 下 ⌥Z 的那一刻,程式自動挑最快的路——使用者只管按鍵,不用管眼前這兩個視窗是什麼類型。往下捲動,看程式怎麼自動選路。
🅰 本來就在目前桌面,getLive() 直接抓到物件,tilePair() 瞬間左右對半分。這是最常見、也最快的情境。
🅰 在別的桌面,但是 Finder/Chrome/Safari——標記當下已經先用 captureContent() 抓好路徑或網址,直接在目前桌面開一份內容相同的新視窗,人完全不用被拖走。
Claude/ChatGPT/Word 這類 app 開不了第二份相同內容,程式改走 mcMoveHere():切桌面、開 MC、拖縮圖、放下、切回——把視窗本尊搬到眼前。失敗才退回即時鏡像。
逐筆掃過整份逐字稿裡 Claude 呼叫工具的紀錄,看得出這不是「一次到位」,是反覆讀、改、測出來的。
我覺得做得不錯。現在可以把所有 Hammerspoon 操作中的提示拿掉(例如跑到哪個進度了之類的),只有在有錯誤訊息的時候才跑出來。 另外也可以試試看另一個方式:如果隔了 30 秒還沒有等到我下一個指令,就直接預設是 Option + Shift + Z,把現在這個動作清掉。這個超時時間(Timeout)我設定為 30 秒。
每一步都彈提示:標記了、切桌面了、開新視窗了⋯畫面一直被打斷。
全程靜默,只有 ⚠️ 錯誤才彈;進度只看右下角常駐 HUD;標記閒置 30 秒自動清除。
因為我現在用起來發現,好像我執行第一次,它會在某一個視窗做左右並排;執行第二次,它好像也會在同一個視窗做左右並排。也就是說,那個視窗執行越久之後,會有越多的 App 疊在上面。
歸屬規則:拉攏永遠落在「按第 2 下 ⌥Z 時,人所在的桌面」——🅱=錨點不動,🅰=被搬過來。這是設計行為,不是 bug:代價是常按第 2 下的那個桌面會越堆越多視窗,只進不出。
經過你的解說,我也理解了,那目前就先不用改,我知道以後該怎麼處理了,現在的機制反而是最好的。
互動層面「兩下拉攏」已經是理論下限,省不了;但程式碼層面把兩下拉攏模式下永遠跑不到的舊三段式流程整段刪除,迴歸測試全綠(併排 ✅ 自動清除 ✅ 倒數啟停 ✅)。
使用者把自己剛才那段落落長的需求貼回來,請 Claude 重寫一次,順便問問「以後該怎麼講才更直接」。
8 句話、含「因為」「另外」「這個對話分兩個部分」等口語迂迴敘述
4 行、動詞開頭、要做的和只是問的分開標示,資訊零損失
字元數為逐字稿原文實測(不含空白換行),減少約 74%;Claude 當下回應原話估算為「從 300 字到 80 字」,方向一致、量級略有出入
你原文的「我覺得做得不錯」其實不算廢話(明確告訴我方向對了、不用回頭重審), 真正的冗餘只有重複的數字和三連猜。你的提示詞底子比你自己評的好。
| 熱鍵 | 作用 |
|---|---|
| ⌥Z | 標記 🅰 → 標記 🅱+立即拉攏 → 殘局重試,同一鍵包三個階段 |
| ⌥⇧Z | 隨時清除配對,靜默不彈提示 |
8 小時 21 分,一個使用者的空間記憶痛點,變成一支 700 行、兩個熱鍵、能對三種 app 類型自動選路的 Hammerspoon 工具。過程經過 15-agent 對抗式審查、使用者兩輪實測回報、一次技術大翻案,最終使用者自己驗收「聖杯」。
下一步如果要往前走:目前工具沒有留下任何使用紀錄,量化「這把工具到底多常被用、多常失敗」需要先補一層最輕量的紀錄(例如失敗時的 alert 順手記一行 log),而不是繼續憑感覺判斷好不好用。