diff --git a/Classes/NJOutput.m b/Classes/NJOutput.m index bf9e2e8..2bc723b 100644 --- a/Classes/NJOutput.m +++ b/Classes/NJOutput.m @@ -12,6 +12,7 @@ #import "NJOutputMouseMove.h" #import "NJOutputMouseButton.h" #import "NJOutputMouseScroll.h" +#import "NJOutputMouseDrag.h" @implementation NJOutput { BOOL running; @@ -45,7 +46,8 @@ + (NJOutput *)outputWithSerialization:(NSDictionary *)serialization { NJOutputMapping.class, NJOutputMouseMove.class, NJOutputMouseButton.class, - NJOutputMouseScroll.class + NJOutputMouseScroll.class, + NJOutputMouseDrag.class ]) { if ([type isEqualToString:cls.serializationCode]) return [cls outputWithSerialization:serialization]; diff --git a/Classes/NJOutputMouseDrag.h b/Classes/NJOutputMouseDrag.h new file mode 100644 index 0000000..28ba9d8 --- /dev/null +++ b/Classes/NJOutputMouseDrag.h @@ -0,0 +1,16 @@ +// +// NJOutputMouseDrag.h +// Enjoyable +// +// Created by Giovanni Muzzolini on 09/10/20. +// + +#import "NJOutput.h" + +@interface NJOutputMouseDrag : NJOutput + +@property (nonatomic, assign) CGMouseButton button; +@property (nonatomic, assign) int axis; +@property (nonatomic, assign) float speed; + +@end diff --git a/Classes/NJOutputMouseDrag.m b/Classes/NJOutputMouseDrag.m new file mode 100644 index 0000000..5878356 --- /dev/null +++ b/Classes/NJOutputMouseDrag.m @@ -0,0 +1,108 @@ +// +// NJOutputMouseDrag.m +// Enjoyable +// +// Created by Giovanni Muzzolini on 09/10/20. +// + +#import "NJOutputMouseDrag.h" + +#import "NJInputController.h" + +@implementation NJOutputMouseDrag + ++ (NSString *)serializationCode { + return @"mouse drag"; +} + +- (NSDictionary *)serialize { + return @{ @"type": self.class.serializationCode, + @"axis": @(_axis), + @"speed": @(_speed), + @"button": @(_button) + }; +} + ++ (NJOutput *)outputWithSerialization:(NSDictionary *)serialization { + NJOutputMouseDrag *output = [[NJOutputMouseDrag alloc] init]; + output.axis = [serialization[@"axis"] intValue]; + output.speed = [serialization[@"speed"] floatValue]; + output.button = [serialization[@"button"] intValue]; + if (output.speed == 0) + output.speed = 10; + return output; +} + +- (BOOL)isContinuous { + return YES; +} + +#define CLAMP(a, l, h) MIN(h, MAX(a, l)) + +- (BOOL)update:(NJInputController *)ic { + + if (self.magnitude < 0.05) + return NO; // dead zone + + CGFloat height = NSScreen.mainScreen.frame.size.height; + NSPoint clickLoc = NSEvent.mouseLocation; + + if(!CGEventSourceButtonState(kCGEventSourceStateHIDSystemState, _button)){ + + // trigger mouseDown + + CGEventType downEventType = _button == kCGMouseButtonLeft ? kCGEventLeftMouseDown + : _button == kCGMouseButtonRight ? kCGEventRightMouseDown + : kCGEventOtherMouseDown; + + CGEventRef down = CGEventCreateMouseEvent(NULL, + downEventType, + CGPointMake(clickLoc.x, height - clickLoc.y), + _button); + CGEventSetIntegerValueField(down, kCGMouseEventClickState, 1); + CGEventPost(kCGHIDEventTap, down); + CFRelease(down); + + } + + CGSize size = NSScreen.mainScreen.frame.size; + + CGFloat dx = 0, dy = 0; + switch (_axis) { + case 0: + dx = -self.magnitude * _speed; + break; + case 1: + dx = self.magnitude * _speed; + break; + case 2: + dy = -self.magnitude * _speed; + break; + case 3: + dy = self.magnitude * _speed; + break; + } + NSPoint mouseLoc = ic.mouseLoc; + mouseLoc.x = CLAMP(mouseLoc.x + dx, 0, size.width - 1); + mouseLoc.y = CLAMP(mouseLoc.y - dy, 0, size.height - 1); + ic.mouseLoc = mouseLoc; + + // trigger mouseDrag + + CGEventType eventType = _button == kCGMouseButtonLeft ? kCGEventLeftMouseDragged + : _button == kCGMouseButtonRight ? kCGEventRightMouseDragged + : kCGEventOtherMouseDragged; + + CGEventRef drag = CGEventCreateMouseEvent(NULL, eventType, + CGPointMake(mouseLoc.x, size.height - mouseLoc.y), + _button); + CGEventSetIntegerValueField(drag, kCGMouseEventDeltaX, (int)dx); + CGEventSetIntegerValueField(drag, kCGMouseEventDeltaY, (int)dy); + CGEventPost(kCGHIDEventTap, drag); + + CFRelease(drag); + + return YES; +} + +@end diff --git a/Classes/NJOutputViewController.h b/Classes/NJOutputViewController.h index 7e35b70..143e04e 100644 --- a/Classes/NJOutputViewController.h +++ b/Classes/NJOutputViewController.h @@ -27,6 +27,9 @@ @property (nonatomic, strong) IBOutlet NSPopUpButton *mappingPopup; @property (nonatomic, strong) IBOutlet NSButton *smoothCheck; @property (nonatomic, strong) IBOutlet NSButton *unknownMapping; +@property (nonatomic, strong) IBOutlet NSSegmentedControl *dragBtnSelect; +@property (nonatomic, strong) IBOutlet NSSegmentedControl *dragDirSelect; +@property (nonatomic, strong) IBOutlet NSSlider *dragSpeedSlider; @property (nonatomic, weak) IBOutlet id delegate; @@ -40,6 +43,9 @@ - (IBAction)mouseSpeedChanged:(id)sender; - (IBAction)scrollSpeedChanged:(id)sender; - (IBAction)scrollTypeChanged:(id)sender; +- (IBAction)dragButtonChanged:(id)sender; +- (IBAction)dragDirectionChanged:(id)sender; +- (IBAction)dragSpeedChanged:(id)sender; @end diff --git a/Classes/NJOutputViewController.m b/Classes/NJOutputViewController.m index 1c5bb72..f7d6e9a 100644 --- a/Classes/NJOutputViewController.m +++ b/Classes/NJOutputViewController.m @@ -18,6 +18,7 @@ #import "NJOutputMouseButton.h" #import "NJOutputMouseMove.h" #import "NJOutputMouseScroll.h" +#import "NJOutputMouseDrag.h" @implementation NJOutputViewController { NJInput *_input; @@ -80,6 +81,20 @@ - (void)cleanUpInterface { if (self.scrollDirSelect.selectedSegment == -1) self.scrollDirSelect.selectedSegment = 0; } + + if (row != 6) { + self.dragDirSelect.selectedSegment = -1; + self.dragSpeedSlider.doubleValue = self.dragSpeedSlider.minValue; + self.dragBtnSelect.selectedSegment = -1; + [self.dragDirSelect resignIfFirstResponder]; + } else { + if (self.dragDirSelect.selectedSegment == -1) + self.dragDirSelect.selectedSegment = 0; + if (self.dragSpeedSlider.floatValue == 0) + self.dragSpeedSlider.floatValue = 10; + if (self.dragBtnSelect.selectedSegment == -1) + self.dragBtnSelect.selectedSegment = 0; + } } @@ -153,6 +168,24 @@ - (IBAction)scrollTypeChanged:(NSButton *)sender { [self commit]; } +- (void)dragButtonChanged:(NSView *)sender { + [self.radioButtons selectCellAtRow:6 column:0]; + [sender.window makeFirstResponder:sender]; + [self commit]; +} + +- (void)dragDirectionChanged:(NSView *)sender { + [self.radioButtons selectCellAtRow:6 column:0]; + [sender.window makeFirstResponder:sender]; + [self commit]; +} + +- (void)dragSpeedChanged:(NSSlider *)sender { + [self.radioButtons selectCellAtRow:6 column:0]; + [sender.window makeFirstResponder:sender]; + [self commit]; +} + - (NJOutput *)makeOutput { switch (self.radioButtons.selectedRow) { case 0: @@ -190,6 +223,13 @@ - (NJOutput *)makeOutput { ms.smooth = self.smoothCheck.state == NSOnState; return ms; } + case 6: { + NJOutputMouseDrag *md = [[NJOutputMouseDrag alloc] init]; + md.axis = (int)self.dragDirSelect.selectedSegment; + md.speed = self.dragSpeedSlider.floatValue; + md.button = (int)[self.dragBtnSelect.cell tagForSegment:self.dragBtnSelect.selectedSegment]; + return md; + } default: return nil; } @@ -216,6 +256,9 @@ - (void)setEnabled:(BOOL)enabled { self.scrollDirSelect.enabled = enabled; self.smoothCheck.enabled = enabled; self.scrollSpeedSlider.enabled = enabled && self.smoothCheck.state; + self.dragDirSelect.enabled = enabled; + self.dragSpeedSlider.enabled = enabled; + self.dragBtnSelect.enabled = enabled; if (!enabled) self.unknownMapping.hidden = YES; } @@ -263,6 +306,12 @@ - (void)loadOutput:(NJOutput *)output forInput:(NJInput *)input { self.scrollSpeedSlider.floatValue = speed; self.smoothCheck.state = smooth ? NSOnState : NSOffState; self.scrollSpeedSlider.enabled = smooth; + } + else if ([output isKindOfClass:NJOutputMouseDrag.class]) { + [self.radioButtons selectCellAtRow:6 column:0]; + self.dragDirSelect.selectedSegment = [(NJOutputMouseDrag *)output axis]; + self.dragSpeedSlider.floatValue = [(NJOutputMouseDrag *)output speed]; + [self.dragBtnSelect selectSegmentWithTag:[(NJOutputMouseDrag *)output button]]; } else { [self.radioButtons selectCellAtRow:self.enabled ? 0 : -1 column:0]; } diff --git a/Enjoyable.xcodeproj/project.pbxproj b/Enjoyable.xcodeproj/project.pbxproj index 3a213e8..3807ce3 100644 --- a/Enjoyable.xcodeproj/project.pbxproj +++ b/Enjoyable.xcodeproj/project.pbxproj @@ -52,6 +52,7 @@ EEF17D6A16E8E2EF00D7DC4D /* NJOutputMouseButton.m in Sources */ = {isa = PBXBuildFile; fileRef = EEF17D5716E8E2EF00D7DC4D /* NJOutputMouseButton.m */; }; EEF17D6B16E8E2EF00D7DC4D /* NJOutputMouseMove.m in Sources */ = {isa = PBXBuildFile; fileRef = EEF17D5916E8E2EF00D7DC4D /* NJOutputMouseMove.m */; }; EEF17D6C16E8E2EF00D7DC4D /* NJOutputMouseScroll.m in Sources */ = {isa = PBXBuildFile; fileRef = EEF17D5B16E8E2EF00D7DC4D /* NJOutputMouseScroll.m */; }; + F279F40125305D3D00676675 /* NJOutputMouseDrag.m in Sources */ = {isa = PBXBuildFile; fileRef = F279F40025305D3D00676675 /* NJOutputMouseDrag.m */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -150,6 +151,8 @@ EEF17D5916E8E2EF00D7DC4D /* NJOutputMouseMove.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJOutputMouseMove.m; path = Classes/NJOutputMouseMove.m; sourceTree = ""; }; EEF17D5A16E8E2EF00D7DC4D /* NJOutputMouseScroll.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NJOutputMouseScroll.h; path = Classes/NJOutputMouseScroll.h; sourceTree = ""; }; EEF17D5B16E8E2EF00D7DC4D /* NJOutputMouseScroll.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJOutputMouseScroll.m; path = Classes/NJOutputMouseScroll.m; sourceTree = ""; }; + F279F3FF25305CFA00676675 /* NJOutputMouseDrag.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = NJOutputMouseDrag.h; path = Classes/NJOutputMouseDrag.h; sourceTree = ""; }; + F279F40025305D3D00676675 /* NJOutputMouseDrag.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = NJOutputMouseDrag.m; path = Classes/NJOutputMouseDrag.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -323,6 +326,8 @@ EEF17D5916E8E2EF00D7DC4D /* NJOutputMouseMove.m */, EEF17D5A16E8E2EF00D7DC4D /* NJOutputMouseScroll.h */, EEF17D5B16E8E2EF00D7DC4D /* NJOutputMouseScroll.m */, + F279F3FF25305CFA00676675 /* NJOutputMouseDrag.h */, + F279F40025305D3D00676675 /* NJOutputMouseDrag.m */, ); name = Output; sourceTree = ""; @@ -465,6 +470,7 @@ EEF17D3616E8E2E100D7DC4D /* NSMutableArray+MoveObject.m in Sources */, EEF17D3716E8E2E100D7DC4D /* NSString+FixFilename.m in Sources */, EEF17D3816E8E2E100D7DC4D /* NSView+FirstResponder.m in Sources */, + F279F40125305D3D00676675 /* NJOutputMouseDrag.m in Sources */, EEF17D5C16E8E2EF00D7DC4D /* EnjoyableApplicationDelegate.m in Sources */, EEF17D5D16E8E2EF00D7DC4D /* NJDevice.m in Sources */, EEF17D5E16E8E2EF00D7DC4D /* NJInputController.m in Sources */, diff --git a/Info.plist b/Info.plist index a5366c0..1b14995 100644 --- a/Info.plist +++ b/Info.plist @@ -46,7 +46,7 @@ CFBundleSignature ???? CFBundleVersion - 663 + 673 LSApplicationCategoryType public.app-category.utilities NSHumanReadableCopyright diff --git a/Resources/English.lproj/MainMenu.xib b/Resources/English.lproj/MainMenu.xib index a7ef96c..8853f3b 100644 --- a/Resources/English.lproj/MainMenu.xib +++ b/Resources/English.lproj/MainMenu.xib @@ -1,14 +1,14 @@ - - + + - + - + @@ -129,26 +129,26 @@ - + - - + + - + - + - + - + @@ -185,7 +185,7 @@ - - - + + + - + - + @@ -226,7 +226,7 @@ Switch back to re-enable input. - + @@ -261,6 +261,10 @@ Switch back to re-enable input. + + + + @@ -268,23 +272,23 @@ Switch back to re-enable input. - + - + - + - + @@ -292,7 +296,7 @@ Switch back to re-enable input. - + @@ -308,8 +312,25 @@ Switch back to re-enable input. + + + + + + + + + + + + + + + + + - + @@ -317,7 +338,7 @@ Switch back to re-enable input. - + @@ -333,7 +354,7 @@ Switch back to re-enable input. - + @@ -359,8 +380,32 @@ Switch back to re-enable input. + + + + + + + + + + + + + + + + + + + + + + + +