3

I try to add additional functionality when doing a right click. Unfortunately, this will break the .context modifier and I don't understand why. This is the code I am using:

extension View {
    func onRightClick(handler: @escaping () -> Void) -> some View {
        modifier(RightClickHandler(handler: handler))
    }
}

struct RightClickHandler: ViewModifier {
    let handler: () -> Void
    func body(content: Content) -> some View {
        content.overlay(RightClickListeningViewRepresentable(handler: handler), alignment: .center)
    }
}

struct RightClickListeningViewRepresentable: NSViewRepresentable {
    let handler: () -> Void
    func makeNSView(context: Context) -> RightClickListeningView {
        RightClickListeningView(handler: handler)
    }
    func updateNSView(_ nsView: RightClickListeningView, context: Context) {}
}

class RightClickListeningView: NSView {
    let handler: () -> Void
    
    init(handler: @escaping () -> Void) {
        self.handler = handler
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func rightMouseDown(with event: NSEvent) {
        handler()
        super.rightMouseDown(with: event)
        if let menu = super.menu(for: event) {
            print(menu)
            let location = event.locationInWindow
            menu.popUp(positioning: nil, at: location, in: self)
        }
    }

}

Later then, I have this:

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .contextMenu(menuItems: {
                Button("Test") { }
            })
            .onRightClick {
                print("right click detcted")
            }
            .padding()
    }
}

If I remove the onRightClick-modifier, the context menu works again.

1 Answer 1

2

Edit

Added onTapGesture to detect left clicks as well. If you don't need that functionality, simply delete it. The order of the modifiers is crucial in order to make it work properly

Original Response

I know it's 6 months since you've asked this but if you swap around the modifiers it will work as intended (assuming you are trying to detect when context menu is opened). When you right click, the context menu will open and the right click will be detected. Hope this helps!

struct ContentView: View {
    var body: some View {
        Text("Hello, world!") // Note: order the click modifiers matters!
            .onRightClick {
                print("right click detcted")
            }
            .contextMenu(menuItems: {
                Button("Test") {}
            })
            .onTapGesture { // added this to detect left clicks
                print("left click detected")
            }
            .padding()
    }
}

Right clicking on Hello world will yield this result

Sign up to request clarification or add additional context in comments.

2 Comments

cause left mouse click not working...
@jrjian Left click won't work because theres nothing set up to detect it! I edited my original response to include the onTapGesture modifier which will detect and handle the left click along with the right click and context menu. Please note: the order of the modifiers is important. Tested and working in Xcode 15 Swift 5.9

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.