From eab67a87c202610c35a2860398edd5d1678a88cf Mon Sep 17 00:00:00 2001 From: Travis Cobbs Date: Wed, 28 Nov 2018 22:52:21 -0800 Subject: [PATCH] Add functionality from discrete-scroll (disabled by default). --- LICENSE-discrete-scroll | 21 +++++++++++ SideButtonFixer/AppDelegate.m | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 LICENSE-discrete-scroll diff --git a/LICENSE-discrete-scroll b/LICENSE-discrete-scroll new file mode 100644 index 0000000..191674b --- /dev/null +++ b/LICENSE-discrete-scroll @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2016 Emre Yolcu + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/SideButtonFixer/AppDelegate.m b/SideButtonFixer/AppDelegate.m index abb2504..4f0c593 100644 --- a/SideButtonFixer/AppDelegate.m +++ b/SideButtonFixer/AppDelegate.m @@ -22,6 +22,9 @@ #import "AppDelegate.h" #import "TouchEvents.h" +#define SIGN(x) (((x) > 0) - ((x) < 0)) +#define SCROLL_LINES 3 + static NSMutableDictionary*>* swipeInfo = nil; static NSArray* nullArray = nil; @@ -36,6 +39,18 @@ static void SBFFakeSwipe(TLInfoSwipeDirection dir) { CFRelease(event2); } +// This logic comes from discrete-scroll (https://github.com/emreyolcu/discrete-scroll), +// which is MIT-licensed by Emre Yolcu. See LICENSE-discrete-scroll. +static CGEventRef SBFScrollCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { + if (!CGEventGetIntegerValueField(event, kCGScrollWheelEventIsContinuous)) { + int64_t delta = CGEventGetIntegerValueField(event, kCGScrollWheelEventPointDeltaAxis1); + + CGEventSetIntegerValueField(event, kCGScrollWheelEventDeltaAxis1, SIGN(delta) * SCROLL_LINES); + } + + return event; +} + static CGEventRef SBFMouseCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { int64_t number = CGEventGetIntegerValueField(event, kCGMouseEventButtonNumber); BOOL down = (CGEventGetType(event) == kCGEventOtherMouseDown); @@ -70,6 +85,7 @@ typedef NS_ENUM(NSInteger, MenuMode) { typedef NS_ENUM(NSInteger, MenuItem) { MenuItemEnabled = 0, + MenuItemAccelDisabled, MenuItemEnabledSeparator, MenuItemTriggerOnMouseDown, MenuItemSwapButtons, @@ -89,6 +105,7 @@ typedef NS_ENUM(NSInteger, MenuItem) { @interface AppDelegate () @property (nonatomic, retain) NSStatusItem* statusItem; @property (nonatomic, assign) CFMachPortRef tap; +@property (nonatomic, assign) CFMachPortRef scrollTap; @property (nonatomic, assign) MenuMode menuMode; @end @@ -102,6 +119,7 @@ @implementation AppDelegate -(void) dealloc { [self startTap:NO]; + [self startScrollTap:NO]; swipeInfo = nil; nullArray = nil; @@ -125,6 +143,7 @@ -(BOOL) applicationShouldHandleReopen:(NSApplication *)sender hasVisibleWindows: -(void) applicationDidFinishLaunching:(NSNotification *)aNotification { [[NSUserDefaults standardUserDefaults] registerDefaults:@{ @"SBFWasEnabled": @YES, + @"SBFAccelWasDisabled": @NO, @"SBFMouseDown": @YES, @"SBFDonated": @NO, @"SBFSwapButtons": @NO @@ -168,6 +187,10 @@ -(void) applicationDidFinishLaunching:(NSNotification *)aNotification { [menu addItem:enabledItem]; assert(menu.itemArray.count - 1 == MenuItemEnabled); + NSMenuItem* accelDisabledItem = [[NSMenuItem alloc] initWithTitle:@"Disable Scroll Wheel Acceleration" action:@selector(accelDisabledToggle:) keyEquivalent:@"a"]; + [menu addItem:accelDisabledItem]; + assert(menu.itemArray.count - 1 == MenuItemAccelDisabled); + [menu addItem:[NSMenuItem separatorItem]]; assert(menu.itemArray.count - 1 == MenuItemEnabledSeparator); @@ -228,6 +251,7 @@ -(void) applicationDidFinishLaunching:(NSNotification *)aNotification { } [self startTap:[[NSUserDefaults standardUserDefaults] boolForKey:@"SBFWasEnabled"]]; + [self startScrollTap:[[NSUserDefaults standardUserDefaults] boolForKey:@"SBFAccelWasDisabled"]]; [self updateMenuMode]; [self refreshSettings]; @@ -261,12 +285,14 @@ -(void) updateMenuMode:(BOOL)active { -(void) refreshSettings { self.statusItem.menu.itemArray[MenuItemEnabled].state = self.tap != NULL && CGEventTapIsEnabled(self.tap); + self.statusItem.menu.itemArray[MenuItemAccelDisabled].state = self.scrollTap != NULL && CGEventTapIsEnabled(self.scrollTap); self.statusItem.menu.itemArray[MenuItemTriggerOnMouseDown].state = [[NSUserDefaults standardUserDefaults] boolForKey:@"SBFMouseDown"]; self.statusItem.menu.itemArray[MenuItemSwapButtons].state = [[NSUserDefaults standardUserDefaults] boolForKey:@"SBFSwapButtons"]; switch (self.menuMode) { case MenuModeAccessibility: self.statusItem.menu.itemArray[MenuItemEnabled].enabled = NO; + self.statusItem.menu.itemArray[MenuItemAccelDisabled].enabled = NO; self.statusItem.menu.itemArray[MenuItemTriggerOnMouseDown].enabled = NO; self.statusItem.menu.itemArray[MenuItemSwapButtons].enabled = NO; self.statusItem.menu.itemArray[MenuItemDonate].hidden = YES; @@ -275,6 +301,7 @@ -(void) refreshSettings { break; case MenuModeDonation: self.statusItem.menu.itemArray[MenuItemEnabled].enabled = YES; + self.statusItem.menu.itemArray[MenuItemAccelDisabled].enabled = YES; self.statusItem.menu.itemArray[MenuItemTriggerOnMouseDown].enabled = YES; self.statusItem.menu.itemArray[MenuItemSwapButtons].enabled = YES; self.statusItem.menu.itemArray[MenuItemDonate].hidden = NO; @@ -283,6 +310,7 @@ -(void) refreshSettings { break; case MenuModeNormal: self.statusItem.menu.itemArray[MenuItemEnabled].enabled = YES; + self.statusItem.menu.itemArray[MenuItemAccelDisabled].enabled = YES; self.statusItem.menu.itemArray[MenuItemTriggerOnMouseDown].enabled = YES; self.statusItem.menu.itemArray[MenuItemSwapButtons].enabled = YES; self.statusItem.menu.itemArray[MenuItemDonate].hidden = YES; @@ -315,6 +343,38 @@ -(void) refreshSettings { } } +// This logic comes from discrete-scroll (https://github.com/emreyolcu/discrete-scroll), +// which is MIT-licensed by Emre Yolcu. See LICENSE-discrete-scroll. +-(void) startScrollTap:(BOOL)start { + if (start) { + if (self.scrollTap == NULL) { + self.scrollTap = CGEventTapCreate(kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + CGEventMaskBit(kCGEventScrollWheel), + &SBFScrollCallback, + NULL); + if (self.scrollTap != NULL) { + CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource(NULL, self.scrollTap, 0); + CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes); + CFRelease(runLoopSource); + + CGEventTapEnable(self.scrollTap, true); + } + } + } + else { + if (self.scrollTap != NULL) { + CGEventTapEnable(self.tap, NO); + CFRelease(self.scrollTap); + + self.scrollTap = NULL; + } + } + + [[NSUserDefaults standardUserDefaults] setBool:self.scrollTap != NULL && CGEventTapIsEnabled(self.scrollTap) forKey:@"SBFAccelWasDisabled"]; +} + -(void) startTap:(BOOL)start { if (start) { if (self.tap == NULL) { @@ -346,6 +406,11 @@ -(void) startTap:(BOOL)start { [[NSUserDefaults standardUserDefaults] setBool:self.tap != NULL && CGEventTapIsEnabled(self.tap) forKey:@"SBFWasEnabled"]; } +-(void) accelDisabledToggle:(id)sender { + [self startScrollTap:self.scrollTap == NULL]; + [self refreshSettings]; +} + -(void) enabledToggle:(id)sender { [self startTap:self.tap == NULL]; [self refreshSettings];