├── .gitignore ├── LICENSE ├── README.md ├── jitouch ├── Jitouch │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── CursorView.h │ ├── CursorView.m │ ├── CursorWindow.h │ ├── CursorWindow.m │ ├── Gesture.h │ ├── Gesture.m │ ├── GestureView.h │ ├── GestureView.m │ ├── GestureWindow.h │ ├── GestureWindow.m │ ├── Info.plist │ ├── Jitouch.xcodeproj │ │ ├── project.pbxproj │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ └── Jitouch.xcscheme │ ├── JitouchAppDelegate.h │ ├── JitouchAppDelegate.m │ ├── Jitouch_Prefix.pch │ ├── KeyUtility.h │ ├── KeyUtility.m │ ├── Settings.h │ ├── Settings.m │ ├── SizeHistory.h │ ├── SizeHistory.m │ ├── SystemEvents.h │ ├── SystemPreferences.h │ └── main.m ├── circle.png ├── instructions │ ├── instructions.html │ ├── step1.png │ ├── step2.png │ ├── step3.png │ ├── step4.png │ └── step5.png ├── jitouchicon.icns ├── logosmall.png ├── logosmall@2x.png ├── logosmalloff.png ├── logosmalloff@2x.png ├── move.png ├── resize.png └── tab.png └── prefpane ├── ApplicationButton.h ├── ApplicationButton.m ├── AutoSetDelegate.h ├── AutoSetDelegate.m ├── Base.lproj └── JitouchPref.xib ├── CommandTableView.h ├── CommandTableView.m ├── GesturePreviewView.h ├── GesturePreviewView.m ├── GestureTableView.h ├── GestureTableView.m ├── ImageAndTextCell.h ├── ImageAndTextCell.m ├── Info.plist ├── Jitouch.xcodeproj └── project.pbxproj ├── JitouchPref.h ├── JitouchPref.m ├── JitouchPref.png ├── JitouchPref@2x.png ├── KeyTextField.h ├── KeyTextField.m ├── KeyTextView.h ├── KeyTextView.m ├── LinkTextField.h ├── LinkTextField.m ├── MAAttachedWindow.h ├── MAAttachedWindow.m ├── MagicMouseTab.h ├── MagicMouseTab.m ├── RecognitionTab.h ├── RecognitionTab.m ├── Settings.h ├── Settings.m ├── TrackpadTab.h ├── TrackpadTab.m ├── jitouchicon.icns └── version.plist /.gitignore: -------------------------------------------------------------------------------- 1 | project.xcworkspace 2 | xcuserdata 3 | /prefpane/Jitouch.app 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jitouch 2 | 3 | **Jitouch** is a Mac application that expands the set of multi-touch gestures for MacBook, Magic Mouse, and Magic Trackpad. These thoughtfully designed gestures enable users to perform frequent tasks more easily such as changing tabs in web browsers, closing windows, minimizing windows, changing spaces, and a lot more. 4 | 5 | For more details, see https://www.jitouch.com/. 6 | 7 | ## How to run 8 | 9 | 1. Open jitouch/Jitouch/Jitouch.xcodeproj in Xcode and build the project. This will create Jitouch.app in the prefpane folder. For the highest performance, set the Build Configuration to Release. 10 | 2. Open prefpane/Jitouch.xcodeproj in Xcode and build the project. This will create Jitouch.prefPane. 11 | 3. Double-click Jitouch.prefPane to install Jitouch. 12 | 13 | ## License 14 | 15 | Copyright (c) Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 16 | 17 | Licensed under the [GNU General Public License v3.0](LICENSE). 18 | -------------------------------------------------------------------------------- /jitouch/Jitouch/CursorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CursorView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface CursorView : NSView { 11 | NSImage *moveImage; 12 | NSImage *resizeImage; 13 | NSImage *tabImage; 14 | } 15 | 16 | @property (nonatomic, retain) NSImage *moveImage; 17 | @property (nonatomic, retain) NSImage *resizeImage; 18 | @property (nonatomic, retain) NSImage *tabImage; 19 | 20 | @end 21 | 22 | extern int cursorImageType; 23 | -------------------------------------------------------------------------------- /jitouch/Jitouch/CursorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CursorView.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "CursorView.h" 9 | 10 | int cursorImageType; 11 | 12 | @implementation CursorView 13 | 14 | @synthesize moveImage; 15 | @synthesize resizeImage; 16 | @synthesize tabImage; 17 | 18 | - (id)initWithFrame:(NSRect)frameRect{ 19 | if (self = [super initWithFrame:frameRect]) { 20 | self.moveImage = [NSImage imageNamed:@"move"]; 21 | self.resizeImage = [NSImage imageNamed:@"resize"]; 22 | self.tabImage = [NSImage imageNamed:@"tab"]; 23 | } 24 | return self; 25 | } 26 | 27 | - (void)drawRect:(NSRect)rect { 28 | [[NSColor clearColor] set]; 29 | NSRectFill(self.frame); 30 | NSImage *image = nil; 31 | if (cursorImageType == 0) { 32 | image = moveImage; 33 | } else if (cursorImageType == 1) { 34 | image = resizeImage; 35 | } else if (cursorImageType == 2) { 36 | image = tabImage; 37 | } 38 | [image drawAtPoint:NSZeroPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 39 | [[self window] setHasShadow:NO]; 40 | } 41 | 42 | - (void)dealloc { 43 | [moveImage release]; 44 | [resizeImage release]; 45 | [tabImage release]; 46 | [super dealloc]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /jitouch/Jitouch/CursorWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // CursorWindow.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface CursorWindow : NSWindow { 11 | NSView *cursorView; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /jitouch/Jitouch/CursorWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // CursorWindow.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "CursorWindow.h" 9 | #import "CursorView.h" 10 | 11 | @implementation CursorWindow 12 | 13 | - (id)init { 14 | self = [super initWithContentRect:NSMakeRect(0.0, 0.0, 100.0, 100.0) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 15 | if (self != nil) { 16 | self.alphaValue = 1.0; 17 | self.opaque = NO; 18 | self.backgroundColor = [NSColor clearColor]; 19 | 20 | cursorView = [[CursorView alloc] initWithFrame:[self frame]]; 21 | [self setContentView:cursorView]; 22 | } 23 | return self; 24 | } 25 | 26 | - (void)drawRect:(NSRect)dirtyRect { 27 | } 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Gesture.h: -------------------------------------------------------------------------------- 1 | // 2 | // Gesture.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface Gesture : NSObject 11 | 12 | - (id)init; 13 | 14 | @end 15 | 16 | void turnOffGestures(void); 17 | -------------------------------------------------------------------------------- /jitouch/Jitouch/GestureView.h: -------------------------------------------------------------------------------- 1 | // 2 | // GestureView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface GestureView : NSView { 11 | NSMutableArray *points; 12 | char hintText[20]; 13 | } 14 | - (void)setHintText:(const char*)str; 15 | - (void)addPointX:(float)x Y:(float)y; 16 | - (void)addRelativePointX:(float)x Y:(float)y; 17 | - (void)clear; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /jitouch/Jitouch/GestureView.m: -------------------------------------------------------------------------------- 1 | // 2 | // GestureView.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "GestureView.h" 9 | 10 | @implementation GestureView 11 | 12 | - (id)initWithFrame:(NSRect)frame { 13 | self = [super initWithFrame:frame]; 14 | if (self) { 15 | points = [[NSMutableArray alloc] init]; 16 | } 17 | return self; 18 | } 19 | 20 | - (void)drawRect:(NSRect)dirtyRect { 21 | [[NSColor clearColor] set]; 22 | NSRectFill([self frame]); 23 | 24 | CGContextRef context = [[NSGraphicsContext currentContext]graphicsPort]; 25 | 26 | if ([points count] > 0) { 27 | NSPoint currentPoint; 28 | CGContextSetLineWidth(context, 12.0); 29 | 30 | currentPoint = [[points objectAtIndex:0] pointValue]; 31 | CGContextSetRGBStrokeColor(context, 0.7, 0, 0, 0.6); 32 | CGContextStrokeEllipseInRect(context, CGRectMake(currentPoint.x-15, currentPoint.y-15, 30, 30)); 33 | 34 | CGContextSetRGBStrokeColor(context, 1, 1, 1, 0.3); 35 | CGContextSetLineCap(context, kCGLineCapRound); 36 | CGContextSetLineJoin(context, kCGLineJoinRound); 37 | 38 | NSPoint startPoint = [[points objectAtIndex:0] pointValue]; 39 | CGContextMoveToPoint(context, startPoint.x, startPoint.y); 40 | float minX = 10000, minY = 10000; 41 | for (NSUInteger i = 1; i < [points count]; i++) { 42 | currentPoint = [[points objectAtIndex:i] pointValue]; 43 | CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y); 44 | if (currentPoint.x < minX) 45 | minX = currentPoint.x; 46 | if (currentPoint.y < minY) 47 | minY = currentPoint.y; 48 | } 49 | CGContextStrokePath(context); 50 | 51 | CGContextSetLineWidth(context, 10.0); 52 | CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.6); 53 | CGContextMoveToPoint(context, startPoint.x, startPoint.y); 54 | for (NSUInteger i = 1; i < [points count]; i++) { 55 | currentPoint = [[points objectAtIndex:i] pointValue]; 56 | CGContextAddLineToPoint(context, currentPoint.x, currentPoint.y); 57 | } 58 | CGContextStrokePath(context); 59 | 60 | [[NSString stringWithUTF8String:hintText] 61 | drawAtPoint:CGPointMake(minX, minY - 70.0) 62 | withAttributes:@{ 63 | NSFontAttributeName: [NSFont systemFontOfSize:40.0], 64 | NSForegroundColorAttributeName: [NSColor colorWithRed:0.7 green:0.0 blue:0.0 alpha:0.5] 65 | }]; 66 | } 67 | } 68 | 69 | - (void)addPointX:(float)x Y:(float)y { 70 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 71 | 72 | CGFloat width = [self frame].size.width - 30 - 150; 73 | CGFloat height = [self frame].size.height - 30 - 100; 74 | 75 | NSValue *point = [NSValue valueWithPoint:NSMakePoint(x*width + 15, y*height + 15 + 100)]; 76 | [points addObject:point]; 77 | [pool release]; 78 | 79 | [self setNeedsDisplay:YES]; 80 | } 81 | 82 | - (void)addRelativePointX:(float)x Y:(float)y { 83 | CGFloat width = [self frame].size.width; 84 | CGFloat height = [self frame].size.height; 85 | 86 | NSValue *point = [NSValue valueWithPoint:NSMakePoint(width/2 + x, height/2 + y)]; 87 | [points addObject:point]; 88 | [self setNeedsDisplay:YES]; 89 | } 90 | 91 | - (void)clear { 92 | [points removeAllObjects]; 93 | [self setNeedsDisplay:YES]; 94 | } 95 | 96 | - (void)setHintText:(const char*)str { 97 | strcpy(hintText, str); 98 | } 99 | 100 | - (void)dealloc { 101 | [points release]; 102 | [super dealloc]; 103 | } 104 | 105 | @end 106 | -------------------------------------------------------------------------------- /jitouch/Jitouch/GestureWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // GestureWindow.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class GestureView; 11 | 12 | @interface GestureWindow : NSWindow { 13 | GestureView *gestureView; 14 | NSTextField *tf; 15 | } 16 | - (void)setHintText:(const char*)str; 17 | - (void)addPointX:(float)x Y:(float)y; 18 | - (void)addRelativePointX:(float)x Y:(float)y; 19 | - (void)clear; 20 | - (void)refresh; 21 | - (void)setPossibleAlphabet:(NSString*)a; 22 | - (void)setUpWindowForTrackpad; 23 | - (void)setUpWindowForMagicMouse; 24 | @end 25 | -------------------------------------------------------------------------------- /jitouch/Jitouch/GestureWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // GestureWindow.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "GestureWindow.h" 9 | #import "GestureView.h" 10 | 11 | @implementation GestureWindow 12 | 13 | static float trackpadWidth = 400 + 150; 14 | static float trackpadHeight = 300 + 100; 15 | 16 | static float magicMouseWidth = 800; 17 | static float magicMouseHeight = 800; 18 | 19 | - (id)init { 20 | NSSize size = [[NSScreen mainScreen] frame].size; 21 | self = [super initWithContentRect:NSMakeRect(size.width/2 - trackpadWidth/2, size.height/2 - trackpadHeight/2, trackpadWidth, trackpadHeight) styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO]; 22 | if (self != nil) { 23 | self.alphaValue = 1.0; 24 | self.opaque = NO; 25 | self.backgroundColor = [NSColor clearColor]; 26 | 27 | gestureView = [[GestureView alloc] initWithFrame:[self frame]]; 28 | [self setContentView:gestureView]; 29 | } 30 | return self; 31 | } 32 | - (void)setUpWindowForTrackpad { 33 | NSArray *arr = [NSScreen screens]; 34 | CGEventRef ourEvent = CGEventCreate(NULL); 35 | CGPoint location = CGEventGetUnflippedLocation(ourEvent); 36 | CFRelease(ourEvent); 37 | 38 | NSRect scr; 39 | NSPoint orig; 40 | NSSize size; 41 | int isIn = 0; 42 | for (int i = 0; i<[arr count]; i++) { 43 | scr = [[arr objectAtIndex:i] frame]; 44 | orig = scr.origin; 45 | size = scr.size; 46 | 47 | if (location.x >= orig.x && location.x <= orig.x + size.width && 48 | location.y >= orig.y && location.y <= orig.y + size.height) { 49 | isIn = i; 50 | break; 51 | } 52 | } 53 | scr = [[arr objectAtIndex:isIn] frame]; 54 | orig = scr.origin; 55 | size = scr.size; 56 | [self setFrame:NSMakeRect(orig.x+size.width/2 - trackpadWidth/2, orig.y+size.height/2 - trackpadHeight/2, trackpadWidth, trackpadHeight) display:YES]; 57 | } 58 | - (void)setUpWindowForMagicMouse { 59 | CGEventRef ourEvent = CGEventCreate(NULL); 60 | CGPoint ourLoc = CGEventGetUnflippedLocation(ourEvent); 61 | CFRelease(ourEvent); 62 | [self setFrame:NSMakeRect(ourLoc.x - magicMouseWidth/2, ourLoc.y - magicMouseHeight/2, magicMouseWidth, magicMouseHeight) display:YES]; 63 | 64 | } 65 | - (void)setPossibleAlphabet:(NSString*)a { 66 | [tf setStringValue:a]; 67 | } 68 | 69 | - (void)drawRect:(NSRect)dirtyRect { 70 | } 71 | 72 | - (void)addPointX:(float)x Y:(float)y { 73 | [gestureView addPointX:x Y:y]; 74 | } 75 | - (void)addRelativePointX:(float)x Y:(float)y { 76 | [gestureView addRelativePointX:x Y:y]; 77 | } 78 | - (void)clear { 79 | [gestureView clear]; 80 | } 81 | 82 | - (void)refresh { 83 | [gestureView setNeedsDisplay:YES]; 84 | } 85 | - (void)setHintText:(const char*)str { 86 | [gestureView setHintText:str]; 87 | [self refresh]; 88 | } 89 | 90 | - (void)dealloc { 91 | [tf release]; 92 | [super dealloc]; 93 | } 94 | 95 | @end 96 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | jitouchicon.icns 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSAppleEventsUsageDescription 28 | 29 | NSHumanReadableCopyright 30 | Copyright © 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 31 | NSMainNibFile 32 | MainMenu 33 | NSPrincipalClass 34 | NSApplication 35 | NSUIElement 36 | 1 37 | 38 | 39 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Jitouch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1B11012910EF486500FF904B /* GestureView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B11012810EF486500FF904B /* GestureView.m */; }; 11 | 1B20007810EE9AD800A75EEC /* GestureWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B20007710EE9AD800A75EEC /* GestureWindow.m */; }; 12 | 1B4F3CC710AA45500062367C /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B4F3CC610AA45500062367C /* Settings.m */; }; 13 | 1B981CE410916F5400652C8F /* CursorWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B981CE310916F5400652C8F /* CursorWindow.m */; }; 14 | 1B981CF11091713E00652C8F /* CursorView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B981CF01091713E00652C8F /* CursorView.m */; }; 15 | 1BF5AA6F10790134000CF532 /* Gesture.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BF5AA6E10790134000CF532 /* Gesture.m */; }; 16 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; 17 | 256AC3DA0F4B6AC300CF3369 /* JitouchAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* JitouchAppDelegate.m */; }; 18 | 7B24200A15F945D000EDAD3D /* logosmall@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7B24200815F945D000EDAD3D /* logosmall@2x.png */; }; 19 | 7B24200B15F945D000EDAD3D /* logosmalloff@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7B24200915F945D000EDAD3D /* logosmalloff@2x.png */; }; 20 | 7B703DB7262EBEA6002157DD /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DB6262EBEA6002157DD /* Cocoa.framework */; }; 21 | 7B703DB9262EBEAB002157DD /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DB8262EBEAB002157DD /* Carbon.framework */; }; 22 | 7B703DBB262EBEB2002157DD /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DBA262EBEB1002157DD /* IOKit.framework */; }; 23 | 7B703DBD262EBEB7002157DD /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DBC262EBEB7002157DD /* ScriptingBridge.framework */; }; 24 | 7B703DBF262EBED6002157DD /* MultitouchSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DBE262EBED6002157DD /* MultitouchSupport.framework */; }; 25 | 7BFB3D2B18612568004A44B6 /* instructions.html in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2518612568004A44B6 /* instructions.html */; }; 26 | 7BFB3D2C18612568004A44B6 /* step1.png in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2618612568004A44B6 /* step1.png */; }; 27 | 7BFB3D2D18612568004A44B6 /* step2.png in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2718612568004A44B6 /* step2.png */; }; 28 | 7BFB3D2E18612568004A44B6 /* step3.png in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2818612568004A44B6 /* step3.png */; }; 29 | 7BFB3D2F18612568004A44B6 /* step4.png in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2918612568004A44B6 /* step4.png */; }; 30 | 7BFB3D3018612568004A44B6 /* step5.png in Resources */ = {isa = PBXBuildFile; fileRef = 7BFB3D2A18612568004A44B6 /* step5.png */; }; 31 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 32 | A80A939B10923DC300F92D3F /* move.png in Resources */ = {isa = PBXBuildFile; fileRef = A80A939A10923DC300F92D3F /* move.png */; }; 33 | A84E89021081B2F30047B86A /* jitouchicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = A84E89011081B2F30047B86A /* jitouchicon.icns */; }; 34 | A85024E7113B2D7600DC6EB3 /* KeyUtility.m in Sources */ = {isa = PBXBuildFile; fileRef = A85024E6113B2D7600DC6EB3 /* KeyUtility.m */; }; 35 | A85BFEC110B8AEFF00201BF7 /* tab.png in Resources */ = {isa = PBXBuildFile; fileRef = A85BFEC010B8AEFF00201BF7 /* tab.png */; }; 36 | A8D092A4113330360066C837 /* SizeHistory.m in Sources */ = {isa = PBXBuildFile; fileRef = A8D092A3113330360066C837 /* SizeHistory.m */; }; 37 | A8D4973710918F7E005C3998 /* resize.png in Resources */ = {isa = PBXBuildFile; fileRef = A8D4973610918F7E005C3998 /* resize.png */; }; 38 | A8DB0A4A10842620000A2A08 /* logosmall.png in Resources */ = {isa = PBXBuildFile; fileRef = A8DB0A4910842620000A2A08 /* logosmall.png */; }; 39 | A8EB72071085318200563ED4 /* logosmalloff.png in Resources */ = {isa = PBXBuildFile; fileRef = A8EB72061085318200563ED4 /* logosmalloff.png */; }; 40 | /* End PBXBuildFile section */ 41 | 42 | /* Begin PBXFileReference section */ 43 | 1B11012710EF486500FF904B /* GestureView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GestureView.h; sourceTree = ""; }; 44 | 1B11012810EF486500FF904B /* GestureView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureView.m; sourceTree = ""; }; 45 | 1B20007610EE9AD800A75EEC /* GestureWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GestureWindow.h; sourceTree = ""; }; 46 | 1B20007710EE9AD800A75EEC /* GestureWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureWindow.m; sourceTree = ""; }; 47 | 1B4F3CC510AA45500062367C /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Settings.h; sourceTree = ""; }; 48 | 1B4F3CC610AA45500062367C /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Settings.m; sourceTree = ""; }; 49 | 1B981CE210916F5400652C8F /* CursorWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CursorWindow.h; sourceTree = ""; }; 50 | 1B981CE310916F5400652C8F /* CursorWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CursorWindow.m; sourceTree = ""; }; 51 | 1B981CEF1091713E00652C8F /* CursorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CursorView.h; sourceTree = ""; }; 52 | 1B981CF01091713E00652C8F /* CursorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CursorView.m; sourceTree = ""; }; 53 | 1B9DC6AB10AB69D900F24E62 /* SystemEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SystemEvents.h; sourceTree = ""; }; 54 | 1BF5AA6D10790134000CF532 /* Gesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Gesture.h; sourceTree = ""; }; 55 | 1BF5AA6E10790134000CF532 /* Gesture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Gesture.m; sourceTree = ""; }; 56 | 256AC3D80F4B6AC300CF3369 /* JitouchAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JitouchAppDelegate.h; sourceTree = ""; }; 57 | 256AC3D90F4B6AC300CF3369 /* JitouchAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JitouchAppDelegate.m; sourceTree = ""; }; 58 | 256AC3F00F4B6AF500CF3369 /* Jitouch_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Jitouch_Prefix.pch; sourceTree = ""; }; 59 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 60 | 7B24200815F945D000EDAD3D /* logosmall@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "logosmall@2x.png"; path = "../logosmall@2x.png"; sourceTree = ""; }; 61 | 7B24200915F945D000EDAD3D /* logosmalloff@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "logosmalloff@2x.png"; path = "../logosmalloff@2x.png"; sourceTree = ""; }; 62 | 7B703D6E262E8775002157DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 63 | 7B703DB6262EBEA6002157DD /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 64 | 7B703DB8262EBEAB002157DD /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 65 | 7B703DBA262EBEB1002157DD /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 66 | 7B703DBC262EBEB7002157DD /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = System/Library/Frameworks/ScriptingBridge.framework; sourceTree = SDKROOT; }; 67 | 7B703DBE262EBED6002157DD /* MultitouchSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultitouchSupport.framework; path = System/Library/PrivateFrameworks/MultitouchSupport.framework; sourceTree = SDKROOT; }; 68 | 7BFB3D23186118A3004A44B6 /* SystemPreferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemPreferences.h; sourceTree = ""; }; 69 | 7BFB3D2518612568004A44B6 /* instructions.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = instructions.html; sourceTree = ""; }; 70 | 7BFB3D2618612568004A44B6 /* step1.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step1.png; sourceTree = ""; }; 71 | 7BFB3D2718612568004A44B6 /* step2.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step2.png; sourceTree = ""; }; 72 | 7BFB3D2818612568004A44B6 /* step3.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step3.png; sourceTree = ""; }; 73 | 7BFB3D2918612568004A44B6 /* step4.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step4.png; sourceTree = ""; }; 74 | 7BFB3D2A18612568004A44B6 /* step5.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = step5.png; sourceTree = ""; }; 75 | 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 76 | A80A939A10923DC300F92D3F /* move.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = move.png; path = ../move.png; sourceTree = SOURCE_ROOT; }; 77 | A84E89011081B2F30047B86A /* jitouchicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = jitouchicon.icns; path = ../jitouchicon.icns; sourceTree = SOURCE_ROOT; }; 78 | A84E892C1081B6980047B86A /* Jitouch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jitouch.app; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | A85024E5113B2D7600DC6EB3 /* KeyUtility.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyUtility.h; sourceTree = ""; }; 80 | A85024E6113B2D7600DC6EB3 /* KeyUtility.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyUtility.m; sourceTree = ""; }; 81 | A85BFEC010B8AEFF00201BF7 /* tab.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = tab.png; path = ../tab.png; sourceTree = SOURCE_ROOT; }; 82 | A8D092A2113330360066C837 /* SizeHistory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SizeHistory.h; sourceTree = ""; }; 83 | A8D092A3113330360066C837 /* SizeHistory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SizeHistory.m; sourceTree = ""; }; 84 | A8D4973610918F7E005C3998 /* resize.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = resize.png; path = ../resize.png; sourceTree = SOURCE_ROOT; }; 85 | A8DB0A4910842620000A2A08 /* logosmall.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logosmall.png; path = ../logosmall.png; sourceTree = SOURCE_ROOT; }; 86 | A8EB72061085318200563ED4 /* logosmalloff.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = logosmalloff.png; path = ../logosmalloff.png; sourceTree = SOURCE_ROOT; }; 87 | /* End PBXFileReference section */ 88 | 89 | /* Begin PBXFrameworksBuildPhase section */ 90 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 91 | isa = PBXFrameworksBuildPhase; 92 | buildActionMask = 2147483647; 93 | files = ( 94 | 7B703DB9262EBEAB002157DD /* Carbon.framework in Frameworks */, 95 | 7B703DB7262EBEA6002157DD /* Cocoa.framework in Frameworks */, 96 | 7B703DBB262EBEB2002157DD /* IOKit.framework in Frameworks */, 97 | 7B703DBD262EBEB7002157DD /* ScriptingBridge.framework in Frameworks */, 98 | 7B703DBF262EBED6002157DD /* MultitouchSupport.framework in Frameworks */, 99 | ); 100 | runOnlyForDeploymentPostprocessing = 0; 101 | }; 102 | /* End PBXFrameworksBuildPhase section */ 103 | 104 | /* Begin PBXGroup section */ 105 | 080E96DDFE201D6D7F000001 /* Classes */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 1B4F3CC510AA45500062367C /* Settings.h */, 109 | 1B4F3CC610AA45500062367C /* Settings.m */, 110 | 256AC3D80F4B6AC300CF3369 /* JitouchAppDelegate.h */, 111 | 256AC3D90F4B6AC300CF3369 /* JitouchAppDelegate.m */, 112 | 1BF5AA6D10790134000CF532 /* Gesture.h */, 113 | 1BF5AA6E10790134000CF532 /* Gesture.m */, 114 | 1B981CE210916F5400652C8F /* CursorWindow.h */, 115 | 1B981CE310916F5400652C8F /* CursorWindow.m */, 116 | 1B981CEF1091713E00652C8F /* CursorView.h */, 117 | 1B981CF01091713E00652C8F /* CursorView.m */, 118 | 1B9DC6AB10AB69D900F24E62 /* SystemEvents.h */, 119 | 1B20007610EE9AD800A75EEC /* GestureWindow.h */, 120 | 1B20007710EE9AD800A75EEC /* GestureWindow.m */, 121 | 1B11012710EF486500FF904B /* GestureView.h */, 122 | 1B11012810EF486500FF904B /* GestureView.m */, 123 | A8D092A2113330360066C837 /* SizeHistory.h */, 124 | A8D092A3113330360066C837 /* SizeHistory.m */, 125 | A85024E5113B2D7600DC6EB3 /* KeyUtility.h */, 126 | A85024E6113B2D7600DC6EB3 /* KeyUtility.m */, 127 | 7BFB3D23186118A3004A44B6 /* SystemPreferences.h */, 128 | 7BFB3D2418612568004A44B6 /* instructions */, 129 | ); 130 | name = Classes; 131 | sourceTree = ""; 132 | }; 133 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 134 | isa = PBXGroup; 135 | children = ( 136 | A84E892C1081B6980047B86A /* Jitouch.app */, 137 | ); 138 | name = Products; 139 | sourceTree = ""; 140 | }; 141 | 29B97314FDCFA39411CA2CEA /* Jitouch */ = { 142 | isa = PBXGroup; 143 | children = ( 144 | 080E96DDFE201D6D7F000001 /* Classes */, 145 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 146 | 29B97317FDCFA39411CA2CEA /* Resources */, 147 | 7B703DB5262EBEA6002157DD /* Frameworks */, 148 | 19C28FACFE9D520D11CA2CBB /* Products */, 149 | ); 150 | name = Jitouch; 151 | sourceTree = ""; 152 | }; 153 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | 256AC3F00F4B6AF500CF3369 /* Jitouch_Prefix.pch */, 157 | ); 158 | name = "Other Sources"; 159 | sourceTree = ""; 160 | }; 161 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 162 | isa = PBXGroup; 163 | children = ( 164 | A85BFEC010B8AEFF00201BF7 /* tab.png */, 165 | A80A939A10923DC300F92D3F /* move.png */, 166 | A8D4973610918F7E005C3998 /* resize.png */, 167 | A8EB72061085318200563ED4 /* logosmalloff.png */, 168 | 7B24200915F945D000EDAD3D /* logosmalloff@2x.png */, 169 | A8DB0A4910842620000A2A08 /* logosmall.png */, 170 | 7B24200815F945D000EDAD3D /* logosmall@2x.png */, 171 | A84E89011081B2F30047B86A /* jitouchicon.icns */, 172 | 8D1107310486CEB800E47090 /* Info.plist */, 173 | 29B97316FDCFA39411CA2CEA /* main.m */, 174 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, 175 | ); 176 | name = Resources; 177 | sourceTree = ""; 178 | }; 179 | 7B703DB5262EBEA6002157DD /* Frameworks */ = { 180 | isa = PBXGroup; 181 | children = ( 182 | 7B703DB8262EBEAB002157DD /* Carbon.framework */, 183 | 7B703DB6262EBEA6002157DD /* Cocoa.framework */, 184 | 7B703DBA262EBEB1002157DD /* IOKit.framework */, 185 | 7B703DBC262EBEB7002157DD /* ScriptingBridge.framework */, 186 | 7B703DBE262EBED6002157DD /* MultitouchSupport.framework */, 187 | ); 188 | name = Frameworks; 189 | sourceTree = ""; 190 | }; 191 | 7BFB3D2418612568004A44B6 /* instructions */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | 7BFB3D2518612568004A44B6 /* instructions.html */, 195 | 7BFB3D2618612568004A44B6 /* step1.png */, 196 | 7BFB3D2718612568004A44B6 /* step2.png */, 197 | 7BFB3D2818612568004A44B6 /* step3.png */, 198 | 7BFB3D2918612568004A44B6 /* step4.png */, 199 | 7BFB3D2A18612568004A44B6 /* step5.png */, 200 | ); 201 | name = instructions; 202 | path = ../instructions; 203 | sourceTree = ""; 204 | }; 205 | /* End PBXGroup section */ 206 | 207 | /* Begin PBXNativeTarget section */ 208 | 8D1107260486CEB800E47090 /* Jitouch */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Jitouch" */; 211 | buildPhases = ( 212 | 8D1107290486CEB800E47090 /* Resources */, 213 | 8D11072C0486CEB800E47090 /* Sources */, 214 | 8D11072E0486CEB800E47090 /* Frameworks */, 215 | 7BB8604815DA332C00031122 /* ShellScript */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | ); 221 | name = Jitouch; 222 | productInstallPath = "$(HOME)/Applications"; 223 | productName = Jitouch; 224 | productReference = A84E892C1081B6980047B86A /* Jitouch.app */; 225 | productType = "com.apple.product-type.application"; 226 | }; 227 | /* End PBXNativeTarget section */ 228 | 229 | /* Begin PBXProject section */ 230 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 231 | isa = PBXProject; 232 | attributes = { 233 | LastUpgradeCheck = 1240; 234 | }; 235 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Jitouch" */; 236 | compatibilityVersion = "Xcode 9.3"; 237 | developmentRegion = en; 238 | hasScannedForEncodings = 1; 239 | knownRegions = ( 240 | Base, 241 | en, 242 | ); 243 | mainGroup = 29B97314FDCFA39411CA2CEA /* Jitouch */; 244 | projectDirPath = ""; 245 | projectRoot = ""; 246 | targets = ( 247 | 8D1107260486CEB800E47090 /* Jitouch */, 248 | ); 249 | }; 250 | /* End PBXProject section */ 251 | 252 | /* Begin PBXResourcesBuildPhase section */ 253 | 8D1107290486CEB800E47090 /* Resources */ = { 254 | isa = PBXResourcesBuildPhase; 255 | buildActionMask = 2147483647; 256 | files = ( 257 | 7BFB3D3018612568004A44B6 /* step5.png in Resources */, 258 | 7BFB3D2C18612568004A44B6 /* step1.png in Resources */, 259 | 7BFB3D2F18612568004A44B6 /* step4.png in Resources */, 260 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, 261 | A84E89021081B2F30047B86A /* jitouchicon.icns in Resources */, 262 | 7BFB3D2D18612568004A44B6 /* step2.png in Resources */, 263 | A8DB0A4A10842620000A2A08 /* logosmall.png in Resources */, 264 | 7BFB3D2B18612568004A44B6 /* instructions.html in Resources */, 265 | A8EB72071085318200563ED4 /* logosmalloff.png in Resources */, 266 | A8D4973710918F7E005C3998 /* resize.png in Resources */, 267 | A80A939B10923DC300F92D3F /* move.png in Resources */, 268 | 7BFB3D2E18612568004A44B6 /* step3.png in Resources */, 269 | A85BFEC110B8AEFF00201BF7 /* tab.png in Resources */, 270 | 7B24200A15F945D000EDAD3D /* logosmall@2x.png in Resources */, 271 | 7B24200B15F945D000EDAD3D /* logosmalloff@2x.png in Resources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXResourcesBuildPhase section */ 276 | 277 | /* Begin PBXShellScriptBuildPhase section */ 278 | 7BB8604815DA332C00031122 /* ShellScript */ = { 279 | isa = PBXShellScriptBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | ); 283 | inputPaths = ( 284 | ); 285 | outputPaths = ( 286 | ); 287 | runOnlyForDeploymentPostprocessing = 0; 288 | shellPath = /bin/sh; 289 | shellScript = "rm -rf ../../prefpane/Jitouch.app\ncp -R \"${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}\" ../../prefpane\n"; 290 | }; 291 | /* End PBXShellScriptBuildPhase section */ 292 | 293 | /* Begin PBXSourcesBuildPhase section */ 294 | 8D11072C0486CEB800E47090 /* Sources */ = { 295 | isa = PBXSourcesBuildPhase; 296 | buildActionMask = 2147483647; 297 | files = ( 298 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 299 | 256AC3DA0F4B6AC300CF3369 /* JitouchAppDelegate.m in Sources */, 300 | 1BF5AA6F10790134000CF532 /* Gesture.m in Sources */, 301 | 1B981CE410916F5400652C8F /* CursorWindow.m in Sources */, 302 | 1B981CF11091713E00652C8F /* CursorView.m in Sources */, 303 | 1B4F3CC710AA45500062367C /* Settings.m in Sources */, 304 | 1B20007810EE9AD800A75EEC /* GestureWindow.m in Sources */, 305 | 1B11012910EF486500FF904B /* GestureView.m in Sources */, 306 | A8D092A4113330360066C837 /* SizeHistory.m in Sources */, 307 | A85024E7113B2D7600DC6EB3 /* KeyUtility.m in Sources */, 308 | ); 309 | runOnlyForDeploymentPostprocessing = 0; 310 | }; 311 | /* End PBXSourcesBuildPhase section */ 312 | 313 | /* Begin PBXVariantGroup section */ 314 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { 315 | isa = PBXVariantGroup; 316 | children = ( 317 | 7B703D6E262E8775002157DD /* Base */, 318 | ); 319 | name = MainMenu.xib; 320 | sourceTree = ""; 321 | }; 322 | /* End PBXVariantGroup section */ 323 | 324 | /* Begin XCBuildConfiguration section */ 325 | C01FCF4B08A954540054247B /* Debug */ = { 326 | isa = XCBuildConfiguration; 327 | buildSettings = { 328 | ALWAYS_SEARCH_USER_PATHS = NO; 329 | CLANG_ENABLE_OBJC_WEAK = YES; 330 | CODE_SIGN_IDENTITY = "-"; 331 | COMBINE_HIDPI_IMAGES = YES; 332 | COPY_PHASE_STRIP = NO; 333 | CURRENT_PROJECT_VERSION = 2.75; 334 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 335 | DEPLOYMENT_POSTPROCESSING = YES; 336 | FRAMEWORK_SEARCH_PATHS = ( 337 | "$(inherited)", 338 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 339 | "\"$(SRCROOT)\"", 340 | ); 341 | GCC_DYNAMIC_NO_PIC = NO; 342 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 343 | GCC_PREFIX_HEADER = Jitouch_Prefix.pch; 344 | INFOPLIST_FILE = Info.plist; 345 | MARKETING_VERSION = 2.75; 346 | PRODUCT_BUNDLE_IDENTIFIER = "com.jitouch.${PRODUCT_NAME:rfc1034identifier}"; 347 | PRODUCT_NAME = Jitouch; 348 | STRIP_INSTALLED_PRODUCT = YES; 349 | }; 350 | name = Debug; 351 | }; 352 | C01FCF4C08A954540054247B /* Release */ = { 353 | isa = XCBuildConfiguration; 354 | buildSettings = { 355 | ALWAYS_SEARCH_USER_PATHS = NO; 356 | CLANG_ENABLE_OBJC_WEAK = YES; 357 | CODE_SIGN_IDENTITY = "-"; 358 | COMBINE_HIDPI_IMAGES = YES; 359 | CURRENT_PROJECT_VERSION = 2.75; 360 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 361 | DEPLOYMENT_POSTPROCESSING = YES; 362 | FRAMEWORK_SEARCH_PATHS = ( 363 | "$(inherited)", 364 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 365 | "\"$(SRCROOT)\"", 366 | ); 367 | GCC_DYNAMIC_NO_PIC = NO; 368 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 369 | GCC_PREFIX_HEADER = Jitouch_Prefix.pch; 370 | INFOPLIST_FILE = Info.plist; 371 | MARKETING_VERSION = 2.75; 372 | PRODUCT_BUNDLE_IDENTIFIER = "com.jitouch.${PRODUCT_NAME:rfc1034identifier}"; 373 | PRODUCT_NAME = Jitouch; 374 | STRIP_INSTALLED_PRODUCT = YES; 375 | }; 376 | name = Release; 377 | }; 378 | C01FCF4F08A954540054247B /* Debug */ = { 379 | isa = XCBuildConfiguration; 380 | buildSettings = { 381 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 382 | CLANG_WARN_BOOL_CONVERSION = YES; 383 | CLANG_WARN_COMMA = YES; 384 | CLANG_WARN_CONSTANT_CONVERSION = YES; 385 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 386 | CLANG_WARN_EMPTY_BODY = YES; 387 | CLANG_WARN_ENUM_CONVERSION = YES; 388 | CLANG_WARN_INFINITE_RECURSION = YES; 389 | CLANG_WARN_INT_CONVERSION = YES; 390 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 391 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 392 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 393 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 394 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 395 | CLANG_WARN_STRICT_PROTOTYPES = YES; 396 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 397 | CLANG_WARN_UNREACHABLE_CODE = YES; 398 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 399 | ENABLE_STRICT_OBJC_MSGSEND = YES; 400 | ENABLE_TESTABILITY = YES; 401 | GCC_C_LANGUAGE_STANDARD = gnu99; 402 | GCC_NO_COMMON_BLOCKS = YES; 403 | GCC_OPTIMIZATION_LEVEL = 0; 404 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 405 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 406 | GCC_WARN_UNDECLARED_SELECTOR = YES; 407 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 408 | GCC_WARN_UNUSED_FUNCTION = YES; 409 | GCC_WARN_UNUSED_VARIABLE = YES; 410 | MACOSX_DEPLOYMENT_TARGET = 10.9; 411 | ONLY_ACTIVE_ARCH = YES; 412 | SDKROOT = macosx; 413 | }; 414 | name = Debug; 415 | }; 416 | C01FCF5008A954540054247B /* Release */ = { 417 | isa = XCBuildConfiguration; 418 | buildSettings = { 419 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 420 | CLANG_WARN_BOOL_CONVERSION = YES; 421 | CLANG_WARN_COMMA = YES; 422 | CLANG_WARN_CONSTANT_CONVERSION = YES; 423 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 424 | CLANG_WARN_EMPTY_BODY = YES; 425 | CLANG_WARN_ENUM_CONVERSION = YES; 426 | CLANG_WARN_INFINITE_RECURSION = YES; 427 | CLANG_WARN_INT_CONVERSION = YES; 428 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 429 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 430 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 431 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 432 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 433 | CLANG_WARN_STRICT_PROTOTYPES = YES; 434 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 435 | CLANG_WARN_UNREACHABLE_CODE = YES; 436 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 437 | ENABLE_STRICT_OBJC_MSGSEND = YES; 438 | GCC_C_LANGUAGE_STANDARD = gnu99; 439 | GCC_NO_COMMON_BLOCKS = YES; 440 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 441 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 442 | GCC_WARN_UNDECLARED_SELECTOR = YES; 443 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 444 | GCC_WARN_UNUSED_FUNCTION = YES; 445 | GCC_WARN_UNUSED_VARIABLE = YES; 446 | MACOSX_DEPLOYMENT_TARGET = 10.9; 447 | SDKROOT = macosx; 448 | }; 449 | name = Release; 450 | }; 451 | /* End XCBuildConfiguration section */ 452 | 453 | /* Begin XCConfigurationList section */ 454 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "Jitouch" */ = { 455 | isa = XCConfigurationList; 456 | buildConfigurations = ( 457 | C01FCF4B08A954540054247B /* Debug */, 458 | C01FCF4C08A954540054247B /* Release */, 459 | ); 460 | defaultConfigurationIsVisible = 0; 461 | defaultConfigurationName = Release; 462 | }; 463 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "Jitouch" */ = { 464 | isa = XCConfigurationList; 465 | buildConfigurations = ( 466 | C01FCF4F08A954540054247B /* Debug */, 467 | C01FCF5008A954540054247B /* Release */, 468 | ); 469 | defaultConfigurationIsVisible = 0; 470 | defaultConfigurationName = Release; 471 | }; 472 | /* End XCConfigurationList section */ 473 | }; 474 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 475 | } 476 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Jitouch.xcodeproj/xcshareddata/xcschemes/Jitouch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /jitouch/Jitouch/JitouchAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JitouchAppDelegate.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class CursorWindow; 11 | @class Gesture; 12 | 13 | @interface JitouchAppDelegate : NSObject { 14 | NSWindow *window; 15 | Gesture *gesture; 16 | NSMenu *theMenu; 17 | NSStatusItem *theItem; 18 | } 19 | 20 | @property (assign) IBOutlet NSWindow *window; 21 | 22 | @end 23 | 24 | extern CursorWindow *cursorWindow; 25 | extern CGKeyCode keyMap[128]; // for dvorak support 26 | -------------------------------------------------------------------------------- /jitouch/Jitouch/JitouchAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // JitouchAppDelegate.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "JitouchAppDelegate.h" 9 | #import "Settings.h" 10 | #import "Gesture.h" 11 | #import "CursorWindow.h" 12 | #import 13 | #import 14 | #import "SystemPreferences.h" 15 | 16 | CursorWindow *cursorWindow; 17 | CGKeyCode keyMap[128]; // for dvorak support 18 | 19 | @implementation JitouchAppDelegate 20 | 21 | @synthesize window; 22 | 23 | - (void)addJitouchToLoginItems{ 24 | NSString *jitouchPath = [[NSString stringWithFormat:@"file://%@",[[NSBundle mainBundle] bundlePath]] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 25 | NSURL *jitouchURL = [NSURL URLWithString:jitouchPath]; 26 | 27 | 28 | LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 29 | if (loginListRef) { 30 | // delete all shortcuts to jitouch in the login items 31 | UInt32 seedValue; 32 | NSArray *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginListRef, &seedValue); 33 | for (id item in loginItemsArray) { 34 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 35 | CFURLRef thePath; 36 | if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) { 37 | NSRange range = [[(NSURL*)thePath path] rangeOfString:@"Jitouch"]; 38 | if (range.location != NSNotFound) 39 | LSSharedFileListItemRemove(loginListRef, itemRef); 40 | } 41 | } 42 | [loginItemsArray release]; 43 | 44 | if (![settings objectForKey:@"StartAtLogin"] || [[settings objectForKey:@"StartAtLogin"] intValue]) { 45 | // add shortcut to jitouch in the login items (there should be only one shortcut) 46 | LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef, kLSSharedFileListItemLast, NULL, NULL, (CFURLRef)jitouchURL, NULL, NULL); 47 | 48 | if (loginItemRef) { 49 | CFRelease(loginItemRef); 50 | } 51 | } 52 | 53 | CFRelease(loginListRef); 54 | } 55 | } 56 | 57 | - (void)removeJitouchFromLoginItems{ 58 | LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 59 | if (loginListRef) { 60 | // delete all shortcuts to jitouch in the login items 61 | UInt32 seedValue; 62 | NSArray *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginListRef, &seedValue); 63 | for (id item in loginItemsArray) { 64 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 65 | CFURLRef thePath; 66 | if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) { 67 | NSRange range = [[(NSURL*)thePath path] rangeOfString:@"Jitouch"]; 68 | if (range.location != NSNotFound) 69 | LSSharedFileListItemRemove(loginListRef, itemRef); 70 | } 71 | } 72 | [loginItemsArray release]; 73 | CFRelease(loginListRef); 74 | } 75 | } 76 | 77 | #pragma mark - Menu 78 | 79 | - (BOOL)validateMenuItem:(NSMenuItem *)item { 80 | if ([item action] == @selector(switchChange:)) 81 | return NO; 82 | return YES; 83 | } 84 | 85 | - (void)showIcon { 86 | theMenu = [[[NSMenu alloc] initWithTitle:@"Contextual Menu"] autorelease]; 87 | 88 | if (enAll) 89 | [theMenu insertItemWithTitle:@"Turn Jitouch Off" action:@selector(switchChange:) keyEquivalent:@"" atIndex:0]; 90 | else 91 | [theMenu insertItemWithTitle:@"Turn Jitouch On" action:@selector(switchChange:) keyEquivalent:@"" atIndex:0]; 92 | 93 | //[theMenu insertItem:[NSMenuItem separatorItem] atIndex:1]; 94 | [theMenu insertItemWithTitle:@"Open Preferences..." action:@selector(preferences:) keyEquivalent:@"" atIndex:1]; 95 | [theMenu insertItem:[NSMenuItem separatorItem] atIndex:2]; 96 | [theMenu insertItemWithTitle:@"Quit Jitouch" action:@selector(quit:) keyEquivalent:@"" atIndex:3]; 97 | 98 | NSStatusBar *bar = [NSStatusBar systemStatusBar]; 99 | theItem = [bar statusItemWithLength:NSVariableStatusItemLength]; 100 | [theItem retain]; 101 | [self updateIconImage]; 102 | [theItem setHighlightMode:YES]; 103 | [theItem setMenu:theMenu]; 104 | } 105 | 106 | - (void)hideIcon { 107 | [[NSStatusBar systemStatusBar] removeStatusItem:theItem]; 108 | [theItem release]; 109 | theItem = nil; 110 | } 111 | 112 | - (void)updateIconImage { 113 | if (enAll) { 114 | NSImage *img = [NSImage imageNamed:@"logosmall"]; 115 | [img setTemplate:YES]; 116 | [theItem setImage:img]; 117 | } else { 118 | NSImage *img = [NSImage imageNamed:@"logosmalloff"]; 119 | [img setTemplate:YES]; 120 | [theItem setImage:img]; 121 | } 122 | } 123 | 124 | - (void)preferences:(id)sender { 125 | NSString *prefPath = [@"~/Library/PreferencePanes/Jitouch.prefPane" stringByExpandingTildeInPath]; 126 | if (![[NSFileManager defaultManager] fileExistsAtPath:prefPath]) { 127 | prefPath = @"/Library/PreferencePanes/Jitouch.prefPane"; 128 | } 129 | 130 | if ([[NSFileManager defaultManager] fileExistsAtPath:prefPath]) { 131 | [[NSWorkspace sharedWorkspace] openFile:prefPath]; 132 | } else { 133 | NSAlert *alert = [[NSAlert alloc] init]; 134 | [alert setMessageText:@"Can't find the jitouch preference panel."]; 135 | [alert setInformativeText:@"Please reinstall jitouch."]; 136 | [alert setAlertStyle:NSWarningAlertStyle]; 137 | [NSApp activateIgnoringOtherApps:YES]; 138 | [alert runModal]; 139 | [alert release]; 140 | } 141 | } 142 | 143 | 144 | - (void)quit:(id)sender { 145 | // Remove from login item 146 | [self removeJitouchFromLoginItems]; 147 | 148 | // Quit 149 | [NSApp terminate: sender]; 150 | } 151 | 152 | - (void)refreshMenu { 153 | if (theItem == nil && [[settings objectForKey:@"ShowIcon"] intValue] == 1){ 154 | [self showIcon]; 155 | } else if (theItem != nil && [[settings objectForKey:@"ShowIcon"] intValue] == 0){ 156 | [self hideIcon]; 157 | } 158 | if (theItem) { 159 | if (enAll) { 160 | [[theMenu itemAtIndex:0] setTitle:@"Turn Jitouch Off"]; 161 | } else { 162 | [[theMenu itemAtIndex:0] setTitle:@"Turn Jitouch On"]; 163 | } 164 | [self updateIconImage]; 165 | } 166 | } 167 | 168 | - (void)switchChange:(id)sender { 169 | enAll = !enAll; 170 | [self refreshMenu]; 171 | [self saveSettings]; 172 | 173 | if (!enAll) 174 | turnOffGestures(); 175 | } 176 | 177 | #pragma mark - Settings 178 | 179 | - (void)saveSettings { 180 | [Settings setKey:@"enAll" withInt:enAll]; 181 | [Settings noteSettingsUpdated2]; 182 | } 183 | 184 | - (void)settingsUpdated:(NSNotification *)aNotification { 185 | //[Settings loadSettings]; 186 | 187 | [Settings loadSettings2:aNotification.userInfo]; // fixes bug in mountain lion 188 | [self refreshMenu]; 189 | 190 | if (!enAll) 191 | turnOffGestures(); 192 | } 193 | 194 | #pragma mark - Initialization 195 | 196 | 197 | - (void)checkAXAPI { 198 | AXIsProcessTrustedWithOptions((CFDictionaryRef)@{(id)kAXTrustedCheckOptionPrompt: @(YES)}); 199 | } 200 | 201 | /* 202 | void languageChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 203 | for (int i = 0; i < 128; i++) 204 | keyMap[i] = (CGKeyCode)i; 205 | NSString *inputSource = (NSString*)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyLocalizedName); 206 | if ([inputSource isEqualToString:@"Dvorak"] || [inputSource isEqualToString:@"Svorak"]) { 207 | keyMap[13] = 43; //w -> , 208 | keyMap[12] = 7; //q -> x 209 | keyMap[17] = 40; //t -> k 210 | keyMap[4] = 38; //h -> j 211 | keyMap[15] = 31; //r -> o 212 | keyMap[45] = 37; //n -> l 213 | keyMap[8] = 34; //c -> i 214 | keyMap[9] = 47; //v -> > 215 | keyMap[31] = 1; //o -> 216 | keyMap[37] = 45; //l -> n 217 | keyMap[3] = 32; // f -> u 218 | keyMap[40] = 17; 219 | } else if ([inputSource isEqualToString:@"French"]) { 220 | keyMap[13] = 6; //w -> z 221 | keyMap[12] = 0; //q -> a 222 | } 223 | } 224 | */ 225 | 226 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 227 | [Settings loadSettings]; 228 | 229 | [self refreshMenu]; 230 | 231 | // Move this task to prefpane instead. Starting at Sierra 232 | //[self addJitouchToLoginItems]; 233 | 234 | cursorWindow = [[CursorWindow alloc] init]; 235 | 236 | //languageChanged(NULL, NULL, NULL, NULL, NULL); 237 | 238 | gesture = [[Gesture alloc] init]; 239 | 240 | //[self showIcon]; 241 | 242 | [self checkAXAPI]; 243 | 244 | [[NSDistributedNotificationCenter defaultCenter] addObserver: self 245 | selector: @selector(settingsUpdated:) 246 | name: @"My Notification" 247 | object: @"com.jitouch.Jitouch.PrefpaneTarget"]; 248 | 249 | [[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:@selector(wokeUp:) name:NSWorkspaceDidWakeNotification object: NULL]; 250 | 251 | //CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), self, languageChanged, kTISNotifySelectedKeyboardInputSourceChanged, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 252 | } 253 | 254 | - (void)wokeUp:(NSNotification *)aNotification { 255 | //restart outselves 256 | NSString *killArg1AndOpenArg2Script = @"kill -9 $1 \n open \"$2\""; 257 | 258 | //NSTask needs its arguments to be strings 259 | NSString *ourPID = [NSString stringWithFormat:@"%d", 260 | [[NSProcessInfo processInfo] processIdentifier]]; 261 | 262 | //this will be the path to the .app bundle, 263 | //not the executable inside it; exactly what `open` wants 264 | NSString * pathToUs = [[NSBundle mainBundle] bundlePath]; 265 | 266 | NSArray *shArgs = [NSArray arrayWithObjects:@"-c", // -c tells sh to execute the next argument, passing it the remaining arguments. 267 | killArg1AndOpenArg2Script, 268 | @"", //$0 path to script (ignored) 269 | ourPID, //$1 in restartScript 270 | pathToUs, //$2 in the restartScript 271 | nil]; 272 | NSTask *restartTask = [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs]; 273 | [restartTask waitUntilExit]; //wait for killArg1AndOpenArg2Script to finish 274 | } 275 | 276 | #pragma mark - 277 | 278 | - (void) dealloc { 279 | [cursorWindow release]; 280 | [super dealloc]; 281 | } 282 | 283 | @end 284 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Jitouch_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'Jitouch' target in the 'Jitouch' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /jitouch/Jitouch/KeyUtility.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyUtility.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @interface KeyUtility : NSObject { 12 | NSMutableDictionary *keyMap; 13 | } 14 | 15 | - (void)simulateKeyCode:(CGKeyCode)code ShftDown:(BOOL)shft CtrlDown:(BOOL)ctrl AltDown:(BOOL)alt CmdDown:(BOOL)cmd; 16 | - (void)simulateKey:(NSString *)key ShftDown:(BOOL)shft CtrlDown:(BOOL)ctrl AltDown:(BOOL)alt CmdDown:(BOOL)cmd; 17 | - (void)simulateSpecialKey:(int)key; 18 | - (CGKeyCode)charToCode:(NSString*) chr; 19 | + (NSString *)codeToChar:(CGKeyCode)keyCode; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /jitouch/Jitouch/KeyUtility.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyUtility.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "KeyUtility.h" 9 | #import 10 | 11 | // to suppress "'CGPostKeyboardEvent' is deprecated" warnings 12 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 13 | 14 | @implementation KeyUtility 15 | 16 | static CGKeyCode a[128]; 17 | 18 | static void languageChanged(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) { 19 | for (int i = 0; i < 128; i++) 20 | a[i] = (CGKeyCode)i; 21 | 22 | NSString *inputSource = (NSString*)TISGetInputSourceProperty(TISCopyCurrentKeyboardInputSource(), kTISPropertyLocalizedName); 23 | if ([inputSource isEqualToString:@"Dvorak"] || [inputSource isEqualToString:@"Svorak"]) { 24 | a[13] = 43; //w -> , 25 | a[12] = 7; //q -> x 26 | a[17] = 40; //t -> k 27 | a[4] = 38; //h -> j 28 | a[15] = 31; //r -> o 29 | a[45] = 37; //n -> l 30 | a[8] = 34; //c -> i 31 | a[9] = 47; //v -> > 32 | a[31] = 1; //o -> 33 | a[37] = 45; //l -> n 34 | a[3] = 32; // f -> u 35 | a[40] = 17; 36 | } else if ([inputSource isEqualToString:@"French"]) { 37 | a[13] = 6; //w -> z 38 | a[12] = 0; //q -> a 39 | } 40 | } 41 | 42 | - (id)init { 43 | self = [super init]; 44 | if (self) { 45 | languageChanged(NULL, NULL, NULL, NULL, NULL); 46 | CFNotificationCenterAddObserver(CFNotificationCenterGetDistributedCenter(), self, languageChanged, kTISNotifySelectedKeyboardInputSourceChanged, NULL, CFNotificationSuspensionBehaviorDeliverImmediately); 47 | keyMap = [[NSMutableDictionary alloc] init]; 48 | for (CGKeyCode i = 0; i < 128; i++) { 49 | [keyMap setObject:[NSNumber numberWithUnsignedInt:i] forKey:[KeyUtility codeToChar:i]]; 50 | } 51 | } 52 | return self; 53 | } 54 | 55 | - (void)simulateKeyCode:(CGKeyCode)code ShftDown:(BOOL)shft CtrlDown:(BOOL)ctrl AltDown:(BOOL)alt CmdDown:(BOOL)cmd { 56 | 57 | if (shft) 58 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)56, true); 59 | if (ctrl) 60 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)59, true); 61 | if (alt) 62 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)58, true); 63 | if (cmd) 64 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, true); 65 | 66 | CGPostKeyboardEvent((CGCharCode)0, a[code], true); 67 | CGPostKeyboardEvent((CGCharCode)0, a[code], false); 68 | 69 | if (shft) 70 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)56, false); 71 | if (ctrl) 72 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)59, false); 73 | if (alt) 74 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)58, false); 75 | if (cmd) 76 | CGPostKeyboardEvent((CGCharCode)0, (CGKeyCode)55, false); 77 | 78 | } 79 | 80 | - (void) simulateKey:(NSString *)key ShftDown:(BOOL)shft CtrlDown:(BOOL)ctrl AltDown:(BOOL)alt CmdDown:(BOOL)cmd { 81 | CGKeyCode km = [(NSNumber *)[keyMap objectForKey:key] unsignedIntValue]; 82 | [self simulateKeyCode:km ShftDown:shft CtrlDown:ctrl AltDown:alt CmdDown:cmd]; 83 | } 84 | 85 | - (void)simulateSpecialKey:(int)key { 86 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 87 | 88 | NSEvent *event = [NSEvent otherEventWithType:NSSystemDefined location:NSZeroPoint modifierFlags:0xa00 timestamp:0 windowNumber:0 context:NULL subtype:8 data1:(key << 16) | (0xa00) data2:-1]; 89 | CGEventPost(kCGSessionEventTap, [event CGEvent]); 90 | 91 | NSEvent *event2 = [NSEvent otherEventWithType:NSSystemDefined location:NSZeroPoint modifierFlags:0xb00 timestamp:0 windowNumber:0 context:NULL subtype:8 data1:(key << 16) | (0xb00) data2:-1]; 92 | CGEventPost(kCGSessionEventTap, [event2 CGEvent]); 93 | 94 | [pool release]; 95 | } 96 | 97 | - (CGKeyCode)charToCode:(NSString*) chr { 98 | return [[keyMap objectForKey:chr] unsignedIntValue]; 99 | } 100 | 101 | + (NSString *)codeToChar:(CGKeyCode)keyCode { 102 | NSString *chr; 103 | if (keyCode == 123) { //left 104 | chr = @"←"; 105 | } else if (keyCode == 124) { //right 106 | chr = @"→"; 107 | } else if (keyCode == 125) { //down 108 | chr = @"↓"; 109 | } else if (keyCode == 126) { //up 110 | chr = @"↑"; 111 | } else if (keyCode == 36) { //return 112 | chr = @"↩"; 113 | } else if (keyCode == 48) { //tab 114 | chr = @"Tab"; 115 | } else if (keyCode == 49) { //space 116 | chr = @"Space"; 117 | } else if (keyCode == 51) { //delete 118 | chr = @"⌫"; 119 | } else if (keyCode == 53) { //escape 120 | chr = @"⎋"; 121 | } else if (keyCode == 117) { //forward delete 122 | chr = @"⌦"; 123 | } else if (keyCode == 76) { //enter 124 | chr = @"⌅"; 125 | } else if (keyCode == 116) { //page up 126 | chr = @"Page Up"; 127 | } else if (keyCode == 121) { //page down 128 | chr = @"Page Down"; 129 | } else if (keyCode == 115) { //home 130 | chr = @"Home"; 131 | } else if (keyCode == 119) { //end 132 | chr = @"End"; 133 | } else if (keyCode == 122) { // 134 | chr = @"F1"; 135 | } else if (keyCode == 120) { // 136 | chr = @"F2"; 137 | } else if (keyCode == 99) { // 138 | chr = @"F3"; 139 | } else if (keyCode == 118) { // 140 | chr = @"F4"; 141 | } else if (keyCode == 96) { // 142 | chr = @"F5"; 143 | } else if (keyCode == 97) { // 144 | chr = @"F6"; 145 | } else if (keyCode == 98) { // 146 | chr = @"F7"; 147 | } else if (keyCode == 100) { // 148 | chr = @"F8"; 149 | } else if (keyCode == 101) { // 150 | chr = @"F9"; 151 | } else if (keyCode == 109) { // 152 | chr = @"F10"; 153 | } else if (keyCode == 103) { // 154 | chr = @"F11"; 155 | } else if (keyCode == 111) { // 156 | chr = @"F12"; 157 | } else if (keyCode == 33) { // 158 | chr = @"["; 159 | } else if (keyCode == 30) { // 160 | chr = @"]"; 161 | 162 | } else { 163 | switch (keyCode) { 164 | case 0: 165 | chr = @"A"; break; 166 | case 11: 167 | chr = @"B"; break; 168 | case 8: 169 | chr = @"C"; break; 170 | case 2: 171 | chr = @"D"; break; 172 | case 14: 173 | chr = @"E"; break; 174 | case 3: 175 | chr = @"F"; break; 176 | case 5: 177 | chr = @"G"; break; 178 | case 4: 179 | chr = @"H"; break; 180 | case 34: 181 | chr = @"I"; break; 182 | case 38: 183 | chr = @"J"; break; 184 | case 40: 185 | chr = @"K"; break; 186 | case 37: 187 | chr = @"L"; break; 188 | case 46: 189 | chr = @"M"; break; 190 | case 45: 191 | chr = @"N"; break; 192 | case 31: 193 | chr = @"O"; break; 194 | case 35: 195 | chr = @"P"; break; 196 | case 12: 197 | chr = @"Q"; break; 198 | case 15: 199 | chr = @"R"; break; 200 | case 1: 201 | chr = @"S"; break; 202 | case 17: 203 | chr = @"T"; break; 204 | case 32: 205 | chr = @"U"; break; 206 | case 9: 207 | chr = @"V"; break; 208 | case 13: 209 | chr = @"W"; break; 210 | case 7: 211 | chr = @"X"; break; 212 | case 16: 213 | chr = @"Y"; break; 214 | case 6: 215 | chr = @"Z"; break; 216 | default: 217 | chr = [NSString stringWithFormat:@"%d", keyCode]; 218 | break; 219 | } 220 | } 221 | return chr; 222 | } 223 | 224 | @end 225 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Settings.h: -------------------------------------------------------------------------------- 1 | // 2 | // Settings.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | #define kCurrentRevision 26 11 | #define kAcceptableOldestRevision 13 12 | #define appID CFSTR("com.jitouch.Jitouch") 13 | 14 | extern NSMutableDictionary *settings; 15 | extern NSMutableDictionary *trackpadMap; 16 | extern NSMutableDictionary *magicMouseMap; 17 | extern NSMutableDictionary *recognitionMap; 18 | 19 | //General 20 | extern float clickSpeed; 21 | extern float stvt; 22 | extern int enAll; 23 | 24 | //Trackpad 25 | extern int enTPAll; 26 | extern int enHanded; 27 | 28 | //Magic Mouse 29 | extern int enMMAll; 30 | extern int enMMHanded; 31 | 32 | //Character Recognition 33 | extern int enCharRegTP; 34 | extern int enCharRegMM; 35 | extern float charRegIndexRingDistance; 36 | extern int charRegMouseButton; 37 | extern int enOneDrawing, enTwoDrawing; 38 | 39 | extern NSMutableArray *trackpadCommands; 40 | extern NSMutableArray *magicMouseCommands; 41 | extern NSMutableArray *recognitionCommands; 42 | 43 | extern BOOL hasloaded; 44 | 45 | extern BOOL isPrefPane; 46 | 47 | 48 | @interface Settings : NSObject 49 | 50 | + (void)loadSettings; 51 | //+ (void)noteSettingsUpdated; 52 | + (void)noteSettingsUpdated2; 53 | + (void)setKey:(NSString*)aKey withInt:(int)aValue; 54 | //+ (void)setKey:(NSString*)aKey withFloat:(float)aValue; 55 | + (void)setKey:(NSString*)aKey with:(id)aValue; 56 | //+ (void)trackpadDefault; 57 | //+ (void)magicMouseDefault; 58 | //+ (void)recognitionDefault; 59 | //+ (void)createDefaultPlist; 60 | + (void)loadSettings:(id)sender; 61 | + (void)loadSettings2:(NSDictionary*)newSettings; 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /jitouch/Jitouch/Settings.m: -------------------------------------------------------------------------------- 1 | // 2 | // Settings.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "Settings.h" 9 | #import 10 | #import 11 | 12 | #define kGesture @"Gesture" 13 | #define kCommand @"Command" 14 | #define kIsAction @"IsAction" 15 | #define ModifierFlags @"ModifierFlags" 16 | #define kKeyCode @"KeyCode" 17 | #define kEnable @"Enable" 18 | 19 | #define ADD_GESTURE(a, gesture, command) [a addObject:[NSDictionary dictionaryWithObjectsAndKeys:gesture, @"Gesture", command, @"Command", @YES, @"IsAction", @0, @"ModifierFlags", @0, @"KeyCode", [NSNumber numberWithInt:NSOnState], @"Enable", nil]]; 20 | 21 | NSMutableDictionary *settings; 22 | NSMutableDictionary *trackpadMap; 23 | NSMutableDictionary *magicMouseMap; 24 | NSMutableDictionary *recognitionMap; 25 | 26 | //General 27 | float clickSpeed; 28 | float stvt; 29 | int enAll; 30 | 31 | //Trackpad 32 | int enTPAll; 33 | int enHanded; 34 | 35 | //Magic Mouse 36 | int enMMAll; 37 | int enMMHanded; 38 | 39 | //Character Recognition 40 | int enCharRegTP; 41 | int enCharRegMM; 42 | float charRegIndexRingDistance; 43 | int charRegMouseButton; 44 | int enOneDrawing, enTwoDrawing; 45 | 46 | NSMutableArray *trackpadCommands; 47 | NSMutableArray *magicMouseCommands; 48 | NSMutableArray *recognitionCommands; 49 | 50 | BOOL hasloaded; 51 | 52 | BOOL isPrefPane; 53 | 54 | 55 | @implementation Settings 56 | 57 | static int notSynchronize; 58 | 59 | + (void)noteSettingsUpdated2 { 60 | NSAutoreleasePool *autoreleasepool = [[NSAutoreleasePool alloc] init]; 61 | [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"My Notification2" 62 | object: @"com.jitouch.Jitouch.PrefpaneTarget2" 63 | userInfo: @{ 64 | @"enAll": [NSNumber numberWithInt:enAll] 65 | } 66 | deliverImmediately: YES]; 67 | [autoreleasepool release]; 68 | } 69 | 70 | 71 | + (void)setKey:(NSString*)aKey withInt:(int)aValue{ 72 | CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &aValue); 73 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 74 | CFRelease(value); 75 | if (!notSynchronize) 76 | CFPreferencesAppSynchronize(appID); 77 | } 78 | 79 | + (void)setKey:(NSString*)aKey withFloat:(float)aValue{ 80 | CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &aValue); 81 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 82 | CFRelease(value); 83 | if (!notSynchronize) 84 | CFPreferencesAppSynchronize(appID); 85 | } 86 | 87 | + (void)setKey:(NSString*)aKey with:(id)aValue { 88 | CFPropertyListRef value = (CFPropertyListRef)aValue; 89 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 90 | //CFRelease(value); 91 | if (!notSynchronize) 92 | CFPreferencesAppSynchronize(appID); 93 | } 94 | 95 | + (void)recognitionDefault { 96 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 97 | ADD_GESTURE(gestures1, @"B", @"Launch Browser"); 98 | ADD_GESTURE(gestures1, @"F", @"Launch Finder"); 99 | ADD_GESTURE(gestures1, @"N", @"New"); 100 | ADD_GESTURE(gestures1, @"O", @"Open"); 101 | ADD_GESTURE(gestures1, @"S", @"Save"); 102 | ADD_GESTURE(gestures1, @"T", @"New Tab"); 103 | ADD_GESTURE(gestures1, @"Up", @"Copy"); 104 | ADD_GESTURE(gestures1, @"Down", @"Paste"); 105 | 106 | ADD_GESTURE(gestures1, @"/ Up", @"Maximize"); 107 | ADD_GESTURE(gestures1, @"Left", @"Maximize Left"); 108 | ADD_GESTURE(gestures1, @"Right", @"Maximize Right"); 109 | ADD_GESTURE(gestures1, @"/ Down", @"Un-Maximize"); 110 | 111 | NSDictionary *app1 = [NSDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 112 | 113 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 114 | [apps addObject:app1]; 115 | 116 | [Settings setKey:@"RecognitionCommands" with:apps]; 117 | [apps release]; 118 | [gestures1 release]; 119 | } 120 | 121 | + (void)trackpadDefault { 122 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 123 | ADD_GESTURE(gestures1, @"One-Fix Left-Tap", @"Previous Tab"); 124 | ADD_GESTURE(gestures1, @"One-Fix Right-Tap", @"Next Tab"); 125 | ADD_GESTURE(gestures1, @"One-Fix One-Slide", @"Move / Resize"); 126 | ADD_GESTURE(gestures1, @"One-Fix Two-Slide-Down", @"Close / Close Tab"); 127 | ADD_GESTURE(gestures1, @"One-Fix-Press Two-Slide-Down", @"Quit"); 128 | ADD_GESTURE(gestures1, @"Two-Fix Index-Double-Tap", @"Refresh"); 129 | ADD_GESTURE(gestures1, @"Three-Finger Tap", @"Middle Click"); 130 | ADD_GESTURE(gestures1, @"Pinky-To-Index", @"Zoom"); 131 | ADD_GESTURE(gestures1, @"Index-To-Pinky", @"Minimize"); 132 | //ADD_GESTURE(gestures1, @"Left-Side Scroll", @"Auto Scroll"); 133 | 134 | NSDictionary *app1 = [NSDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 135 | 136 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 137 | [apps addObject:app1]; 138 | 139 | [Settings setKey:@"TrackpadCommands" with:apps]; 140 | 141 | [apps release]; 142 | [gestures1 release]; 143 | } 144 | 145 | + (void)magicMouseDefault { 146 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 147 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Near-Tap", @"Next Tab"); 148 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Far-Tap", @"Previous Tab"); 149 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Slide-Out", @"Close / Close Tab"); 150 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Slide-In", @"Refresh"); 151 | ADD_GESTURE(gestures1, @"Three-Swipe-Up", @"Show Desktop"); 152 | ADD_GESTURE(gestures1, @"Three-Swipe-Down", @"Mission Control"); 153 | ADD_GESTURE(gestures1, @"V-Shape", @"Move / Resize"); 154 | ADD_GESTURE(gestures1, @"Middle Click", @"Middle Click"); 155 | 156 | NSDictionary *app1 = [NSDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 157 | 158 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 159 | [apps addObject:app1]; 160 | [Settings setKey:@"MagicMouseCommands" with:apps]; 161 | [apps release]; 162 | [gestures1 release]; 163 | } 164 | 165 | + (void)createDefaultPlist { 166 | notSynchronize = 1; 167 | 168 | //General 169 | [Settings setKey:@"enAll" withInt:1]; 170 | [Settings setKey:@"ClickSpeed" withFloat:0.25]; 171 | [Settings setKey:@"Sensitivity" withFloat:4.6666]; 172 | [Settings setKey:@"ShowIcon" withInt:1]; 173 | [Settings setKey:@"Revision" withInt:kCurrentRevision]; 174 | 175 | //Trackpad 176 | [Settings setKey:@"enTPAll" withInt:1]; 177 | [Settings setKey:@"Handed" withInt:0]; 178 | 179 | //Magic Mouse 180 | [Settings setKey:@"enMMAll" withInt:1]; 181 | [Settings setKey:@"MMHanded" withInt:0]; 182 | 183 | //Recognition 184 | [Settings setKey:@"enCharRegTP" withInt:0]; 185 | [Settings setKey:@"enCharRegMM" withInt:0]; 186 | [Settings setKey:@"charRegMouseButton" withInt:0]; 187 | [Settings setKey:@"charRegIndexRingDistance" withFloat:0.33]; 188 | [Settings setKey:@"enOneDrawing" withInt:0]; 189 | [Settings setKey:@"enTwoDrawing" withInt:1]; 190 | 191 | [Settings trackpadDefault]; 192 | [Settings magicMouseDefault]; 193 | [Settings recognitionDefault]; 194 | 195 | CFPreferencesAppSynchronize(appID); 196 | 197 | notSynchronize = 0; 198 | } 199 | 200 | + (void)loadSettings2:(NSDictionary*)newSettings { 201 | if (!newSettings) 202 | return; 203 | 204 | if (settings != newSettings) { 205 | [settings release]; 206 | settings = [[NSMutableDictionary alloc] initWithDictionary:newSettings]; 207 | } 208 | 209 | //General 210 | enAll = [[settings objectForKey:@"enAll"] intValue]; 211 | clickSpeed = [[settings objectForKey:@"ClickSpeed"] floatValue]; 212 | stvt = [[settings objectForKey:@"Sensitivity"] floatValue]; 213 | 214 | //Trackpad 215 | enTPAll = [[settings objectForKey:@"enTPAll"] intValue]; 216 | enHanded = [[settings objectForKey:@"Handed"] intValue]; 217 | 218 | //Magic Mouse 219 | enMMAll = [[settings objectForKey:@"enMMAll"] intValue]; 220 | enMMHanded = [[settings objectForKey:@"MMHanded"] intValue]; 221 | 222 | //Recognition 223 | enCharRegTP = [[settings objectForKey:@"enCharRegTP"] intValue]; 224 | enCharRegMM = [[settings objectForKey:@"enCharRegMM"] intValue]; 225 | enOneDrawing = [[settings objectForKey:@"enOneDrawing"] intValue]; 226 | enTwoDrawing = [[settings objectForKey:@"enTwoDrawing"] intValue]; 227 | 228 | if (![settings objectForKey:@"charRegIndexRingDistance"]) 229 | charRegIndexRingDistance = 0.3; 230 | else 231 | charRegIndexRingDistance = [[settings objectForKey:@"charRegIndexRingDistance"] floatValue]; 232 | 233 | if (![settings objectForKey:@"charRegMouseButton"]) 234 | charRegMouseButton = 0; 235 | else 236 | charRegMouseButton = [[settings objectForKey:@"charRegMouseButton"] intValue]; 237 | 238 | 239 | trackpadCommands = [settings objectForKey:@"TrackpadCommands"]; 240 | magicMouseCommands = [settings objectForKey:@"MagicMouseCommands"]; 241 | recognitionCommands = [settings objectForKey:@"RecognitionCommands"]; 242 | 243 | 244 | void (^optimize)(NSArray*, NSMutableDictionary*) = ^(NSArray *commands, NSMutableDictionary *map) { 245 | for (NSDictionary *app in commands) { 246 | NSString *appName = [app objectForKey:@"Application"]; 247 | if (!isPrefPane) { 248 | if ([appName isEqualToString:@"Chrome"]) 249 | appName = @"Google Chrome"; 250 | else if ([appName isEqualToString:@"Word"]) 251 | appName = @"Microsoft Word"; 252 | } 253 | 254 | NSMutableDictionary *gestures = [[NSMutableDictionary alloc] init]; 255 | for (NSDictionary *gesture in [app objectForKey:@"Gestures"]) { 256 | [gestures setObject:gesture forKey:[gesture objectForKey:@"Gesture"]]; 257 | } 258 | [map setObject:gestures forKey:appName]; 259 | [gestures release]; 260 | } 261 | }; 262 | 263 | // optimization for trackpad commands 264 | [trackpadMap release]; 265 | trackpadMap = [[NSMutableDictionary alloc] init]; 266 | optimize(trackpadCommands, trackpadMap); 267 | 268 | // optimization for magicmouse commands 269 | [magicMouseMap release]; 270 | magicMouseMap = [[NSMutableDictionary alloc] init]; 271 | optimize(magicMouseCommands, magicMouseMap); 272 | 273 | // optimization for recognition commands 274 | [recognitionMap release]; 275 | recognitionMap = [[NSMutableDictionary alloc] init]; 276 | optimize(recognitionCommands, recognitionMap); 277 | } 278 | 279 | + (void)loadSettings { 280 | NSString *plistPath = [@"~/Library/Preferences/com.jitouch.Jitouch.plist" stringByStandardizingPath]; 281 | 282 | NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath]; 283 | NSString *errorDesc = nil; 284 | NSDictionary *newSettings = [NSPropertyListSerialization 285 | propertyListFromData:plistXML 286 | mutabilityOption:NSPropertyListMutableContainersAndLeaves 287 | format:NULL 288 | errorDescription:&errorDesc]; 289 | [Settings loadSettings2:newSettings]; 290 | } 291 | 292 | + (void)loadSettings:(id)sender { 293 | @synchronized(sender) { 294 | if (hasloaded) 295 | return; 296 | [Settings loadSettings]; 297 | hasloaded = YES; 298 | } 299 | } 300 | 301 | @end 302 | -------------------------------------------------------------------------------- /jitouch/Jitouch/SizeHistory.h: -------------------------------------------------------------------------------- 1 | // 2 | // SizeHistory.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface SizeHistory : NSObject { 11 | NSRect curRect, savRect; 12 | } 13 | @property (readonly) NSRect curRect; 14 | @property (readonly) NSRect savRect; 15 | - (id)initWithCurRect:(NSRect)curRect SaveRect:(NSRect) savRect; 16 | 17 | @end 18 | 19 | 20 | @interface SizeHistoryKey : NSObject { 21 | const CFTypeRef *windowRef; 22 | } 23 | - (void)setWindowRef:(CFTypeRef) a; 24 | - (id)initWithKey:(CFTypeRef)a; 25 | - (id) copyWithZone:(NSZone *)zone; 26 | - (BOOL) isEqual:(id)other; 27 | - (NSUInteger) hash; 28 | @end 29 | -------------------------------------------------------------------------------- /jitouch/Jitouch/SizeHistory.m: -------------------------------------------------------------------------------- 1 | // 2 | // SizeHistory.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "SizeHistory.h" 9 | 10 | @implementation SizeHistory 11 | 12 | @synthesize curRect; 13 | @synthesize savRect; 14 | 15 | - (id)initWithCurRect:(NSRect)a SaveRect:(NSRect) b { 16 | if (self = [super init]) { 17 | curRect = a; 18 | savRect = b; 19 | } 20 | return self; 21 | } 22 | @end 23 | 24 | 25 | @implementation SizeHistoryKey 26 | 27 | - (id)initWithKey:(CFTypeRef)a { 28 | if (self = [super init]) { 29 | [self setWindowRef:a]; 30 | } 31 | return self; 32 | } 33 | - (void)setWindowRef:(CFTypeRef) a { 34 | windowRef = a; 35 | CFRetain(windowRef); 36 | } 37 | - (id) copyWithZone:(NSZone *)zone { 38 | SizeHistoryKey* copy = [[self class] alloc]; 39 | [copy setWindowRef:windowRef]; 40 | return copy; 41 | } 42 | - (void) dealloc { 43 | CFRelease(windowRef); 44 | [super dealloc]; 45 | } 46 | - (BOOL) isEqual:(id)other { 47 | return CFEqual(windowRef, other); 48 | } 49 | 50 | - (NSUInteger) hash { 51 | return CFHash(windowRef);; 52 | } 53 | @end 54 | -------------------------------------------------------------------------------- /jitouch/Jitouch/SystemPreferences.h: -------------------------------------------------------------------------------- 1 | /* 2 | * SystemPreferences.h 3 | */ 4 | 5 | #import 6 | #import 7 | 8 | 9 | @class SystemPreferencesApplication, SystemPreferencesDocument, SystemPreferencesWindow, SystemPreferencesPane, SystemPreferencesAnchor; 10 | 11 | enum SystemPreferencesSaveOptions { 12 | SystemPreferencesSaveOptionsYes = 'yes ' /* Save the file. */, 13 | SystemPreferencesSaveOptionsNo = 'no ' /* Do not save the file. */, 14 | SystemPreferencesSaveOptionsAsk = 'ask ' /* Ask the user whether or not to save the file. */ 15 | }; 16 | typedef enum SystemPreferencesSaveOptions SystemPreferencesSaveOptions; 17 | 18 | enum SystemPreferencesPrintingErrorHandling { 19 | SystemPreferencesPrintingErrorHandlingStandard = 'lwst' /* Standard PostScript error handling */, 20 | SystemPreferencesPrintingErrorHandlingDetailed = 'lwdt' /* print a detailed report of PostScript errors */ 21 | }; 22 | typedef enum SystemPreferencesPrintingErrorHandling SystemPreferencesPrintingErrorHandling; 23 | 24 | 25 | 26 | /* 27 | * Standard Suite 28 | */ 29 | 30 | // The application's top-level scripting object. 31 | @interface SystemPreferencesApplication : SBApplication 32 | 33 | - (SBElementArray *) documents; 34 | - (SBElementArray *) windows; 35 | 36 | @property (copy, readonly) NSString *name; // The name of the application. 37 | @property (readonly) BOOL frontmost; // Is this the active application? 38 | @property (copy, readonly) NSString *version; // The version number of the application. 39 | 40 | - (id) open:(id)x; // Open a document. 41 | - (void) print:(id)x withProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. 42 | - (void) quitSaving:(SystemPreferencesSaveOptions)saving; // Quit the application. 43 | - (BOOL) exists:(id)x; // Verify that an object exists. 44 | 45 | @end 46 | 47 | // A document. 48 | @interface SystemPreferencesDocument : SBObject 49 | 50 | @property (copy, readonly) NSString *name; // Its name. 51 | @property (readonly) BOOL modified; // Has it been modified since the last save? 52 | @property (copy, readonly) NSURL *file; // Its location on disk, if it has one. 53 | 54 | - (void) closeSaving:(SystemPreferencesSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. 55 | - (void) saveIn:(NSURL *)in_ as:(id)as; // Save a document. 56 | - (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. 57 | - (void) delete; // Delete an object. 58 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. 59 | - (void) moveTo:(SBObject *)to; // Move an object to a new location. 60 | 61 | @end 62 | 63 | // A window. 64 | @interface SystemPreferencesWindow : SBObject 65 | 66 | @property (copy, readonly) NSString *name; // The title of the window. 67 | - (NSInteger) id; // The unique identifier of the window. 68 | @property NSInteger index; // The index of the window, ordered front to back. 69 | @property NSRect bounds; // The bounding rectangle of the window. 70 | @property (readonly) BOOL closeable; // Does the window have a close button? 71 | @property (readonly) BOOL miniaturizable; // Does the window have a minimize button? 72 | @property BOOL miniaturized; // Is the window minimized right now? 73 | @property (readonly) BOOL resizable; // Can the window be resized? 74 | @property BOOL visible; // Is the window visible right now? 75 | @property (readonly) BOOL zoomable; // Does the window have a zoom button? 76 | @property BOOL zoomed; // Is the window zoomed right now? 77 | @property (copy, readonly) SystemPreferencesDocument *document; // The document whose contents are displayed in the window. 78 | 79 | - (void) closeSaving:(SystemPreferencesSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. 80 | - (void) saveIn:(NSURL *)in_ as:(id)as; // Save a document. 81 | - (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. 82 | - (void) delete; // Delete an object. 83 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. 84 | - (void) moveTo:(SBObject *)to; // Move an object to a new location. 85 | 86 | @end 87 | 88 | 89 | 90 | /* 91 | * System Preferences 92 | */ 93 | 94 | // System Preferences top level scripting object 95 | @interface SystemPreferencesApplication (SystemPreferences) 96 | 97 | - (SBElementArray *) panes; 98 | 99 | @property (copy) SystemPreferencesPane *currentPane; // the currently selected pane 100 | @property (copy, readonly) SystemPreferencesWindow *preferencesWindow; // the main preferences window 101 | @property BOOL showAll; // Is SystemPrefs in show all view. (Setting to false will do nothing) 102 | 103 | @end 104 | 105 | // a preference pane 106 | @interface SystemPreferencesPane : SBObject 107 | 108 | - (SBElementArray *) anchors; 109 | 110 | - (NSString *) id; // locale independent name of the preference pane; can refer to a pane using the expression: pane id "" 111 | @property (copy, readonly) NSString *localizedName; // localized name of the preference pane 112 | @property (copy, readonly) NSString *name; // name of the preference pane as it appears in the title bar; can refer to a pane using the expression: pane "" 113 | 114 | - (void) closeSaving:(SystemPreferencesSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. 115 | - (void) saveIn:(NSURL *)in_ as:(id)as; // Save a document. 116 | - (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. 117 | - (void) delete; // Delete an object. 118 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. 119 | - (void) moveTo:(SBObject *)to; // Move an object to a new location. 120 | - (id) reveal; // Reveals an anchor within a preference pane or preference pane itself 121 | 122 | @end 123 | 124 | // an anchor within a preference pane 125 | @interface SystemPreferencesAnchor : SBObject 126 | 127 | @property (copy, readonly) NSString *name; // name of the anchor within a preference pane 128 | 129 | - (void) closeSaving:(SystemPreferencesSaveOptions)saving savingIn:(NSURL *)savingIn; // Close a document. 130 | - (void) saveIn:(NSURL *)in_ as:(id)as; // Save a document. 131 | - (void) printWithProperties:(NSDictionary *)withProperties printDialog:(BOOL)printDialog; // Print a document. 132 | - (void) delete; // Delete an object. 133 | - (void) duplicateTo:(SBObject *)to withProperties:(NSDictionary *)withProperties; // Copy an object. 134 | - (void) moveTo:(SBObject *)to; // Move an object to a new location. 135 | - (id) reveal; // Reveals an anchor within a preference pane or preference pane itself 136 | 137 | @end 138 | 139 | -------------------------------------------------------------------------------- /jitouch/Jitouch/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | int main(int argc, const char * argv[]) 11 | { 12 | return NSApplicationMain(argc, argv); 13 | } 14 | -------------------------------------------------------------------------------- /jitouch/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/circle.png -------------------------------------------------------------------------------- /jitouch/instructions/instructions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | To enable jitouch,

