I have the same need. There is some logic I want to run before a window closes. My SwiftUI window contains a NSViewControllerRepresentable view, and I can set the window delegate inside that NSViewController subclass and implement windowShouldClose:, but that interferes with something SwiftUI sets up and my window's resources are never freed on close. (The window goes away, but re-opening it shows the old window with whatever state it had, instead of instantiating a brand new one.)
Post
Replies
Boosts
Views
Activity
I need to correct my last reply. After looking at my sample app again, it was calling NSWindow.sendEvent(_:). That works, but I should be calling postEvent(_:atStart:). After making that change, the sample app no longer scrolls.
This doesn't appear unique to the VM view. Something more general in AppKit's event handling is rejecting my synthesized scroll event.
Here is some info on where I am with scroll events. Unlike keystrokes, flag changes and mouse clicks, these cannot be created directly as NSEvents, so I have to start with a CGEvent and create the NSEvent from that. There is some math involved to create the CGEvent at the proper location in the VM view in screen coordinates, but I believe I have that worked out.
My local monitor (inside the VM host app) sees the event. Here is a dump of one:
- NSEvent: type=ScrollWheel loc=(50,300) time=903547.3 flags=0 win=0x0 winNum=0 ctxt=0x0 deltaX=0.000000 deltaY=-10.000000 count:0 phase=None momentumPhase=None #0
- super: NSObject
The part that jumps out the most from a real scroll event is that the win and winNum values are nil/zero. CGEvents, as much as I understand, sit at a lower level of the system and have no concept of a window. The conversion to NSEvent either doesn't attempt to identify a window or fails to do so. I've tried various ObjC tricks to assign a window, since in Swift this property is read-only. So far, no luck.
Real scroll events have a window and flow into the VM just fine, where the global monitor there logs them. Synthesized events are dropped somewhere. They work in a sample app without the VM view.
Again, this is an internal tool. It'll never be distributed, Mac App Store or otherwise, so I'm not opposed to some dirty tricks to get this working, even if it means revisiting it when it breaks.
This was the little push I needed. Thank you!
I had tried sythesizing .flagsChanged events equivalent to key-down and key-up for the modifier key, but it didn't make a difference. I revisited it once you confirmed that it mattered.
The flags are a 32-bit bitmask. There are the device independent bits, which are documented for each of the modifier keys plus some others, in the upper 16 bits. The lower 16 bits are not documented, but if you attach a monitor, you'll notice some are set. In particular, bits 3 and 8 (0x108) are set when the modifier key is pressed down, and bit 8 (0x100) is still set when the modifier is released.
I turned my synthesized .keyDown/.keyUp pair into a sequence of .flagsChanged with 0x108 set for each modifier, .keyDown, .keyUp, .flagsChanged with 0x100 set. Injecting this sequence of events produces the desired behavior in the VM. Success!
I don't like needing to set these undocumented bits, but my use case is for an internal tool and I can live with it. (Perhaps they can be documented and become part of the public API?)
Now I'm hoping we can find a similar breakthrough for scroll wheel events! 😄
The VZVirtualMachineView is in a view hierarchy managed by an NSViewController subclass that is wrapped in NSViewControllerRepresentable, but I doubt that matters, so yes, mostly correct.
I have tried both true and false for capturesSystemKeys and it does not change the behavior seen in the VM.
Mouse scroll wheel events are similar. Real ones from my mouse scroll content in the VM, synthetic ones never show up in the global monitor in the VM and nothing happens.
Speaking of docs, I should be using NSWindow.postEvent(_:atStart:). Doing that instead now triggers the local monitor, but modified keystrokes still appear in the VM without modifiers and scroll wheel events don't do anything. The latter may be due to how I have to start with a CGEvent since NSEvent doesn't have direct support for creating scroll wheel events.
Yes, it does. "Create Info.plist section in binary" is set to true. Same bundle ID when run inside Xcode or standalone.
I have a project that shows the same error when running tests on macOS. I isolated the problem in a sample project yesterday and attached it to my feedback (FB11992869). The commit that broke it added the Keychain Sharing entitlement, which, unfortunately, is required for some of the tests.