In Mavericks, Apple introduced responsive scrolling architecture in NSScrollView. This feature adds a smart way for generating overdraws and decouples handling of the incoming scroll events from the main event loop into a separate one. This topic is described in detail in the session 215 from WWDC 2013.
Because of the different event model, the scroll events no longer go through the scrollWheel(with:) method. In fact, if you override this method in the NSScrollView subclass, you opt-out from the responsive scrolling architecture completely and fall back to the legacy model.
In my NSScrollView I'd like to implement an interaction for magnification using scrolling while holding the command key. This can be observed in MindNode or OmniGraffle apps. The standard way to do this would be overriding scrollWheel(with:) and checking the modifierFlags on each scroll event. As described above, this would cause an opt-out from the responsive scrolling model.
I wonder whether there is a way to implement this interaction while also preserving the responsive scrolling?
What I have already achieved/tried:
- In my
NSScrollViewsubclass I have overriddenscrollWheel(with:)and am returningtruefrom the static propertyisCompatibleWithResponsiveScrollingin order to force the participation in responsive scrolling. - This way I am able to check the first scroll event for the modifier flags. If the command key is NOT pressed, I simply pass the event to
superand let theNSScrollViewdo its thing. If the command key is pressed, I go a different route and track next scroll events on the window to do the magnification. - The problem is when one of these tracking loops is running and the user changes the press state of the command key (either presses it or releases it).
- The switch from magnification to scrolling (on command key release) is simple, since the tracking loop is fully under my control.
- The switch from scrolling to magnification (on command key press) is more tricky, because I cannot check the scroll events. I have overridden
flagsChanged(with:)and can observe when this moment happens but I have not found a way to end the scrolling. This SO question asks about ending/disabling scrolling but has no answer yet.