## 事象 [[Ghostty]]から[[Raycast]]を起動した状態で[[Karabiner-Elements]]のEventViewerを見ても、Applicationの判定が[[Ghostty]]のままになる。 ![[20250510_17_45_19.webp]] 期待値は[[Raycast]]になること。これでは以下の点で不都合。 - [[Raycast]]に対するキーバインドができない - [[Raycast]]を起動したアプリケーションによってキーバインドが変わってしまう ### 環境 | 対象 | バージョン | | ---------------------- | ------ | | [[macOS]] | 15.4.1 | | [[Ghostty]] | 1.1.3 | | [[Karabiner-Elements]] | 15.3.0 | | [[karabiner.ts]] | 1.31.0 | | [[Raycast]] | 1.98.2 | ## 原因 [[Raycast]]はオーバーレイであるため、[[Karabiner-Elements]]のアプリケーション判定が効いてなさそう。明確に言及されていないが、以下のissueの状況から推定。 <div class="link-card-v2"> <div class="link-card-v2-site"> <img class="link-card-v2-site-icon" src="https://github.githubassets.com/favicons/favicon.svg" /> <span class="link-card-v2-site-name">GitHub</span> </div> <div class="link-card-v2-title"> Possible to operate conditionally on overlay (e.g. ChatGPT, Raycast, Alfred, etc.)? · Issue #3966 · pqrs-org/Karabiner-Elements </div> <div class="link-card-v2-content"> I’d like to disable certain keyboard shortcuts while using the overlays for ChatGPT, Raycast, and Alfred. Throug ... </div> <img class="link-card-v2-image" src="https://opengraph.githubassets.com/6f4dfc8aea13ad4084a32c7de05fab2e5059f8e2adf5f2d03c00c363240fd310/pqrs-org/Karabiner-Elements/issues/3966" /> <a href="https://github.com/pqrs-org/Karabiner-Elements/issues/3966"></a> </div> ## 回避策 [[Hammerspoon]]でスクリプトを組めば、[[#制限事項]]つきで実現できる。 `./hammerspoon/init.lua` ```lua -- Overlay Activator hs.loadSpoon("OverlayActivator") spoon.OverlayActivator:start({ -- Raycastの起動キーを列挙する ["com.raycast.macos"] = { { { "alt", "fn" }, "f13" }, { { "cmd", "fn" }, "f14" }, { { "cmd", "fn" }, "f15" }, }, }) ``` `~/.hammerspoon/Spoons/OverlayActivator.spoon/init.lua` ```lua local M = {} M.__index = M M.name = "OverlayActivator" M.description = "OverlayActivator is a spoon that allows you to activate applications using a key combination." M.version = "0.1.0" local toKeyMap = function(modifiers, key) if #modifiers == 0 then return key end table.sort(modifiers) return table.concat(modifiers, "+") .. "+" .. key end M.eventTap = nil M.previousBundleId = nil function M:start(keysByBundleId) if self.eventTap then self.eventTap:stop() end local bundleIdByKey = {} for bundleID, keys in pairs(keysByBundleId) do for _, key in ipairs(keys) do bundleIdByKey[toKeyMap(key[1], key[2])] = bundleID end end self.eventTap = hs.eventtap .new({ hs.eventtap.event.types.keyDown }, function(event) -- INFO: Escapeでoverlayを閉じた時は元のアプリケーションにフォーカスを戻す必要があるため local currentBundleId = hs.application.frontmostApplication():bundleID() local activeModifiers = {} for mod, isPressed in pairs(event:getFlags()) do if isPressed then table.insert(activeModifiers, mod) end end local mapKey = toKeyMap(activeModifiers, hs.keycodes.map[event:getKeyCode()]) local bundleID = bundleIdByKey[mapKey] if currentBundleId ~= M.previousBundleId and keysByBundleId[currentBundleId] and mapKey == "escape" then hs.application.launchOrFocusByBundleID(M.previousBundleId) return false end if not bundleID then return false end local app = hs.application.get(bundleID) M.previousBundleId = currentBundleId if app then app:activate() else hs.application.launchOrFocusByBundleID(bundleID) end return false end) :start() return self end function M:stop() if self.eventTap then self.eventTap:stop() self.eventTap = nil end return self end return M ``` ### 制限事項 - Window Managementなどアクティブウィンドウの取得が必要な機能を **[[Raycast]]起動後のUIから** 使うことができない - アクティブが[[Raycast]]に切り替わってしまっているため - ホットキーで使うようにすれば問題はない - ただし、**他にも予期せぬ問題に遭遇する可能性は高くなる** - [[Raycast]]のUIがすでに起動した状態でランチャーを立ち上げると、2つ以上のウィンドウがアクティブになってしまう - 設定とかしているとき以外はクリティカルでないはず... - オーバーレイの終了は `escape` キーを使う ## 参考 - [Possible to operate conditionally on overlay (e.g. ChatGPT, Raycast, Alfred, etc.)? · Issue #3966 · pqrs-org/Karabiner-Elements](https://github.com/pqrs-org/Karabiner-Elements/issues/3966)