2

Cocoa provides many useful methods to detect the beginning and ending states of gestures and mouse clicks. For mouse clicks, we can easily override mouseDown: and mouseUp: methods. However, we don't seem to have a way to do the same for mouse scrolling event -- we are only provided with scrollWheel: method which is activated when scrolling happens.

I have tried beginGestureWithEvent: but it only responds to touch events.

Is there a way to detect the beginning and the ending states of mouse scrolling in Cocoa?

HuaTham
  • 7,486
  • 5
  • 31
  • 50

3 Answers3

2

As I see there's no such a simple solution. But you still can do this.

The most evident is using timer to check when the wheel did scroll last time. I prefer using lightweight GCD-timers for this purposes (they also ARC-capable objects instead of NSTimer's which are storing strong target-references).

- (void) scrollWheel:(NSEvent *)event
{
  _lastStamp = mach_absolute_time(); // get current timestamp
  if (!_running)
  {
    if (!_timer)
      [self createTimerSource];
    if (!_running)
      dispatch_resume(_timer); 
    _running = YES;
  }
}

- (void)createTimerSource
{
  NSTimeInterval timeout = ...;
  _timer=dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _timerQueue);
  dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, timeout * NSEC_PER_SEC, 0);
  // set the event handler
  dispatch_source_set_event_handler(_timer, ^{
     uint64_t stamp = mach_absolute_time(); // current stamp
     if (stamp - _lastStamp > some_tolerance_value)
     {
       // wheel did end scroll
       if (_running)
         dispatch_source_cancel(_timer);
       _running = NO;
     }
  });
}

Check the article out to know more about Dispatch Sources.

Daniyar
  • 2,975
  • 2
  • 26
  • 39
  • Thank you for the approach. I can see now that it's possible to do but not sure if this is the best answer. I upvote your answer for appreciation. – HuaTham Apr 07 '15 at 09:08
2

The best way I've found to detect onScrollWheelDown and onScrollWheelUp is to use event.phase == MayBegin for onDown event.phase == Cancelled and event.phase == Ended for onUp. This even works when your gesture goes off the trackpad and should work for MagicMouse as well. I Will test the MagicMouse later.

You can read a more in-depth analysis of how I came to this conclusion here: http://stylekit.org/blog/2016/02/28/Scroll-wheel/

Sentry.co
  • 5,355
  • 43
  • 38
0

I solved the problem with these 2 lines of code

- (void)scrollWheel:(NSEvent*)theEvent
{
    BOOL    begin = theEvent.phase & NSEventPhaseBegan;
    BOOL    end   = theEvent.phase & NSEventPhaseEnded || theEvent.momentumPhase & NSEventPhaseEnded;

    if(begin){
       // do something when the scroll begins
       // as store some initial value
    }
    else if(end)
    {
        //... do something when the scroll ends
    }
    else{
       //... do something when scrolling
    }

}
Leonardo
  • 751
  • 8
  • 15
  • For me theEvent.phase and theEvent.momentumPhase are always always 0 . Any idea why ? can this happen because i'm not using Apple mouse ? – user1105951 Oct 16 '22 at 11:37
  • May be. It could depend on the macOS version too. I can tell you that it works with the trackpad on my MacBook Pro with macOS 12.6.1. – Leonardo Nov 03 '22 at 20:34