HuaTham
HuaTham

Reputation: 7596

Detect Beginning and Ending state of Scroll Wheel event in Cocoa

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?

Upvotes: 2

Views: 1969

Answers (3)

Leonardo
Leonardo

Reputation: 815

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
    }

}

Upvotes: 0

Sentry.co
Sentry.co

Reputation: 5569

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/

Upvotes: 2

Daniyar
Daniyar

Reputation: 3003

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.

Upvotes: 2

Related Questions