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
NSScrollView
subclass I have overriddenscrollWheel(with:)
and am returningtrue
from the static propertyisCompatibleWithResponsiveScrolling
in 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
super
and let theNSScrollView
do 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.