## 事象
[[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)