Switch supports changing the window selection by moving your cursor, but it can’t use hover state to accomplish this because its views sometimes get created underneath the cursor, which can result in a quick1 ⌥⇥ raising a long-forgotten window instead of the next one in line.

In the legacy codebase I’d resolved this using an Event Tap that updated the selection state whenever the cursor moved. I’m trying to do better in the rewrite, and my procrastination paid off with the introduction of .onContinuousHover in macOS Ventura. Combining it with some @State variables allows us to create a view modifier that only invokes its action when the cursor actually travels into/out of the view:

import SwiftUI

struct LazyHover: ViewModifier {
  let action: (Bool) -> Void
  @State private var hoverLocation: CGPoint = .zero
  @State private var inFrame = false { didSet {
  } }

  func body(content: Content) -> some View {
    content.onContinuousHover { phase in
      switch phase {
      case .active(let location):
        if hoverLocation != .zero && !inFrame {
          inFrame = true
        hoverLocation = location
      case .ended:
        if inFrame { inFrame = false }
        hoverLocation = .zero

extension View {
  func onLazyHover(
    _ perform: @escaping (Bool) -> Void
  ) -> some View {
    modifier(LazyHover(action: perform))
  1. quickish—the interface isn’t displayed unless ⌥ is held for around ¼s, to minimize visual impact during quick switches