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 @@
-
+
@@ -196,7 +196,7 @@ Connect a device to begin mapping.
-
+
@@ -208,16 +208,16 @@ Switch back to re-enable input.
-
-
-
+
+
+
-
+
-
+
@@ -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.
-
+
@@ -344,7 +365,7 @@ Switch back to re-enable input.
-
+
@@ -359,8 +380,32 @@ Switch back to re-enable input.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
@@ -416,6 +461,7 @@ Switch back to re-enable input.
+
@@ -472,6 +518,9 @@ Switch back to re-enable input.
+
+
+
@@ -582,7 +631,7 @@ CA
-
+
diff --git a/Resources/Help/Contents/Resources/English.lproj/pgs/mouse.html b/Resources/Help/Contents/Resources/English.lproj/pgs/mouse.html
index f52c5b6..6d26c1e 100644
--- a/Resources/Help/Contents/Resources/English.lproj/pgs/mouse.html
+++ b/Resources/Help/Contents/Resources/English.lproj/pgs/mouse.html
@@ -76,5 +76,21 @@ Scrolling
change this globally in > System Preferences… > Mouse
and > System Preferences… > Trackpad .
+
+ Dragging
+
+ Select the mouse button you'd like the input to simulate while dragging.
+
+
+ Select the direction you'd like the input to move the
+ mouse. Adjust the movement speed using the slider underneath.
+ If you're mapping an analog input then this is the maximum
+ speed; for a button it's a constant speed.
+
+
+ The speed is independent for each input. You can have faster
+ horizontal movement than vertical movement, or map one set of
+ inputs to a fast speed and another set to a slow speed.
+