FREE TRIAL: Accelerate your app development career with Hacking with Swift+! >>

Allowing a user to define a rectangle on the screen in SwiftUI (MacOS)

Forums > macOS

I'm trying to write an app that will allow users to identify a section of a screen. I'd like to mimic the way the built-in screen shot utility works: Dimming the screen, and allowing the user to click and drag a rectangle that then shows at full brightness. I need a way to get the coordinates and screen id of the user selected bounding box.

In SwiftUI.

I've seen some example code (ancient) from Apple called DrawMouseBoxView, but I'm at a loss as to how to do this in SwiftUI (not AppKit).

Any pointers?

   

you want to do this on the screen, not a window in your app, right?

   

I was wondering if you could get a reference to a Window in a SwifUI app and you can, like this

 struct HostingWindowKey: EnvironmentKey {

#if canImport(UIKit)
    typealias WrappedValue = UIWindow
#elseif canImport(AppKit)
    typealias WrappedValue = NSWindow
#else
    #error("Unsupported platform")
#endif

    typealias Value = () -> WrappedValue? // needed for weak link
    static let defaultValue: Self.Value = { nil }
}

extension EnvironmentValues {
    var hostingWindow: HostingWindowKey.Value {
        get {
            return self[HostingWindowKey.self]
        }
        set {
            self[HostingWindowKey.self] = newValue
        }
    }
}

you can then get it via the environmentObject paramater. To make this work the way you want, the window needs to be at a high level and have a non opaque background and be the size of the sreen. There are settings for the windo that can do that.

   

@eoinnorris Yep, I need to be able let the user draw the rectangle anywhere on the screen, not just in the app's window(s).

It's very much like the screen shot example. I need to be able to let the user decide which portion of their screen will be mirrored.

   

@eoinnorris Yep, I need to be able let the user draw the rectangle anywhere on the screen, not just in the app's window(s).

It's very much like the screen shot example. I need to be able to let the user decide which portion of their screen will be mirrored.

   

@eoinnorris Let me see if i understand your second response correctly...

  1. generate a window that is:
    1. transparent
    2. on top
    3. takes up all the possible screen real estate

In general, I know how to do #2, I think. But I'm not certain how to force a window to stay on top until some user interaction has occured? I'm also not clear on how to make a window take up the full screen on all screens. (Think multi-monitor setups)

I want to thank you for the pointers and code you've provided. I'm sure I'm an anoying newb, not quite putting together the perls you're laying down. Any future help is greatly appreciated.

   

You are going to have to work with a bit of appKit there to get the multiple monitors. Take a look at NSScreens. I tried this

struct Screens {

    static func getScreens() -> [NSScreen]{
        return NSScreen.screens
    }

}

for screen in Screens.getScreens() {
    print(screen.frame)
}

I tried that and I got the dimensions of my main screen. The other dimensions are relative to the main screen so in theory setting the the windows you generate to the frame of those values will cover all the screens.

Thats problem 1.

I am not certain how to create these windows on SwiftUI - on my app it just works with the contentview, maybe use windowgroup - there is some mention of that on the web.

So on launch if can create the windows, you need to iterate the screens and create a window on each screen. If you are stuck there I might be able to help. I might need auto window generation in my own app soon.

For the window opacity you need something ike this

  window.opaque = false
    window.backgroundColor = NSColor.clearColor()

Levels are set with window.level. Take the highest from here.

https://developer.apple.com/documentation/appkit/nswindowlevel?language=objc

And to make it borderless take a look at the styleMask

https://developer.apple.com/documentation/appkit/nswindow/stylemask

   

And to ignore events use

var ignoresMouseEvents: Bool { get set } or your machine will be broken.

which you can toggle if the user has hit a key combo.

This is all tricky enough in AppKit where there is more access to the fundamentals of an NSWindow but thats the general Idea I think.

   

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Get started

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.