├── iOS Simulator Plus ├── en.lproj │ ├── InfoPlist.strings │ └── Credits.rtf ├── iconTemplate.png ├── Images.xcassets │ └── AppIcon.appiconset │ │ ├── icon_16x16.png │ │ ├── icon_32x32.png │ │ ├── icon_128x128.png │ │ ├── icon_256x256.png │ │ ├── icon_512x512.png │ │ ├── icon_128x128@2x.png │ │ ├── icon_16x16@2x.png │ │ ├── icon_256x256@2x.png │ │ ├── icon_32x32@2x.png │ │ ├── icon_512x512@2x.png │ │ └── Contents.json ├── iOS Simulator Plus-Prefix.pch ├── main.m ├── iOS Simulator Plus-Info.plist ├── AppDelegate.h ├── AppDelegate.m └── Base.lproj │ └── MainMenu.xib ├── .gitignore ├── iOS Simulator Plus.xcodeproj ├── xcuserdata │ └── nerdani.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── iOS Simulator Touch.xcscheme ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── nerdani.xcuserdatad │ │ ├── UserInterfaceState.xcuserstate │ │ └── WorkspaceSettings.xcsettings └── project.pbxproj ├── LICENSE └── README.md /iOS Simulator Plus/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /iOS Simulator Plus/iconTemplate.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/iconTemplate.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | ehthumbs.db 9 | Thumbs.db 10 | -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/xcuserdata/nerdani.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_128x128@2x.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_16x16@2x.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_256x256@2x.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_32x32@2x.png -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /iOS Simulator Plus/iOS Simulator Plus-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/project.xcworkspace/xcuserdata/nerdani.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/n3rd4n1/iOS-Simulator-Plus/HEAD/iOS Simulator Plus.xcodeproj/project.xcworkspace/xcuserdata/nerdani.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /iOS Simulator Plus/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // iOS Simulator Plus 4 | // 5 | // Created by Billy Millare on 10/30/13. 6 | // Copyright (c) 2013 Billy Millare. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, const char * argv[]) 12 | { 13 | return NSApplicationMain(argc, argv); 14 | } 15 | -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/project.xcworkspace/xcuserdata/nerdani.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /iOS Simulator Plus/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf1\ansi\ansicpg1252\cocoartf1265 2 | {\fonttbl\f0\fswiss\fcharset0 Helvetica;\f1\fmodern\fcharset0 CourierNewPSMT;} 3 | {\colortbl;\red255\green255\blue255;} 4 | \paperw11900\paperh16840\vieww9600\viewh8400\viewkind0 5 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc 6 | 7 | \f0\fs24 \cf0 {\field{\*\fldinst{HYPERLINK "https://github.com/n3rd4n1/iOS-Simulator-Plus"}}{\fldrslt 8 | \f1 GitHub}} 9 | \f1 | {\field{\*\fldinst{HYPERLINK "https://github.com/n3rd4n1/iOS-Simulator-Plus/blob/master/LICENSE"}}{\fldrslt MIT License}}} -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/xcuserdata/nerdani.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | iOS Simulator Touch.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 50C7CE331820F54E0076A49B 16 | 17 | primary 18 | 19 | 20 | 50C7CE541820F54F0076A49B 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Billy Millare 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /iOS Simulator Plus/iOS Simulator Plus-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | AppIcon 11 | CFBundleIdentifier 12 | com.nerdani.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | LSMinimumSystemVersion 24 | ${MACOSX_DEPLOYMENT_TARGET} 25 | LSUIElement 26 | 27 | NSHumanReadableCopyright 28 | Copyright © 2013 Billy Millare. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /iOS Simulator Plus/AppDelegate.h: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013 Billy Millare 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* 25 | * AppDelegate.h 26 | * 27 | * Created on: Oct 30, 2013 28 | * Author: Billy 29 | */ 30 | 31 | #import 32 | 33 | @interface AppDelegate : NSObject 34 | @end 35 | -------------------------------------------------------------------------------- /iOS Simulator Plus/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_16x16@2x.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32@2x.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_128x128@2x.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_256x256@2x.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | iOS Simulator Plus 2 | ================== 3 | 4 | A background utility that aims to simplify and improve interaction with the iOS Simulator on the trackpad. 5 | 6 | Hardware Interaction 7 | -------------------- 8 | 9 | Trackpad gestures to trigger Hardware menu items. 10 | 11 | | Menu option | Trackpad gesture | 12 | | -------------- | :-----------------------------: | 13 | | Rotate left | Left rotate | 14 | | Rotate right | Right rotate | 15 | | Shake gesture | Back-and-forth rotate or pinch | 16 | | Home | Pinch in | 17 | | Lock | Pinch out | 18 | 19 | User Gestures 20 | ------------- 21 | 22 | Trackpad gestures to simplify interaction with the iOS Simulator screen (touchscreen). This does not interfere with the original way iOS Simulator is operated; this merely augments it. All gestures are simulated using a single touch, combined with modifier keys. 23 | 24 | + Hold the `shift` key before touching the trackpad to make the trackpad behave like a real touchscreen, i.e. the trackpad area is scaled to the iOS Simulator screen, and touch is tracked and translated. 25 | + Position the mouse cursor as desired. Hold the `control` key before touching the trackpad to easily simulate pinch and rotate gestures. The pivot point will be the mouse cursor location. 26 | + Hold the `control` and `shift` keys before touching the trackpad to simulate a two-finger drag gesture. The trackpad area is scaled to the iOS Simulator screen, and touch is tracked and translated. 27 | 28 | Limitation 29 | ---------- 30 | 31 | Because simulating the pinch, rotate, and two-finger drag gestures is normally a two-step process (i.e. holding the `option` and `shift` keys initiates these gestures centered at the iOS Simulator's screen, then moving the center at the desired location), and because the iOS Simulator Plus does these steps automatically, when the iOS Simulator's screen is not maximized and scroll bars are not centered, the translation that iOS Simulator Plus applies will be incorrect. Therefore, when simulating pinch, rotate, and two-finger drag gestures, iOS Simulator Plus is recommended only if the iOS Simulator window is maximized. 32 | 33 | Usage 34 | ----- 35 | 36 | Simply execute `iOS Simulator Plus.app`. Once running, a status item (shown as a phone with a plus sign) for iOS Simulator Plus will become available in the status bar. Selecting `Activate iOS Simulator...` will activate the iOS Simulator -- for convenience. iOS Simulator Plus is only really active when iOS Simulator is active, that is to say that functionalities of iOS Simulator Plus is only enabled once iOS Simulator becomes active. 37 | 38 | Download 39 | -------- 40 | 41 | [iOS-Simulator-Plus-1.0.zip](http://n3rd4n1.github.io/bin/iOS-Simulator-Plus-1.0.zip) 42 | -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/xcuserdata/nerdani.xcuserdatad/xcschemes/iOS Simulator Touch.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /iOS Simulator Plus.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 50A9F130184C616500F2C251 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 50A9F123184C616500F2C251 /* AppDelegate.m */; }; 11 | 50A9F132184C616500F2C251 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F126184C616500F2C251 /* Credits.rtf */; }; 12 | 50A9F133184C616500F2C251 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F128184C616500F2C251 /* InfoPlist.strings */; }; 13 | 50A9F135184C616500F2C251 /* iconTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F12B184C616500F2C251 /* iconTemplate.png */; }; 14 | 50A9F136184C616500F2C251 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F12C184C616500F2C251 /* Images.xcassets */; }; 15 | 50A9F138184C616500F2C251 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 50A9F12F184C616500F2C251 /* main.m */; }; 16 | 50A9F139184CEB3900F2C251 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 50A9F124184C616500F2C251 /* MainMenu.xib */; }; 17 | 50C7CE381820F54E0076A49B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50C7CE371820F54E0076A49B /* Cocoa.framework */; }; 18 | 50C7CE6C1821052F0076A49B /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50C7CE6B1821052F0076A49B /* Carbon.framework */; }; 19 | 50C7CE70182115610076A49B /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 50C7CE6F182115610076A49B /* Quartz.framework */; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 50A9F122184C616500F2C251 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 24 | 50A9F123184C616500F2C251 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 25 | 50A9F125184C616500F2C251 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 26 | 50A9F127184C616500F2C251 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 27 | 50A9F129184C616500F2C251 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 28 | 50A9F12B184C616500F2C251 /* iconTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = iconTemplate.png; sourceTree = ""; }; 29 | 50A9F12C184C616500F2C251 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 30 | 50A9F12D184C616500F2C251 /* iOS Simulator Plus-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "iOS Simulator Plus-Info.plist"; sourceTree = ""; }; 31 | 50A9F12E184C616500F2C251 /* iOS Simulator Plus-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "iOS Simulator Plus-Prefix.pch"; sourceTree = ""; }; 32 | 50A9F12F184C616500F2C251 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 33 | 50C7CE341820F54E0076A49B /* iOS Simulator Plus.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS Simulator Plus.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 34 | 50C7CE371820F54E0076A49B /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 35 | 50C7CE3A1820F54E0076A49B /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 36 | 50C7CE3B1820F54E0076A49B /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 37 | 50C7CE3C1820F54E0076A49B /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 38 | 50C7CE561820F54F0076A49B /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 39 | 50C7CE6B1821052F0076A49B /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 40 | 50C7CE6D182115410076A49B /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; 41 | 50C7CE6F182115610076A49B /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; 42 | /* End PBXFileReference section */ 43 | 44 | /* Begin PBXFrameworksBuildPhase section */ 45 | 50C7CE311820F54E0076A49B /* Frameworks */ = { 46 | isa = PBXFrameworksBuildPhase; 47 | buildActionMask = 2147483647; 48 | files = ( 49 | 50C7CE70182115610076A49B /* Quartz.framework in Frameworks */, 50 | 50C7CE6C1821052F0076A49B /* Carbon.framework in Frameworks */, 51 | 50C7CE381820F54E0076A49B /* Cocoa.framework in Frameworks */, 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 50A9F121184C616500F2C251 /* iOS Simulator Plus */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 50A9F122184C616500F2C251 /* AppDelegate.h */, 62 | 50A9F123184C616500F2C251 /* AppDelegate.m */, 63 | 50A9F124184C616500F2C251 /* MainMenu.xib */, 64 | 50A9F126184C616500F2C251 /* Credits.rtf */, 65 | 50A9F128184C616500F2C251 /* InfoPlist.strings */, 66 | 50A9F12B184C616500F2C251 /* iconTemplate.png */, 67 | 50A9F12C184C616500F2C251 /* Images.xcassets */, 68 | 50A9F12D184C616500F2C251 /* iOS Simulator Plus-Info.plist */, 69 | 50A9F12E184C616500F2C251 /* iOS Simulator Plus-Prefix.pch */, 70 | 50A9F12F184C616500F2C251 /* main.m */, 71 | ); 72 | path = "iOS Simulator Plus"; 73 | sourceTree = ""; 74 | }; 75 | 50C7CE2B1820F54E0076A49B = { 76 | isa = PBXGroup; 77 | children = ( 78 | 50A9F121184C616500F2C251 /* iOS Simulator Plus */, 79 | 50C7CE361820F54E0076A49B /* Frameworks */, 80 | 50C7CE351820F54E0076A49B /* Products */, 81 | ); 82 | sourceTree = ""; 83 | }; 84 | 50C7CE351820F54E0076A49B /* Products */ = { 85 | isa = PBXGroup; 86 | children = ( 87 | 50C7CE341820F54E0076A49B /* iOS Simulator Plus.app */, 88 | ); 89 | name = Products; 90 | sourceTree = ""; 91 | }; 92 | 50C7CE361820F54E0076A49B /* Frameworks */ = { 93 | isa = PBXGroup; 94 | children = ( 95 | 50C7CE6F182115610076A49B /* Quartz.framework */, 96 | 50C7CE6D182115410076A49B /* QuartzCore.framework */, 97 | 50C7CE6B1821052F0076A49B /* Carbon.framework */, 98 | 50C7CE371820F54E0076A49B /* Cocoa.framework */, 99 | 50C7CE561820F54F0076A49B /* XCTest.framework */, 100 | 50C7CE391820F54E0076A49B /* Other Frameworks */, 101 | ); 102 | name = Frameworks; 103 | sourceTree = ""; 104 | }; 105 | 50C7CE391820F54E0076A49B /* Other Frameworks */ = { 106 | isa = PBXGroup; 107 | children = ( 108 | 50C7CE3A1820F54E0076A49B /* AppKit.framework */, 109 | 50C7CE3B1820F54E0076A49B /* CoreData.framework */, 110 | 50C7CE3C1820F54E0076A49B /* Foundation.framework */, 111 | ); 112 | name = "Other Frameworks"; 113 | sourceTree = ""; 114 | }; 115 | /* End PBXGroup section */ 116 | 117 | /* Begin PBXNativeTarget section */ 118 | 50C7CE331820F54E0076A49B /* iOS Simulator Plus */ = { 119 | isa = PBXNativeTarget; 120 | buildConfigurationList = 50C7CE651820F54F0076A49B /* Build configuration list for PBXNativeTarget "iOS Simulator Plus" */; 121 | buildPhases = ( 122 | 50C7CE301820F54E0076A49B /* Sources */, 123 | 50C7CE311820F54E0076A49B /* Frameworks */, 124 | 50C7CE321820F54E0076A49B /* Resources */, 125 | ); 126 | buildRules = ( 127 | ); 128 | dependencies = ( 129 | ); 130 | name = "iOS Simulator Plus"; 131 | productName = "iOS Simulator Touch"; 132 | productReference = 50C7CE341820F54E0076A49B /* iOS Simulator Plus.app */; 133 | productType = "com.apple.product-type.application"; 134 | }; 135 | /* End PBXNativeTarget section */ 136 | 137 | /* Begin PBXProject section */ 138 | 50C7CE2C1820F54E0076A49B /* Project object */ = { 139 | isa = PBXProject; 140 | attributes = { 141 | LastUpgradeCheck = 0500; 142 | ORGANIZATIONNAME = "Billy Millare"; 143 | }; 144 | buildConfigurationList = 50C7CE2F1820F54E0076A49B /* Build configuration list for PBXProject "iOS Simulator Plus" */; 145 | compatibilityVersion = "Xcode 3.2"; 146 | developmentRegion = English; 147 | hasScannedForEncodings = 0; 148 | knownRegions = ( 149 | en, 150 | Base, 151 | ); 152 | mainGroup = 50C7CE2B1820F54E0076A49B; 153 | productRefGroup = 50C7CE351820F54E0076A49B /* Products */; 154 | projectDirPath = ""; 155 | projectRoot = ""; 156 | targets = ( 157 | 50C7CE331820F54E0076A49B /* iOS Simulator Plus */, 158 | ); 159 | }; 160 | /* End PBXProject section */ 161 | 162 | /* Begin PBXResourcesBuildPhase section */ 163 | 50C7CE321820F54E0076A49B /* Resources */ = { 164 | isa = PBXResourcesBuildPhase; 165 | buildActionMask = 2147483647; 166 | files = ( 167 | 50A9F139184CEB3900F2C251 /* MainMenu.xib in Resources */, 168 | 50A9F133184C616500F2C251 /* InfoPlist.strings in Resources */, 169 | 50A9F136184C616500F2C251 /* Images.xcassets in Resources */, 170 | 50A9F135184C616500F2C251 /* iconTemplate.png in Resources */, 171 | 50A9F132184C616500F2C251 /* Credits.rtf in Resources */, 172 | ); 173 | runOnlyForDeploymentPostprocessing = 0; 174 | }; 175 | /* End PBXResourcesBuildPhase section */ 176 | 177 | /* Begin PBXSourcesBuildPhase section */ 178 | 50C7CE301820F54E0076A49B /* Sources */ = { 179 | isa = PBXSourcesBuildPhase; 180 | buildActionMask = 2147483647; 181 | files = ( 182 | 50A9F138184C616500F2C251 /* main.m in Sources */, 183 | 50A9F130184C616500F2C251 /* AppDelegate.m in Sources */, 184 | ); 185 | runOnlyForDeploymentPostprocessing = 0; 186 | }; 187 | /* End PBXSourcesBuildPhase section */ 188 | 189 | /* Begin PBXVariantGroup section */ 190 | 50A9F124184C616500F2C251 /* MainMenu.xib */ = { 191 | isa = PBXVariantGroup; 192 | children = ( 193 | 50A9F125184C616500F2C251 /* Base */, 194 | ); 195 | name = MainMenu.xib; 196 | sourceTree = ""; 197 | }; 198 | 50A9F126184C616500F2C251 /* Credits.rtf */ = { 199 | isa = PBXVariantGroup; 200 | children = ( 201 | 50A9F127184C616500F2C251 /* en */, 202 | ); 203 | name = Credits.rtf; 204 | sourceTree = ""; 205 | }; 206 | 50A9F128184C616500F2C251 /* InfoPlist.strings */ = { 207 | isa = PBXVariantGroup; 208 | children = ( 209 | 50A9F129184C616500F2C251 /* en */, 210 | ); 211 | name = InfoPlist.strings; 212 | sourceTree = ""; 213 | }; 214 | /* End PBXVariantGroup section */ 215 | 216 | /* Begin XCBuildConfiguration section */ 217 | 50C7CE631820F54F0076A49B /* Debug */ = { 218 | isa = XCBuildConfiguration; 219 | buildSettings = { 220 | ALWAYS_SEARCH_USER_PATHS = NO; 221 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 222 | CLANG_CXX_LIBRARY = "libc++"; 223 | CLANG_ENABLE_OBJC_ARC = YES; 224 | CLANG_WARN_BOOL_CONVERSION = YES; 225 | CLANG_WARN_CONSTANT_CONVERSION = YES; 226 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 227 | CLANG_WARN_EMPTY_BODY = YES; 228 | CLANG_WARN_ENUM_CONVERSION = YES; 229 | CLANG_WARN_INT_CONVERSION = YES; 230 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 231 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 232 | COPY_PHASE_STRIP = NO; 233 | GCC_C_LANGUAGE_STANDARD = gnu99; 234 | GCC_DYNAMIC_NO_PIC = NO; 235 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 236 | GCC_OPTIMIZATION_LEVEL = 0; 237 | GCC_PREPROCESSOR_DEFINITIONS = ( 238 | "DEBUG=1", 239 | "$(inherited)", 240 | ); 241 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | MACOSX_DEPLOYMENT_TARGET = 10.9; 249 | ONLY_ACTIVE_ARCH = YES; 250 | SDKROOT = macosx; 251 | }; 252 | name = Debug; 253 | }; 254 | 50C7CE641820F54F0076A49B /* Release */ = { 255 | isa = XCBuildConfiguration; 256 | buildSettings = { 257 | ALWAYS_SEARCH_USER_PATHS = NO; 258 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 259 | CLANG_CXX_LIBRARY = "libc++"; 260 | CLANG_ENABLE_OBJC_ARC = YES; 261 | CLANG_WARN_BOOL_CONVERSION = YES; 262 | CLANG_WARN_CONSTANT_CONVERSION = YES; 263 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 264 | CLANG_WARN_EMPTY_BODY = YES; 265 | CLANG_WARN_ENUM_CONVERSION = YES; 266 | CLANG_WARN_INT_CONVERSION = YES; 267 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 268 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 269 | COPY_PHASE_STRIP = YES; 270 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 271 | ENABLE_NS_ASSERTIONS = NO; 272 | GCC_C_LANGUAGE_STANDARD = gnu99; 273 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 274 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 275 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 276 | GCC_WARN_UNDECLARED_SELECTOR = YES; 277 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 278 | GCC_WARN_UNUSED_FUNCTION = YES; 279 | GCC_WARN_UNUSED_VARIABLE = YES; 280 | MACOSX_DEPLOYMENT_TARGET = 10.9; 281 | SDKROOT = macosx; 282 | }; 283 | name = Release; 284 | }; 285 | 50C7CE661820F54F0076A49B /* Debug */ = { 286 | isa = XCBuildConfiguration; 287 | buildSettings = { 288 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 289 | CLANG_ENABLE_OBJC_ARC = NO; 290 | COMBINE_HIDPI_IMAGES = YES; 291 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 292 | GCC_PREFIX_HEADER = "iOS Simulator Plus/iOS Simulator Plus-Prefix.pch"; 293 | INFOPLIST_FILE = "iOS Simulator Plus/iOS Simulator Plus-Info.plist"; 294 | MACOSX_DEPLOYMENT_TARGET = 10.4; 295 | PRODUCT_NAME = "iOS Simulator Plus"; 296 | WRAPPER_EXTENSION = app; 297 | }; 298 | name = Debug; 299 | }; 300 | 50C7CE671820F54F0076A49B /* Release */ = { 301 | isa = XCBuildConfiguration; 302 | buildSettings = { 303 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 304 | CLANG_ENABLE_OBJC_ARC = NO; 305 | COMBINE_HIDPI_IMAGES = YES; 306 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 307 | GCC_PREFIX_HEADER = "iOS Simulator Plus/iOS Simulator Plus-Prefix.pch"; 308 | INFOPLIST_FILE = "iOS Simulator Plus/iOS Simulator Plus-Info.plist"; 309 | MACOSX_DEPLOYMENT_TARGET = 10.4; 310 | PRODUCT_NAME = "iOS Simulator Plus"; 311 | WRAPPER_EXTENSION = app; 312 | }; 313 | name = Release; 314 | }; 315 | /* End XCBuildConfiguration section */ 316 | 317 | /* Begin XCConfigurationList section */ 318 | 50C7CE2F1820F54E0076A49B /* Build configuration list for PBXProject "iOS Simulator Plus" */ = { 319 | isa = XCConfigurationList; 320 | buildConfigurations = ( 321 | 50C7CE631820F54F0076A49B /* Debug */, 322 | 50C7CE641820F54F0076A49B /* Release */, 323 | ); 324 | defaultConfigurationIsVisible = 0; 325 | defaultConfigurationName = Release; 326 | }; 327 | 50C7CE651820F54F0076A49B /* Build configuration list for PBXNativeTarget "iOS Simulator Plus" */ = { 328 | isa = XCConfigurationList; 329 | buildConfigurations = ( 330 | 50C7CE661820F54F0076A49B /* Debug */, 331 | 50C7CE671820F54F0076A49B /* Release */, 332 | ); 333 | defaultConfigurationIsVisible = 0; 334 | defaultConfigurationName = Release; 335 | }; 336 | /* End XCConfigurationList section */ 337 | }; 338 | rootObject = 50C7CE2C1820F54E0076A49B /* Project object */; 339 | } 340 | -------------------------------------------------------------------------------- /iOS Simulator Plus/AppDelegate.m: -------------------------------------------------------------------------------- 1 | /* 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2013 Billy Millare 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy of 7 | * this software and associated documentation files (the "Software"), to deal in 8 | * the Software without restriction, including without limitation the rights to 9 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 10 | * the Software, and to permit persons to whom the Software is furnished to do so, 11 | * subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 18 | * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 19 | * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 20 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 21 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | 24 | /* 25 | * AppDelegate.m 26 | * 27 | * Created on: Oct 30, 2013 28 | * Author: Billy 29 | */ 30 | 31 | #import "AppDelegate.h" 32 | #import 33 | #import 34 | 35 | #define TargetApplicationName @"iPhone Simulator" 36 | #define TargetApplicationBundleIdentifier @"com.apple.iphonesimulator" 37 | 38 | @interface AppDelegate () 39 | { 40 | IBOutlet NSMenu *menu; 41 | IBOutlet NSMenuItem *targetApplicationActivateMenuItem; 42 | NSStatusItem *statusItem; 43 | 44 | CFMachPortRef portRef; 45 | CFRunLoopSourceRef runLoopSourceRef; 46 | 47 | CGFloat windowTitleBarHeight; 48 | CGRect targetWindowBounds; 49 | CGRect normalizedTargetWindowBounds; 50 | CGEventFlags eventFlags; 51 | CGPoint currentScreenPosition; 52 | CGPoint cursorPosition; 53 | 54 | enum { 55 | UnknownGesture, 56 | Rotation, 57 | Magnification, 58 | } gesture; 59 | 60 | CGFloat gestureValue; 61 | CGFloat gestureMinValue; 62 | CGFloat gestureMaxValue; 63 | 64 | BOOL mouseIsDown; 65 | BOOL isTouchscreenMode; 66 | 67 | enum { 68 | Inactive, 69 | Ready, 70 | Active 71 | } touchStatus; 72 | } 73 | 74 | @property (assign) IBOutlet NSWindow *window; 75 | @property (nonatomic, assign) BOOL eventTapEnabled; 76 | @property (nonatomic, retain) NSRunningApplication *targetApplication; 77 | - (CGRect)targetApplicationBounds; 78 | @end 79 | 80 | @implementation AppDelegate 81 | @synthesize window; 82 | @synthesize eventTapEnabled; 83 | @synthesize targetApplication; 84 | 85 | - (void)dealloc 86 | { 87 | [[NSWorkspace sharedWorkspace].notificationCenter removeObserver:self]; 88 | self.eventTapEnabled = NO; 89 | self.targetApplication = nil; 90 | [menu release]; 91 | [targetApplicationActivateMenuItem release]; 92 | [statusItem release]; 93 | [super dealloc]; 94 | } 95 | 96 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 97 | { 98 | windowTitleBarHeight = window.frame.size.height - [window.contentView frame].size.height; 99 | window.showsToolbarButton = YES; 100 | [window orderOut:self]; 101 | statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength] retain]; 102 | statusItem.highlightMode = YES; 103 | statusItem.image = [NSImage imageNamed:@"iconTemplate.png"]; 104 | statusItem.image.size = NSMakeSize(21, 21); 105 | statusItem.menu = menu; 106 | [[NSWorkspace sharedWorkspace].notificationCenter addObserver:self selector:@selector(workspaceDidActivateApplication:) name:NSWorkspaceDidActivateApplicationNotification object:nil]; 107 | [self didActivateApplication:[NSWorkspace sharedWorkspace].frontmostApplication]; 108 | } 109 | 110 | - (IBAction)showAbout:(id)sender 111 | { 112 | [NSApp orderFrontStandardAboutPanel:sender]; 113 | } 114 | 115 | - (IBAction)terminate:(id)sender 116 | { 117 | [NSApp terminate:sender]; 118 | } 119 | 120 | - (void)activateTargetApplication:(id)sender 121 | { 122 | [[NSWorkspace sharedWorkspace] launchAppWithBundleIdentifier:TargetApplicationBundleIdentifier options:NSWorkspaceLaunchDefault additionalEventParamDescriptor:nil launchIdentifier:NULL]; 123 | } 124 | 125 | - (void)didActivateApplication:(NSRunningApplication *)application 126 | { 127 | self.targetApplication = [application.bundleIdentifier isEqualToString:TargetApplicationBundleIdentifier] ? application : nil; 128 | 129 | if(targetApplication == nil) 130 | self.eventTapEnabled = NO; 131 | else 132 | { 133 | while(CGRectIsEmpty([self targetApplicationBounds])) 134 | [NSThread sleepForTimeInterval:0.1]; 135 | 136 | self.eventTapEnabled = YES; 137 | } 138 | } 139 | 140 | - (void)workspaceDidActivateApplication:(NSNotification *)notification 141 | { 142 | [self didActivateApplication:[[notification userInfo] objectForKey:NSWorkspaceApplicationKey]]; 143 | } 144 | 145 | - (void)setEventTapEnabled:(BOOL)eventTapEnabled_ 146 | { 147 | [targetApplicationActivateMenuItem setAction:(eventTapEnabled_ ? nil : @selector(activateTargetApplication:))]; 148 | 149 | if(eventTapEnabled_ != eventTapEnabled) 150 | { 151 | if(eventTapEnabled_) 152 | { 153 | mouseIsDown = NO; 154 | isTouchscreenMode = NO; 155 | touchStatus = Inactive; 156 | portRef = CGEventTapCreate(kCGHIDEventTap, kCGTailAppendEventTap, kCGEventTapOptionDefault, NSFlagsChangedMask | NSMouseMovedMask | NSLeftMouseDownMask | NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSEventMaskGesture, (CGEventTapCallBack)eventTapCallback, self); 157 | runLoopSourceRef = CFMachPortCreateRunLoopSource(NULL, portRef, 0); 158 | CFRunLoopAddSource(CFRunLoopGetMain(), runLoopSourceRef, kCFRunLoopCommonModes); 159 | } 160 | else if(runLoopSourceRef != nil && CFRunLoopContainsSource(CFRunLoopGetMain(), runLoopSourceRef, kCFRunLoopCommonModes)) 161 | { 162 | CFRunLoopRemoveSource(CFRunLoopGetMain(), runLoopSourceRef, kCFRunLoopCommonModes); 163 | 164 | if(portRef != nil) 165 | { 166 | CFMachPortInvalidate(portRef); 167 | CFRelease(portRef); 168 | portRef = nil; 169 | } 170 | 171 | if(runLoopSourceRef != nil) 172 | { 173 | CFRelease(runLoopSourceRef); 174 | runLoopSourceRef = nil; 175 | } 176 | } 177 | 178 | eventTapEnabled = eventTapEnabled_; 179 | } 180 | } 181 | 182 | - (CGRect)targetApplicationBounds 183 | { 184 | NSArray *windowInfoList = (NSArray *)CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID); 185 | normalizedTargetWindowBounds = CGRectZero; 186 | 187 | for(NSDictionary *windowInfo in windowInfoList) 188 | { 189 | if([[windowInfo valueForKey:(NSString *)kCGWindowOwnerPID] intValue] == targetApplication.processIdentifier) 190 | { 191 | CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[windowInfo valueForKey:(NSString *)kCGWindowBounds], &targetWindowBounds); 192 | normalizedTargetWindowBounds = targetWindowBounds; 193 | normalizedTargetWindowBounds.origin.y += normalizedTargetWindowBounds.size.height; 194 | normalizedTargetWindowBounds.size.height -= windowTitleBarHeight; 195 | targetWindowBounds.origin.y = [NSScreen mainScreen].frame.size.height - (targetWindowBounds.origin.y + targetWindowBounds.size.height); 196 | targetWindowBounds.size.height -= windowTitleBarHeight; 197 | break; 198 | } 199 | } 200 | 201 | CFRelease(windowInfoList); 202 | return normalizedTargetWindowBounds; 203 | } 204 | 205 | - (void)sendFlagsChangedEvent:(CGEventFlags)flags 206 | { 207 | if(flags != eventFlags) 208 | { 209 | CGEventRef eventRef = CGEventCreate(NULL); 210 | CGEventSetType(eventRef, kCGEventFlagsChanged); 211 | CGEventSetFlags(eventRef, flags); 212 | CGEventPost(kCGHIDEventTap, eventRef); 213 | CFRelease(eventRef); 214 | eventFlags = flags; 215 | } 216 | } 217 | 218 | - (void)sendMouseEvent:(CGEventType)eventType atPosition:(CGPoint)position 219 | { 220 | BOOL send = YES; 221 | 222 | switch(eventType) 223 | { 224 | case kCGEventLeftMouseDragged: 225 | if(!mouseIsDown) 226 | [self sendMouseEvent:kCGEventLeftMouseDown atPosition:position]; 227 | 228 | break; 229 | 230 | case kCGEventMouseMoved: 231 | if(mouseIsDown) 232 | [self sendMouseEvent:kCGEventLeftMouseUp atPosition:position]; 233 | 234 | break; 235 | 236 | case kCGEventLeftMouseDown: 237 | send = !mouseIsDown; 238 | mouseIsDown = YES; 239 | break; 240 | 241 | case kCGEventLeftMouseUp: 242 | send = mouseIsDown; 243 | mouseIsDown = NO; 244 | break; 245 | 246 | default: 247 | send = NO; 248 | break; 249 | } 250 | 251 | if(send) 252 | { 253 | CGEventRef eventRef = CGEventCreateMouseEvent(NULL, eventType, position, 0); 254 | CGEventSetFlags(eventRef, eventFlags); 255 | CGEventPost(kCGHIDEventTap, eventRef); 256 | CFRelease(eventRef); 257 | } 258 | 259 | CGWarpMouseCursorPosition([self screenPosition:cursorPosition]); 260 | } 261 | 262 | enum { 263 | RotateLeft, 264 | RotateRight, 265 | ShakeGesture, 266 | Home, 267 | Lock, 268 | Dummy 269 | }; 270 | 271 | - (void)triggerHardwareCommand:(int)command 272 | { 273 | CGKeyCode keyCode; 274 | CGEventFlags flags = kCGEventFlagMaskCommand; 275 | 276 | switch(command) 277 | { 278 | case RotateLeft: 279 | keyCode = kVK_LeftArrow; 280 | break; 281 | 282 | case RotateRight: 283 | keyCode = kVK_RightArrow; 284 | break; 285 | 286 | case ShakeGesture: 287 | keyCode = kVK_ANSI_Z; 288 | flags |= kCGEventFlagMaskControl; 289 | break; 290 | 291 | case Home: 292 | keyCode = kVK_ANSI_H; 293 | flags |= kCGEventFlagMaskShift; 294 | break; 295 | 296 | case Lock: 297 | keyCode = kVK_ANSI_L; 298 | break; 299 | 300 | default: 301 | return; 302 | } 303 | 304 | CGEventRef eventRef = CGEventCreateKeyboardEvent(NULL, keyCode, true); 305 | CGEventSetFlags(eventRef, flags); 306 | CGEventPost(kCGHIDEventTap, eventRef); 307 | CFRelease(eventRef); 308 | } 309 | 310 | - (CGPoint)screenPosition:(CGPoint)normalizedPosition 311 | { 312 | CGPoint screenPosition; 313 | screenPosition.x = normalizedTargetWindowBounds.origin.x + (normalizedTargetWindowBounds.size.width * normalizedPosition.x); 314 | screenPosition.y = normalizedTargetWindowBounds.origin.y - (normalizedTargetWindowBounds.size.height * normalizedPosition.y); 315 | return screenPosition; 316 | } 317 | 318 | - (CGPoint)normalizedPosition 319 | { 320 | CGPoint screenPosition = [NSEvent mouseLocation]; 321 | 322 | if(CGRectContainsPoint(targetWindowBounds, screenPosition)) 323 | return CGPointMake((screenPosition.x - targetWindowBounds.origin.x) / targetWindowBounds.size.width, (screenPosition.y - targetWindowBounds.origin.y) / targetWindowBounds.size.height); 324 | 325 | return CGPointMake(0.5, 0.5); 326 | } 327 | 328 | static CGEventRef eventTapCallback(CGEventTapProxy proxy, CGEventType type, CGEventRef eventRef, AppDelegate *appDelegate) 329 | { 330 | NSEvent *event = [NSEvent eventWithCGEvent:eventRef]; 331 | 332 | switch(type) 333 | { 334 | case NSEventTypeGesture: 335 | switch(event.type) 336 | { 337 | case NSEventTypeGesture: 338 | { 339 | NSArray *touches = [event touchesMatchingPhase:NSTouchPhaseAny inView:nil].allObjects; 340 | 341 | if(touches.count == 1) 342 | { 343 | NSTouch *touch = touches.firstObject; 344 | NSUInteger modifierFlags = event.modifierFlags & (NSShiftKeyMask | NSControlKeyMask); 345 | 346 | if(touch.phase == NSTouchPhaseBegan) 347 | appDelegate->isTouchscreenMode = (modifierFlags != 0) && (event.modifierFlags & NSAlternateKeyMask) == 0; 348 | 349 | if(appDelegate->isTouchscreenMode) 350 | { 351 | CGEventType eventType = kCGEventNull; 352 | CGPoint position; 353 | 354 | switch(touch.phase) 355 | { 356 | case NSTouchPhaseBegan: 357 | [appDelegate targetApplicationBounds]; 358 | [appDelegate sendFlagsChangedEvent:0]; 359 | appDelegate->touchStatus = (modifierFlags & NSControlKeyMask) ? Ready : Active; 360 | 361 | if(appDelegate->touchStatus == Ready) 362 | { 363 | CGEventFlags flags = kCGEventFlagMaskAlternate; 364 | 365 | if((modifierFlags & NSShiftKeyMask)) 366 | { 367 | flags |= kCGEventFlagMaskShift; 368 | appDelegate->cursorPosition = touch.normalizedPosition; 369 | position.x = 0.5; 370 | position.y = 0.5; 371 | } 372 | else 373 | { 374 | appDelegate->cursorPosition = [appDelegate normalizedPosition]; 375 | position.x = 0.5 + touch.normalizedPosition.x - appDelegate->cursorPosition.x; 376 | position.y = 0.5 + touch.normalizedPosition.y - appDelegate->cursorPosition.y; 377 | } 378 | 379 | [appDelegate sendFlagsChangedEvent:kCGEventFlagMaskAlternate]; 380 | [appDelegate sendMouseEvent:kCGEventMouseMoved atPosition:[appDelegate screenPosition:position]]; 381 | position = [appDelegate screenPosition:touch.normalizedPosition]; 382 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 383 | if(appDelegate->touchStatus == Ready) 384 | { 385 | [appDelegate sendFlagsChangedEvent:(kCGEventFlagMaskAlternate | kCGEventFlagMaskShift)]; 386 | [appDelegate sendMouseEvent:kCGEventMouseMoved atPosition:position]; 387 | [appDelegate sendFlagsChangedEvent:flags]; 388 | [appDelegate sendMouseEvent:kCGEventLeftMouseDown atPosition:position]; 389 | appDelegate->touchStatus = Active; 390 | } 391 | }); 392 | 393 | break; 394 | } 395 | 396 | case NSTouchPhaseMoved: 397 | if(appDelegate->touchStatus == Active) 398 | { 399 | eventType = kCGEventLeftMouseDragged; 400 | position = [appDelegate screenPosition:touch.normalizedPosition]; 401 | appDelegate->currentScreenPosition = position; 402 | 403 | if(appDelegate->eventFlags != kCGEventFlagMaskAlternate) 404 | appDelegate->cursorPosition = touch.normalizedPosition; 405 | } 406 | 407 | break; 408 | 409 | case NSTouchPhaseEnded: 410 | case NSTouchPhaseCancelled: 411 | appDelegate->touchStatus = Inactive; 412 | [appDelegate sendFlagsChangedEvent:0]; 413 | eventType = kCGEventLeftMouseUp; 414 | position = appDelegate->currentScreenPosition; 415 | break; 416 | 417 | default: 418 | break; 419 | } 420 | 421 | [appDelegate sendMouseEvent:eventType atPosition:position]; 422 | } 423 | } 424 | 425 | break; 426 | } 427 | 428 | case NSEventTypeBeginGesture: 429 | appDelegate->gestureValue = 0; 430 | appDelegate->gestureMinValue = 0; 431 | appDelegate->gestureMaxValue = 0; 432 | appDelegate->gesture = UnknownGesture; 433 | break; 434 | 435 | case NSEventTypeMagnify: 436 | if(appDelegate->gesture == Magnification) 437 | { 438 | appDelegate->gestureValue += event.magnification; 439 | 440 | if(event.magnification < 0) 441 | appDelegate->gestureMinValue += event.magnification; 442 | else 443 | appDelegate->gestureMaxValue += event.magnification; 444 | } 445 | else if(appDelegate->gesture == UnknownGesture) 446 | appDelegate->gesture = Magnification; 447 | 448 | break; 449 | 450 | case NSEventTypeRotate: 451 | if(appDelegate->gesture == Rotation) 452 | { 453 | appDelegate->gestureValue += event.rotation; 454 | 455 | if(event.rotation < 0) 456 | appDelegate->gestureMinValue += event.rotation; 457 | else 458 | appDelegate->gestureMaxValue += event.rotation; 459 | } 460 | else if(appDelegate->gesture == UnknownGesture) 461 | appDelegate->gesture = Rotation; 462 | 463 | break; 464 | 465 | case NSEventTypeEndGesture: 466 | { 467 | int command = Dummy; 468 | 469 | if(appDelegate->gesture == Magnification) 470 | { 471 | if(appDelegate->gestureMinValue < -0.5 && appDelegate->gestureMaxValue > 0.5) 472 | command = ShakeGesture; 473 | else if(appDelegate->gestureValue > 0.5) 474 | command = Lock; 475 | else if(appDelegate->gestureValue < -0.5) 476 | command = Home; 477 | } 478 | else if(appDelegate->gesture == Rotation) 479 | { 480 | if(appDelegate->gestureMinValue < -20 && appDelegate->gestureMaxValue > 20) 481 | command = ShakeGesture; 482 | else if(appDelegate->gestureValue > 20) 483 | command = RotateLeft; 484 | else if(appDelegate->gestureValue < -20) 485 | command = RotateRight; 486 | } 487 | 488 | [appDelegate triggerHardwareCommand:command]; 489 | break; 490 | } 491 | 492 | default: 493 | break; 494 | } 495 | 496 | break; 497 | 498 | case NSFlagsChanged: 499 | if((event.modifierFlags & 0x20000000) || appDelegate->touchStatus == Inactive) 500 | return eventRef; 501 | 502 | break; 503 | 504 | case NSMouseMoved: 505 | case NSLeftMouseDown: 506 | case NSLeftMouseDragged: 507 | case NSLeftMouseUp: 508 | if(CGEventGetIntegerValueField(eventRef, kCGMouseEventSubtype) != kCGEventMouseSubtypeDefault && appDelegate->isTouchscreenMode) 509 | break; 510 | 511 | default: 512 | return eventRef; 513 | } 514 | 515 | return NULL; 516 | } 517 | 518 | @end 519 | -------------------------------------------------------------------------------- /iOS Simulator Plus/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | Default 522 | 523 | 524 | 525 | 526 | 527 | 528 | Left to Right 529 | 530 | 531 | 532 | 533 | 534 | 535 | Right to Left 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | Default 547 | 548 | 549 | 550 | 551 | 552 | 553 | Left to Right 554 | 555 | 556 | 557 | 558 | 559 | 560 | Right to Left 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | --------------------------------------------------------------------------------