├── 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 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 |
658 |
659 |
660 |
661 |
662 |
663 |
664 |
665 |
666 |
667 |
668 |
669 |
672 |
673 |
679 |
680 |
686 |
687 |
688 |
689 |
--------------------------------------------------------------------------------