Skip to content

Instantly share code, notes, and snippets.

@dagronf
Last active April 9, 2025 14:04
Show Gist options
  • Save dagronf/b71315a999678aece610838497fe9d0e to your computer and use it in GitHub Desktop.
Save dagronf/b71315a999678aece610838497fe9d0e to your computer and use it in GitHub Desktop.
Swift command-line tool to find which application is stealing your Mac's focus [macOS, script, steal, focus]
#!/usr/bin/swift
import Foundation
import AppKit.NSWorkspace
// Returns the name of the frontmost app, or <none> if no app is frontmost
func currentFocusApp() -> String {
NSWorkspace.shared.frontmostApplication?.localizedName ?? "<none>"
}
var prev_name = currentFocusApp()
Swift.print("New focus: \(prev_name)")
// Schedule a timer to check every second
let updateTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in
let new_name = currentFocusApp()
if prev_name != new_name {
Swift.print("New focus: \(new_name)")
prev_name = new_name
}
})
// Detect Ctrl-C to stop observing
let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
Swift.print("")
exit(0)
}
sigintSrc.resume()
RunLoop.current.run(mode: .default, before: .distantFuture)
@dagronf
Copy link
Author

dagronf commented Jan 31, 2023

Example output

% ./find-focus-stealer.swift 
New focus: Terminal
New focus: Finder
New focus: Mountie
New focus: Finder
New focus: Mountie
New focus: Terminal
^C
%

@klimenttoshkov
Copy link

Hi there. Can you make the script remember last active application details and switch to it in case "WindowManager" is focused?
Sequoia introduced nasty productivity killer bug when switching between spaces:

New focus: Mail
New focus: Google Chrome
New focus: WindowManager
New focus: Google Chrome

@edmundcraske-bjss
Copy link

I've updated this a little to print the current time at the beginning of each output line, and to make it check every 0.1 second rather than every second:

#!/usr/bin/swift

import Foundation
import AppKit.NSWorkspace

func printTime() -> String {
    let date = Date()
    let formatter = DateFormatter()
    formatter.dateFormat = "HH:mm:ss.SSS"
    return formatter.string(from: date)
}

// Returns the name of the frontmost app, or <none> if no app is frontmost
func currentFocusApp() -> String {
   NSWorkspace.shared.frontmostApplication?.localizedName ?? "<none>"
}

var prev_name = currentFocusApp()
Swift.print(printTime() + " New focus: \(prev_name)")

// Schedule a timer to check every second
let updateTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true, block: { _ in
   let new_name = currentFocusApp()
   if prev_name != new_name {
      Swift.print(printTime() + " New focus: \(new_name)")
      prev_name = new_name
   }
})

// Detect Ctrl-C to stop observing
let sigintSrc = DispatchSource.makeSignalSource(signal: SIGINT, queue: .main)
sigintSrc.setEventHandler {
   Swift.print("")
   exit(0)
}
sigintSrc.resume()

RunLoop.current.run(mode: .default, before: .distantFuture)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment