Reputation: 7596
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
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
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
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