Skip to content

Instantly share code, notes, and snippets.

@tyirvine
Created June 14, 2021 21:02
Show Gist options
  • Select an option

  • Save tyirvine/93ee7b4d6f44ee333cdfc5f419f11389 to your computer and use it in GitHub Desktop.

Select an option

Save tyirvine/93ee7b4d6f44ee333cdfc5f419f11389 to your computer and use it in GitHub Desktop.

Revisions

  1. tyirvine created this gist Jun 14, 2021.
    84 changes: 84 additions & 0 deletions InactiveWindowTapHelper.swift
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,84 @@
    //
    // InactiveWindowTapHelper.swift
    //
    // Created by Ty Irvine on 2021-06-14.
    //
    // This registers clicks on a view in SwiftUI even when the window is not key or main.
    //
    // Usage ⤵︎
    /*

    Text("Hello world!")
    .inactiveWindowTap { pressed in
    print(pressed)
    }

    */

    import Foundation
    import SwiftUI

    extension View {
    func inactiveWindowTap(_ pressed: @escaping (Bool) -> Void) -> some View {
    modifier(InactiveWindowTapModifier(pressed))
    }
    }

    struct InactiveWindowTapModifier: ViewModifier {
    let pressed: (Bool) -> Void

    init(_ pressed: @escaping (Bool) -> Void) {
    self.pressed = pressed
    }

    func body(content: Content) -> some View {
    content.overlay(
    GeometryReader { proxy in
    ClickableViewRepresentable(
    pressed: pressed,
    frame: proxy.frame(in: .global)
    )
    }
    )
    }
    }

    private struct ClickableViewRepresentable: NSViewRepresentable {
    let pressed: (Bool) -> Void
    let frame: NSRect

    func updateNSView(_ nsView: ClickableView, context: Context) {
    nsView.pressed = pressed
    }

    func makeNSView(context: Context) -> ClickableView {
    ClickableView(frame: frame, pressed: pressed)
    }
    }

    class ClickableView: NSView {

    public var pressed: ((Bool) -> Void)?

    init(frame: NSRect, pressed: ((Bool) -> Void)?) {
    super.init(frame: frame)
    self.pressed = pressed
    }

    @available(*, unavailable)
    required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
    }

    override func acceptsFirstMouse(for event: NSEvent?) -> Bool {
    return true
    }

    override func mouseDown(with event: NSEvent) {
    pressed?(true)
    }

    override func mouseUp(with event: NSEvent) {
    pressed?(false)
    }
    }