pqrs-org / Karabiner-Elements

Karabiner-Elements is a powerful tool for customizing keyboards on macOS
https://karabiner-elements.pqrs.org/
The Unlicense
18.94k stars 839 forks source link

Possible to operate conditionally on overlay (e.g. ChatGPT, Raycast, Alfred, etc.)? #3966

Open kfirfer opened 1 month ago

kfirfer commented 1 month ago

I’d like to disable certain keyboard shortcuts while using the overlays for ChatGPT, Raycast, and Alfred. Through EventViewer, I can find the bundle identifiers for these apps when I’m in their settings windows, but the overlays themselves don’t seem to register as the active application. Instead, the system considers the previously active application (before the overlay was triggered) as the foremost app.

For example, if I disable a keyboard shortcut in iTerm, then activate the ChatGPT or Raycast overlay while iTerm is open, the shortcut remains disabled because iTerm is still considered the active app.

Is there a way to disable keyboard shortcuts specifically in these overlays? I’m unsure if the overlays send any signals or set flags that would allow this, so I apologize if this request is for something technically unfeasible.

kfirfer commented 1 month ago

The closest I could get is with "hammerspoon" with this configuration:

local targetAppBundleID1 = "com.raycast.macos"
local targetAppBundleID2 = "com.openai.chat"

function bringAppToFront(bundleID)
    local app = hs.application.get(bundleID)
    if app then
        app:activate()  -- Brings the app to the front
    else
        hs.application.launchOrFocusByBundleID(bundleID)  -- Launch or focus on the app
    end
end

-- Function to check the frontmost window's application
local function checkFrontmostWindow()
    local focusedWindow = hs.window.frontmostWindow()
    if focusedWindow then
        local app = focusedWindow:application()
        local bundleID = app:bundleID()

        -- Check if the frontmost app is Raycast or ChatGPT, and if it is an overlay
        if bundleID == targetAppBundleID1 and not focusedWindow:isStandard() then
            -- hs.alert.show("Raycast Overlay Window Detected")
            bringAppToFront(targetAppBundleID1)
        elseif bundleID == targetAppBundleID2 and not focusedWindow:isStandard() then
            -- hs.alert.show("ChatGPT Overlay Window Detected")
            bringAppToFront(targetAppBundleID2)
        end
    end
end

-- Use an event tap to trigger the overlay check on every key and mouse click
overlayCheckEventTap = hs.eventtap.new({ hs.eventtap.event.types.flagsChanged, hs.eventtap.event.types.keyDown }, function()
    checkFrontmostWindow()
    return false  -- Pass the event to the next handler
end)

overlayCheckEventTap:start()

I would like to know if there is a better or built-in solution.