15 | (Steps 1 - 3 may have already been done for you.) 16 |
    17 |
  1. Open "System Preferences"
  2. 18 |
  3. Click "Security & Privacy"
  4. 19 |
  5. Go to the "Privacy" tab and select "Accessibility"
  6. 20 |
  7. Click the lock icon if it is locked
  8. 21 |
  9. Check "Jitouch" and "System Preferences"
  10. 22 |
  11. Close the window
  12. 23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /jitouch/instructions/step1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/instructions/step1.png -------------------------------------------------------------------------------- /jitouch/instructions/step2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/instructions/step2.png -------------------------------------------------------------------------------- /jitouch/instructions/step3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/instructions/step3.png -------------------------------------------------------------------------------- /jitouch/instructions/step4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/instructions/step4.png -------------------------------------------------------------------------------- /jitouch/instructions/step5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/instructions/step5.png -------------------------------------------------------------------------------- /jitouch/jitouchicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/jitouchicon.icns -------------------------------------------------------------------------------- /jitouch/logosmall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/logosmall.png -------------------------------------------------------------------------------- /jitouch/logosmall@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/logosmall@2x.png -------------------------------------------------------------------------------- /jitouch/logosmalloff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/logosmalloff.png -------------------------------------------------------------------------------- /jitouch/logosmalloff@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/logosmalloff@2x.png -------------------------------------------------------------------------------- /jitouch/move.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/move.png -------------------------------------------------------------------------------- /jitouch/resize.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/resize.png -------------------------------------------------------------------------------- /jitouch/tab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/jitouch/tab.png -------------------------------------------------------------------------------- /prefpane/ApplicationButton.h: -------------------------------------------------------------------------------- 1 | // 2 | // ApplicationButton.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface ApplicationButton : NSPopUpButton 11 | 12 | - (void)addApplication:(NSString*)path; 13 | - (NSString*)pathOfSelectedItem; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /prefpane/ApplicationButton.m: -------------------------------------------------------------------------------- 1 | // 2 | // ApplicationButton.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "ApplicationButton.h" 9 | #import "Settings.h" 10 | 11 | @implementation ApplicationButton 12 | 13 | - (NSString*)pathOfSelectedItem { 14 | if ([self indexOfSelectedItem]-2 < 0 || [self indexOfSelectedItem]-2 >= [allAppPaths count]) 15 | return @""; 16 | return [allAppPaths objectAtIndex:[self indexOfSelectedItem]-2]; 17 | } 18 | 19 | - (void)addApplication:(NSString*)path { 20 | NSBundle *bundle = [NSBundle bundleWithPath: path]; 21 | NSDictionary *infoDict = [bundle infoDictionary]; 22 | NSString *displayName = [infoDict objectForKey: @"CFBundleName"]; 23 | if (!displayName) 24 | displayName = [infoDict objectForKey: @"CFBundleExecutable"]; 25 | 26 | if (displayName) { //TODO: workaround 27 | 28 | if ([displayName isEqualToString:@"RDC"]) 29 | displayName = @"Remote Desktop Connection"; //TODO: workaround 30 | 31 | [allApps addObject:displayName]; 32 | [allAppPaths addObject:path]; 33 | 34 | NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile:path]; 35 | [icon setSize:NSMakeSize(16, 16)]; 36 | [iconDict setObject:icon forKey:displayName]; 37 | 38 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:displayName action:nil keyEquivalent:@""]; 39 | [item setImage:icon]; 40 | { 41 | [[self menu] insertItem:item atIndex:[[[self menu] itemArray] count]-2]; 42 | [self selectItemAtIndex:[[[self menu] itemArray] count]-3]; 43 | } 44 | [item release]; 45 | } 46 | } 47 | 48 | - (void)awakeFromNib { 49 | isPrefPane = YES; 50 | [Settings loadSettings:self]; 51 | 52 | [self addItemWithTitle:@"All Applications"]; 53 | [[self menu] addItem:[NSMenuItem separatorItem]]; 54 | 55 | for (NSUInteger i = 0; i<[allApps count]; i++) { 56 | NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[allApps objectAtIndex:i] action:nil keyEquivalent:@""]; 57 | [item setImage:[iconDict objectForKey:[allApps objectAtIndex:i]]]; 58 | [[self menu] addItem:item]; 59 | [item release]; 60 | } 61 | 62 | [[self menu] addItem:[NSMenuItem separatorItem]]; 63 | [self addItemWithTitle:@"Other..."]; 64 | } 65 | 66 | @end 67 | -------------------------------------------------------------------------------- /prefpane/AutoSetDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AutoSetDelegate.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface AutoSetDelegate : NSObject { 11 | IBOutlet NSWindow *advancedWindow; 12 | IBOutlet NSWindow *autoSetWindow; 13 | 14 | IBOutlet NSTextField *fingersName; 15 | IBOutlet NSTextField *counter; 16 | 17 | IBOutlet NSButton *oneDrawing; 18 | IBOutlet NSButton *twoDrawing; 19 | 20 | IBOutlet NSButton *autoSetButton; 21 | IBOutlet NSButton *cancelButton; 22 | IBOutlet NSButton *restartButton; 23 | IBOutlet NSButton *resetButton; 24 | 25 | IBOutlet NSMatrix *mouseButton; 26 | IBOutlet NSSlider *indexRing; 27 | } 28 | 29 | - (IBAction)done:(id)sender; 30 | - (IBAction)doneAutoSet:(id)sender; 31 | - (IBAction)change:(id)sender; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /prefpane/AutoSetDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AutoSetDelegate.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "AutoSetDelegate.h" 9 | #import "Settings.h" 10 | 11 | #define TOUCHEXAM 10 12 | #define px normalized.pos.x 13 | #define py normalized.pos.y 14 | 15 | @implementation AutoSetDelegate 16 | 17 | // Based on the code at http://steike.com/code/multitouch 18 | typedef struct { float x, y; } MTPoint; 19 | typedef struct { MTPoint pos, vel; } MTReadout; 20 | 21 | typedef struct { 22 | int frame; 23 | double timestamp; 24 | int identifier, state, fingerId, handId; 25 | MTReadout normalized; 26 | float size; 27 | int zero1; 28 | float angle, majorAxis, minorAxis; // ellipsoid 29 | MTReadout mm; 30 | int zero2[2]; 31 | float zDensity; 32 | } Finger; 33 | 34 | typedef void *MTDeviceRef; 35 | typedef int (*MTContactCallbackFunction)(int, Finger*, int, double, int); 36 | 37 | MTDeviceRef MTDeviceCreateDefault(void); 38 | void MTRegisterContactFrameCallback(MTDeviceRef, MTContactCallbackFunction); 39 | void MTDeviceStart(MTDeviceRef, int); 40 | 41 | static int touchState = 0; 42 | 43 | static float dx[2][TOUCHEXAM]; 44 | static int dxCount[2]; 45 | 46 | static NSTextField *_counter; 47 | static NSTextField *_fingersName; 48 | static NSWindow *_autoSetWindow; 49 | static NSSlider *_indexRing; 50 | 51 | static void setIndexRing() { 52 | charRegIndexRingDistance = [_indexRing floatValue] / 100; 53 | [Settings setKey:@"charRegIndexRingDistance" withFloat:charRegIndexRingDistance]; 54 | [Settings noteSettingsUpdated]; 55 | } 56 | 57 | static int callback(int device, Finger *data, int nFingers, double timestamp, int frame) { 58 | static int waitForRelease = 1; 59 | if (touchState == 1) { 60 | if (!waitForRelease && nFingers == 2) { 61 | dx[dxCount[0]][dxCount[1]++] = fabs(data[0].px - data[1].px); 62 | if (dxCount[1] == TOUCHEXAM) { 63 | dxCount[0]++; 64 | dxCount[1] = 0; 65 | if (dxCount[0] == 1) 66 | [_fingersName setStringValue:@"Index and Ring fingers"]; 67 | if (dxCount[0] == 2) { 68 | touchState = 2; 69 | [_fingersName setStringValue:@"Index and Middle fingers"]; 70 | } 71 | } 72 | [_counter setStringValue:[NSString stringWithFormat:@"%d Time%c", TOUCHEXAM - dxCount[1], TOUCHEXAM - dxCount[1] == 1 ? ' ' : 's'] ]; 73 | waitForRelease = 1; 74 | } else if (nFingers == 0) { 75 | waitForRelease = 0; 76 | } 77 | } else if (touchState == 2) { 78 | touchState = 0; 79 | waitForRelease = 1; 80 | 81 | float val; 82 | float minV = 1, maxV = 0; 83 | for (int i = 0; i < TOUCHEXAM; i++) { 84 | if (dx[0][i] > maxV) 85 | maxV = dx[0][i]; 86 | if (dx[1][i] < minV) 87 | minV = dx[1][i]; 88 | } 89 | val = (maxV + minV) / 2 * 100; 90 | [_indexRing setFloatValue:val]; 91 | setIndexRing(); 92 | 93 | [NSApp performSelectorOnMainThread:@selector(endSheet:) withObject:_autoSetWindow waitUntilDone:NO]; 94 | } 95 | return 0; 96 | } 97 | 98 | - (IBAction)done:(id)sender { 99 | [NSApp endSheet:advancedWindow]; 100 | } 101 | 102 | - (IBAction)doneAutoSet:(id)sender { 103 | [NSApp endSheet:autoSetWindow]; 104 | touchState = 0; 105 | //[_window orderOut:nil]; 106 | [Settings setKey:@"charRegIndexRingDistance" withFloat:charRegIndexRingDistance]; 107 | [Settings noteSettingsUpdated]; 108 | } 109 | 110 | - (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo{ 111 | [sheet orderOut:self]; 112 | } 113 | 114 | - (IBAction)change:(id)sender { 115 | if (sender == autoSetButton || sender == restartButton) { 116 | if (sender == autoSetButton) { 117 | /*[autoSetWindow display]; 118 | [autoSetWindow setLevel:NSScreenSaverWindowLevel]; 119 | [autoSetWindow makeKeyAndOrderFront:nil]; 120 | */ 121 | [NSApp beginSheet: autoSetWindow 122 | modalForWindow: advancedWindow 123 | modalDelegate: self 124 | didEndSelector: @selector(didEndSheet:returnCode:contextInfo:) 125 | contextInfo: nil]; 126 | } 127 | touchState = 1; 128 | dxCount[0] = 0; 129 | dxCount[1] = 0; 130 | [_fingersName setStringValue:@"Index and Middle fingers"]; 131 | [_counter setStringValue:[NSString stringWithFormat:@"%d Times", TOUCHEXAM]]; 132 | 133 | // Temporarily disable character recognition by setting the dist = 1 134 | [Settings setKey:@"charRegIndexRingDistance" withFloat:1.0]; 135 | [Settings noteSettingsUpdated]; 136 | } else if (sender == indexRing) { 137 | setIndexRing(); 138 | } else if (sender == resetButton) { 139 | [indexRing setFloatValue:33]; 140 | setIndexRing(); 141 | } else if (sender == mouseButton) { 142 | charRegMouseButton = (int)[sender selectedColumn]; 143 | [Settings setKey:@"charRegMouseButton" withInt:charRegMouseButton]; 144 | [Settings noteSettingsUpdated]; 145 | } else if (sender == oneDrawing) { 146 | enOneDrawing = ([sender state] == NSOnState); 147 | [Settings setKey:@"enOneDrawing" withInt:enOneDrawing]; 148 | [Settings noteSettingsUpdated]; 149 | } else if (sender == twoDrawing) { 150 | enTwoDrawing = ([sender state] == NSOnState); 151 | [Settings setKey:@"enTwoDrawing" withInt:enTwoDrawing]; 152 | [Settings noteSettingsUpdated]; 153 | } 154 | } 155 | 156 | - (void)awakeFromNib { 157 | MTDeviceRef dev = MTDeviceCreateDefault(); 158 | MTRegisterContactFrameCallback(dev, callback); 159 | MTDeviceStart(dev, 0); 160 | 161 | _counter = counter; 162 | _fingersName = fingersName; 163 | _autoSetWindow = autoSetWindow; 164 | _indexRing = indexRing; 165 | } 166 | 167 | @end 168 | -------------------------------------------------------------------------------- /prefpane/CommandTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CommandTableView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface CommandTableView : NSTableView { 11 | NSUInteger modifierFlags; 12 | unsigned short keyCode; 13 | } 14 | 15 | @property NSUInteger modifierFlags; 16 | @property unsigned short keyCode; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /prefpane/CommandTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CommandTableView.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "CommandTableView.h" 9 | 10 | @implementation CommandTableView 11 | 12 | @synthesize modifierFlags, keyCode; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /prefpane/GesturePreviewView.h: -------------------------------------------------------------------------------- 1 | // 2 | // GesturePreviewView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | typedef struct { 11 | float x[2],y[2]; 12 | float cpx[2], cpy[2]; 13 | double t[4]; 14 | float len; 15 | int pressed; 16 | int type; 17 | } FingerGesture; 18 | 19 | typedef struct { 20 | FingerGesture fg[10]; 21 | int n; 22 | double t; 23 | int type; 24 | } HandGesture; 25 | 26 | @interface GesturePreviewView : NSView { 27 | NSTimer *timer; 28 | HandGesture hg; 29 | int counter; 30 | int handed; 31 | NSString *ges; 32 | int device; 33 | int lastI; 34 | } 35 | 36 | - (id)initWithDevice:(int)aDevice; 37 | - (void)create:(NSString*)gesture forDevice:(int)aDevice; 38 | - (void)startTimer; 39 | - (void)stopTimer; 40 | 41 | @property (nonatomic) int handed; 42 | @property (nonatomic, retain) NSString *ges; 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /prefpane/GestureTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // GestureTableView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class MAAttachedWindow, GesturePreviewView; 11 | 12 | @interface GestureTableView : NSTableView { 13 | NSArray *gestures; 14 | int device; 15 | NSSize size; 16 | 17 | MAAttachedWindow *attachedWindow; 18 | NSView *realView; 19 | GesturePreviewView *gesturePreviewView; 20 | 21 | NSInteger saveRowIndex; 22 | } 23 | 24 | - (NSString*)titleOfSelectedItem; 25 | - (void)selectItemWithObjectValue:(NSString*)value; 26 | - (void)hidePreview; 27 | - (void)willUnselect; 28 | 29 | @property (nonatomic, retain) NSArray *gestures; 30 | @property (nonatomic) NSSize size; 31 | @property (nonatomic) int device; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /prefpane/GestureTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // GestureTableView.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "GestureTableView.h" 9 | #import "GesturePreviewView.h" 10 | #import "MAAttachedWindow.h" 11 | 12 | @implementation GestureTableView 13 | 14 | @synthesize gestures, device, size; 15 | 16 | - (void)hidePreview { 17 | if (attachedWindow) { 18 | [gesturePreviewView stopTimer]; 19 | gesturePreviewView = nil; 20 | NSWindow *localAttachedWindow = attachedWindow; 21 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 22 | float alpha = 1.0; 23 | for (int i = 0; i < 10; i++) { 24 | alpha -= 0.1; 25 | dispatch_async(dispatch_get_main_queue(), ^{ 26 | [localAttachedWindow setAlphaValue:alpha]; 27 | }); 28 | usleep(20 * 1000); 29 | } 30 | dispatch_async(dispatch_get_main_queue(), ^{ 31 | [[self window] removeChildWindow:localAttachedWindow]; 32 | [localAttachedWindow orderOut:self]; 33 | [localAttachedWindow release]; 34 | }); 35 | }); 36 | attachedWindow = nil; 37 | } 38 | saveRowIndex = -1; 39 | } 40 | 41 | - (void)showPreview:(BOOL)scroll { 42 | NSInteger rowIndex; 43 | 44 | NSPoint point = [self convertPoint:[[self window] mouseLocationOutsideOfEventStream] fromView:[[self window] contentView]]; 45 | 46 | rowIndex = [self rowAtPoint:point]; 47 | if (rowIndex == -1) { 48 | [self hidePreview]; 49 | return; 50 | } 51 | if ([[gestures objectAtIndex:rowIndex] isEqualToString:@"All Unassigned Gestures"]) { 52 | [self hidePreview]; 53 | return; 54 | } 55 | 56 | 57 | NSRect frame = [self frameOfCellAtColumn:0 row:rowIndex]; 58 | 59 | if (saveRowIndex != rowIndex) { 60 | saveRowIndex = rowIndex; 61 | 62 | [gesturePreviewView stopTimer]; 63 | gesturePreviewView = [[GesturePreviewView alloc] initWithDevice:device]; 64 | [gesturePreviewView startTimer]; 65 | [gesturePreviewView create:[gestures objectAtIndex:rowIndex] forDevice:device]; 66 | 67 | 68 | NSPoint attachedPoint = [[[self window] contentView] convertPoint:frame.origin fromView:self]; 69 | attachedPoint.y -= frame.size.height / 2; 70 | MAAttachedWindow *newAttachedWindow = [[MAAttachedWindow alloc] initWithView:gesturePreviewView 71 | attachedToPoint:attachedPoint 72 | inWindow:[self window] 73 | onSide:0 74 | atDistance:2.0]; 75 | [newAttachedWindow setDevice:device]; 76 | //[attachedWindow setBorderColor:[borderColorWell color]]; 77 | //[textField setTextColor:[borderColorWell color]]; 78 | //NSColor *color = [NSColor colorWithDeviceRed:0 green:0 blue:0 alpha:0.6]; 79 | [newAttachedWindow setBackgroundColor:[NSColor colorWithDeviceRed:1 green:1 blue:1 alpha:0.8]]; 80 | //[attachedWindow setViewMargin:[viewMarginSlider floatValue]]; 81 | [newAttachedWindow setBorderWidth:0]; 82 | //[attachedWindow setCornerRadius:[cornerRadiusSlider floatValue]]; 83 | //[attachedWindow setHasArrow:([hasArrowCheckbox state] == NSOnState)]; 84 | //[attachedWindow setDrawsRoundCornerBesideArrow:([drawRoundCornerBesideArrowCheckbox state] == NSOnState)]; 85 | [newAttachedWindow setArrowBaseWidth:3 * 5]; 86 | [newAttachedWindow setArrowHeight:2 * 5]; 87 | 88 | 89 | [[self window] addChildWindow:newAttachedWindow ordered:NSWindowAbove]; 90 | 91 | 92 | if (attachedWindow) { 93 | [[self window] removeChildWindow:attachedWindow]; 94 | [attachedWindow orderOut:self]; 95 | [attachedWindow release]; 96 | //attachedWindow = nil; 97 | } 98 | 99 | attachedWindow = newAttachedWindow; 100 | 101 | [gesturePreviewView release]; 102 | 103 | } else if (scroll) { 104 | if (attachedWindow) { 105 | NSPoint attachedPoint = [[[self window] contentView] convertPoint:frame.origin fromView:self]; 106 | attachedPoint.y -= frame.size.height / 2; 107 | [attachedWindow setPoint:attachedPoint side:0]; 108 | } 109 | } 110 | } 111 | 112 | - (void)mouseEntered:(NSEvent *)theEvent { 113 | [self showPreview:NO]; 114 | } 115 | 116 | - (void)mouseExited:(NSEvent *)theEvent { 117 | [self hidePreview]; 118 | } 119 | 120 | - (void)mouseMoved:(NSEvent *)theEvent { 121 | [self showPreview:NO]; 122 | } 123 | 124 | - (void)outlineViewScrolled:(NSNotification*)notification { 125 | [self showPreview:YES]; 126 | } 127 | 128 | - (void)awakeFromNib { 129 | [self setDataSource:self]; 130 | 131 | size = NSMakeSize(4 * 50, 3 * 50); 132 | 133 | saveRowIndex = -1; 134 | realView = [self enclosingScrollView]; 135 | 136 | NSRect rect = [realView frame]; 137 | rect.origin.x = 0; 138 | rect.origin.y = 0; 139 | NSTrackingArea *trackingArea = [[NSTrackingArea alloc] initWithRect: rect 140 | options: (NSTrackingMouseEnteredAndExited | NSTrackingMouseMoved | NSTrackingActiveAlways ) 141 | owner:self userInfo:nil]; 142 | [realView addTrackingArea:trackingArea]; 143 | 144 | [[NSNotificationCenter defaultCenter] addObserver:self 145 | selector: @selector(outlineViewScrolled:) 146 | name: NSViewBoundsDidChangeNotification 147 | object: [[self enclosingScrollView] contentView]]; 148 | } 149 | 150 | 151 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { 152 | return [gestures count]; 153 | } 154 | 155 | - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { 156 | return [gestures objectAtIndex:rowIndex]; 157 | } 158 | 159 | - (NSString*)titleOfSelectedItem { 160 | if ([self selectedRow] == -1) 161 | return nil; 162 | return [gestures objectAtIndex:[self selectedRow]]; 163 | } 164 | 165 | - (void)selectItemWithObjectValue:(NSString*)value { 166 | NSUInteger index = [gestures indexOfObject:value]; 167 | if (index != NSNotFound) 168 | [self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO]; 169 | } 170 | 171 | - (void)willUnselect { 172 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil]; 173 | [self hidePreview]; 174 | } 175 | 176 | - (void)dealloc { 177 | [[NSNotificationCenter defaultCenter] removeObserver:self name:NSViewBoundsDidChangeNotification object:nil]; 178 | [attachedWindow release]; 179 | [gestures release]; 180 | [super dealloc]; 181 | } 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /prefpane/ImageAndTextCell.h: -------------------------------------------------------------------------------- 1 | /* 2 | File: ImageAndTextCell.h 3 | Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously. 4 | 5 | Copyright (C) 2009 Apple Inc. All Rights Reserved. 6 | */ 7 | 8 | #import 9 | 10 | @interface ImageAndTextCell : NSTextFieldCell { 11 | @private 12 | NSImage *image; 13 | } 14 | 15 | @property(readwrite, retain) NSImage *image; 16 | 17 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView; 18 | - (NSSize)cellSize; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /prefpane/ImageAndTextCell.m: -------------------------------------------------------------------------------- 1 | /* 2 | File: ImageAndTextCell.m 3 | Abstract: Subclass of NSTextFieldCell which can display text and an image simultaneously. 4 | 5 | Copyright (C) 2009 Apple Inc. All Rights Reserved. 6 | */ 7 | 8 | #import "ImageAndTextCell.h" 9 | #import 10 | 11 | @implementation ImageAndTextCell 12 | 13 | - (id)init { 14 | if ((self = [super init])) { 15 | [self setLineBreakMode:NSLineBreakByTruncatingTail]; 16 | [self setSelectable:YES]; 17 | } 18 | return self; 19 | } 20 | 21 | - (void)dealloc { 22 | [image release]; 23 | [super dealloc]; 24 | } 25 | 26 | - (id)copyWithZone:(NSZone *)zone { 27 | ImageAndTextCell *cell = (ImageAndTextCell *)[super copyWithZone:zone]; 28 | // The image ivar will be directly copied; we need to retain or copy it. 29 | cell->image = [image retain]; 30 | return cell; 31 | } 32 | 33 | @synthesize image; 34 | 35 | - (NSRect)imageRectForBounds:(NSRect)cellFrame { 36 | NSRect result; 37 | if (image != nil) { 38 | result.size = [image size]; 39 | result.origin = cellFrame.origin; 40 | result.origin.x += 3; 41 | result.origin.y += ceil((cellFrame.size.height - result.size.height) / 2); 42 | } else { 43 | result = NSZeroRect; 44 | } 45 | return result; 46 | } 47 | 48 | // We could manually implement expansionFrameWithFrame:inView: and drawWithExpansionFrame:inView: or just properly implement titleRectForBounds to get expansion tooltips to automatically work for us 49 | - (NSRect)titleRectForBounds:(NSRect)cellFrame { 50 | NSRect result; 51 | if (image != nil) { 52 | CGFloat imageWidth = [image size].width; 53 | result = cellFrame; 54 | result.origin.x += (3 + imageWidth); 55 | result.size.width -= (3 + imageWidth); 56 | } else { 57 | result = [super titleRectForBounds:cellFrame]; 58 | } 59 | return result; 60 | } 61 | 62 | - (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject event:(NSEvent *)theEvent { 63 | NSRect textFrame, imageFrame; 64 | NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge); 65 | [super editWithFrame: textFrame inView: controlView editor:textObj delegate:anObject event: theEvent]; 66 | } 67 | 68 | - (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj delegate:(id)anObject start:(NSInteger)selStart length:(NSInteger)selLength { 69 | NSRect textFrame, imageFrame; 70 | NSDivideRect (aRect, &imageFrame, &textFrame, 3 + [image size].width, NSMinXEdge); 71 | [super selectWithFrame: textFrame inView: controlView editor:textObj delegate:anObject start:selStart length:selLength]; 72 | } 73 | 74 | - (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView { 75 | if (image != nil) { 76 | NSRect imageFrame; 77 | NSSize imageSize = [image size]; 78 | NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge); 79 | if ([self drawsBackground]) { 80 | [[self backgroundColor] set]; 81 | NSRectFill(imageFrame); 82 | } 83 | imageFrame.origin.x += 3; 84 | imageFrame.size = imageSize; 85 | 86 | imageFrame.origin.y += ceil((cellFrame.size.height - imageFrame.size.height) / 2); 87 | [image drawInRect:imageFrame fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil]; 88 | } 89 | [super drawWithFrame:cellFrame inView:controlView]; 90 | } 91 | 92 | - (NSSize)cellSize { 93 | NSSize cellSize = [super cellSize]; 94 | if (image != nil) { 95 | cellSize.width += [image size].width; 96 | } 97 | cellSize.width += 3; 98 | return cellSize; 99 | } 100 | 101 | - (NSCellHitResult)hitTestForEvent:(NSEvent *)event inRect:(NSRect)cellFrame ofView:(NSView *)controlView { 102 | NSPoint point = [controlView convertPoint:[event locationInWindow] fromView:nil]; 103 | // If we have an image, we need to see if the user clicked on the image portion. 104 | if (image != nil) { 105 | // This code closely mimics drawWithFrame:inView: 106 | NSSize imageSize = [image size]; 107 | NSRect imageFrame; 108 | NSDivideRect(cellFrame, &imageFrame, &cellFrame, 3 + imageSize.width, NSMinXEdge); 109 | 110 | imageFrame.origin.x += 3; 111 | imageFrame.size = imageSize; 112 | // If the point is in the image rect, then it is a content hit 113 | if (NSMouseInRect(point, imageFrame, [controlView isFlipped])) { 114 | // We consider this just a content area. It is not trackable, nor it it editable text. If it was, we would or in the additional items. 115 | // By returning the correct parts, we allow NSTableView to correctly begin an edit when the text portion is clicked on. 116 | return NSCellHitContentArea; 117 | } 118 | } 119 | // At this point, the cellFrame has been modified to exclude the portion for the image. Let the superclass handle the hit testing at this point. 120 | return [super hitTestForEvent:event inRect:cellFrame ofView:controlView]; 121 | } 122 | 123 | @end 124 | -------------------------------------------------------------------------------- /prefpane/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | jitouchicon.icns 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | BNDL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | NSAppleEventsUsageDescription 26 | 27 | NSHumanReadableCopyright 28 | Copyright © 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 29 | NSMainNibFile 30 | JitouchPref 31 | NSPrefPaneIconFile 32 | JitouchPref.png 33 | NSPrefPaneIconLabel 34 | Jitouch 35 | NSPrincipalClass 36 | JitouchPref 37 | 38 | 39 | -------------------------------------------------------------------------------- /prefpane/Jitouch.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1B92A25910D70265005901E6 /* ApplicationButton.h in Headers */ = {isa = PBXBuildFile; fileRef = 1B92A25710D70265005901E6 /* ApplicationButton.h */; }; 11 | 1B92A25A10D70265005901E6 /* ApplicationButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 1B92A25810D70265005901E6 /* ApplicationButton.m */; }; 12 | 1BC3361710BFA540000DB964 /* Settings.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3361510BFA540000DB964 /* Settings.h */; }; 13 | 1BC3361810BFA540000DB964 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3361610BFA540000DB964 /* Settings.m */; }; 14 | 1BC3361B10BFA549000DB964 /* TrackpadTab.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3361910BFA549000DB964 /* TrackpadTab.h */; }; 15 | 1BC3361C10BFA549000DB964 /* TrackpadTab.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3361A10BFA549000DB964 /* TrackpadTab.m */; }; 16 | 1BC3361F10BFA551000DB964 /* MagicMouseTab.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3361D10BFA551000DB964 /* MagicMouseTab.h */; }; 17 | 1BC3362010BFA551000DB964 /* MagicMouseTab.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3361E10BFA551000DB964 /* MagicMouseTab.m */; }; 18 | 1BC3362310BFA55B000DB964 /* GestureTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3362110BFA55B000DB964 /* GestureTableView.h */; }; 19 | 1BC3362410BFA55B000DB964 /* GestureTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3362210BFA55B000DB964 /* GestureTableView.m */; }; 20 | 1BC3362710BFA566000DB964 /* GesturePreviewView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3362510BFA566000DB964 /* GesturePreviewView.h */; }; 21 | 1BC3362810BFA566000DB964 /* GesturePreviewView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3362610BFA566000DB964 /* GesturePreviewView.m */; }; 22 | 1BC3362B10BFA571000DB964 /* KeyTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3362910BFA571000DB964 /* KeyTextField.h */; }; 23 | 1BC3362C10BFA571000DB964 /* KeyTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3362A10BFA571000DB964 /* KeyTextField.m */; }; 24 | 1BC3362F10BFA579000DB964 /* KeyTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3362D10BFA579000DB964 /* KeyTextView.h */; }; 25 | 1BC3363010BFA579000DB964 /* KeyTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3362E10BFA579000DB964 /* KeyTextView.m */; }; 26 | 1BC3363310BFA584000DB964 /* ImageAndTextCell.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3363110BFA584000DB964 /* ImageAndTextCell.h */; }; 27 | 1BC3363410BFA584000DB964 /* ImageAndTextCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3363210BFA584000DB964 /* ImageAndTextCell.m */; }; 28 | 1BC3363710BFA595000DB964 /* MAAttachedWindow.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3363510BFA595000DB964 /* MAAttachedWindow.h */; }; 29 | 1BC3363810BFA595000DB964 /* MAAttachedWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3363610BFA595000DB964 /* MAAttachedWindow.m */; }; 30 | 1BC3364110BFA5A7000DB964 /* CommandTableView.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3363F10BFA5A7000DB964 /* CommandTableView.h */; }; 31 | 1BC3364210BFA5A7000DB964 /* CommandTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3364010BFA5A7000DB964 /* CommandTableView.m */; }; 32 | 1BC3364510BFA5B0000DB964 /* LinkTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = 1BC3364310BFA5B0000DB964 /* LinkTextField.h */; }; 33 | 1BC3364610BFA5B0000DB964 /* LinkTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = 1BC3364410BFA5B0000DB964 /* LinkTextField.m */; }; 34 | 1BF4317D10F460F5005DC569 /* Jitouch.app in Resources */ = {isa = PBXBuildFile; fileRef = 1BF4317C10F460F5005DC569 /* Jitouch.app */; }; 35 | 1BF4319610F462A8005DC569 /* jitouchicon.icns in Resources */ = {isa = PBXBuildFile; fileRef = 1BF4319510F462A8005DC569 /* jitouchicon.icns */; }; 36 | 7B10BDD615F947D90062660F /* JitouchPref.png in Resources */ = {isa = PBXBuildFile; fileRef = 7B10BDD415F947D90062660F /* JitouchPref.png */; }; 37 | 7B10BDD715F947D90062660F /* JitouchPref@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7B10BDD515F947D90062660F /* JitouchPref@2x.png */; }; 38 | 7B703DA9262EBC90002157DD /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DA8262EBC90002157DD /* IOKit.framework */; }; 39 | 7B703DAB262EBC94002157DD /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DAA262EBC94002157DD /* Cocoa.framework */; }; 40 | 7B703DAD262EBC98002157DD /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DAC262EBC98002157DD /* Carbon.framework */; }; 41 | 7B703DAF262EBC9D002157DD /* PreferencePanes.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DAE262EBC9D002157DD /* PreferencePanes.framework */; }; 42 | 7B703DB4262EBE26002157DD /* MultitouchSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7B703DB3262EBE26002157DD /* MultitouchSupport.framework */; }; 43 | 8D202CEB0486D31800D8A456 /* JitouchPref.h in Headers */ = {isa = PBXBuildFile; fileRef = F506C03C013D9D7901CA16C8 /* JitouchPref.h */; }; 44 | 8D202CEF0486D31800D8A456 /* JitouchPref.xib in Resources */ = {isa = PBXBuildFile; fileRef = F506C042013D9D8C01CA16C8 /* JitouchPref.xib */; }; 45 | 8D202CF10486D31800D8A456 /* JitouchPref.m in Sources */ = {isa = PBXBuildFile; fileRef = F506C03D013D9D7901CA16C8 /* JitouchPref.m */; }; 46 | A8B03D6D10F8DAEA00A9397E /* RecognitionTab.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B03D6B10F8DAEA00A9397E /* RecognitionTab.m */; }; 47 | A8B03D6E10F8DAEA00A9397E /* RecognitionTab.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B03D6C10F8DAEA00A9397E /* RecognitionTab.h */; }; 48 | A8B4F4711100DEC300290CC4 /* AutoSetDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = A8B4F46F1100DEC300290CC4 /* AutoSetDelegate.h */; }; 49 | A8B4F4721100DEC300290CC4 /* AutoSetDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = A8B4F4701100DEC300290CC4 /* AutoSetDelegate.m */; }; 50 | /* End PBXBuildFile section */ 51 | 52 | /* Begin PBXFileReference section */ 53 | 1B92A25710D70265005901E6 /* ApplicationButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ApplicationButton.h; sourceTree = ""; }; 54 | 1B92A25810D70265005901E6 /* ApplicationButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ApplicationButton.m; sourceTree = ""; }; 55 | 1BC3361510BFA540000DB964 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Settings.h; sourceTree = ""; }; 56 | 1BC3361610BFA540000DB964 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Settings.m; sourceTree = ""; }; 57 | 1BC3361910BFA549000DB964 /* TrackpadTab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TrackpadTab.h; sourceTree = ""; }; 58 | 1BC3361A10BFA549000DB964 /* TrackpadTab.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TrackpadTab.m; sourceTree = ""; }; 59 | 1BC3361D10BFA551000DB964 /* MagicMouseTab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MagicMouseTab.h; sourceTree = ""; }; 60 | 1BC3361E10BFA551000DB964 /* MagicMouseTab.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MagicMouseTab.m; sourceTree = ""; }; 61 | 1BC3362110BFA55B000DB964 /* GestureTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GestureTableView.h; sourceTree = ""; }; 62 | 1BC3362210BFA55B000DB964 /* GestureTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GestureTableView.m; sourceTree = ""; }; 63 | 1BC3362510BFA566000DB964 /* GesturePreviewView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GesturePreviewView.h; sourceTree = ""; }; 64 | 1BC3362610BFA566000DB964 /* GesturePreviewView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GesturePreviewView.m; sourceTree = ""; }; 65 | 1BC3362910BFA571000DB964 /* KeyTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyTextField.h; sourceTree = ""; }; 66 | 1BC3362A10BFA571000DB964 /* KeyTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyTextField.m; sourceTree = ""; }; 67 | 1BC3362D10BFA579000DB964 /* KeyTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyTextView.h; sourceTree = ""; }; 68 | 1BC3362E10BFA579000DB964 /* KeyTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyTextView.m; sourceTree = ""; }; 69 | 1BC3363110BFA584000DB964 /* ImageAndTextCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ImageAndTextCell.h; sourceTree = ""; }; 70 | 1BC3363210BFA584000DB964 /* ImageAndTextCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImageAndTextCell.m; sourceTree = ""; }; 71 | 1BC3363510BFA595000DB964 /* MAAttachedWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MAAttachedWindow.h; sourceTree = ""; }; 72 | 1BC3363610BFA595000DB964 /* MAAttachedWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MAAttachedWindow.m; sourceTree = ""; }; 73 | 1BC3363F10BFA5A7000DB964 /* CommandTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CommandTableView.h; sourceTree = ""; }; 74 | 1BC3364010BFA5A7000DB964 /* CommandTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CommandTableView.m; sourceTree = ""; }; 75 | 1BC3364310BFA5B0000DB964 /* LinkTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LinkTextField.h; sourceTree = ""; }; 76 | 1BC3364410BFA5B0000DB964 /* LinkTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LinkTextField.m; sourceTree = ""; }; 77 | 1BF4317C10F460F5005DC569 /* Jitouch.app */ = {isa = PBXFileReference; lastKnownFileType = wrapper.application; path = Jitouch.app; sourceTree = ""; }; 78 | 1BF4319510F462A8005DC569 /* jitouchicon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = jitouchicon.icns; sourceTree = ""; }; 79 | 7B10BDD415F947D90062660F /* JitouchPref.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = JitouchPref.png; sourceTree = ""; }; 80 | 7B10BDD515F947D90062660F /* JitouchPref@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "JitouchPref@2x.png"; sourceTree = ""; }; 81 | 7B703D8D262E9F7F002157DD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/JitouchPref.xib; sourceTree = ""; }; 82 | 7B703DA8262EBC90002157DD /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; }; 83 | 7B703DAA262EBC94002157DD /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 84 | 7B703DAC262EBC98002157DD /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 85 | 7B703DAE262EBC9D002157DD /* PreferencePanes.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = PreferencePanes.framework; path = System/Library/Frameworks/PreferencePanes.framework; sourceTree = SDKROOT; }; 86 | 7B703DB3262EBE26002157DD /* MultitouchSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultitouchSupport.framework; path = System/Library/PrivateFrameworks/MultitouchSupport.framework; sourceTree = SDKROOT; }; 87 | 8D202CF70486D31800D8A456 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 88 | 8D202CF80486D31800D8A456 /* Jitouch.prefPane */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Jitouch.prefPane; sourceTree = BUILT_PRODUCTS_DIR; }; 89 | A8B03D6B10F8DAEA00A9397E /* RecognitionTab.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RecognitionTab.m; sourceTree = ""; }; 90 | A8B03D6C10F8DAEA00A9397E /* RecognitionTab.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RecognitionTab.h; sourceTree = ""; }; 91 | A8B4F46F1100DEC300290CC4 /* AutoSetDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AutoSetDelegate.h; sourceTree = ""; }; 92 | A8B4F4701100DEC300290CC4 /* AutoSetDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AutoSetDelegate.m; sourceTree = ""; }; 93 | F506C03C013D9D7901CA16C8 /* JitouchPref.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JitouchPref.h; sourceTree = ""; }; 94 | F506C03D013D9D7901CA16C8 /* JitouchPref.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JitouchPref.m; sourceTree = ""; }; 95 | /* End PBXFileReference section */ 96 | 97 | /* Begin PBXFrameworksBuildPhase section */ 98 | 8D202CF20486D31800D8A456 /* Frameworks */ = { 99 | isa = PBXFrameworksBuildPhase; 100 | buildActionMask = 2147483647; 101 | files = ( 102 | 7B703DAD262EBC98002157DD /* Carbon.framework in Frameworks */, 103 | 7B703DAB262EBC94002157DD /* Cocoa.framework in Frameworks */, 104 | 7B703DA9262EBC90002157DD /* IOKit.framework in Frameworks */, 105 | 7B703DAF262EBC9D002157DD /* PreferencePanes.framework in Frameworks */, 106 | 7B703DB4262EBE26002157DD /* MultitouchSupport.framework in Frameworks */, 107 | ); 108 | runOnlyForDeploymentPostprocessing = 0; 109 | }; 110 | /* End PBXFrameworksBuildPhase section */ 111 | 112 | /* Begin PBXGroup section */ 113 | 089C166AFE841209C02AAC07 /* Jitouch */ = { 114 | isa = PBXGroup; 115 | children = ( 116 | 08FB77AFFE84173DC02AAC07 /* Classes */, 117 | 089C167CFE841241C02AAC07 /* Resources */, 118 | 7B703DA7262EBC90002157DD /* Frameworks */, 119 | 19C28FB8FE9D52D311CA2CBB /* Products */, 120 | ); 121 | name = Jitouch; 122 | sourceTree = ""; 123 | }; 124 | 089C167CFE841241C02AAC07 /* Resources */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | 7B10BDD415F947D90062660F /* JitouchPref.png */, 128 | 7B10BDD515F947D90062660F /* JitouchPref@2x.png */, 129 | 1BF4319510F462A8005DC569 /* jitouchicon.icns */, 130 | 1BF4317C10F460F5005DC569 /* Jitouch.app */, 131 | 8D202CF70486D31800D8A456 /* Info.plist */, 132 | F506C042013D9D8C01CA16C8 /* JitouchPref.xib */, 133 | ); 134 | name = Resources; 135 | sourceTree = ""; 136 | }; 137 | 08FB77AFFE84173DC02AAC07 /* Classes */ = { 138 | isa = PBXGroup; 139 | children = ( 140 | 1BC3361510BFA540000DB964 /* Settings.h */, 141 | 1BC3361610BFA540000DB964 /* Settings.m */, 142 | F506C03C013D9D7901CA16C8 /* JitouchPref.h */, 143 | F506C03D013D9D7901CA16C8 /* JitouchPref.m */, 144 | 1BC3361910BFA549000DB964 /* TrackpadTab.h */, 145 | 1BC3361A10BFA549000DB964 /* TrackpadTab.m */, 146 | 1BC3361D10BFA551000DB964 /* MagicMouseTab.h */, 147 | 1BC3361E10BFA551000DB964 /* MagicMouseTab.m */, 148 | A8B03D6C10F8DAEA00A9397E /* RecognitionTab.h */, 149 | A8B03D6B10F8DAEA00A9397E /* RecognitionTab.m */, 150 | 1BC3362110BFA55B000DB964 /* GestureTableView.h */, 151 | 1BC3362210BFA55B000DB964 /* GestureTableView.m */, 152 | 1BC3362510BFA566000DB964 /* GesturePreviewView.h */, 153 | 1BC3362610BFA566000DB964 /* GesturePreviewView.m */, 154 | 1BC3362910BFA571000DB964 /* KeyTextField.h */, 155 | 1BC3362A10BFA571000DB964 /* KeyTextField.m */, 156 | 1BC3362D10BFA579000DB964 /* KeyTextView.h */, 157 | 1BC3362E10BFA579000DB964 /* KeyTextView.m */, 158 | 1BC3363110BFA584000DB964 /* ImageAndTextCell.h */, 159 | 1BC3363210BFA584000DB964 /* ImageAndTextCell.m */, 160 | 1BC3363510BFA595000DB964 /* MAAttachedWindow.h */, 161 | 1BC3363610BFA595000DB964 /* MAAttachedWindow.m */, 162 | 1BC3363F10BFA5A7000DB964 /* CommandTableView.h */, 163 | 1BC3364010BFA5A7000DB964 /* CommandTableView.m */, 164 | 1BC3364310BFA5B0000DB964 /* LinkTextField.h */, 165 | 1BC3364410BFA5B0000DB964 /* LinkTextField.m */, 166 | 1B92A25710D70265005901E6 /* ApplicationButton.h */, 167 | 1B92A25810D70265005901E6 /* ApplicationButton.m */, 168 | A8B4F46F1100DEC300290CC4 /* AutoSetDelegate.h */, 169 | A8B4F4701100DEC300290CC4 /* AutoSetDelegate.m */, 170 | ); 171 | name = Classes; 172 | sourceTree = ""; 173 | }; 174 | 19C28FB8FE9D52D311CA2CBB /* Products */ = { 175 | isa = PBXGroup; 176 | children = ( 177 | 8D202CF80486D31800D8A456 /* Jitouch.prefPane */, 178 | ); 179 | name = Products; 180 | sourceTree = ""; 181 | }; 182 | 7B703DA7262EBC90002157DD /* Frameworks */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | 7B703DAC262EBC98002157DD /* Carbon.framework */, 186 | 7B703DAA262EBC94002157DD /* Cocoa.framework */, 187 | 7B703DA8262EBC90002157DD /* IOKit.framework */, 188 | 7B703DAE262EBC9D002157DD /* PreferencePanes.framework */, 189 | 7B703DB3262EBE26002157DD /* MultitouchSupport.framework */, 190 | ); 191 | name = Frameworks; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXGroup section */ 195 | 196 | /* Begin PBXHeadersBuildPhase section */ 197 | 8D202CE90486D31800D8A456 /* Headers */ = { 198 | isa = PBXHeadersBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | 8D202CEB0486D31800D8A456 /* JitouchPref.h in Headers */, 202 | 1BC3361710BFA540000DB964 /* Settings.h in Headers */, 203 | 1BC3361B10BFA549000DB964 /* TrackpadTab.h in Headers */, 204 | 1BC3361F10BFA551000DB964 /* MagicMouseTab.h in Headers */, 205 | 1BC3362310BFA55B000DB964 /* GestureTableView.h in Headers */, 206 | 1BC3362710BFA566000DB964 /* GesturePreviewView.h in Headers */, 207 | 1BC3362B10BFA571000DB964 /* KeyTextField.h in Headers */, 208 | 1BC3362F10BFA579000DB964 /* KeyTextView.h in Headers */, 209 | 1BC3363310BFA584000DB964 /* ImageAndTextCell.h in Headers */, 210 | 1BC3363710BFA595000DB964 /* MAAttachedWindow.h in Headers */, 211 | 1BC3364110BFA5A7000DB964 /* CommandTableView.h in Headers */, 212 | 1BC3364510BFA5B0000DB964 /* LinkTextField.h in Headers */, 213 | 1B92A25910D70265005901E6 /* ApplicationButton.h in Headers */, 214 | A8B03D6E10F8DAEA00A9397E /* RecognitionTab.h in Headers */, 215 | A8B4F4711100DEC300290CC4 /* AutoSetDelegate.h in Headers */, 216 | ); 217 | runOnlyForDeploymentPostprocessing = 0; 218 | }; 219 | /* End PBXHeadersBuildPhase section */ 220 | 221 | /* Begin PBXNativeTarget section */ 222 | 8D202CE80486D31800D8A456 /* Jitouch */ = { 223 | isa = PBXNativeTarget; 224 | buildConfigurationList = 1DBD214808BA80EA00186707 /* Build configuration list for PBXNativeTarget "Jitouch" */; 225 | buildPhases = ( 226 | 8D202CE90486D31800D8A456 /* Headers */, 227 | 8D202CEC0486D31800D8A456 /* Resources */, 228 | 8D202CF00486D31800D8A456 /* Sources */, 229 | 8D202CF20486D31800D8A456 /* Frameworks */, 230 | 8D202CF50486D31800D8A456 /* Rez */, 231 | ); 232 | buildRules = ( 233 | ); 234 | dependencies = ( 235 | ); 236 | name = Jitouch; 237 | productInstallPath = "$(HOME)/Library/PreferencePanes"; 238 | productName = Jitouch; 239 | productReference = 8D202CF80486D31800D8A456 /* Jitouch.prefPane */; 240 | productType = "com.apple.product-type.bundle"; 241 | }; 242 | /* End PBXNativeTarget section */ 243 | 244 | /* Begin PBXProject section */ 245 | 089C1669FE841209C02AAC07 /* Project object */ = { 246 | isa = PBXProject; 247 | attributes = { 248 | LastUpgradeCheck = 1240; 249 | }; 250 | buildConfigurationList = 1DBD214C08BA80EA00186707 /* Build configuration list for PBXProject "Jitouch" */; 251 | compatibilityVersion = "Xcode 9.3"; 252 | developmentRegion = en; 253 | hasScannedForEncodings = 1; 254 | knownRegions = ( 255 | en, 256 | Base, 257 | ); 258 | mainGroup = 089C166AFE841209C02AAC07 /* Jitouch */; 259 | projectDirPath = ""; 260 | projectRoot = ""; 261 | targets = ( 262 | 8D202CE80486D31800D8A456 /* Jitouch */, 263 | ); 264 | }; 265 | /* End PBXProject section */ 266 | 267 | /* Begin PBXResourcesBuildPhase section */ 268 | 8D202CEC0486D31800D8A456 /* Resources */ = { 269 | isa = PBXResourcesBuildPhase; 270 | buildActionMask = 2147483647; 271 | files = ( 272 | 8D202CEF0486D31800D8A456 /* JitouchPref.xib in Resources */, 273 | 1BF4317D10F460F5005DC569 /* Jitouch.app in Resources */, 274 | 1BF4319610F462A8005DC569 /* jitouchicon.icns in Resources */, 275 | 7B10BDD615F947D90062660F /* JitouchPref.png in Resources */, 276 | 7B10BDD715F947D90062660F /* JitouchPref@2x.png in Resources */, 277 | ); 278 | runOnlyForDeploymentPostprocessing = 0; 279 | }; 280 | /* End PBXResourcesBuildPhase section */ 281 | 282 | /* Begin PBXRezBuildPhase section */ 283 | 8D202CF50486D31800D8A456 /* Rez */ = { 284 | isa = PBXRezBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | ); 288 | runOnlyForDeploymentPostprocessing = 0; 289 | }; 290 | /* End PBXRezBuildPhase section */ 291 | 292 | /* Begin PBXSourcesBuildPhase section */ 293 | 8D202CF00486D31800D8A456 /* Sources */ = { 294 | isa = PBXSourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | 8D202CF10486D31800D8A456 /* JitouchPref.m in Sources */, 298 | 1BC3361810BFA540000DB964 /* Settings.m in Sources */, 299 | 1BC3361C10BFA549000DB964 /* TrackpadTab.m in Sources */, 300 | 1BC3362010BFA551000DB964 /* MagicMouseTab.m in Sources */, 301 | 1BC3362410BFA55B000DB964 /* GestureTableView.m in Sources */, 302 | 1BC3362810BFA566000DB964 /* GesturePreviewView.m in Sources */, 303 | 1BC3362C10BFA571000DB964 /* KeyTextField.m in Sources */, 304 | 1BC3363010BFA579000DB964 /* KeyTextView.m in Sources */, 305 | 1BC3363410BFA584000DB964 /* ImageAndTextCell.m in Sources */, 306 | 1BC3363810BFA595000DB964 /* MAAttachedWindow.m in Sources */, 307 | 1BC3364210BFA5A7000DB964 /* CommandTableView.m in Sources */, 308 | 1BC3364610BFA5B0000DB964 /* LinkTextField.m in Sources */, 309 | 1B92A25A10D70265005901E6 /* ApplicationButton.m in Sources */, 310 | A8B03D6D10F8DAEA00A9397E /* RecognitionTab.m in Sources */, 311 | A8B4F4721100DEC300290CC4 /* AutoSetDelegate.m in Sources */, 312 | ); 313 | runOnlyForDeploymentPostprocessing = 0; 314 | }; 315 | /* End PBXSourcesBuildPhase section */ 316 | 317 | /* Begin PBXVariantGroup section */ 318 | F506C042013D9D8C01CA16C8 /* JitouchPref.xib */ = { 319 | isa = PBXVariantGroup; 320 | children = ( 321 | 7B703D8D262E9F7F002157DD /* Base */, 322 | ); 323 | name = JitouchPref.xib; 324 | sourceTree = ""; 325 | }; 326 | /* End PBXVariantGroup section */ 327 | 328 | /* Begin XCBuildConfiguration section */ 329 | 1DBD214908BA80EA00186707 /* Debug */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | CLANG_ENABLE_OBJC_WEAK = YES; 333 | COMBINE_HIDPI_IMAGES = YES; 334 | COPY_PHASE_STRIP = NO; 335 | CURRENT_PROJECT_VERSION = 2.75; 336 | DEPLOYMENT_POSTPROCESSING = YES; 337 | FRAMEWORK_SEARCH_PATHS = ( 338 | "$(inherited)", 339 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 340 | ); 341 | GCC_DYNAMIC_NO_PIC = NO; 342 | GCC_OPTIMIZATION_LEVEL = 0; 343 | INFOPLIST_FILE = Info.plist; 344 | INSTALL_PATH = "$(HOME)/Library/PreferencePanes"; 345 | LIBRARY_SEARCH_PATHS = ( 346 | "$(inherited)", 347 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/MultitouchSupport.framework\"", 348 | "$(PROJECT_DIR)", 349 | ); 350 | MARKETING_VERSION = 2.75; 351 | PRODUCT_BUNDLE_IDENTIFIER = "com.jitouch.${PRODUCT_NAME:identifier}"; 352 | PRODUCT_NAME = Jitouch; 353 | STRIP_INSTALLED_PRODUCT = YES; 354 | SYSTEM_FRAMEWORK_SEARCH_PATHS = ( 355 | "$(inherited)", 356 | "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", 357 | ); 358 | WRAPPER_EXTENSION = prefPane; 359 | }; 360 | name = Debug; 361 | }; 362 | 1DBD214A08BA80EA00186707 /* Release */ = { 363 | isa = XCBuildConfiguration; 364 | buildSettings = { 365 | CLANG_ENABLE_OBJC_WEAK = YES; 366 | COMBINE_HIDPI_IMAGES = YES; 367 | CURRENT_PROJECT_VERSION = 2.75; 368 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 369 | DEPLOYMENT_POSTPROCESSING = YES; 370 | FRAMEWORK_SEARCH_PATHS = ( 371 | "$(inherited)", 372 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"", 373 | ); 374 | INFOPLIST_FILE = Info.plist; 375 | INSTALL_PATH = "$(HOME)/Library/PreferencePanes"; 376 | LIBRARY_SEARCH_PATHS = ( 377 | "$(inherited)", 378 | "\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks/MultitouchSupport.framework\"", 379 | "$(PROJECT_DIR)", 380 | ); 381 | MARKETING_VERSION = 2.75; 382 | PRODUCT_BUNDLE_IDENTIFIER = "com.jitouch.${PRODUCT_NAME:identifier}"; 383 | PRODUCT_NAME = Jitouch; 384 | STRIP_INSTALLED_PRODUCT = YES; 385 | SYSTEM_FRAMEWORK_SEARCH_PATHS = ( 386 | "$(inherited)", 387 | "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks", 388 | ); 389 | WRAPPER_EXTENSION = prefPane; 390 | }; 391 | name = Release; 392 | }; 393 | 1DBD214D08BA80EA00186707 /* Debug */ = { 394 | isa = XCBuildConfiguration; 395 | buildSettings = { 396 | CLANG_ENABLE_MODULES = YES; 397 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 398 | CLANG_WARN_BOOL_CONVERSION = YES; 399 | CLANG_WARN_COMMA = YES; 400 | CLANG_WARN_CONSTANT_CONVERSION = YES; 401 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 402 | CLANG_WARN_EMPTY_BODY = YES; 403 | CLANG_WARN_ENUM_CONVERSION = YES; 404 | CLANG_WARN_INFINITE_RECURSION = YES; 405 | CLANG_WARN_INT_CONVERSION = YES; 406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 409 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 411 | CLANG_WARN_STRICT_PROTOTYPES = YES; 412 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 413 | CLANG_WARN_UNREACHABLE_CODE = YES; 414 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 415 | ENABLE_STRICT_OBJC_MSGSEND = YES; 416 | ENABLE_TESTABILITY = YES; 417 | GCC_C_LANGUAGE_STANDARD = gnu99; 418 | GCC_NO_COMMON_BLOCKS = YES; 419 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 420 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 421 | GCC_WARN_UNDECLARED_SELECTOR = YES; 422 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 423 | GCC_WARN_UNUSED_FUNCTION = YES; 424 | GCC_WARN_UNUSED_VARIABLE = YES; 425 | MACOSX_DEPLOYMENT_TARGET = 10.9; 426 | MTL_ENABLE_DEBUG_INFO = YES; 427 | ONLY_ACTIVE_ARCH = YES; 428 | SDKROOT = macosx; 429 | }; 430 | name = Debug; 431 | }; 432 | 1DBD214E08BA80EA00186707 /* Release */ = { 433 | isa = XCBuildConfiguration; 434 | buildSettings = { 435 | CLANG_ENABLE_MODULES = YES; 436 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 437 | CLANG_WARN_BOOL_CONVERSION = YES; 438 | CLANG_WARN_COMMA = YES; 439 | CLANG_WARN_CONSTANT_CONVERSION = YES; 440 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 441 | CLANG_WARN_EMPTY_BODY = YES; 442 | CLANG_WARN_ENUM_CONVERSION = YES; 443 | CLANG_WARN_INFINITE_RECURSION = YES; 444 | CLANG_WARN_INT_CONVERSION = YES; 445 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 446 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 447 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 448 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; 449 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 450 | CLANG_WARN_STRICT_PROTOTYPES = YES; 451 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 452 | CLANG_WARN_UNREACHABLE_CODE = YES; 453 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 454 | ENABLE_NS_ASSERTIONS = NO; 455 | ENABLE_STRICT_OBJC_MSGSEND = YES; 456 | GCC_C_LANGUAGE_STANDARD = gnu99; 457 | GCC_NO_COMMON_BLOCKS = YES; 458 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 459 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 460 | GCC_WARN_UNDECLARED_SELECTOR = YES; 461 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 462 | GCC_WARN_UNUSED_FUNCTION = YES; 463 | GCC_WARN_UNUSED_VARIABLE = YES; 464 | MACOSX_DEPLOYMENT_TARGET = 10.9; 465 | MTL_ENABLE_DEBUG_INFO = NO; 466 | ONLY_ACTIVE_ARCH = NO; 467 | SDKROOT = macosx; 468 | }; 469 | name = Release; 470 | }; 471 | /* End XCBuildConfiguration section */ 472 | 473 | /* Begin XCConfigurationList section */ 474 | 1DBD214808BA80EA00186707 /* Build configuration list for PBXNativeTarget "Jitouch" */ = { 475 | isa = XCConfigurationList; 476 | buildConfigurations = ( 477 | 1DBD214908BA80EA00186707 /* Debug */, 478 | 1DBD214A08BA80EA00186707 /* Release */, 479 | ); 480 | defaultConfigurationIsVisible = 0; 481 | defaultConfigurationName = Release; 482 | }; 483 | 1DBD214C08BA80EA00186707 /* Build configuration list for PBXProject "Jitouch" */ = { 484 | isa = XCConfigurationList; 485 | buildConfigurations = ( 486 | 1DBD214D08BA80EA00186707 /* Debug */, 487 | 1DBD214E08BA80EA00186707 /* Release */, 488 | ); 489 | defaultConfigurationIsVisible = 0; 490 | defaultConfigurationName = Release; 491 | }; 492 | /* End XCConfigurationList section */ 493 | }; 494 | rootObject = 089C1669FE841209C02AAC07 /* Project object */; 495 | } 496 | -------------------------------------------------------------------------------- /prefpane/JitouchPref.h: -------------------------------------------------------------------------------- 1 | // 2 | // JitouchPref.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class KeyTextView; 11 | @class Update; 12 | 13 | @interface JitouchPref : NSPreferencePane { 14 | NSWindow *window; 15 | 16 | IBOutlet NSSlider *sdClickSpeed; 17 | IBOutlet NSSlider *sdSensitivity; 18 | IBOutlet NSSegmentedControl *scAll; 19 | IBOutlet NSButton *cbShowIcon; 20 | IBOutlet NSTabView *mainTabView; 21 | IBOutlet NSScrollView *scrollView; 22 | 23 | KeyTextView *keyTextView; 24 | } 25 | 26 | - (IBAction)change:(id)sender; 27 | - (void) mainViewDidLoad; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /prefpane/JitouchPref.m: -------------------------------------------------------------------------------- 1 | // 2 | // JitouchPref.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "JitouchPref.h" 9 | #import "KeyTextField.h" 10 | #import "KeyTextView.h" 11 | #import "Settings.h" 12 | #import "TrackpadTab.h" 13 | #import "MagicMouseTab.h" 14 | #import "RecognitionTab.h" 15 | #import 16 | 17 | @implementation JitouchPref 18 | 19 | CFMachPortRef eventTap; 20 | 21 | - (void)enUpdated { 22 | [trackpadTab enUpdated]; 23 | [magicMouseTab enUpdated]; 24 | [recognitionTab enUpdated]; 25 | if (enAll) { 26 | [sdClickSpeed setEnabled:YES]; 27 | [sdSensitivity setEnabled:YES]; 28 | } else { 29 | [sdClickSpeed setEnabled:NO]; 30 | [sdSensitivity setEnabled:NO]; 31 | } 32 | } 33 | 34 | - (IBAction)change:(id)sender { 35 | if (sender == scAll) { 36 | int value = (int)[sender selectedSegment]; 37 | enAll = value; 38 | [Settings setKey:@"enAll" withInt:value]; 39 | 40 | [self enUpdated]; 41 | } else if (sender == cbShowIcon) { 42 | int value = [sender state] == NSOnState ? 1: 0; 43 | [Settings setKey:@"ShowIcon" withInt:value]; 44 | } else if (sender == sdClickSpeed) { 45 | clickSpeed = 0.5 - [sender floatValue]; 46 | [Settings setKey:@"ClickSpeed" withFloat:0.5 - [sender floatValue]]; 47 | } else if (sender == sdSensitivity) { 48 | stvt = [sender floatValue]; 49 | [Settings setKey:@"Sensitivity" withFloat:[sender floatValue]]; 50 | } 51 | [Settings noteSettingsUpdated]; 52 | } 53 | 54 | - (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject { 55 | if ([anObject isKindOfClass:[KeyTextField class]]) { 56 | if (!keyTextView) { 57 | keyTextView = [[KeyTextView alloc] init]; 58 | [keyTextView setFieldEditor:YES]; 59 | } 60 | return keyTextView; 61 | } 62 | return nil; 63 | } 64 | 65 | #pragma mark - 66 | 67 | - (BOOL)jitouchIsRunning { 68 | NSArray *apps = [[NSWorkspace sharedWorkspace] runningApplications]; 69 | for (NSRunningApplication *app in apps) { 70 | if ([app.bundleIdentifier isEqualToString:@"com.jitouch.Jitouch"]) 71 | return YES; 72 | } 73 | return NO; 74 | } 75 | 76 | - (void)settingsUpdated:(NSNotification *)aNotification { 77 | NSDictionary *d = [aNotification userInfo]; 78 | [Settings readSettings2:d]; 79 | 80 | [scAll setSelectedSegment:enAll]; 81 | [self enUpdated]; 82 | } 83 | 84 | 85 | - (void)killAllJitouchs { 86 | NSString *script = @"killall Jitouch"; 87 | NSArray *shArgs = [NSArray arrayWithObjects:@"-c", script, @"", nil]; 88 | [NSTask launchedTaskWithLaunchPath:@"/bin/sh" arguments:shArgs]; 89 | } 90 | 91 | 92 | static CGEventRef CGEventCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon) { 93 | if ([NSApp isActive] && [[[NSApp keyWindow] firstResponder] isKindOfClass:[KeyTextView class]]) { 94 | if (type == kCGEventKeyDown) { 95 | int64_t keyCode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode); 96 | CGEventFlags flags = CGEventGetFlags(event); 97 | [(KeyTextView*)[[NSApp keyWindow] firstResponder] handleEventKeyCode:keyCode flags:flags]; 98 | return NULL; 99 | } else if (type == kCGEventKeyUp) { 100 | return NULL; 101 | } 102 | } 103 | return event; 104 | } 105 | 106 | 107 | - (void)addJitouchToLoginItems{ 108 | NSString *jitouchPath = [NSString stringWithFormat:@"file://%@", [[self bundle] pathForResource:@"Jitouch" ofType:@"app"]]; 109 | NSURL *jitouchURL = [NSURL URLWithString:jitouchPath]; 110 | 111 | LSSharedFileListRef loginListRef = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL); 112 | if (loginListRef) { 113 | // delete all shortcuts to jitouch in the login items 114 | UInt32 seedValue; 115 | NSArray *loginItemsArray = (NSArray *)LSSharedFileListCopySnapshot(loginListRef, &seedValue); 116 | for (id item in loginItemsArray) { 117 | LSSharedFileListItemRef itemRef = (LSSharedFileListItemRef)item; 118 | CFURLRef thePath; 119 | if (LSSharedFileListItemResolve(itemRef, 0, (CFURLRef*) &thePath, NULL) == noErr) { 120 | NSRange range = [[(NSURL*)thePath path] rangeOfString:@"Jitouch"]; 121 | if (range.location != NSNotFound) 122 | LSSharedFileListItemRemove(loginListRef, itemRef); 123 | } 124 | } 125 | [loginItemsArray release]; 126 | 127 | 128 | if (![settings objectForKey:@"StartAtLogin"] || [[settings objectForKey:@"StartAtLogin"] intValue]) { 129 | // add shortcut to jitouch in the login items (there should be only one shortcut) 130 | LSSharedFileListItemRef loginItemRef = LSSharedFileListInsertItemURL(loginListRef, kLSSharedFileListItemLast, NULL, NULL, (CFURLRef)jitouchURL, NULL, NULL); 131 | 132 | if (loginItemRef) { 133 | CFRelease(loginItemRef); 134 | } 135 | } 136 | 137 | CFRelease(loginListRef); 138 | } 139 | } 140 | 141 | - (void)mainViewDidLoad { 142 | isPrefPane = YES; 143 | [Settings loadSettings:self]; 144 | 145 | [scAll setSelectedSegment:enAll]; 146 | [cbShowIcon setState:[[settings objectForKey:@"ShowIcon"] intValue]]; 147 | [sdClickSpeed setFloatValue:0.5-clickSpeed]; 148 | [sdSensitivity setFloatValue:stvt]; 149 | 150 | [self enUpdated]; 151 | 152 | [[NSDistributedNotificationCenter defaultCenter] addObserver: self 153 | selector: @selector(settingsUpdated:) 154 | name: @"My Notification2" 155 | object: @"com.jitouch.Jitouch.PrefpaneTarget2"]; 156 | 157 | 158 | BOOL running = [self jitouchIsRunning]; 159 | if (running && hasPreviousVersion) { 160 | [self killAllJitouchs]; 161 | running = NO; 162 | } 163 | [self addJitouchToLoginItems]; 164 | //if (!running) { 165 | NSString *pathToJitouchInBundle = [[self bundle] pathForResource:@"Jitouch" ofType:@"app"]; 166 | [[NSWorkspace sharedWorkspace] openFile:pathToJitouchInBundle]; 167 | //} 168 | 169 | 170 | NSInteger tabIndex; 171 | if ([settings objectForKey:@"LastTab"] && (tabIndex=[mainTabView indexOfTabViewItemWithIdentifier:[settings objectForKey:@"LastTab"]]) != NSNotFound) { 172 | [mainTabView selectTabViewItemAtIndex:tabIndex]; 173 | } else { 174 | CFMutableDictionaryRef matchingDict = IOServiceNameMatching("AppleUSBMultitouchDriver"); 175 | io_registry_entry_t service = (io_registry_entry_t)IOServiceGetMatchingService(kIOMasterPortDefault, matchingDict); 176 | if (service) { 177 | [mainTabView selectTabViewItemWithIdentifier:@"Trackpad"]; 178 | } else { 179 | [mainTabView selectTabViewItemWithIdentifier:@"Magic Mouse"]; 180 | } 181 | } 182 | 183 | mainView = [self mainView]; 184 | 185 | } 186 | 187 | - (void)willSelect { 188 | BOOL trusted = AXIsProcessTrustedWithOptions((CFDictionaryRef)@{(id)kAXTrustedCheckOptionPrompt: @(YES)}); 189 | 190 | if (trusted && !eventKeyboard) { 191 | CGEventMask eventMask = CGEventMaskBit(kCGEventKeyDown) | CGEventMaskBit(kCGEventKeyUp); 192 | eventKeyboard = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, eventMask, CGEventCallback, NULL); 193 | 194 | CGEventTapEnable(eventKeyboard, false); 195 | CFRunLoopSourceRef runLoopSource = CFMachPortCreateRunLoopSource( kCFAllocatorDefault, eventKeyboard, 0); 196 | CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSource, kCFRunLoopCommonModes); 197 | } 198 | } 199 | 200 | - (void)willUnselect { 201 | [trackpadTab willUnselect]; 202 | [magicMouseTab willUnselect]; 203 | [recognitionTab willUnselect]; 204 | } 205 | 206 | - (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem { 207 | [Settings setKey:@"LastTab" with:[tabViewItem identifier]]; 208 | [settings setObject:[tabViewItem identifier] forKey:@"LastTab"]; 209 | } 210 | 211 | @end 212 | -------------------------------------------------------------------------------- /prefpane/JitouchPref.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/prefpane/JitouchPref.png -------------------------------------------------------------------------------- /prefpane/JitouchPref@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/prefpane/JitouchPref@2x.png -------------------------------------------------------------------------------- /prefpane/KeyTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyTextField.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface KeyTextField : NSTextField { 11 | NSUInteger modifierFlags; 12 | unsigned short keyCode; 13 | } 14 | 15 | @property (nonatomic) NSUInteger modifierFlags; 16 | @property (nonatomic) unsigned short keyCode; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /prefpane/KeyTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyTextField.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "KeyTextField.h" 9 | 10 | @implementation KeyTextField 11 | 12 | @synthesize modifierFlags, keyCode; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /prefpane/KeyTextView.h: -------------------------------------------------------------------------------- 1 | // 2 | // KeyTextView.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface KeyTextView : NSTextView 11 | 12 | - (void)handleEventKeyCode:(int64_t)keyCode flags:(CGEventFlags)flags; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /prefpane/KeyTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // KeyTextView.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "KeyTextView.h" 9 | #import 10 | #import "KeyTextField.h" 11 | #import "CommandTableView.h" 12 | #import "Settings.h" 13 | 14 | @implementation KeyTextView 15 | 16 | - (BOOL)becomeFirstResponder { 17 | if (eventKeyboard) CGEventTapEnable(eventKeyboard, true); 18 | return YES; 19 | } 20 | 21 | - (BOOL)resignFirstResponder { 22 | if (eventKeyboard) CGEventTapEnable(eventKeyboard, false); 23 | return YES; 24 | } 25 | 26 | - (void)handleEventKeyCode:(int64_t)keyCode flags:(CGEventFlags)flags { 27 | NSString *modifierKeys = @""; 28 | 29 | if (flags & kCGEventFlagMaskControl) { 30 | modifierKeys = [modifierKeys stringByAppendingString:@"⌃"]; 31 | } 32 | if (flags & kCGEventFlagMaskAlternate) { 33 | modifierKeys = [modifierKeys stringByAppendingString:@"⌥"]; 34 | } 35 | if (flags & kCGEventFlagMaskShift) { 36 | modifierKeys = [modifierKeys stringByAppendingString:@"⇧"]; 37 | } 38 | if (flags & kCGEventFlagMaskCommand) { 39 | modifierKeys = [modifierKeys stringByAppendingString:@"⌘"]; 40 | } 41 | 42 | NSString *chr; 43 | if (keyCode == 123) { //left 44 | chr = @"←"; 45 | } else if (keyCode == 124) { //right 46 | chr = @"→"; 47 | } else if (keyCode == 125) { //down 48 | chr = @"↓"; 49 | } else if (keyCode == 126) { //up 50 | chr = @"↑"; 51 | } else if (keyCode == 36) { //return 52 | chr = @"↩"; 53 | } else if (keyCode == 48) { //tab 54 | chr = @"⇥"; 55 | } else if (keyCode == 49) { //space 56 | chr = @"Space"; 57 | } else if (keyCode == 51) { //delete 58 | chr = @"⌫"; 59 | } else if (keyCode == 53) { //escape 60 | chr = @"⎋"; 61 | } else if (keyCode == 117) { //forward delete 62 | chr = @"⌦"; 63 | } else if (keyCode == 76) { //enter 64 | chr = @"⌅"; 65 | } else if (keyCode == 116) { //page up 66 | chr = @"Page Up"; 67 | } else if (keyCode == 121) { //page down 68 | chr = @"Page Down"; 69 | } else if (keyCode == 115) { //home 70 | chr = @"Home"; 71 | } else if (keyCode == 119) { //end 72 | chr = @"End"; 73 | } else if (keyCode == 122) { // 74 | chr = @"F1"; 75 | } else if (keyCode == 120) { // 76 | chr = @"F2"; 77 | } else if (keyCode == 99) { // 78 | chr = @"F3"; 79 | } else if (keyCode == 118) { // 80 | chr = @"F4"; 81 | } else if (keyCode == 96) { // 82 | chr = @"F5"; 83 | } else if (keyCode == 97) { // 84 | chr = @"F6"; 85 | } else if (keyCode == 98) { // 86 | chr = @"F7"; 87 | } else if (keyCode == 100) { // 88 | chr = @"F8"; 89 | } else if (keyCode == 101) { // 90 | chr = @"F9"; 91 | } else if (keyCode == 109) { // 92 | chr = @"F10"; 93 | } else if (keyCode == 103) { // 94 | chr = @"F11"; 95 | } else if (keyCode == 111) { // 96 | chr = @"F12"; 97 | } else { 98 | UInt32 deadKeyState = 0; 99 | UniCharCount actualCount = 0; 100 | UniChar baseChar; 101 | TISInputSourceRef sourceRef = TISCopyCurrentKeyboardLayoutInputSource(); 102 | CFDataRef keyLayoutPtr = (CFDataRef)TISGetInputSourceProperty( sourceRef, kTISPropertyUnicodeKeyLayoutData); 103 | CFRelease( sourceRef); 104 | UCKeyTranslate( (UCKeyboardLayout*)CFDataGetBytePtr(keyLayoutPtr), 105 | keyCode, 106 | kUCKeyActionDown, 107 | 0, 108 | LMGetKbdType(), 109 | kUCKeyTranslateNoDeadKeysBit, 110 | &deadKeyState, 111 | 1, 112 | &actualCount, 113 | &baseChar); 114 | chr = [[NSString stringWithFormat:@"%c", baseChar] capitalizedString]; 115 | } 116 | 117 | 118 | modifierKeys = [modifierKeys stringByAppendingString:chr]; 119 | [self replaceCharactersInRange:NSMakeRange(0, [[self.textStorage mutableString] length]) 120 | withString:modifierKeys]; 121 | if ([[self delegate] isKindOfClass:[KeyTextField class]]) { 122 | KeyTextField *textField = (KeyTextField*)[self delegate]; 123 | textField.modifierFlags = flags; 124 | textField.keyCode = keyCode; 125 | [self selectAll:nil]; 126 | //[self didChangeText]; 127 | //[textField textDidChange:nil]; 128 | [textField sendAction:[textField action] to:[textField target]]; 129 | } 130 | } 131 | 132 | - (void)keyDown:(NSEvent *)theEvent { 133 | if (eventKeyboard) 134 | CGEventTapEnable(eventKeyboard, true); //in case something goes wrong 135 | } 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /prefpane/LinkTextField.h: -------------------------------------------------------------------------------- 1 | // 2 | // LinkTextField.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @interface LinkTextField : NSTextField 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /prefpane/LinkTextField.m: -------------------------------------------------------------------------------- 1 | // 2 | // LinkTextField.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "LinkTextField.h" 9 | 10 | @implementation LinkTextField 11 | 12 | - (void)mouseUp:(NSEvent *)event { 13 | [[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:[self stringValue]]]; 14 | } 15 | 16 | - (void)resetCursorRects { 17 | [self addCursorRect:self.bounds cursor:[NSCursor pointingHandCursor]]; 18 | } 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /prefpane/MAAttachedWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // MAAttachedWindow.h 3 | // 4 | // Created by Matt Gemmell on 27/09/2007. 5 | // Copyright 2007 Magic Aubergine. 6 | // 7 | 8 | #import 9 | 10 | /* 11 | Below are the positions the attached window can be displayed at. 12 | 13 | Note that these positions are relative to the point passed to the constructor, 14 | e.g. MAPositionBottomRight will put the window below the point and towards the right, 15 | MAPositionTop will horizontally center the window above the point, 16 | MAPositionRightTop will put the window to the right and above the point, 17 | and so on. 18 | 19 | You can also pass MAPositionAutomatic (or use an initializer which omits the 'onSide:' 20 | argument) and the attached window will try to position itself sensibly, based on 21 | available screen-space. 22 | 23 | Notes regarding automatically-positioned attached windows: 24 | 25 | (a) The window prefers to position itself horizontally centered below the specified point. 26 | This gives a certain enhanced visual sense of an attachment/relationship. 27 | 28 | (b) The window will try to align itself with its parent window (if any); i.e. it will 29 | attempt to stay within its parent window's frame if it can. 30 | 31 | (c) The algorithm isn't perfect. :) If in doubt, do your own calculations and then 32 | explicitly request that the window attach itself to a particular side. 33 | */ 34 | 35 | typedef enum _MAWindowPosition { 36 | // The four primary sides are compatible with the preferredEdge of NSDrawer. 37 | MAPositionLeft = NSMinXEdge, // 0 38 | MAPositionRight = NSMaxXEdge, // 2 39 | MAPositionTop = NSMaxYEdge, // 3 40 | MAPositionBottom = NSMinYEdge, // 1 41 | MAPositionLeftTop = 4, 42 | MAPositionLeftBottom = 5, 43 | MAPositionRightTop = 6, 44 | MAPositionRightBottom = 7, 45 | MAPositionTopLeft = 8, 46 | MAPositionTopRight = 9, 47 | MAPositionBottomLeft = 10, 48 | MAPositionBottomRight = 11, 49 | MAPositionAutomatic = 12 50 | } MAWindowPosition; 51 | 52 | @interface MAAttachedWindow : NSWindow { 53 | NSColor *borderColor; 54 | float borderWidth; 55 | float viewMargin; 56 | float arrowBaseWidth; 57 | float arrowHeight; 58 | BOOL hasArrow; 59 | float cornerRadius; 60 | BOOL drawsRoundCornerBesideArrow; 61 | 62 | @private 63 | NSColor *_MABackgroundColor; 64 | __weak NSView *_view; 65 | __weak NSWindow *_window; 66 | NSPoint _point; 67 | MAWindowPosition _side; 68 | float _distance; 69 | NSRect _viewFrame; 70 | BOOL _resizing; 71 | int _device; 72 | } 73 | 74 | /* 75 | Initialization methods 76 | 77 | Parameters: 78 | 79 | view The view to display in the attached window. Must not be nil. 80 | 81 | point The point to which the attached window should be attached. If you 82 | are also specifying a parent window, the point should be in the 83 | coordinate system of that parent window. If you are not specifying 84 | a window, the point should be in the screen's coordinate space. 85 | This value is required. 86 | 87 | window The parent window to attach this one to. Note that no actual 88 | relationship is created (particularly, this window is not made 89 | a childWindow of the parent window). 90 | Default: nil. 91 | 92 | side The side of the specified point on which to attach this window. 93 | Default: MAPositionAutomatic. 94 | 95 | distance How far from the specified point this window should be. 96 | Default: 0. 97 | */ 98 | 99 | - (MAAttachedWindow *)initWithView:(NSView *)view // designated initializer 100 | attachedToPoint:(NSPoint)point 101 | inWindow:(NSWindow *)window 102 | onSide:(MAWindowPosition)side 103 | atDistance:(float)distance; 104 | - (MAAttachedWindow *)initWithView:(NSView *)view 105 | attachedToPoint:(NSPoint)point 106 | inWindow:(NSWindow *)window 107 | atDistance:(float)distance; 108 | - (MAAttachedWindow *)initWithView:(NSView *)view 109 | attachedToPoint:(NSPoint)point 110 | onSide:(MAWindowPosition)side 111 | atDistance:(float)distance; 112 | - (MAAttachedWindow *)initWithView:(NSView *)view 113 | attachedToPoint:(NSPoint)point 114 | atDistance:(float)distance; 115 | - (MAAttachedWindow *)initWithView:(NSView *)view 116 | attachedToPoint:(NSPoint)point 117 | inWindow:(NSWindow *)window; 118 | - (MAAttachedWindow *)initWithView:(NSView *)view 119 | attachedToPoint:(NSPoint)point 120 | onSide:(MAWindowPosition)side; 121 | - (MAAttachedWindow *)initWithView:(NSView *)view 122 | attachedToPoint:(NSPoint)point; 123 | 124 | // Accessor methods 125 | - (void)setPoint:(NSPoint)point side:(MAWindowPosition)side; 126 | - (NSColor *)borderColor; 127 | - (void)setBorderColor:(NSColor *)value; 128 | - (float)borderWidth; 129 | - (void)setBorderWidth:(float)value; // See note 1 below. 130 | - (float)viewMargin; 131 | - (void)setViewMargin:(float)value; // See note 2 below. 132 | - (float)arrowBaseWidth; 133 | - (void)setArrowBaseWidth:(float)value; // See note 2 below. 134 | - (float)arrowHeight; 135 | - (void)setArrowHeight:(float)value; // See note 2 below. 136 | - (float)hasArrow; 137 | - (void)setHasArrow:(float)value; 138 | - (float)cornerRadius; 139 | - (void)setCornerRadius:(float)value; // See note 2 below. 140 | - (float)drawsRoundCornerBesideArrow; // See note 3 below. 141 | - (void)setDrawsRoundCornerBesideArrow:(float)value; // See note 2 below. 142 | - (void)setBackgroundImage:(NSImage *)value; 143 | - (NSColor *)windowBackgroundColor; // See note 4 below. 144 | - (void)setBackgroundColor:(NSColor *)value; 145 | - (void)setDevice:(int)device; 146 | 147 | /* 148 | Notes regarding accessor methods: 149 | 150 | 1. The border is drawn inside the viewMargin area, expanding inwards; it does not 151 | increase the width/height of the window. You can use the -setBorderWidth: and 152 | -setViewMargin: methods together to achieve the exact look/geometry you want. 153 | (viewMargin is the distance between the edge of the view and the window edge.) 154 | 155 | 2. The specified setter methods are primarily intended to be used _before_ the window 156 | is first shown. If you use them while the window is already visible, be aware 157 | that they may cause the window to move and/or resize, in order to stay anchored 158 | to the point specified in the initializer. They may also cause the view to move 159 | within the window, in order to remain centered there. 160 | 161 | Note that the -setHasArrow: method can safely be used at any time, and will not 162 | cause moving/resizing of the window. This is for convenience, in case you want 163 | to add or remove the arrow in response to user interaction. For example, you 164 | could make the attached window movable by its background, and if the user dragged 165 | it away from its initial point, the arrow could be removed. This would duplicate 166 | how Aperture's attached windows behave. 167 | 168 | 3. drawsRoundCornerBesideArrow takes effect when the arrow is being drawn at a corner, 169 | i.e. when it's not at one of the four primary compass directions. In this situation, 170 | if drawsRoundCornerBesideArrow is YES (the default), then that corner of the window 171 | will be rounded just like the other three corners, thus the arrow will be inset 172 | slightly from the edge of the window to allow room for the rounded corner. If this 173 | value is NO, the corner beside the arrow will be a square corner, and the other 174 | three corners will be rounded. 175 | 176 | This is useful when you want to attach a window very near the edge of another window, 177 | and don't want the attached window's edge to be visually outside the frame of the 178 | parent window. 179 | 180 | 4. Note that to retrieve the background color of the window, you should use the 181 | -windowBackgroundColor method, instead of -backgroundColor. This is because we draw 182 | the entire background of the window (rounded path, arrow, etc) in an NSColor pattern 183 | image, and set it as the backgroundColor of the window. 184 | */ 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /prefpane/MAAttachedWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // MAAttachedWindow.m 3 | // 4 | // Created by Matt Gemmell on 27/09/2007. 5 | // Copyright 2007 Magic Aubergine. 6 | // 7 | 8 | #import "MAAttachedWindow.h" 9 | 10 | #define MAATTACHEDWINDOW_DEFAULT_BACKGROUND_COLOR [NSColor colorWithCalibratedWhite:0.1 alpha:0.75] 11 | #define MAATTACHEDWINDOW_DEFAULT_BORDER_COLOR [NSColor whiteColor] 12 | #define MAATTACHEDWINDOW_SCALE_FACTOR 1.0 13 | 14 | @interface MAAttachedWindow (MAPrivateMethods) 15 | 16 | // Geometry 17 | - (void)_updateGeometry; 18 | - (float)_arrowInset; 19 | 20 | // Drawing 21 | - (void)_updateBackground; 22 | - (NSColor *)_backgroundColorPatternImage; 23 | - (NSBezierPath *)_backgroundPath; 24 | - (void)_appendArrowToPath:(NSBezierPath *)path; 25 | - (void)_redisplay; 26 | 27 | @end 28 | 29 | @implementation MAAttachedWindow 30 | 31 | 32 | #pragma mark Initializers 33 | 34 | 35 | - (MAAttachedWindow *)initWithView:(NSView *)view 36 | attachedToPoint:(NSPoint)point 37 | inWindow:(NSWindow *)window 38 | onSide:(MAWindowPosition)side 39 | atDistance:(float)distance 40 | { 41 | // Insist on having a valid view. 42 | if (!view) { 43 | return nil; 44 | } 45 | 46 | // Create dummy initial contentRect for window. 47 | NSRect contentRect = NSZeroRect; 48 | contentRect.size = [view frame].size; 49 | 50 | if ((self = [super initWithContentRect:contentRect 51 | styleMask:NSBorderlessWindowMask 52 | backing:NSBackingStoreBuffered 53 | defer:NO])) { 54 | _view = view; 55 | _window = window; 56 | _point = point; 57 | _side = side; 58 | _distance = distance; 59 | 60 | // Configure window characteristics. 61 | [super setBackgroundColor:[NSColor clearColor]]; 62 | [self setMovableByWindowBackground:NO]; 63 | [self setExcludedFromWindowsMenu:YES]; 64 | [self setAlphaValue:1.0]; 65 | [self setOpaque:NO]; 66 | [self setHasShadow:YES]; 67 | [self useOptimizedDrawing:YES]; 68 | 69 | // Set up some sensible defaults for display. 70 | _MABackgroundColor = [MAATTACHEDWINDOW_DEFAULT_BACKGROUND_COLOR copy]; 71 | borderColor = [MAATTACHEDWINDOW_DEFAULT_BORDER_COLOR copy]; 72 | borderWidth = 2.0; 73 | viewMargin = 2.0; 74 | arrowBaseWidth = 20.0; 75 | arrowHeight = 16.0; 76 | hasArrow = YES; 77 | cornerRadius = 8.0; 78 | drawsRoundCornerBesideArrow = YES; 79 | _resizing = NO; 80 | 81 | 82 | // Configure our initial geometry. 83 | [self _updateGeometry]; 84 | 85 | // Update the background. 86 | [self _updateBackground]; 87 | 88 | // Add view as subview of our contentView. 89 | [[self contentView] addSubview:_view]; 90 | 91 | // Subscribe to notifications for when we change size. 92 | /* 93 | [[NSNotificationCenter defaultCenter] addObserver:self 94 | selector:@selector(windowDidResize:) 95 | name:NSWindowDidResizeNotification 96 | object:self]; 97 | */ 98 | } 99 | return self; 100 | } 101 | 102 | 103 | - (MAAttachedWindow *)initWithView:(NSView *)view 104 | attachedToPoint:(NSPoint)point 105 | inWindow:(NSWindow *)window 106 | atDistance:(float)distance 107 | { 108 | return [self initWithView:view attachedToPoint:point 109 | inWindow:window onSide:MAPositionAutomatic 110 | atDistance:distance]; 111 | } 112 | 113 | 114 | - (MAAttachedWindow *)initWithView:(NSView *)view 115 | attachedToPoint:(NSPoint)point 116 | onSide:(MAWindowPosition)side 117 | atDistance:(float)distance 118 | { 119 | return [self initWithView:view attachedToPoint:point 120 | inWindow:nil onSide:side 121 | atDistance:distance]; 122 | } 123 | 124 | 125 | - (MAAttachedWindow *)initWithView:(NSView *)view 126 | attachedToPoint:(NSPoint)point 127 | atDistance:(float)distance 128 | { 129 | return [self initWithView:view attachedToPoint:point 130 | inWindow:nil onSide:MAPositionAutomatic 131 | atDistance:distance]; 132 | } 133 | 134 | 135 | - (MAAttachedWindow *)initWithView:(NSView *)view 136 | attachedToPoint:(NSPoint)point 137 | inWindow:(NSWindow *)window 138 | { 139 | return [self initWithView:view attachedToPoint:point 140 | inWindow:window onSide:MAPositionAutomatic 141 | atDistance:0]; 142 | } 143 | 144 | 145 | - (MAAttachedWindow *)initWithView:(NSView *)view 146 | attachedToPoint:(NSPoint)point 147 | onSide:(MAWindowPosition)side 148 | { 149 | return [self initWithView:view attachedToPoint:point 150 | inWindow:nil onSide:side 151 | atDistance:0]; 152 | } 153 | 154 | 155 | - (MAAttachedWindow *)initWithView:(NSView *)view 156 | attachedToPoint:(NSPoint)point 157 | { 158 | return [self initWithView:view attachedToPoint:point 159 | inWindow:nil onSide:MAPositionAutomatic 160 | atDistance:0]; 161 | } 162 | 163 | 164 | - (void)dealloc 165 | { 166 | //[[NSNotificationCenter defaultCenter] removeObserver:self]; 167 | [borderColor release]; 168 | [_MABackgroundColor release]; 169 | 170 | [super dealloc]; 171 | } 172 | 173 | 174 | #pragma mark Geometry 175 | 176 | 177 | - (void)_updateGeometry 178 | { 179 | NSRect contentRect = NSZeroRect; 180 | contentRect.size = [_view frame].size; 181 | 182 | // Account for viewMargin. 183 | _viewFrame = NSMakeRect(viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR, 184 | viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR, 185 | [_view frame].size.width, [_view frame].size.height); 186 | contentRect = NSInsetRect(contentRect, 187 | -viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR, 188 | -viewMargin * MAATTACHEDWINDOW_SCALE_FACTOR); 189 | 190 | // Account for arrowHeight in new window frame. 191 | // Note: we always leave room for the arrow, even if it currently set to 192 | // not be shown. This is so it can easily be toggled whilst the window 193 | // is visible, without altering the window's frame origin point. 194 | float scaledArrowHeight = arrowHeight * MAATTACHEDWINDOW_SCALE_FACTOR; 195 | switch (_side) { 196 | case MAPositionLeft: 197 | case MAPositionLeftTop: 198 | case MAPositionLeftBottom: 199 | contentRect.size.width += scaledArrowHeight; 200 | break; 201 | case MAPositionRight: 202 | case MAPositionRightTop: 203 | case MAPositionRightBottom: 204 | _viewFrame.origin.x += scaledArrowHeight; 205 | contentRect.size.width += scaledArrowHeight; 206 | break; 207 | case MAPositionTop: 208 | case MAPositionTopLeft: 209 | case MAPositionTopRight: 210 | _viewFrame.origin.y += scaledArrowHeight; 211 | contentRect.size.height += scaledArrowHeight; 212 | break; 213 | case MAPositionBottom: 214 | case MAPositionBottomLeft: 215 | case MAPositionBottomRight: 216 | contentRect.size.height += scaledArrowHeight; 217 | break; 218 | default: 219 | break; // won't happen, but this satisfies gcc with -Wall 220 | } 221 | 222 | // Position frame origin appropriately for _side, accounting for arrow-inset. 223 | contentRect.origin = (_window) ? [_window convertPointToScreen:_point] : _point; 224 | float arrowInset = [self _arrowInset]; 225 | float halfWidth = contentRect.size.width / 2.0; 226 | float halfHeight = contentRect.size.height / 2.0; 227 | switch (_side) { 228 | case MAPositionTopLeft: 229 | contentRect.origin.x -= contentRect.size.width - arrowInset; 230 | break; 231 | case MAPositionTop: 232 | contentRect.origin.x -= halfWidth; 233 | break; 234 | case MAPositionTopRight: 235 | contentRect.origin.x -= arrowInset; 236 | break; 237 | case MAPositionBottomLeft: 238 | contentRect.origin.y -= contentRect.size.height; 239 | contentRect.origin.x -= contentRect.size.width - arrowInset; 240 | break; 241 | case MAPositionBottom: 242 | contentRect.origin.y -= contentRect.size.height; 243 | contentRect.origin.x -= halfWidth; 244 | break; 245 | case MAPositionBottomRight: 246 | contentRect.origin.x -= arrowInset; 247 | contentRect.origin.y -= contentRect.size.height; 248 | break; 249 | case MAPositionLeftTop: 250 | contentRect.origin.x -= contentRect.size.width; 251 | contentRect.origin.y -= arrowInset; 252 | break; 253 | case MAPositionLeft: 254 | contentRect.origin.x -= contentRect.size.width; 255 | contentRect.origin.y -= halfHeight; 256 | break; 257 | case MAPositionLeftBottom: 258 | contentRect.origin.x -= contentRect.size.width; 259 | contentRect.origin.y -= contentRect.size.height - arrowInset; 260 | break; 261 | case MAPositionRightTop: 262 | contentRect.origin.y -= arrowInset; 263 | break; 264 | case MAPositionRight: 265 | contentRect.origin.y -= halfHeight; 266 | break; 267 | case MAPositionRightBottom: 268 | contentRect.origin.y -= contentRect.size.height - arrowInset; 269 | break; 270 | default: 271 | break; // won't happen, but this satisfies gcc with -Wall 272 | } 273 | 274 | // Account for _distance in new window frame. 275 | switch (_side) { 276 | case MAPositionLeft: 277 | case MAPositionLeftTop: 278 | case MAPositionLeftBottom: 279 | contentRect.origin.x -= _distance; 280 | break; 281 | case MAPositionRight: 282 | case MAPositionRightTop: 283 | case MAPositionRightBottom: 284 | contentRect.origin.x += _distance; 285 | break; 286 | case MAPositionTop: 287 | case MAPositionTopLeft: 288 | case MAPositionTopRight: 289 | contentRect.origin.y += _distance; 290 | break; 291 | case MAPositionBottom: 292 | case MAPositionBottomLeft: 293 | case MAPositionBottomRight: 294 | contentRect.origin.y -= _distance; 295 | break; 296 | default: 297 | break; // won't happen, but this satisfies gcc with -Wall 298 | } 299 | 300 | // Reconfigure window and view frames appropriately. 301 | [self setFrame:contentRect display:NO]; 302 | [_view setFrame:_viewFrame]; 303 | } 304 | 305 | 306 | - (float)_arrowInset 307 | { 308 | float cornerInset = (drawsRoundCornerBesideArrow) ? cornerRadius : 0; 309 | return (cornerInset + (arrowBaseWidth / 2.0)) * MAATTACHEDWINDOW_SCALE_FACTOR; 310 | } 311 | 312 | 313 | #pragma mark Drawing 314 | 315 | 316 | - (void)_updateBackground 317 | { 318 | // Call NSWindow's implementation of -setBackgroundColor: because we override 319 | // it in this class to let us set the entire background image of the window 320 | // as an NSColor patternImage. 321 | NSDisableScreenUpdates(); 322 | [super setBackgroundColor:[self _backgroundColorPatternImage]]; 323 | if ([self isVisible]) { 324 | [self display]; 325 | [self invalidateShadow]; 326 | } 327 | NSEnableScreenUpdates(); 328 | } 329 | 330 | 331 | - (NSColor *)_backgroundColorPatternImage 332 | { 333 | NSImage *bg = [[NSImage alloc] initWithSize:[self frame].size]; 334 | NSRect bgRect = NSZeroRect; 335 | bgRect.size = [bg size]; 336 | 337 | [bg lockFocus]; 338 | NSBezierPath *bgPath = [self _backgroundPath]; 339 | [NSGraphicsContext saveGraphicsState]; 340 | [bgPath addClip]; 341 | 342 | // Draw background. 343 | [_MABackgroundColor set]; 344 | [bgPath fill]; 345 | //[bgPath stroke]; 346 | 347 | [NSGraphicsContext restoreGraphicsState]; 348 | [bg unlockFocus]; 349 | 350 | return [NSColor colorWithPatternImage:[bg autorelease]]; 351 | } 352 | 353 | 354 | - (NSBezierPath *)_backgroundPath 355 | { 356 | /* 357 | Construct path for window background, taking account of: 358 | 1. hasArrow 359 | 2. _side 360 | 3. drawsRoundCornerBesideArrow 361 | 4. arrowBaseWidth 362 | 5. arrowHeight 363 | 6. cornerRadius 364 | */ 365 | 366 | float scaleFactor = MAATTACHEDWINDOW_SCALE_FACTOR; 367 | float scaledRadius = cornerRadius * scaleFactor; 368 | float scaledArrowWidth = arrowBaseWidth * scaleFactor; 369 | float halfArrowWidth = scaledArrowWidth / 2.0; 370 | NSRect contentArea = NSInsetRect(_viewFrame, 371 | -viewMargin * scaleFactor, 372 | -viewMargin * scaleFactor); 373 | float minX = ceilf(NSMinX(contentArea) * scaleFactor + 0.5f); 374 | //float midX = NSMidX(contentArea) * scaleFactor; 375 | float maxX = floorf(NSMaxX(contentArea) * scaleFactor - 0.5f); 376 | float minY = ceilf(NSMinY(contentArea) * scaleFactor + 0.5f); 377 | float midY = NSMidY(contentArea) * scaleFactor; 378 | float maxY = floorf(NSMaxY(contentArea) * scaleFactor - 0.5f); 379 | 380 | NSBezierPath *path2; 381 | 382 | if (_device == 0) { //Trackpad 383 | 384 | path2 = [NSBezierPath bezierPath]; 385 | [path2 moveToPoint:NSMakePoint(0,0)]; 386 | [path2 appendBezierPathWithRoundedRect:NSMakeRect(minX, minY, maxX-minX, maxY-minY) xRadius:scaledRadius yRadius:scaledRadius]; 387 | [path2 closePath]; 388 | 389 | NSBezierPath *path3 = [NSBezierPath bezierPath]; 390 | [path3 moveToPoint:NSMakePoint(maxX, midY + halfArrowWidth)]; 391 | [self _appendArrowToPath:path3]; 392 | [path3 closePath]; 393 | 394 | [path2 appendBezierPath:path3]; 395 | 396 | } else { 397 | 398 | float w = maxX - minX; 399 | float h = maxY - minY; 400 | /* 401 | path2 = [NSBezierPath bezierPath]; 402 | [path2 moveToPoint:NSMakePoint((0.5-0.163)*w,(0.5-0.495)*h)]; 403 | [path2 curveToPoint:NSMakePoint(0.5*w, 0*h) controlPoint1:NSMakePoint((0.5-0.079)*w, (0.5-0.499)*h) controlPoint2:NSMakePoint((0.5-0.079)*w, (0.5-0.499)*h)]; 404 | [path2 curveToPoint:NSMakePoint((0.5+0.163)*w, (0.5-0.495)*h) controlPoint1:NSMakePoint((0.5+0.079)*w, (0.5-0.499)*h) controlPoint2:NSMakePoint((0.5+0.084)*w, (0.5-0.499)*h)]; 405 | [path2 curveToPoint:NSMakePoint((0.5+0.48)*w, (0.5-0.316)*h) controlPoint1:NSMakePoint((0.5+0.321)*w, (0.5-0.483)*h) controlPoint2:NSMakePoint((0.5+0.449)*w, (0.5-0.451)*h)]; 406 | [path2 curveToPoint:NSMakePoint((0.5+0.48)*w, (0.5+0.316)*h) controlPoint1:NSMakePoint((0.5+0.516)*w, (0.5-0.177)*h) controlPoint2:NSMakePoint((0.5+0.516)*w, (0.5+0.177)*h)]; 407 | [path2 curveToPoint:NSMakePoint((0.5+0.163)*w, (0.5+0.495)*h) controlPoint1:NSMakePoint((0.5+0.449)*w, (0.5+0.451)*h) controlPoint2:NSMakePoint((0.5+0.321)*w, (0.5+0.483)*h)]; 408 | [path2 curveToPoint:NSMakePoint(0.5*w, 1*h) controlPoint1:NSMakePoint((0.5+0.084)*w, (0.5+0.499)*h) controlPoint2:NSMakePoint((0.5+0.079)*w, (0.5+0.499)*h) ]; 409 | [path2 curveToPoint:NSMakePoint((0.5-0.163)*w,(0.5+0.495)*h) controlPoint1:NSMakePoint((0.5-0.079)*w, (0.5+0.499)*h) controlPoint2:NSMakePoint((0.5-0.079)*w, (0.5+0.499)*h) ]; 410 | [path2 curveToPoint:NSMakePoint((0.5-0.48)*w, (0.5+0.316)*h) controlPoint1:NSMakePoint((0.5-0.321)*w, (0.5+0.483)*h) controlPoint2:NSMakePoint((0.5-0.449)*w, (0.5+0.451)*h)]; 411 | [path2 curveToPoint:NSMakePoint((0.5-0.48)*w, (0.5-0.316)*h) controlPoint1:NSMakePoint((0.5-0.516)*w, (0.5+0.177)*h) controlPoint2:NSMakePoint((0.5-0.516)*w, (0.5-0.177)*h)]; 412 | [path2 curveToPoint:NSMakePoint((0.5-0.163)*w, (0.5-0.495)*h) controlPoint1:NSMakePoint((0.5-0.449)*w, (0.5-0.451)*h) controlPoint2:NSMakePoint((0.5-0.321)*w, (0.5-0.483)*h)]; 413 | [path2 closePath]; 414 | */ 415 | 416 | path2 = [NSBezierPath bezierPath]; 417 | [path2 moveToPoint:NSMakePoint((0.5-0.163)*w,(0.5+0.495)*h)]; 418 | [path2 curveToPoint:NSMakePoint(0.5*w, 1*h) controlPoint1:NSMakePoint((0.5-0.079)*w, (0.5+0.499)*h) controlPoint2:NSMakePoint((0.5-0.079)*w, (0.5+0.499)*h)]; 419 | [path2 curveToPoint:NSMakePoint((0.5+0.163)*w, (0.5+0.495)*h) controlPoint1:NSMakePoint((0.5+0.079)*w, (0.5+0.499)*h) controlPoint2:NSMakePoint((0.5+0.084)*w, (0.5+0.499)*h)]; 420 | [path2 curveToPoint:NSMakePoint((0.5+0.48)*w, (0.5+0.316)*h) controlPoint1:NSMakePoint((0.5+0.321)*w, (0.5+0.483)*h) controlPoint2:NSMakePoint((0.5+0.449)*w, (0.5+0.451)*h)]; 421 | 422 | [path2 curveToPoint:NSMakePoint(maxX-1, midY + halfArrowWidth) controlPoint1:NSMakePoint((0.5+0.516 - (0.516-0.48)/2)*w, (0.5+0.177 - (0.177-0.316)/2)*h) controlPoint2:NSMakePoint(maxX-1, midY + halfArrowWidth)]; 423 | 424 | //[path2 lineToPoint:NSMakePoint(maxX-2, midY + halfArrowWidth)]; 425 | [self _appendArrowToPath:path2]; 426 | 427 | [path2 curveToPoint:NSMakePoint((0.5+0.48)*w, (0.5-0.316)*h) controlPoint1:NSMakePoint(maxX-1, midY - halfArrowWidth) controlPoint2:NSMakePoint((0.5+0.516 - (0.516-0.48)/2)*w, (0.5-0.177 - (-0.177+0.316)/2)*h)]; 428 | 429 | //[path2 curveToPoint:NSMakePoint((0.5+0.48)*w, (0.5-0.316)*h) controlPoint1:NSMakePoint((0.5+0.516)*w, (0.5+0.177)*h) controlPoint2:NSMakePoint((0.5+0.516)*w, (0.5-0.177)*h)]; 430 | 431 | [path2 curveToPoint:NSMakePoint((0.5+0.163)*w, (0.5-0.495)*h) controlPoint1:NSMakePoint((0.5+0.449)*w, (0.5-0.451)*h) controlPoint2:NSMakePoint((0.5+0.321)*w, (0.5-0.483)*h)]; 432 | [path2 curveToPoint:NSMakePoint(0.5*w, 0*h) controlPoint1:NSMakePoint((0.5+0.084)*w, (0.5-0.499)*h) controlPoint2:NSMakePoint((0.5+0.079)*w, (0.5-0.499)*h) ]; 433 | [path2 curveToPoint:NSMakePoint((0.5-0.163)*w,(0.5-0.495)*h) controlPoint1:NSMakePoint((0.5-0.079)*w, (0.5-0.499)*h) controlPoint2:NSMakePoint((0.5-0.079)*w, (0.5-0.499)*h) ]; 434 | [path2 curveToPoint:NSMakePoint((0.5-0.48)*w, (0.5-0.316)*h) controlPoint1:NSMakePoint((0.5-0.321)*w, (0.5-0.483)*h) controlPoint2:NSMakePoint((0.5-0.449)*w, (0.5-0.451)*h)]; 435 | [path2 curveToPoint:NSMakePoint((0.5-0.48)*w, (0.5+0.316)*h) controlPoint1:NSMakePoint((0.5-0.516)*w, (0.5-0.177)*h) controlPoint2:NSMakePoint((0.5-0.516)*w, (0.5+0.177)*h)]; 436 | [path2 curveToPoint:NSMakePoint((0.5-0.163)*w, (0.5+0.495)*h) controlPoint1:NSMakePoint((0.5-0.449)*w, (0.5+0.451)*h) controlPoint2:NSMakePoint((0.5-0.321)*w, (0.5+0.483)*h)]; 437 | 438 | [path2 closePath]; 439 | } 440 | 441 | return path2; 442 | } 443 | 444 | 445 | - (void)_appendArrowToPath:(NSBezierPath *)path 446 | { 447 | if (!hasArrow) { 448 | return; 449 | } 450 | 451 | float scaleFactor = MAATTACHEDWINDOW_SCALE_FACTOR; 452 | float scaledArrowWidth = arrowBaseWidth * scaleFactor; 453 | float halfArrowWidth = scaledArrowWidth / 2.0; 454 | float scaledArrowHeight = arrowHeight * scaleFactor; 455 | NSPoint currPt = [path currentPoint]; 456 | NSPoint tipPt = currPt; 457 | NSPoint endPt = currPt; 458 | 459 | // Note: we always build the arrow path in a clockwise direction. 460 | switch (_side) { 461 | case MAPositionLeft: 462 | case MAPositionLeftTop: 463 | case MAPositionLeftBottom: 464 | // Arrow points towards right. We're starting from the top. 465 | tipPt.x += scaledArrowHeight; 466 | tipPt.y -= halfArrowWidth; 467 | endPt.y -= scaledArrowWidth; 468 | break; 469 | case MAPositionRight: 470 | case MAPositionRightTop: 471 | case MAPositionRightBottom: 472 | // Arrow points towards left. We're starting from the bottom. 473 | tipPt.x -= scaledArrowHeight; 474 | tipPt.y += halfArrowWidth; 475 | endPt.y += scaledArrowWidth; 476 | break; 477 | case MAPositionTop: 478 | case MAPositionTopLeft: 479 | case MAPositionTopRight: 480 | // Arrow points towards bottom. We're starting from the right. 481 | tipPt.y -= scaledArrowHeight; 482 | tipPt.x -= halfArrowWidth; 483 | endPt.x -= scaledArrowWidth; 484 | break; 485 | case MAPositionBottom: 486 | case MAPositionBottomLeft: 487 | case MAPositionBottomRight: 488 | // Arrow points towards top. We're starting from the left. 489 | tipPt.y += scaledArrowHeight; 490 | tipPt.x += halfArrowWidth; 491 | endPt.x += scaledArrowWidth; 492 | break; 493 | default: 494 | break; // won't happen, but this satisfies gcc with -Wall 495 | } 496 | 497 | [path lineToPoint:tipPt]; 498 | [path lineToPoint:endPt]; 499 | } 500 | 501 | 502 | - (void)_redisplay 503 | { 504 | if (_resizing) { 505 | return; 506 | } 507 | 508 | _resizing = YES; 509 | NSDisableScreenUpdates(); 510 | [self _updateGeometry]; 511 | [self _updateBackground]; 512 | NSEnableScreenUpdates(); 513 | _resizing = NO; 514 | } 515 | 516 | 517 | # pragma mark Window Behaviour 518 | 519 | 520 | - (BOOL)canBecomeMainWindow 521 | { 522 | return NO; 523 | } 524 | 525 | 526 | - (BOOL)canBecomeKeyWindow 527 | { 528 | return YES; 529 | } 530 | 531 | 532 | - (BOOL)isExcludedFromWindowsMenu 533 | { 534 | return YES; 535 | } 536 | 537 | 538 | - (BOOL)validateMenuItem:(NSMenuItem *)item 539 | { 540 | if (_window) { 541 | return [_window validateMenuItem:item]; 542 | } 543 | return [super validateMenuItem:item]; 544 | } 545 | 546 | 547 | - (IBAction)performClose:(id)sender 548 | { 549 | if (_window) { 550 | [_window performClose:sender]; 551 | } else { 552 | [super performClose:sender]; 553 | } 554 | } 555 | 556 | 557 | # pragma mark Notification handlers 558 | 559 | 560 | - (void)windowDidResize:(NSNotification *)note 561 | { 562 | [self _redisplay]; 563 | } 564 | 565 | 566 | #pragma mark Accessors 567 | 568 | 569 | - (void)setPoint:(NSPoint)point side:(MAWindowPosition)side 570 | { 571 | // Thanks to Martin Redington. 572 | _point = point; 573 | _side = side; 574 | NSDisableScreenUpdates(); 575 | [self _updateGeometry]; 576 | [self _updateBackground]; 577 | NSEnableScreenUpdates(); 578 | } 579 | 580 | 581 | - (NSColor *)windowBackgroundColor { 582 | return [[_MABackgroundColor retain] autorelease]; 583 | } 584 | 585 | 586 | - (void)setBackgroundColor:(NSColor *)value { 587 | if (_MABackgroundColor != value) { 588 | [_MABackgroundColor release]; 589 | _MABackgroundColor = [value copy]; 590 | 591 | [self _updateBackground]; 592 | } 593 | } 594 | 595 | 596 | - (NSColor *)borderColor { 597 | return [[borderColor retain] autorelease]; 598 | } 599 | 600 | 601 | - (void)setBorderColor:(NSColor *)value { 602 | if (borderColor != value) { 603 | [borderColor release]; 604 | borderColor = [value copy]; 605 | 606 | [self _updateBackground]; 607 | } 608 | } 609 | 610 | 611 | - (float)borderWidth { 612 | return borderWidth; 613 | } 614 | 615 | 616 | - (void)setBorderWidth:(float)value { 617 | if (borderWidth != value) { 618 | float maxBorderWidth = viewMargin; 619 | if (value <= maxBorderWidth) { 620 | borderWidth = value; 621 | } else { 622 | borderWidth = maxBorderWidth; 623 | } 624 | 625 | [self _updateBackground]; 626 | } 627 | } 628 | 629 | 630 | - (float)viewMargin { 631 | return viewMargin; 632 | } 633 | 634 | 635 | - (void)setViewMargin:(float)value { 636 | if (viewMargin != value) { 637 | viewMargin = MAX(value, 0.0); 638 | 639 | // Adjust cornerRadius appropriately (which will also adjust arrowBaseWidth). 640 | [self setCornerRadius:cornerRadius]; 641 | } 642 | } 643 | 644 | 645 | - (float)arrowBaseWidth { 646 | return arrowBaseWidth; 647 | } 648 | 649 | 650 | - (void)setArrowBaseWidth:(float)value { 651 | float maxWidth = (MIN(_viewFrame.size.width, _viewFrame.size.height) + 652 | (viewMargin * 2.0)) - cornerRadius; 653 | if (drawsRoundCornerBesideArrow) { 654 | maxWidth -= cornerRadius; 655 | } 656 | if (value <= maxWidth) { 657 | arrowBaseWidth = value; 658 | } else { 659 | arrowBaseWidth = maxWidth; 660 | } 661 | 662 | [self _redisplay]; 663 | } 664 | 665 | 666 | - (float)arrowHeight { 667 | return arrowHeight; 668 | } 669 | 670 | 671 | - (void)setArrowHeight:(float)value { 672 | if (arrowHeight != value) { 673 | arrowHeight = value; 674 | 675 | [self _redisplay]; 676 | } 677 | } 678 | 679 | 680 | - (float)hasArrow { 681 | return hasArrow; 682 | } 683 | 684 | 685 | - (void)setHasArrow:(float)value { 686 | if (hasArrow != value) { 687 | hasArrow = value; 688 | 689 | [self _updateBackground]; 690 | } 691 | } 692 | 693 | 694 | - (float)cornerRadius { 695 | return cornerRadius; 696 | } 697 | 698 | 699 | - (void)setCornerRadius:(float)value { 700 | float maxRadius = ((MIN(_viewFrame.size.width, _viewFrame.size.height) + 701 | (viewMargin * 2.0)) - arrowBaseWidth) / 2.0; 702 | if (value <= maxRadius) { 703 | cornerRadius = value; 704 | } else { 705 | cornerRadius = maxRadius; 706 | } 707 | cornerRadius = MAX(cornerRadius, 0.0); 708 | 709 | // Adjust arrowBaseWidth appropriately. 710 | [self setArrowBaseWidth:arrowBaseWidth]; 711 | } 712 | 713 | 714 | - (float)drawsRoundCornerBesideArrow { 715 | return drawsRoundCornerBesideArrow; 716 | } 717 | 718 | 719 | - (void)setDrawsRoundCornerBesideArrow:(float)value { 720 | if (drawsRoundCornerBesideArrow != value) { 721 | drawsRoundCornerBesideArrow = value; 722 | 723 | [self _redisplay]; 724 | } 725 | } 726 | 727 | 728 | - (void)setBackgroundImage:(NSImage *)value 729 | { 730 | if (value) { 731 | [self setBackgroundColor:[NSColor colorWithPatternImage:value]]; 732 | } 733 | } 734 | 735 | - (void)setDevice:(int)device 736 | { 737 | _device = device; 738 | [self _updateBackground]; 739 | } 740 | 741 | @end 742 | -------------------------------------------------------------------------------- /prefpane/MagicMouseTab.h: -------------------------------------------------------------------------------- 1 | // 2 | // MagicMouseTab.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class GesturePreviewView; 11 | @class KeyTextField; 12 | @class GestureTableView; 13 | @class MAAttachedWindow; 14 | @class ApplicationButton; 15 | 16 | @interface MagicMouseTab : NSObject { 17 | NSArray *allGestures; 18 | 19 | //General 20 | IBOutlet NSMatrix *rdMMHanded; 21 | IBOutlet NSButton *cbAll; 22 | 23 | IBOutlet NSOutlineView *commandOutlineView; 24 | IBOutlet NSButton *addButton; 25 | IBOutlet NSButton *removeButton; 26 | IBOutlet NSButton *restoreDefaultsButton; 27 | 28 | 29 | IBOutlet NSWindow *window; 30 | IBOutlet NSWindow *commandSheet; 31 | IBOutlet NSWindow *urlWindow; 32 | IBOutlet NSButton *urlWindowOk; 33 | IBOutlet NSButton *urlWindowCancel; 34 | IBOutlet NSTextField *urlWindowUrl; 35 | IBOutlet ApplicationButton *applicationButton; 36 | IBOutlet GestureTableView *gestureTableView; 37 | IBOutlet NSPopUpButton *actionButton; 38 | IBOutlet KeyTextField *shortcutTextField; 39 | IBOutlet NSButton *commitButton; 40 | 41 | 42 | BOOL addsCommand; 43 | NSDictionary *oldItem; 44 | NSInteger oldItemIndex; 45 | NSString *saveApplication; 46 | 47 | NSView *realView; 48 | MAAttachedWindow *attachedWindow; 49 | NSInteger saveRowIndex; 50 | GesturePreviewView *gesturePreviewView; 51 | 52 | NSString *openFilePath; 53 | NSString *openURL; 54 | } 55 | 56 | - (IBAction)change:(id)sender; 57 | - (IBAction)cancelCommandSheet:(id)sender; 58 | - (IBAction)commitCommandSheet:(id)sender; 59 | - (IBAction)addCommand:(id)sender; 60 | - (IBAction)removeCommand:(id)sender; 61 | - (IBAction)restoreDefaults:(id)sender; 62 | - (void)enUpdated; 63 | - (void)willUnselect; 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /prefpane/RecognitionTab.h: -------------------------------------------------------------------------------- 1 | // 2 | // RecognitionTab.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class GesturePreviewView; 11 | @class KeyTextField; 12 | @class GestureTableView; 13 | @class MAAttachedWindow; 14 | @class ApplicationButton; 15 | 16 | @interface RecognitionTab : NSObject { 17 | NSArray *allGestures; 18 | 19 | //General 20 | IBOutlet NSButton *cbTrackpad; 21 | IBOutlet NSButton *cbMouse; 22 | 23 | IBOutlet NSOutlineView *commandOutlineView; 24 | IBOutlet NSButton *addButton; 25 | IBOutlet NSButton *removeButton; 26 | IBOutlet NSButton *restoreDefaultsButton; 27 | 28 | IBOutlet NSWindow *window; 29 | IBOutlet NSWindow *commandSheet; 30 | IBOutlet NSWindow *urlWindow; 31 | IBOutlet NSButton *urlWindowOk; 32 | IBOutlet NSButton *urlWindowCancel; 33 | IBOutlet NSTextField *urlWindowUrl; 34 | IBOutlet NSWindow *advancedSheet; 35 | IBOutlet ApplicationButton *applicationButton; 36 | IBOutlet GestureTableView *gestureTableView; 37 | IBOutlet NSPopUpButton *actionButton; 38 | IBOutlet KeyTextField *shortcutTextField; 39 | IBOutlet NSButton *commitButton; 40 | 41 | IBOutlet NSButton *oneDrawing; 42 | IBOutlet NSButton *twoDrawing; 43 | 44 | IBOutlet NSMatrix *mouseButton; 45 | IBOutlet NSSlider *indexRing; 46 | 47 | BOOL addsCommand; 48 | NSDictionary *oldItem; 49 | NSInteger oldItemIndex; 50 | NSString *saveApplication; 51 | 52 | NSView *realView; 53 | MAAttachedWindow *attachedWindow; 54 | NSInteger saveRowIndex; 55 | GesturePreviewView *gesturePreviewView; 56 | 57 | NSString *openFilePath; 58 | NSString *openURL; 59 | } 60 | 61 | - (IBAction)change:(id)sender; 62 | - (IBAction)showAdvancedSheet:(id)sender; 63 | - (IBAction)cancelCommandSheet:(id)sender; 64 | - (IBAction)commitCommandSheet:(id)sender; 65 | - (IBAction)addCommand:(id)sender; 66 | - (IBAction)removeCommand:(id)sender; 67 | - (IBAction)restoreDefaults:(id)sender; 68 | - (void)enUpdated; 69 | - (void)willUnselect; 70 | 71 | @end 72 | -------------------------------------------------------------------------------- /prefpane/Settings.h: -------------------------------------------------------------------------------- 1 | // 2 | // Settings.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | #define kCurrentRevision 26 11 | #define kAcceptableOldestRevision 13 12 | #define appID CFSTR("com.jitouch.Jitouch") 13 | 14 | @class TrackpadTab, MagicMouseTab, RecognitionTab; 15 | 16 | extern NSMutableDictionary *settings; 17 | extern NSMutableDictionary *trackpadMap; 18 | extern NSMutableDictionary *magicMouseMap; 19 | extern NSMutableDictionary *recognitionMap; 20 | 21 | //General 22 | extern float clickSpeed; 23 | extern float stvt; 24 | extern int enAll; 25 | 26 | //Trackpad 27 | extern int enTPAll; 28 | extern int enHanded; 29 | 30 | //Magic Mouse 31 | extern int enMMAll; 32 | extern int enMMHanded; 33 | 34 | //Character Recognition 35 | extern int enCharRegTP; 36 | extern int enCharRegMM; 37 | extern float charRegIndexRingDistance; 38 | extern int charRegMouseButton; 39 | extern int enOneDrawing, enTwoDrawing; 40 | 41 | extern NSMutableArray *trackpadCommands; 42 | extern NSMutableArray *magicMouseCommands; 43 | extern NSMutableArray *recognitionCommands; 44 | 45 | extern BOOL hasloaded; 46 | 47 | extern BOOL isPrefPane; 48 | 49 | extern BOOL hasPreviousVersion; 50 | 51 | extern NSView *mainView; 52 | 53 | extern TrackpadTab *trackpadTab; 54 | extern MagicMouseTab *magicMouseTab; 55 | extern RecognitionTab *recognitionTab; 56 | 57 | extern NSMutableDictionary *iconDict; 58 | extern NSMutableArray *allApps; 59 | extern NSMutableArray *allAppPaths; 60 | 61 | extern CFMachPortRef eventKeyboard; 62 | 63 | 64 | @interface Settings : NSObject 65 | 66 | //+ (void)loadSettings; 67 | + (void)noteSettingsUpdated; 68 | //+ (void)noteSettingsUpdated2; 69 | + (void)setKey:(NSString*)aKey withInt:(int)aValue; 70 | + (void)setKey:(NSString*)aKey withFloat:(float)aValue; 71 | + (void)setKey:(NSString*)aKey with:(id)aValue; 72 | + (void)trackpadDefault; 73 | + (void)magicMouseDefault; 74 | + (void)recognitionDefault; 75 | + (void)createDefaultPlist; 76 | + (void)loadSettings:(id)sender; 77 | + (void)readSettings; 78 | + (void)readSettings2:(NSDictionary*)d; 79 | 80 | @end 81 | -------------------------------------------------------------------------------- /prefpane/Settings.m: -------------------------------------------------------------------------------- 1 | // 2 | // Settings.m 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import "Settings.h" 9 | #import 10 | #import 11 | 12 | #define ADD_GESTURE(a, gesture, command) [a addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:gesture, @"Gesture", command, @"Command", @YES, @"IsAction", @0, @"ModifierFlags", @0, @"KeyCode", [NSNumber numberWithInt:NSOnState], @"Enable", nil]]; 13 | 14 | NSMutableDictionary *settings; 15 | NSMutableDictionary *trackpadMap; 16 | NSMutableDictionary *magicMouseMap; 17 | NSMutableDictionary *recognitionMap; 18 | 19 | //General 20 | float clickSpeed; 21 | float stvt; 22 | int enAll; 23 | 24 | //Trackpad 25 | int enTPAll; 26 | int enHanded; 27 | 28 | //Magic Mouse 29 | int enMMAll; 30 | int enMMHanded; 31 | 32 | //Character Recognition 33 | int enCharRegTP; 34 | int enCharRegMM; 35 | float charRegIndexRingDistance; 36 | int charRegMouseButton; 37 | int enOneDrawing, enTwoDrawing; 38 | 39 | NSMutableArray *trackpadCommands; 40 | NSMutableArray *magicMouseCommands; 41 | NSMutableArray *recognitionCommands; 42 | 43 | BOOL hasloaded; 44 | 45 | BOOL isPrefPane; 46 | 47 | BOOL hasPreviousVersion; 48 | 49 | NSView *mainView; 50 | 51 | TrackpadTab *trackpadTab; 52 | MagicMouseTab *magicMouseTab; 53 | RecognitionTab *recognitionTab; 54 | 55 | NSMutableDictionary *iconDict; 56 | NSMutableArray *allApps; 57 | NSMutableArray *allAppPaths; 58 | 59 | CFMachPortRef eventKeyboard; 60 | 61 | 62 | @implementation Settings 63 | 64 | static int notSynchronize; 65 | 66 | + (void)noteSettingsUpdated { 67 | [[NSDistributedNotificationCenter defaultCenter] postNotificationName: @"My Notification" 68 | object: @"com.jitouch.Jitouch.PrefpaneTarget" 69 | userInfo: settings 70 | deliverImmediately: YES]; 71 | } 72 | 73 | + (void)setKey:(NSString*)aKey withInt:(int)aValue{ 74 | [settings setObject:[NSNumber numberWithInt:aValue] forKey:aKey]; 75 | 76 | CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &aValue); 77 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 78 | CFRelease(value); 79 | if (!notSynchronize) 80 | CFPreferencesAppSynchronize(appID); 81 | } 82 | 83 | + (void)setKey:(NSString*)aKey withFloat:(float)aValue{ 84 | [settings setObject:[NSNumber numberWithFloat:aValue] forKey:aKey]; 85 | 86 | CFNumberRef value = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &aValue); 87 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 88 | CFRelease(value); 89 | if (!notSynchronize) 90 | CFPreferencesAppSynchronize(appID); 91 | } 92 | 93 | + (void)setKey:(NSString*)aKey with:(id)aValue { 94 | [settings setObject:aValue forKey:aKey]; 95 | 96 | CFPropertyListRef value = (CFPropertyListRef)aValue; 97 | CFPreferencesSetAppValue((CFStringRef)aKey, value, appID); 98 | //CFRelease(value); 99 | if (!notSynchronize) 100 | CFPreferencesAppSynchronize(appID); 101 | } 102 | 103 | // must make sure that everything is mutable 104 | 105 | + (void)recognitionDefault { 106 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 107 | ADD_GESTURE(gestures1, @"B", @"Launch Browser"); 108 | ADD_GESTURE(gestures1, @"F", @"Launch Finder"); 109 | ADD_GESTURE(gestures1, @"N", @"New"); 110 | ADD_GESTURE(gestures1, @"O", @"Open"); 111 | ADD_GESTURE(gestures1, @"S", @"Save"); 112 | ADD_GESTURE(gestures1, @"T", @"New Tab"); 113 | ADD_GESTURE(gestures1, @"Up", @"Copy"); 114 | ADD_GESTURE(gestures1, @"Down", @"Paste"); 115 | 116 | ADD_GESTURE(gestures1, @"Left", @"Maximize Left"); 117 | ADD_GESTURE(gestures1, @"Right", @"Maximize Right"); 118 | ADD_GESTURE(gestures1, @"/ Up", @"Maximize"); 119 | ADD_GESTURE(gestures1, @"/ Down", @"Un-Maximize"); 120 | 121 | NSDictionary *app1 = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 122 | 123 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 124 | [apps addObject:app1]; 125 | 126 | [Settings setKey:@"RecognitionCommands" with:apps]; 127 | [apps release]; 128 | [gestures1 release]; 129 | } 130 | 131 | + (void)trackpadDefault { 132 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 133 | ADD_GESTURE(gestures1, @"One-Fix Left-Tap", @"Previous Tab"); 134 | ADD_GESTURE(gestures1, @"One-Fix Right-Tap", @"Next Tab"); 135 | ADD_GESTURE(gestures1, @"One-Fix One-Slide", @"Move / Resize"); 136 | ADD_GESTURE(gestures1, @"One-Fix Two-Slide-Down", @"Close / Close Tab"); 137 | ADD_GESTURE(gestures1, @"One-Fix-Press Two-Slide-Down", @"Quit"); 138 | ADD_GESTURE(gestures1, @"Two-Fix Index-Double-Tap", @"Refresh"); 139 | ADD_GESTURE(gestures1, @"Three-Finger Tap", @"Middle Click"); 140 | ADD_GESTURE(gestures1, @"Pinky-To-Index", @"Zoom"); 141 | ADD_GESTURE(gestures1, @"Index-To-Pinky", @"Minimize"); 142 | //ADD_GESTURE(gestures1, @"Left-Side Scroll", @"Auto Scroll"); 143 | 144 | NSDictionary *app1 = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 145 | 146 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 147 | [apps addObject:app1]; 148 | 149 | [Settings setKey:@"TrackpadCommands" with:apps]; 150 | 151 | [apps release]; 152 | [gestures1 release]; 153 | } 154 | 155 | + (void)magicMouseDefault { 156 | NSMutableArray *gestures1 = [[NSMutableArray alloc] init]; 157 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Near-Tap", @"Next Tab"); 158 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Far-Tap", @"Previous Tab"); 159 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Slide-Out", @"Close / Close Tab"); 160 | ADD_GESTURE(gestures1, @"Middle-Fix Index-Slide-In", @"Refresh"); 161 | ADD_GESTURE(gestures1, @"Three-Swipe-Up", @"Show Desktop"); 162 | ADD_GESTURE(gestures1, @"Three-Swipe-Down", @"Mission Control"); 163 | ADD_GESTURE(gestures1, @"V-Shape", @"Move / Resize"); 164 | ADD_GESTURE(gestures1, @"Middle Click", @"Middle Click"); 165 | 166 | NSDictionary *app1 = [NSMutableDictionary dictionaryWithObjectsAndKeys:@"All Applications", @"Application", @"", @"Path", gestures1, @"Gestures", nil]; 167 | 168 | NSMutableArray *apps = [[NSMutableArray alloc] init]; 169 | [apps addObject:app1]; 170 | [Settings setKey:@"MagicMouseCommands" with:apps]; 171 | [apps release]; 172 | [gestures1 release]; 173 | } 174 | 175 | + (void)createDefaultPlist { 176 | notSynchronize = 1; 177 | 178 | //General 179 | [Settings setKey:@"enAll" withInt:1]; 180 | [Settings setKey:@"ClickSpeed" withFloat:0.25]; 181 | [Settings setKey:@"Sensitivity" withFloat:4.6666]; 182 | [Settings setKey:@"ShowIcon" withInt:1]; 183 | [Settings setKey:@"Revision" withInt:kCurrentRevision]; 184 | 185 | //Trackpad 186 | [Settings setKey:@"enTPAll" withInt:1]; 187 | [Settings setKey:@"Handed" withInt:0]; 188 | 189 | //Magic Mouse 190 | [Settings setKey:@"enMMAll" withInt:1]; 191 | [Settings setKey:@"MMHanded" withInt:0]; 192 | 193 | //Recognition 194 | [Settings setKey:@"enCharRegTP" withInt:0]; 195 | [Settings setKey:@"enCharRegMM" withInt:0]; 196 | [Settings setKey:@"charRegMouseButton" withInt:0]; 197 | [Settings setKey:@"charRegIndexRingDistance" withFloat:0.33]; 198 | [Settings setKey:@"enOneDrawing" withInt:0]; 199 | [Settings setKey:@"enTwoDrawing" withInt:1]; 200 | 201 | [Settings trackpadDefault]; 202 | [Settings magicMouseDefault]; 203 | [Settings recognitionDefault]; 204 | 205 | CFPreferencesAppSynchronize(appID); 206 | 207 | notSynchronize = 0; 208 | } 209 | 210 | // The jitouch app doesn't have ability to change settings 211 | // except these three keys: enAll 212 | + (void)readSettings2:(NSDictionary*)d { 213 | [settings setObject:[d objectForKey:@"enAll"] forKey:@"enAll"]; 214 | 215 | enAll = [[settings objectForKey:@"enAll"] intValue]; 216 | } 217 | 218 | 219 | + (void)readSettings { 220 | 221 | //General 222 | enAll = [[settings objectForKey:@"enAll"] intValue]; 223 | clickSpeed = [[settings objectForKey:@"ClickSpeed"] floatValue]; 224 | stvt = [[settings objectForKey:@"Sensitivity"] floatValue]; 225 | 226 | //Trackpad 227 | enTPAll = [[settings objectForKey:@"enTPAll"] intValue]; 228 | enHanded = [[settings objectForKey:@"Handed"] intValue]; 229 | 230 | //Magic Mouse 231 | enMMAll = [[settings objectForKey:@"enMMAll"] intValue]; 232 | enMMHanded = [[settings objectForKey:@"MMHanded"] intValue]; 233 | 234 | //Recognition 235 | enCharRegTP = [[settings objectForKey:@"enCharRegTP"] intValue]; 236 | enCharRegMM = [[settings objectForKey:@"enCharRegMM"] intValue]; 237 | enOneDrawing = [[settings objectForKey:@"enOneDrawing"] intValue]; 238 | enTwoDrawing = [[settings objectForKey:@"enTwoDrawing"] intValue]; 239 | 240 | if (![settings objectForKey:@"charRegIndexRingDistance"]) 241 | charRegIndexRingDistance = 0.3; 242 | else 243 | charRegIndexRingDistance = [[settings objectForKey:@"charRegIndexRingDistance"] floatValue]; 244 | 245 | if (![settings objectForKey:@"charRegMouseButton"]) 246 | charRegMouseButton = 0; 247 | else 248 | charRegMouseButton = [[settings objectForKey:@"charRegMouseButton"] intValue]; 249 | 250 | 251 | trackpadCommands = [settings objectForKey:@"TrackpadCommands"]; 252 | magicMouseCommands = [settings objectForKey:@"MagicMouseCommands"]; 253 | recognitionCommands = [settings objectForKey:@"RecognitionCommands"]; 254 | 255 | 256 | void (^optimize)(NSArray*, NSMutableDictionary*) = ^(NSArray *commands, NSMutableDictionary *map) { 257 | for (NSDictionary *app in commands) { 258 | NSString *appName = [app objectForKey:@"Application"]; 259 | if (!isPrefPane) { 260 | if ([appName isEqualToString:@"Chrome"]) 261 | appName = @"Google Chrome"; 262 | else if ([appName isEqualToString:@"Word"]) 263 | appName = @"Microsoft Word"; 264 | } 265 | 266 | NSMutableDictionary *gestures = [[NSMutableDictionary alloc] init]; 267 | for (NSDictionary *gesture in [app objectForKey:@"Gestures"]) { 268 | [gestures setObject:gesture forKey:[gesture objectForKey:@"Gesture"]]; 269 | } 270 | [map setObject:gestures forKey:appName]; 271 | [gestures release]; 272 | } 273 | }; 274 | 275 | // optimization for trackpad commands 276 | [trackpadMap release]; 277 | trackpadMap = [[NSMutableDictionary alloc] init]; 278 | optimize(trackpadCommands, trackpadMap); 279 | 280 | // optimization for magicmouse commands 281 | [magicMouseMap release]; 282 | magicMouseMap = [[NSMutableDictionary alloc] init]; 283 | optimize(magicMouseCommands, magicMouseMap); 284 | 285 | // optimization for recognition commands 286 | [recognitionMap release]; 287 | recognitionMap = [[NSMutableDictionary alloc] init]; 288 | optimize(recognitionCommands, recognitionMap); 289 | 290 | 291 | // load all icons and all apps 292 | if (isPrefPane) { 293 | [allApps release]; 294 | [allAppPaths release]; 295 | 296 | allApps = [[NSMutableArray alloc] init]; 297 | allAppPaths = [[NSMutableArray alloc] init]; 298 | 299 | [allApps addObject:@"Finder"]; 300 | [allAppPaths addObject:@"/System/Library/CoreServices/Finder.app"]; 301 | 302 | NSEnumerator* dirEnum = [[[NSFileManager defaultManager] contentsOfDirectoryAtPath:@"/Applications" error:NULL] objectEnumerator]; 303 | NSString *file; 304 | while (file = [dirEnum nextObject]) { 305 | if ([[file pathExtension] isEqualToString: @"app"]) { 306 | NSString* path = [NSString stringWithFormat:@"/Applications/%@", file]; 307 | 308 | NSBundle *bundle = [NSBundle bundleWithPath:path]; 309 | NSDictionary *infoDict = [bundle infoDictionary]; 310 | NSString *displayName = [infoDict objectForKey: @"CFBundleName"]; 311 | if (!displayName) 312 | displayName = [infoDict objectForKey: @"CFBundleExecutable"]; 313 | 314 | if (displayName) { //TODO: workaround 315 | if ([displayName isEqualToString:@"RDC"]) 316 | displayName = @"Remote Desktop Connection"; //TODO: workaround 317 | 318 | [allApps addObject:displayName]; 319 | [allAppPaths addObject:path]; 320 | } 321 | } 322 | } 323 | for (NSDictionary *app in trackpadCommands) { 324 | if (![[app objectForKey:@"Application"] isEqualToString:@"All Applications"] && 325 | ![allApps containsObject:[app objectForKey:@"Application"]]) { 326 | [allApps addObject:[app objectForKey:@"Application"]]; 327 | [allAppPaths addObject:[app objectForKey:@"Path"]]; 328 | } 329 | } 330 | for (NSDictionary *app in magicMouseCommands) { 331 | if (![[app objectForKey:@"Application"] isEqualToString:@"All Applications"] && 332 | ![allApps containsObject:[app objectForKey:@"Application"]]) { 333 | [allApps addObject:[app objectForKey:@"Application"]]; 334 | [allAppPaths addObject:[app objectForKey:@"Path"]]; 335 | } 336 | } 337 | for (NSDictionary *app in recognitionCommands) { 338 | if (![[app objectForKey:@"Application"] isEqualToString:@"All Applications"] && 339 | ![allApps containsObject:[app objectForKey:@"Application"]]) { 340 | [allApps addObject:[app objectForKey:@"Application"]]; 341 | [allAppPaths addObject:[app objectForKey:@"Path"]]; 342 | } 343 | } 344 | 345 | 346 | [iconDict release]; 347 | iconDict = [[NSMutableDictionary alloc] init]; 348 | 349 | NSImage *icon = [NSImage imageNamed:@"NSComputer"]; 350 | [icon setSize:NSMakeSize(16, 16)]; 351 | [iconDict setObject:icon forKey:@"All Applications"]; 352 | 353 | for (NSUInteger i = 0; i<[allApps count]; i++) { 354 | NSString *app = [allApps objectAtIndex:i]; 355 | NSString *path = [allAppPaths objectAtIndex:i]; 356 | if (![path isEqualToString:@""]) { 357 | NSImage *icon = [[NSWorkspace sharedWorkspace] iconForFile:path]; 358 | [icon setSize:NSMakeSize(16, 16)]; 359 | [iconDict setObject:icon forKey:app]; 360 | } else { 361 | NSImage *icon = [NSImage imageNamed:@"NSComputer"]; 362 | [icon setSize:NSMakeSize(16, 16)]; 363 | [iconDict setObject:icon forKey:app]; 364 | } 365 | } 366 | } 367 | } 368 | 369 | 370 | + (void)loadSettings { 371 | [settings release]; 372 | 373 | settings = [[NSMutableDictionary alloc] init]; 374 | 375 | NSString *plistPath = [@"~/Library/Preferences/com.jitouch.Jitouch.plist" stringByStandardizingPath]; 376 | if (![[NSFileManager defaultManager] fileExistsAtPath:plistPath]) { 377 | [Settings createDefaultPlist]; 378 | hasPreviousVersion = YES; //may have .. because the previous version doesn't have plist 379 | } else { 380 | NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath]; 381 | NSString *errorDesc = nil; 382 | [settings setDictionary:[NSPropertyListSerialization 383 | propertyListFromData:plistXML 384 | mutabilityOption:NSPropertyListMutableContainersAndLeaves 385 | format:NULL 386 | errorDescription:&errorDesc]]; 387 | } 388 | 389 | if (isPrefPane) { 390 | if ([settings objectForKey:@"Revision"] == nil || 391 | [[settings objectForKey:@"Revision"] intValue] < kAcceptableOldestRevision) { 392 | NSAlert *alert = [NSAlert alertWithMessageText:@"Do you want to update the preference file?" 393 | defaultButton:@"Update" 394 | alternateButton:@"Don't Update" 395 | otherButton:nil 396 | informativeTextWithFormat:@"Your jitouch preference file is out of date. Would you like to use the new default settings? Your current settings will be permanently deleted.\n\nAlternately, you may later click \"Restore Defaults\" to use the new default settings."]; 397 | NSModalResponse response = [alert runModal]; 398 | if (response == NSOKButton) { 399 | [Settings createDefaultPlist]; 400 | [settings release]; 401 | NSData *plistXML = [[NSFileManager defaultManager] contentsAtPath:plistPath]; 402 | settings = [[NSMutableDictionary alloc] init]; 403 | 404 | NSString *errorDesc = nil; 405 | [settings setDictionary:[NSPropertyListSerialization 406 | propertyListFromData:plistXML 407 | mutabilityOption:NSPropertyListMutableContainersAndLeaves 408 | format:NULL 409 | errorDescription:&errorDesc]]; 410 | hasPreviousVersion = YES; 411 | } 412 | } 413 | 414 | if ([settings objectForKey:@"Revision"] == nil || 415 | [[settings objectForKey:@"Revision"] intValue] != kCurrentRevision) { 416 | hasPreviousVersion = YES; 417 | [Settings setKey:@"Revision" withInt:kCurrentRevision]; 418 | } 419 | } 420 | 421 | [Settings readSettings]; 422 | } 423 | 424 | + (void)loadSettings:(id)sender { 425 | if (hasloaded) 426 | return; 427 | [Settings loadSettings]; 428 | hasloaded = YES; 429 | } 430 | 431 | @end 432 | -------------------------------------------------------------------------------- /prefpane/TrackpadTab.h: -------------------------------------------------------------------------------- 1 | // 2 | // TrackpadTab.h 3 | // Jitouch 4 | // 5 | // Copyright 2021 Supasorn Suwajanakorn and Sukolsak Sakshuwong. All rights reserved. 6 | // 7 | 8 | #import 9 | 10 | @class GesturePreviewView; 11 | @class KeyTextField; 12 | @class GestureTableView; 13 | @class MAAttachedWindow; 14 | @class ApplicationButton; 15 | 16 | @interface TrackpadTab : NSObject { 17 | NSMutableArray *allGestures; 18 | 19 | //General 20 | IBOutlet NSMatrix *rdHanded; 21 | IBOutlet NSButton *cbAll; 22 | 23 | IBOutlet NSOutlineView *commandOutlineView; 24 | IBOutlet NSButton *addButton; 25 | IBOutlet NSButton *removeButton; 26 | IBOutlet NSButton *restoreDefaultsButton; 27 | 28 | 29 | IBOutlet NSButton *disableButton; 30 | IBOutlet NSWindow *window; 31 | IBOutlet NSWindow *commandSheet; 32 | IBOutlet NSWindow *urlWindow; 33 | IBOutlet NSButton *urlWindowOk; 34 | IBOutlet NSButton *urlWindowCancel; 35 | IBOutlet NSTextField *urlWindowUrl; 36 | IBOutlet ApplicationButton *applicationButton; 37 | IBOutlet GestureTableView *gestureTableView; 38 | IBOutlet NSPopUpButton *actionButton; 39 | IBOutlet KeyTextField *shortcutTextField; 40 | IBOutlet NSButton *commitButton; 41 | 42 | 43 | BOOL addsCommand; 44 | NSDictionary *oldItem; 45 | NSInteger oldItemIndex; 46 | NSString *saveApplication; 47 | 48 | 49 | NSView *realView; 50 | MAAttachedWindow *attachedWindow; 51 | NSInteger saveRowIndex; 52 | GesturePreviewView *gesturePreviewView; 53 | 54 | NSString *openFilePath; 55 | NSString *openURL; 56 | } 57 | 58 | - (IBAction)change:(id)sender; 59 | - (IBAction)okUrlWindow:(id)sender; 60 | - (IBAction)cancelUrlWindow:(id)sender; 61 | - (IBAction)cancelCommandSheet:(id)sender; 62 | - (IBAction)commitCommandSheet:(id)sender; 63 | - (IBAction)addCommand:(id)sender; 64 | - (IBAction)removeCommand:(id)sender; 65 | - (IBAction)restoreDefaults:(id)sender; 66 | - (void)enUpdated; 67 | - (void)willUnselect; 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /prefpane/jitouchicon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sukolsak/jitouch/913c8384a87db95c1ce3bfc20c06a00a0a863737/prefpane/jitouchicon.icns -------------------------------------------------------------------------------- /prefpane/version.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BuildVersion 6 | 1 7 | CFBundleShortVersionString 8 | 1.0 9 | CFBundleVersion 10 | 1.0 11 | ProjectName 12 | PreferencePaneTemplate 13 | SourceVersion 14 | 270000 15 | 16 | 17 | --------------------------------------------------------------------------------