├── .gitignore
├── DRKonamiCode-Info.plist
├── DRKonamiCode-Prefix.pch
├── DRKonamiCode.podspec
├── DRKonamiCode.xcodeproj
├── project.pbxproj
└── project.xcworkspace
│ └── contents.xcworkspacedata
├── Default-568h@2x.png
├── README.md
├── Resources
├── DRViewController.xib
├── nes.png
└── nes@2x.png
├── Sources
├── DRAppDelegate.h
├── DRAppDelegate.m
├── DRKonamiGestureRecognizer.h
├── DRKonamiGestureRecognizer.m
├── DRViewController.h
├── DRViewController.m
└── main.m
└── license
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode Noise
2 | *build
3 | *xcuserdata
4 | *.pbxuser
5 | *.mode1v3
6 | *.mode2v3
7 |
8 | # OS X Noise
9 | *.DS_Store
10 |
--------------------------------------------------------------------------------
/DRKonamiCode-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | ${PRODUCT_NAME}
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIconFiles
12 |
13 | CFBundleIdentifier
14 | us.theredb.${PRODUCT_NAME:rfc1034identifier}
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | ${PRODUCT_NAME}
19 | CFBundlePackageType
20 | APPL
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleSignature
24 | ????
25 | CFBundleVersion
26 | 1.0
27 | LSRequiresIPhoneOS
28 |
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/DRKonamiCode-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'DRKonamiCode' target in the 'DRKonamiCode' project
3 | //
4 |
5 | #import
6 |
7 | #ifndef __IPHONE_4_0
8 | #warning "This project uses features only available in iOS SDK 4.0 and later."
9 | #endif
10 |
11 | #ifdef __OBJC__
12 | #import
13 | #import
14 | #endif
15 |
--------------------------------------------------------------------------------
/DRKonamiCode.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'DRKonamiCode'
3 | s.version = '1.1.1'
4 | s.platform = :ios
5 | s.ios.deployment_target = '5.0'
6 | s.license = 'MIT'
7 | s.summary = 'The Konami Code gesture recognizer for iOS.'
8 | s.homepage = 'https://github.com/objectiveSee/DRKonamiCode'
9 | s.author = { "Danny Ricciotti" => "dan.ricciotti@gmail.com" }
10 |
11 | s.source = { :git => 'https://github.com/objectiveSee/DRKonamiCode.git', :tag=>'v1.1.1' }
12 | s.source_files = 'Sources/DRKonamiGestureRecognizer.*'
13 |
14 | s.requires_arc = true
15 | end
16 |
--------------------------------------------------------------------------------
/DRKonamiCode.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 304949CC1579A63C0045FB4B /* DRAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 304949C71579A63C0045FB4B /* DRAppDelegate.m */; };
11 | 304949CD1579A63C0045FB4B /* DRKonamiGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 304949C91579A63C0045FB4B /* DRKonamiGestureRecognizer.m */; };
12 | 304949CE1579A63C0045FB4B /* DRViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 304949CB1579A63C0045FB4B /* DRViewController.m */; };
13 | 304949D21579A6670045FB4B /* DRViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 304949D11579A6670045FB4B /* DRViewController.xib */; };
14 | 304949D51579A6910045FB4B /* nes.png in Resources */ = {isa = PBXBuildFile; fileRef = 304949D31579A6910045FB4B /* nes.png */; };
15 | 304949D61579A6910045FB4B /* nes@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 304949D41579A6910045FB4B /* nes@2x.png */; };
16 | 304949D81579A6B60045FB4B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 304949D71579A6B60045FB4B /* main.m */; };
17 | 305E5B8118DC6FCA00CE5892 /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 305E5B8018DC6FCA00CE5892 /* Default-568h@2x.png */; };
18 | 3098B2CD1504515300F743BD /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3098B2CC1504515300F743BD /* UIKit.framework */; };
19 | 3098B2CF1504515300F743BD /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3098B2CE1504515300F743BD /* Foundation.framework */; };
20 | 3098B2D11504515300F743BD /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3098B2D01504515300F743BD /* CoreGraphics.framework */; };
21 | /* End PBXBuildFile section */
22 |
23 | /* Begin PBXFileReference section */
24 | 304949C61579A63C0045FB4B /* DRAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRAppDelegate.h; sourceTree = ""; };
25 | 304949C71579A63C0045FB4B /* DRAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRAppDelegate.m; sourceTree = ""; };
26 | 304949C81579A63C0045FB4B /* DRKonamiGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRKonamiGestureRecognizer.h; sourceTree = ""; };
27 | 304949C91579A63C0045FB4B /* DRKonamiGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRKonamiGestureRecognizer.m; sourceTree = ""; };
28 | 304949CA1579A63C0045FB4B /* DRViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DRViewController.h; sourceTree = ""; };
29 | 304949CB1579A63C0045FB4B /* DRViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DRViewController.m; sourceTree = ""; };
30 | 304949D11579A6670045FB4B /* DRViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = DRViewController.xib; sourceTree = ""; };
31 | 304949D31579A6910045FB4B /* nes.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = nes.png; sourceTree = ""; };
32 | 304949D41579A6910045FB4B /* nes@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "nes@2x.png"; sourceTree = ""; };
33 | 304949D71579A6B60045FB4B /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
34 | 304949DB1579A73A0045FB4B /* DRKonamiCode-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "DRKonamiCode-Info.plist"; sourceTree = ""; };
35 | 304949DD1579A7560045FB4B /* DRKonamiCode-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "DRKonamiCode-Prefix.pch"; sourceTree = ""; };
36 | 305E5B8018DC6FCA00CE5892 /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; };
37 | 3098B2C81504515300F743BD /* DRKonamiCode.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DRKonamiCode.app; sourceTree = BUILT_PRODUCTS_DIR; };
38 | 3098B2CC1504515300F743BD /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
39 | 3098B2CE1504515300F743BD /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
40 | 3098B2D01504515300F743BD /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
41 | /* End PBXFileReference section */
42 |
43 | /* Begin PBXFrameworksBuildPhase section */
44 | 3098B2C51504515300F743BD /* Frameworks */ = {
45 | isa = PBXFrameworksBuildPhase;
46 | buildActionMask = 2147483647;
47 | files = (
48 | 3098B2CD1504515300F743BD /* UIKit.framework in Frameworks */,
49 | 3098B2CF1504515300F743BD /* Foundation.framework in Frameworks */,
50 | 3098B2D11504515300F743BD /* CoreGraphics.framework in Frameworks */,
51 | );
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXFrameworksBuildPhase section */
55 |
56 | /* Begin PBXGroup section */
57 | 304949C51579A63C0045FB4B /* Sources */ = {
58 | isa = PBXGroup;
59 | children = (
60 | 304949D71579A6B60045FB4B /* main.m */,
61 | 304949C61579A63C0045FB4B /* DRAppDelegate.h */,
62 | 304949C71579A63C0045FB4B /* DRAppDelegate.m */,
63 | 304949C81579A63C0045FB4B /* DRKonamiGestureRecognizer.h */,
64 | 304949C91579A63C0045FB4B /* DRKonamiGestureRecognizer.m */,
65 | 304949CA1579A63C0045FB4B /* DRViewController.h */,
66 | 304949CB1579A63C0045FB4B /* DRViewController.m */,
67 | );
68 | path = Sources;
69 | sourceTree = "";
70 | };
71 | 304949D01579A6670045FB4B /* Resources */ = {
72 | isa = PBXGroup;
73 | children = (
74 | 304949D31579A6910045FB4B /* nes.png */,
75 | 304949D41579A6910045FB4B /* nes@2x.png */,
76 | 304949D11579A6670045FB4B /* DRViewController.xib */,
77 | );
78 | path = Resources;
79 | sourceTree = "";
80 | };
81 | 3098B2BD1504515200F743BD = {
82 | isa = PBXGroup;
83 | children = (
84 | 305E5B8018DC6FCA00CE5892 /* Default-568h@2x.png */,
85 | 304949DD1579A7560045FB4B /* DRKonamiCode-Prefix.pch */,
86 | 304949DB1579A73A0045FB4B /* DRKonamiCode-Info.plist */,
87 | 304949C51579A63C0045FB4B /* Sources */,
88 | 304949D01579A6670045FB4B /* Resources */,
89 | 3098B2CB1504515300F743BD /* Frameworks */,
90 | 3098B2C91504515300F743BD /* Products */,
91 | );
92 | sourceTree = "";
93 | };
94 | 3098B2C91504515300F743BD /* Products */ = {
95 | isa = PBXGroup;
96 | children = (
97 | 3098B2C81504515300F743BD /* DRKonamiCode.app */,
98 | );
99 | name = Products;
100 | sourceTree = "";
101 | };
102 | 3098B2CB1504515300F743BD /* Frameworks */ = {
103 | isa = PBXGroup;
104 | children = (
105 | 3098B2CC1504515300F743BD /* UIKit.framework */,
106 | 3098B2CE1504515300F743BD /* Foundation.framework */,
107 | 3098B2D01504515300F743BD /* CoreGraphics.framework */,
108 | );
109 | name = Frameworks;
110 | sourceTree = "";
111 | };
112 | /* End PBXGroup section */
113 |
114 | /* Begin PBXNativeTarget section */
115 | 3098B2C71504515300F743BD /* DRKonamiCode */ = {
116 | isa = PBXNativeTarget;
117 | buildConfigurationList = 3098B2E61504515300F743BD /* Build configuration list for PBXNativeTarget "DRKonamiCode" */;
118 | buildPhases = (
119 | 3098B2C41504515300F743BD /* Sources */,
120 | 3098B2C51504515300F743BD /* Frameworks */,
121 | 3098B2C61504515300F743BD /* Resources */,
122 | );
123 | buildRules = (
124 | );
125 | dependencies = (
126 | );
127 | name = DRKonamiCode;
128 | productName = DRKonamiCode;
129 | productReference = 3098B2C81504515300F743BD /* DRKonamiCode.app */;
130 | productType = "com.apple.product-type.application";
131 | };
132 | /* End PBXNativeTarget section */
133 |
134 | /* Begin PBXProject section */
135 | 3098B2BF1504515200F743BD /* Project object */ = {
136 | isa = PBXProject;
137 | attributes = {
138 | LastUpgradeCheck = 0500;
139 | ORGANIZATIONNAME = "CouchSurfing International";
140 | };
141 | buildConfigurationList = 3098B2C21504515200F743BD /* Build configuration list for PBXProject "DRKonamiCode" */;
142 | compatibilityVersion = "Xcode 3.2";
143 | developmentRegion = English;
144 | hasScannedForEncodings = 0;
145 | knownRegions = (
146 | en,
147 | );
148 | mainGroup = 3098B2BD1504515200F743BD;
149 | productRefGroup = 3098B2C91504515300F743BD /* Products */;
150 | projectDirPath = "";
151 | projectRoot = "";
152 | targets = (
153 | 3098B2C71504515300F743BD /* DRKonamiCode */,
154 | );
155 | };
156 | /* End PBXProject section */
157 |
158 | /* Begin PBXResourcesBuildPhase section */
159 | 3098B2C61504515300F743BD /* Resources */ = {
160 | isa = PBXResourcesBuildPhase;
161 | buildActionMask = 2147483647;
162 | files = (
163 | 304949D21579A6670045FB4B /* DRViewController.xib in Resources */,
164 | 305E5B8118DC6FCA00CE5892 /* Default-568h@2x.png in Resources */,
165 | 304949D51579A6910045FB4B /* nes.png in Resources */,
166 | 304949D61579A6910045FB4B /* nes@2x.png in Resources */,
167 | );
168 | runOnlyForDeploymentPostprocessing = 0;
169 | };
170 | /* End PBXResourcesBuildPhase section */
171 |
172 | /* Begin PBXSourcesBuildPhase section */
173 | 3098B2C41504515300F743BD /* Sources */ = {
174 | isa = PBXSourcesBuildPhase;
175 | buildActionMask = 2147483647;
176 | files = (
177 | 304949CC1579A63C0045FB4B /* DRAppDelegate.m in Sources */,
178 | 304949CD1579A63C0045FB4B /* DRKonamiGestureRecognizer.m in Sources */,
179 | 304949CE1579A63C0045FB4B /* DRViewController.m in Sources */,
180 | 304949D81579A6B60045FB4B /* main.m in Sources */,
181 | );
182 | runOnlyForDeploymentPostprocessing = 0;
183 | };
184 | /* End PBXSourcesBuildPhase section */
185 |
186 | /* Begin XCBuildConfiguration section */
187 | 3098B2E41504515300F743BD /* Debug */ = {
188 | isa = XCBuildConfiguration;
189 | buildSettings = {
190 | ALWAYS_SEARCH_USER_PATHS = NO;
191 | CLANG_WARN_BOOL_CONVERSION = YES;
192 | CLANG_WARN_CONSTANT_CONVERSION = YES;
193 | CLANG_WARN_EMPTY_BODY = YES;
194 | CLANG_WARN_ENUM_CONVERSION = YES;
195 | CLANG_WARN_INT_CONVERSION = YES;
196 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
197 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
198 | COPY_PHASE_STRIP = NO;
199 | GCC_C_LANGUAGE_STANDARD = gnu99;
200 | GCC_DYNAMIC_NO_PIC = NO;
201 | GCC_OPTIMIZATION_LEVEL = 0;
202 | GCC_PREPROCESSOR_DEFINITIONS = (
203 | "DEBUG=1",
204 | "$(inherited)",
205 | );
206 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
207 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
208 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
209 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
210 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
211 | GCC_WARN_UNDECLARED_SELECTOR = YES;
212 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
213 | GCC_WARN_UNUSED_FUNCTION = YES;
214 | GCC_WARN_UNUSED_VARIABLE = YES;
215 | IPHONEOS_DEPLOYMENT_TARGET = 5.0;
216 | ONLY_ACTIVE_ARCH = YES;
217 | SDKROOT = iphoneos;
218 | };
219 | name = Debug;
220 | };
221 | 3098B2E51504515300F743BD /* Release */ = {
222 | isa = XCBuildConfiguration;
223 | buildSettings = {
224 | ALWAYS_SEARCH_USER_PATHS = NO;
225 | CLANG_WARN_BOOL_CONVERSION = YES;
226 | CLANG_WARN_CONSTANT_CONVERSION = YES;
227 | CLANG_WARN_EMPTY_BODY = YES;
228 | CLANG_WARN_ENUM_CONVERSION = YES;
229 | CLANG_WARN_INT_CONVERSION = YES;
230 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
231 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
232 | COPY_PHASE_STRIP = YES;
233 | GCC_C_LANGUAGE_STANDARD = gnu99;
234 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0;
235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
236 | GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
237 | GCC_WARN_ABOUT_RETURN_TYPE = YES;
238 | GCC_WARN_UNDECLARED_SELECTOR = YES;
239 | GCC_WARN_UNINITIALIZED_AUTOS = YES;
240 | GCC_WARN_UNUSED_FUNCTION = YES;
241 | GCC_WARN_UNUSED_VARIABLE = YES;
242 | IPHONEOS_DEPLOYMENT_TARGET = 5.0;
243 | OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1";
244 | SDKROOT = iphoneos;
245 | VALIDATE_PRODUCT = YES;
246 | };
247 | name = Release;
248 | };
249 | 3098B2E71504515300F743BD /* Debug */ = {
250 | isa = XCBuildConfiguration;
251 | buildSettings = {
252 | CLANG_ENABLE_OBJC_ARC = YES;
253 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
254 | GCC_PREFIX_HEADER = "DRKonamiCode-Prefix.pch";
255 | INFOPLIST_FILE = "DRKonamiCode-Info.plist";
256 | PRODUCT_NAME = "$(TARGET_NAME)";
257 | WRAPPER_EXTENSION = app;
258 | };
259 | name = Debug;
260 | };
261 | 3098B2E81504515300F743BD /* Release */ = {
262 | isa = XCBuildConfiguration;
263 | buildSettings = {
264 | CLANG_ENABLE_OBJC_ARC = YES;
265 | GCC_PRECOMPILE_PREFIX_HEADER = YES;
266 | GCC_PREFIX_HEADER = "DRKonamiCode-Prefix.pch";
267 | INFOPLIST_FILE = "DRKonamiCode-Info.plist";
268 | PRODUCT_NAME = "$(TARGET_NAME)";
269 | WRAPPER_EXTENSION = app;
270 | };
271 | name = Release;
272 | };
273 | /* End XCBuildConfiguration section */
274 |
275 | /* Begin XCConfigurationList section */
276 | 3098B2C21504515200F743BD /* Build configuration list for PBXProject "DRKonamiCode" */ = {
277 | isa = XCConfigurationList;
278 | buildConfigurations = (
279 | 3098B2E41504515300F743BD /* Debug */,
280 | 3098B2E51504515300F743BD /* Release */,
281 | );
282 | defaultConfigurationIsVisible = 0;
283 | defaultConfigurationName = Release;
284 | };
285 | 3098B2E61504515300F743BD /* Build configuration list for PBXNativeTarget "DRKonamiCode" */ = {
286 | isa = XCConfigurationList;
287 | buildConfigurations = (
288 | 3098B2E71504515300F743BD /* Debug */,
289 | 3098B2E81504515300F743BD /* Release */,
290 | );
291 | defaultConfigurationIsVisible = 0;
292 | defaultConfigurationName = Release;
293 | };
294 | /* End XCConfigurationList section */
295 | };
296 | rootObject = 3098B2BF1504515200F743BD /* Project object */;
297 | }
298 |
--------------------------------------------------------------------------------
/DRKonamiCode.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objectiveSee/DRKonamiCode/98a00b3b4b57601e0b0cfb9bb783159297cb83f2/Default-568h@2x.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | DRKonamiCode
2 | ============
3 |
4 |
5 |
6 |
7 | [Konami code](http://en.wikipedia.org/wiki/Konami_Code) gesture recognizer for iOS. The recognizer is a subclass of UIGestureRecognizer has can be used in the same way as any other recognizer. Swipe gestures correspond to the Up/Down/Left/Right parts of the sequence. An optional feature allows you to implement a custom B+A+Enter action.
8 |
9 | Contact me via Github issue or comment.
10 |
11 | ### Installation with CocoaPods
12 |
13 | [CocoaPods](http://cocoapods.org) is a dependency manager for Objective-C, which automates and simplifies the process of using 3rd-party libraries like AFNetworking in your projects. See the ["Getting Started" guide for more information](https://github.com/AFNetworking/AFNetworking/wiki/Getting-Started-with-AFNetworking).
14 |
15 | ```ruby
16 | pod "DRKonamiCode", "~> 1.1.0"
17 | ```
18 |
19 | If you don't use CocoaPods, then add DRKonamiGestureRecognizer.h and DRKonamiGestureRecognizer.m to your project.
20 |
21 |
22 | ### Using DRKonamiCode in your App ###
23 |
24 | Add the gesture recognizer to a UIView using the following code.
25 |
26 | ```objective-c
27 |
28 | #import "DRKonamiGestureRecognizer.h"
29 |
30 | - (void)addKonami
31 | {
32 | konami = [[DRKonamiGestureRecognizer alloc] initWithTarget:self action:@selector(_konamiHappened:)];
33 | [self.view addGestureRecognizer:konami];
34 | }
35 |
36 | - (void)_konamiHappened:(DRKonamiGestureRecognizer *)recognizer
37 | {
38 | // NOTE: Test the state to make sure the recognizer is finished.
39 | if ( [recognizer konamiState] == DRKonamiGestureStateRecognized ) {
40 | NSLog(@"Konami Code Recognized!");
41 | }
42 | }
43 |
44 | ```
45 |
46 | ### B+A+Unlock (OPTIONAL) ###
47 |
48 | Optionally, you can require the user to enter B+A+Enter in order for the gesture to be recognized. You will need to implement the DRKonamiGestureProtocol which has required methods that let your UI respond to the request for the A, B, or Enter action. If you are not using the B+A+Enter feature than you do not need to set the recognizer's delegate.
49 |
50 | ```objective-c
51 |
52 | - (void)addKonami
53 | {
54 | konami = [[DRKonamiGestureRecognizer alloc] initWithTarget:self action:@selector(_konamiHappened:)];
55 | [konami setKonamiDelegate:self];
56 | [konami setRequiresABEnterToUnlock:YES];
57 | [self.view addGestureRecognizer:konami];
58 | }
59 |
60 | - (void)_konamiHappened:(DRKonamiGestureRecognizer *)recognizer
61 | {
62 | NSLog(@"Konami Code Recognized!");
63 | }
64 |
65 | #pragma mark -
66 | #pragma mark DRKonamiGestureProtocol
67 |
68 | - (void)DRKonamiGestureRecognizerNeedsABEnterSequence:(DRKonamiGestureRecognizer*)gesture
69 | {
70 | /// your code here.
71 | }
72 |
73 | - (void)DRKonamiGestureRecognizer:(DRKonamiGestureRecognizer*)gesture didFinishNeedingABEnterSequenceWithError:(BOOL)error
74 | {
75 | /// your code here.
76 | }
77 | ```
78 |
79 | ### DRKonamiGestureProtocol ###
80 |
81 | The DRKonamiGestureProtocol protocol is required only if you are using the B+A+Enter feature. The recognizer will inform its delegate when the B+A+Enter sequence is needed and when the sequence is no longer needed (due to gesture failing or succeeding).
82 |
83 | ### Tips ###
84 |
85 | * TIP 1: NSLog() statements are disabled inside of DRKonamiGestureRecognizer.m. You can enable them at the top of the file and then the console will print the konami state.
86 | * TIP 2: Practice actually doing the konami gesture with the sample app. Some people have a hard time figuring out how to actually get it going.
87 |
--------------------------------------------------------------------------------
/Resources/DRViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1280
5 | 14A361c
6 | 6245
7 | 1339
8 | 755.00
9 |
13 |
14 | IBProxyObject
15 | IBUIButton
16 | IBUIImageView
17 | IBUILabel
18 | IBUISwitch
19 | IBUIView
20 |
21 |
22 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
23 |
24 |
28 |
29 |
33 |
37 |
315 |
316 |
317 |
318 |
319 |
320 | view
321 |
322 |
323 |
324 | 7
325 |
326 |
327 |
328 | NESControllerView
329 |
330 |
331 |
332 | 24
333 |
334 |
335 |
336 | statusLabel
337 |
338 |
339 |
340 | 26
341 |
342 |
343 |
344 | guideLabel
345 |
346 |
347 |
348 | 30
349 |
350 |
351 |
352 | aButtonWasPressed:
353 |
354 |
355 | 7
356 |
357 | 13
358 |
359 |
360 |
361 | bButtonWasPressed:
362 |
363 |
364 | 7
365 |
366 | 14
367 |
368 |
369 |
370 | enterButtonWasPressed:
371 |
372 |
373 | 7
374 |
375 | 15
376 |
377 |
378 |
379 | nesControllerWasPressed:
380 |
381 |
382 | 7
383 |
384 | 19
385 |
386 |
387 |
388 | advancedModeSwitchValueChanged:
389 |
390 |
391 | 13
392 |
393 | 22
394 |
395 |
396 |
397 |
398 |
399 | 0
400 |
401 |
402 |
403 |
404 |
405 | -1
406 |
407 |
408 | File's Owner
409 |
410 |
411 | -2
412 |
413 |
414 |
415 |
416 | 6
417 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 | 11
430 |
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
439 |
440 |
441 | 8
442 |
443 |
444 |
445 |
446 | 10
447 |
448 |
449 |
450 |
451 | 9
452 |
453 |
454 |
455 |
456 | 16
457 |
458 |
459 |
460 |
461 | 17
462 |
463 |
464 |
465 |
466 | 20
467 |
468 |
469 |
470 |
471 | 21
472 |
473 |
474 |
475 |
476 | 25
477 |
478 |
479 |
480 |
481 | 27
482 |
483 |
484 |
485 |
486 | 29
487 |
488 |
489 |
490 |
491 |
492 |
493 | DRViewController
494 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
495 | UIResponder
496 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
497 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
498 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
499 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
500 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
501 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
502 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
503 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
504 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
505 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
506 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
507 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
508 | com.apple.InterfaceBuilder.IBCocoaTouchPlugin
509 |
510 |
511 |
512 |
513 |
514 | 30
515 |
516 |
517 |
518 |
519 | DRViewController
520 | UIViewController
521 |
522 | id
523 | id
524 | id
525 | id
526 | id
527 |
528 |
529 |
530 | aButtonWasPressed:
531 | id
532 |
533 |
534 | advancedModeSwitchValueChanged:
535 | id
536 |
537 |
538 | bButtonWasPressed:
539 | id
540 |
541 |
542 | enterButtonWasPressed:
543 | id
544 |
545 |
546 | nesControllerWasPressed:
547 | id
548 |
549 |
550 |
551 | UIView
552 | UILabel
553 | UILabel
554 |
555 |
556 |
557 | NESControllerView
558 | UIView
559 |
560 |
561 | guideLabel
562 | UILabel
563 |
564 |
565 | statusLabel
566 | UILabel
567 |
568 |
569 |
570 | IBProjectSource
571 | ../Sources/DRViewController.h
572 |
573 |
574 |
575 | DRViewController
576 |
577 | id
578 | id
579 | id
580 | id
581 | id
582 |
583 |
584 |
585 | aButtonWasPressed:
586 | id
587 |
588 |
589 | advancedModeSwitchValueChanged:
590 | id
591 |
592 |
593 | bButtonWasPressed:
594 | id
595 |
596 |
597 | enterButtonWasPressed:
598 | id
599 |
600 |
601 | nesControllerWasPressed:
602 | id
603 |
604 |
605 |
606 | IBProjectSource
607 | ../Sources/DRViewController.m
608 |
609 |
610 |
611 |
612 |
613 | UIButton
614 | UIControl
615 |
616 | IBFrameworkSource
617 | UIKit.framework/Headers/UIButton.h
618 |
619 |
620 |
621 | UIControl
622 | UIView
623 |
624 | IBFrameworkSource
625 | UIKit.framework/Headers/UIControl.h
626 |
627 |
628 |
629 | UIGestureRecognizer
630 | NSObject
631 |
632 | IBFrameworkSource
633 | UIKit.framework/Headers/UIGestureRecognizer.h
634 |
635 |
636 |
637 | UIImageView
638 | UIView
639 |
640 | IBFrameworkSource
641 | UIKit.framework/Headers/UIImageView.h
642 |
643 |
644 |
645 | UILabel
646 | UIView
647 |
648 | IBFrameworkSource
649 | UIKit.framework/Headers/UILabel.h
650 |
651 |
652 |
653 | UIResponder
654 | NSObject
655 |
656 | IBFrameworkSource
657 | UIKit.framework/Headers/UIResponder.h
658 |
659 |
660 |
661 | UISearchBar
662 | UIView
663 |
664 | IBFrameworkSource
665 | UIKit.framework/Headers/UISearchBar.h
666 |
667 |
668 |
669 | UISearchDisplayController
670 | NSObject
671 |
672 | IBFrameworkSource
673 | UIKit.framework/Headers/UISearchDisplayController.h
674 |
675 |
676 |
677 | UISwitch
678 | UIControl
679 |
680 | IBFrameworkSource
681 | UIKit.framework/Headers/UISwitch.h
682 |
683 |
684 |
685 | UIView
686 | UIResponder
687 |
688 | IBFrameworkSource
689 | UIKit.framework/Headers/UIView.h
690 |
691 |
692 |
693 | UIViewController
694 | UIResponder
695 |
696 | IBFrameworkSource
697 | UIKit.framework/Headers/UIViewController.h
698 |
699 |
700 |
701 |
702 | 0
703 | IBCocoaTouchFramework
704 | NO
705 |
706 | com.apple.InterfaceBuilder.CocoaTouchPlugin.iPhoneOS
707 |
708 |
709 |
710 | com.apple.InterfaceBuilder.CocoaTouchPlugin.InterfaceBuilder3
711 |
712 |
713 | YES
714 | 3
715 |
716 | nes.png
717 | {270, 138}
718 |
719 |
720 |
721 |
--------------------------------------------------------------------------------
/Resources/nes.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objectiveSee/DRKonamiCode/98a00b3b4b57601e0b0cfb9bb783159297cb83f2/Resources/nes.png
--------------------------------------------------------------------------------
/Resources/nes@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/objectiveSee/DRKonamiCode/98a00b3b4b57601e0b0cfb9bb783159297cb83f2/Resources/nes@2x.png
--------------------------------------------------------------------------------
/Sources/DRAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // DRAppDelegate.h
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | @class DRViewController;
9 |
10 | @interface DRAppDelegate : UIResponder
11 |
12 | @property (strong, nonatomic) UIWindow *window;
13 |
14 | @property (strong, nonatomic) DRViewController *viewController;
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/Sources/DRAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // DRAppDelegate.m
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | #import "DRAppDelegate.h"
9 | #import "DRViewController.h"
10 |
11 | @implementation DRAppDelegate
12 |
13 | @synthesize window = _window;
14 | @synthesize viewController = _viewController;
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
18 | {
19 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
20 |
21 | self.viewController = [[DRViewController alloc] initWithNibName:@"DRViewController" bundle:nil];
22 | self.window.rootViewController = self.viewController;
23 | [self.window makeKeyAndVisible];
24 | return YES;
25 | }
26 |
27 | - (void)applicationWillResignActive:(UIApplication *)application
28 | {
29 | /*
30 | Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
31 | Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
32 | */
33 | }
34 |
35 | - (void)applicationDidEnterBackground:(UIApplication *)application
36 | {
37 | /*
38 | Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
39 | If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
40 | */
41 | }
42 |
43 | - (void)applicationWillEnterForeground:(UIApplication *)application
44 | {
45 | /*
46 | Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
47 | */
48 | }
49 |
50 | - (void)applicationDidBecomeActive:(UIApplication *)application
51 | {
52 | /*
53 | Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
54 | */
55 | }
56 |
57 | - (void)applicationWillTerminate:(UIApplication *)application
58 | {
59 | /*
60 | Called when the application is about to terminate.
61 | Save data if appropriate.
62 | See also applicationDidEnterBackground:.
63 | */
64 | }
65 |
66 | @end
67 |
--------------------------------------------------------------------------------
/Sources/DRKonamiGestureRecognizer.h:
--------------------------------------------------------------------------------
1 | //
2 | // DRKonamiGestureRecognizer.h
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | /**
9 | The delegate (DRKonamiGestureProtocol) is optional! If you are using the delegate, however, then you must implement all of the required methods. The delegate is only needed if you wish to include A+B+Enter as the final steps of the Konami sequence.
10 | The Konami Gesture protocol implements communication between the gesture recognizer and the delegate when the A+B+Enter action is required to complete the gesture. If the A+B+Enter sequence is not used then none of the protocol methods are required.
11 | */
12 | @class DRKonamiGestureRecognizer;
13 | @protocol DRKonamiGestureProtocol
14 | @required
15 |
16 | /**
17 | Informs the delegate that the gesture recognizer has reached the point where the B+A+Enter sequence is requied to complete the gesture. This is when your code would add UI on the screen to represent the B+A+Enter options.
18 | */
19 | - (void)DRKonamiGestureRecognizerNeedsABEnterSequence:(DRKonamiGestureRecognizer*)gesture;
20 |
21 | /**
22 | Informs the delegate that the gesture recognizer no longers requires the B+A+Enter sequence. This will happen either because the sequence has succeeded or failed. This is where you can remove the B+A+Enter options from the screen.
23 | */
24 | - (void)DRKonamiGestureRecognizer:(DRKonamiGestureRecognizer*)gesture didFinishNeedingABEnterSequenceWithError:(BOOL)error;
25 |
26 | @end
27 |
28 | //////////////////////////////////////////////////////////////////////
29 |
30 | /**
31 | Konami code states. Mostly used internally, but you will need to use 'DRKonamiGestureStateRecognized'.
32 | */
33 | typedef NS_ENUM(NSInteger, DRKonamiGestureState)
34 | {
35 | DRKonamiGestureStateNone = 0,
36 | DRKonamiGestureStateBegan,
37 | DRKonamiGestureStateUp1,
38 | DRKonamiGestureStateUp2,
39 | DRKonamiGestureStateDown1,
40 | DRKonamiGestureStateDown2,
41 | DRKonamiGestureStateLeft1,
42 | DRKonamiGestureStateRight1,
43 | DRKonamiGestureStateLeft2,
44 | DRKonamiGestureStateRight2, // 9
45 | DRKonamiGestureStateB, // 10
46 | DRKonamiGestureStateA, // 11
47 | DRKonamiGestureStateRecognized // 12
48 | };
49 |
50 | /**
51 | @class DRKonamiGestureRecognizer
52 | @brief A custom UIGestureRecognizer which recognized the Konami Code.
53 | @todo Reset the state of self.konamiState on gesture fails due to timeout between swipes in sequence.
54 | */
55 | @interface DRKonamiGestureRecognizer : UIGestureRecognizer
56 |
57 | /**
58 | Indicates whether the konami sequence requires B+A+Enter to finish the sequence. If NO then the sequence is finished successfully after the final RIGHT gesture. Default value is NO.
59 | */
60 | @property (nonatomic, readwrite) BOOL requiresABEnterToUnlock;
61 |
62 | /**
63 | The current state of the konami gesture.
64 | */
65 | @property (nonatomic, readonly) DRKonamiGestureState konamiState;
66 |
67 | /**
68 | The delegate of the gesture. If the delegate is set then the delegate must conform to DRKonamiGestureRecognizer. The delegate does not need to be used if requiresABEnterToUnlock is set to NO.
69 | */
70 | @property (nonatomic, weak, readwrite) id konamiDelegate;
71 |
72 | /**
73 | Methods used by the delegate (if delegate exists) to specify when the A, B, and Enter actions occur.
74 | */
75 | - (void) AButtonAction;
76 | - (void) BButtonAction;
77 | - (void) enterButtonAction;
78 |
79 | /**
80 | Cancels the gesture recognizer from waiting on the A+B+Enter sequence. Also sets the gesture recognizer state to failed.
81 | Used by the delegate (if delegate exists).
82 | */
83 | - (void) cancelSequence;
84 |
85 | @end
86 |
--------------------------------------------------------------------------------
/Sources/DRKonamiGestureRecognizer.m:
--------------------------------------------------------------------------------
1 | //
2 | // DRKonamiGestureRecognizer.m
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | #import "DRKonamiGestureRecognizer.h"
9 | #import // required for subclassing UIGestureRecognizer
10 |
11 | ///////////////////////////////////////////////////////////////
12 |
13 | // Line below disables logging if uncommented
14 | #define NSLog(...);
15 |
16 | // Constant Declarations
17 | static const CGFloat kKonamiSwipeDistanceTolerance = 50.0f; // Max tolerence in direction perpendicular to expected swipe state
18 | static const CGFloat kKonamiSwipeDistanceMin = 50.0f; // Min distance to detect a swipe gesture
19 | static const NSTimeInterval kKonamiGestureMaxTimeBetweenGestures = 1.0f; // The max time allowed between swipe gestures.
20 | static const NSTimeInterval kKonamiGestureMaxTimeDuringGesture = 1.0f; // The max time allowed during swipe gestures.
21 |
22 | ///////////////////////////////////////////////////////////////
23 |
24 | // Some helper functions
25 | void getCheckValuesAfterTouchesEnded(DRKonamiGestureState konamiState, BOOL* pCheckXLeft, BOOL* pCheckXRight, BOOL* pCheckYUp, BOOL* pCheckYDown);
26 |
27 | void getCheckValuesDuringDrag(DRKonamiGestureState konamiState, BOOL* pCheckX, BOOL* pCheckY);
28 |
29 |
30 | ///////////////////////////////////////////////////////////////
31 |
32 | @interface DRKonamiGestureRecognizer ()
33 | @property (nonatomic, readwrite) DRKonamiGestureState konamiState;
34 | @property (nonatomic, strong, readwrite) NSDate* lastGestureDate;
35 | @property (nonatomic, readwrite) CGPoint lastGestureStartPoint;
36 | @end
37 |
38 | ///////////////////////////////////////////////////////////////
39 |
40 | @implementation DRKonamiGestureRecognizer
41 |
42 | #pragma mark -
43 | #pragma mark Lifecycle
44 |
45 | - (id) initWithTarget:(id)target action:(SEL)action
46 | {
47 | self = [super initWithTarget:target action:action];
48 | if ( self != nil )
49 | {
50 | self.konamiState = DRKonamiGestureStateNone;
51 | self.lastGestureDate = [NSDate new];
52 | self.lastGestureStartPoint = CGPointZero;
53 | self.requiresABEnterToUnlock = NO;
54 | self.cancelsTouchesInView = NO;
55 | }
56 | return self;
57 | }
58 |
59 | #pragma mark -
60 | #pragma mark Touches
61 |
62 | - (void)reset
63 | {
64 | self.konamiState = DRKonamiGestureStateNone;
65 | }
66 |
67 | - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer
68 | {
69 | // basically we don't prevent any other recognizer from being recoginzed.
70 | // TODO: Explore the idea of returning YES if self.konamiState != DRKonamiGestureStateNone.
71 | return NO;
72 | }
73 |
74 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
75 | {
76 | // Fail when more than 1 finger detected.
77 | if ([[event touchesForGestureRecognizer:self] count] > 1)
78 | {
79 | [self setState:UIGestureRecognizerStateFailed];
80 | }
81 | else
82 | {
83 | if ( self.state == UIGestureRecognizerStateChanged )
84 | {
85 | // If an existing touch already exists (ie. state is UIGestureRecognizerStateChanged) then see if the pause between gestures took too long. However, if the konami code state has reached DRKonamiGestureStateRight2 then the timeout between gestures no longer applies. DRKonamiGestureRecognizer is either waiting for A+B+Enter or a logic error has occured.
86 | if ( self.konamiState < DRKonamiGestureStateRight2 )
87 | {
88 | // Check whether the time between now and the previous gesture was too long.
89 | NSDate* now = [NSDate date];
90 | if ( [now timeIntervalSinceDate:self.lastGestureDate] > kKonamiGestureMaxTimeBetweenGestures )
91 | {
92 | NSLog(@"Waited too long between gestures. Re-starting the konami sequence.");
93 | self.konamiState = DRKonamiGestureStateBegan;
94 | }
95 | }
96 | }
97 | else if ( self.state == UIGestureRecognizerStatePossible ) // default beginning state.
98 | {
99 | NSLog(@"Starting the konami sequence");
100 | [self setState:UIGestureRecognizerStateBegan];
101 | self.konamiState = DRKonamiGestureStateBegan;
102 | }
103 | else
104 | {
105 | // unexpected case. Handle with failure and return.
106 | NSLog(@"Invalid UIGestureRecognizerState: %d", self.state);
107 | [self setState:UIGestureRecognizerStateFailed];
108 | return;
109 | }
110 |
111 | self.lastGestureDate = [NSDate new];
112 | UITouch *touch = [touches anyObject];
113 | self.lastGestureStartPoint = [touch locationInView:self.view];
114 | }
115 | }
116 |
117 | /**
118 | Determine whether the gesture is still happening during a swipe event.
119 | */
120 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
121 | {
122 | if ( self.konamiState >= DRKonamiGestureStateRight2 )
123 | {
124 | // in this case the touch-based part of the sequence is done. We either have recognized Konami or are waiting on the B+A inputs.
125 | return;
126 | }
127 |
128 | // Check whether the gesture is being completed fast enough
129 | NSDate* now = [NSDate date];
130 | if ( [now timeIntervalSinceDate:self.lastGestureDate] > kKonamiGestureMaxTimeDuringGesture )
131 | {
132 | NSLog(@"Failed to swipe quick enough!");
133 | [self setState:UIGestureRecognizerStateFailed];
134 | return;
135 | }
136 |
137 | // Check if user has dragged finger too far away from the gesture axis
138 | BOOL checkY = NO;
139 | BOOL checkX = NO;
140 | getCheckValuesDuringDrag(self.konamiState + 1, &checkX, &checkY); // use the next konami state since we are detecting that one.
141 |
142 | // TODO add timeout on swipe gestures
143 |
144 | // Check if the X and/or Y distance of the swipe was so far that the gesture if considered failed
145 | if (( checkX == YES) || (checkY == YES))
146 | {
147 | // Only 1 touch object is possible.
148 | BOOL cancelGesture = NO;
149 | UITouch *touch = [touches anyObject];
150 | UIView *view = [self view];
151 | CGPoint currentTouchPoint = [touch locationInView:view];
152 |
153 | if ( checkX == YES )
154 | {
155 | CGFloat xdifference = fabs( currentTouchPoint.x - self.lastGestureStartPoint.x );
156 | if ( xdifference > kKonamiSwipeDistanceTolerance )
157 | {
158 | // finger moved too far (in the X direction) from the expected vertical swipe.
159 | NSLog(@"Cancelling gesture. Xdifference = %2.2f", xdifference);
160 | cancelGesture = YES;
161 | }
162 | }
163 | else
164 | {
165 | // CheckY == YES
166 | CGFloat ydifference = fabs( currentTouchPoint.y - self.lastGestureStartPoint.y );
167 | if ( ydifference > kKonamiSwipeDistanceTolerance )
168 | {
169 | // finger moved too far (in the Y direction) from the expected horizontal swipe.
170 | NSLog(@"Cancelling gesture. Ydifference = %2.2f", ydifference);
171 | cancelGesture = YES;
172 | }
173 | }
174 | if ( cancelGesture == YES )
175 | {
176 | [self setState:UIGestureRecognizerStateFailed]; // Use cancelled or failed state?
177 | }
178 | }
179 | }
180 |
181 | /**
182 | At the end of each swipe event determine if the gesture failed or not.
183 | */
184 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
185 | {
186 | if ( self.konamiState >= DRKonamiGestureStateRight2 )
187 | {
188 | // if in DRKonamiGestureStateRight2 or higher than B+A sequence is being waited upon. We no longer are concerned with touch gestures.
189 | return;
190 | }
191 |
192 | // Perform final check to make sure a tap was not misinterpreted.
193 | if ( self.state != UIGestureRecognizerStateChanged ) {
194 |
195 | NSLog(@"Gesture failed. touchesEnded state is not UIGestureRecognizerStateChanged");
196 | [self setState:UIGestureRecognizerStateFailed];
197 | return;
198 | }
199 |
200 | // Check whether the correct gesture happened
201 | BOOL checkYUp = NO;
202 | BOOL checkYDown = NO;
203 | BOOL checkXLeft = NO;
204 | BOOL checkXRight = NO;
205 | getCheckValuesAfterTouchesEnded(self.konamiState + 1, &checkXLeft, &checkXRight, &checkYUp, &checkYDown);
206 | if ( checkXLeft || checkXRight || checkYDown || checkYUp )
207 | {
208 | // Only 1 touch object is possible.
209 | BOOL cancelGesture = NO;
210 | UITouch *touch = [touches anyObject];
211 | UIView *view = [self view];
212 | CGPoint currentTouchPoint = [touch locationInView:view];
213 | if ( checkXLeft || checkXRight )
214 | {
215 | CGFloat xdifference = currentTouchPoint.x - self.lastGestureStartPoint.x;
216 | if ( (checkXLeft == YES) && (xdifference < -1 * kKonamiSwipeDistanceMin) )
217 | {
218 | NSLog(@"Konami X-Left passed!");
219 | }
220 | else if ( (checkXRight == YES) && (xdifference > kKonamiSwipeDistanceMin) )
221 | {
222 | NSLog(@"Konami X-Right passed!");
223 | }
224 | else
225 | {
226 | NSLog(@"Konami X failed!. xdifference = %2.2f", xdifference);
227 | cancelGesture = YES;
228 | }
229 | }
230 | else
231 | {
232 | // checkYUP or checkYDown
233 | CGFloat ydifference = currentTouchPoint.y - self.lastGestureStartPoint.y;
234 | if ( (checkYUp == YES) && (ydifference < -1 * kKonamiSwipeDistanceMin) )
235 | {
236 | NSLog(@"Konami Y-Up passed!");
237 | }
238 | else if ( (checkYDown == YES) && (ydifference > kKonamiSwipeDistanceMin) )
239 | {
240 | NSLog(@"Konami Y-Down passed!");
241 | }
242 | else
243 | {
244 | NSLog(@"Konami Y failed!. ydifference = %2.2f", ydifference);
245 | cancelGesture = YES;
246 | }
247 | }
248 | if ( cancelGesture == YES )
249 | {
250 | NSLog(@"Konami Failed on state %d", self.konamiState);
251 | [self setState:UIGestureRecognizerStateFailed];
252 | return;
253 | }
254 | }
255 |
256 | self.konamiState++;
257 | self.lastGestureDate = [NSDate new];
258 |
259 | [self setState:UIGestureRecognizerStateChanged];
260 |
261 | if ( self.konamiState >= DRKonamiGestureStateRight2 )
262 | {
263 | // if we need B+A+Enter to finish, then do so. Else, gesture is success.
264 | if ( self.requiresABEnterToUnlock == YES )
265 | {
266 | if ( self.konamiDelegate == nil )
267 | {
268 | NSLog(@"Warning: Konami Gesture delegate was not set.");
269 | [self setState:UIGestureRecognizerStateFailed];
270 | return;
271 | }
272 | [self.konamiDelegate DRKonamiGestureRecognizerNeedsABEnterSequence:self];
273 | }
274 | else
275 | {
276 | // Gesture complete!
277 | NSLog(@"Konami Gesture recognized!");
278 | self.konamiState = DRKonamiGestureStateRecognized;
279 | [self setState:UIGestureRecognizerStateRecognized];
280 | }
281 | }
282 | }
283 |
284 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
285 | {
286 | [self setState:UIGestureRecognizerStateFailed];
287 | }
288 |
289 | #pragma mark -
290 | #pragma mark Button actions
291 |
292 | - (void) AButtonAction
293 | {
294 | if ( self.konamiState == DRKonamiGestureStateB )
295 | {
296 | self.konamiState ++;
297 | [self setState:UIGestureRecognizerStateChanged];
298 | NSLog(@"A-Button was pressed. Konami state is now %d", self.konamiState);
299 | }
300 | else
301 | {
302 | NSLog(@"Konami gesture failed due to pressing A-Button at incorrect time. State was %d", self.konamiState);
303 | [self setState:UIGestureRecognizerStateFailed];
304 | [self.konamiDelegate DRKonamiGestureRecognizer:self didFinishNeedingABEnterSequenceWithError:YES];
305 | }
306 | }
307 |
308 | - (void) BButtonAction
309 | {
310 | if ( self.konamiState == DRKonamiGestureStateRight2 )
311 | {
312 | self.konamiState ++;
313 | [self setState:UIGestureRecognizerStateChanged];
314 | }
315 | else
316 | {
317 | NSLog(@"Konami gesture failed due to pressing B-Button at incorrect time. State was %d", self.konamiState);
318 | [self setState:UIGestureRecognizerStateFailed];
319 | [self.konamiDelegate DRKonamiGestureRecognizer:self didFinishNeedingABEnterSequenceWithError:YES];
320 | }
321 | }
322 |
323 | - (void) enterButtonAction
324 | {
325 | if ( self.konamiState == DRKonamiGestureStateA )
326 | {
327 | self.konamiState ++;
328 | NSLog(@"Enter-Button was pressed. Konami state is now %d. Gesture complete!", self.konamiState);
329 | [self setState:UIGestureRecognizerStateRecognized];
330 | [self.konamiDelegate DRKonamiGestureRecognizer:self didFinishNeedingABEnterSequenceWithError:NO];
331 | }
332 | else
333 | {
334 | NSLog(@"Konami gesture failed due to pressing Enter-Button at incorrect time. State was %d", self.konamiState);
335 | [self setState:UIGestureRecognizerStateFailed];
336 | [self.konamiDelegate DRKonamiGestureRecognizer:self didFinishNeedingABEnterSequenceWithError:YES];
337 | }
338 | }
339 |
340 | - (void) cancelSequence
341 | {
342 | NSLog(@"Konami gesture failed due to calling cancelSequence");
343 | [self setState:UIGestureRecognizerStateFailed];
344 | [self.konamiDelegate DRKonamiGestureRecognizer:self didFinishNeedingABEnterSequenceWithError:YES];
345 | }
346 |
347 | @end
348 |
349 | #pragma mark -
350 | #pragma mark C Helper Functiona
351 |
352 | /**
353 | Determines whether the gesture recognizer needs to check the X and Y touch coordinates depending on the gesture state.
354 | */
355 | void getCheckValuesAfterTouchesEnded(DRKonamiGestureState konamiState, BOOL* pCheckXLeft, BOOL* pCheckXRight, BOOL* pCheckYUp, BOOL* pCheckYDown)
356 | {
357 | switch (konamiState)
358 | {
359 | case DRKonamiGestureStateBegan:
360 | case DRKonamiGestureStateUp1:
361 | case DRKonamiGestureStateUp2:
362 | *pCheckYUp = YES;
363 | break;
364 | case DRKonamiGestureStateDown1:
365 | case DRKonamiGestureStateDown2:
366 | *pCheckYDown = YES;
367 | break;
368 |
369 | case DRKonamiGestureStateLeft1:
370 | case DRKonamiGestureStateLeft2:
371 | *pCheckXLeft = YES;
372 | break;
373 |
374 | case DRKonamiGestureStateRight1:
375 | case DRKonamiGestureStateRight2:
376 | *pCheckXRight = YES;
377 | break;
378 |
379 | case DRKonamiGestureStateB:
380 | case DRKonamiGestureStateA:
381 | break;
382 |
383 | case DRKonamiGestureStateRecognized:
384 | case DRKonamiGestureStateNone:
385 | default:
386 | NSLog(@"unexpected gesture state %d (in %s)", konamiState, __FUNCTION__);
387 | break;
388 |
389 | }
390 | }
391 |
392 | /**
393 | Determines whether the gesture recognizer needs to check the X and Y touch coordinates depending on the gesture state.
394 | */
395 | void getCheckValuesDuringDrag(DRKonamiGestureState konamiState, BOOL* pCheckX, BOOL* pCheckY)
396 | {
397 | switch (konamiState)
398 | {
399 | case DRKonamiGestureStateBegan:
400 | case DRKonamiGestureStateUp1:
401 | case DRKonamiGestureStateUp2:
402 | case DRKonamiGestureStateDown1:
403 | case DRKonamiGestureStateDown2:
404 | *pCheckX = YES;
405 | break;
406 |
407 | case DRKonamiGestureStateLeft1:
408 | case DRKonamiGestureStateRight1:
409 | case DRKonamiGestureStateLeft2:
410 | case DRKonamiGestureStateRight2:
411 | *pCheckY = YES;
412 | break;
413 |
414 | case DRKonamiGestureStateB:
415 | case DRKonamiGestureStateA:
416 | break;
417 |
418 | case DRKonamiGestureStateRecognized:
419 | case DRKonamiGestureStateNone:
420 | default:
421 | NSLog(@"unexpected gesture state %d (in %s)", konamiState, __FUNCTION__);
422 | break;
423 | }
424 | }
425 |
426 |
--------------------------------------------------------------------------------
/Sources/DRViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // DRViewController.h
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | #import "DRKonamiGestureRecognizer.h"
9 |
10 | @interface DRViewController : UIViewController
11 | {
12 | @protected
13 | DRKonamiGestureRecognizer* _konamiGestureRecognizer;
14 |
15 | @protected
16 | UIView* __weak _NESControllerView;
17 | UILabel *__weak _statusLabel;
18 | }
19 |
20 | @property (weak, nonatomic, readonly) IBOutlet UIView *NESControllerView;
21 | @property (weak, nonatomic, readonly) IBOutlet UILabel *statusLabel;
22 | @property (weak, nonatomic, readonly) IBOutlet UILabel *guideLabel;
23 | @property (nonatomic, readonly) DRKonamiGestureRecognizer* konamiGestureRecognizer;
24 |
25 | - (IBAction)aButtonWasPressed:(id)sender;
26 |
27 | - (IBAction)bButtonWasPressed:(id)sender;
28 |
29 | - (IBAction)enterButtonWasPressed:(id)sender;
30 |
31 | - (IBAction)nesControllerWasPressed:(id)sender;
32 |
33 | - (IBAction)advancedModeSwitchValueChanged:(id)sender;
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/Sources/DRViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // DRViewController.m
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | #import "DRViewController.h"
9 |
10 | @interface DRViewController()
11 | - (void)_konamiGestureRecognized:(DRKonamiGestureRecognizer*)gesture;
12 | @property (nonatomic) UILabel *nesLabel;
13 | @end
14 |
15 | #pragma mark -
16 |
17 | @implementation DRViewController
18 | @synthesize NESControllerView = _NESControllerView;
19 | @synthesize konamiGestureRecognizer = _konamiGestureRecognizer;
20 | @synthesize statusLabel = _statusLabel;
21 |
22 |
23 | static NSString * konamiProgressString = @"↑↑↓↓←→←→BA";
24 |
25 |
26 | #pragma mark -
27 | #pragma mark UIViewController
28 |
29 | - (void)viewDidLoad
30 | {
31 | [super viewDidLoad];
32 |
33 | _konamiGestureRecognizer = [[DRKonamiGestureRecognizer alloc] initWithTarget:self action:@selector(_konamiGestureRecognized:)];
34 | [self.konamiGestureRecognizer setKonamiDelegate:self];
35 | [self.konamiGestureRecognizer setRequiresABEnterToUnlock:YES];
36 | [self.view addGestureRecognizer:self.konamiGestureRecognizer];
37 |
38 | if ( !self.nesLabel )
39 | {
40 | UILabel *nesLabel = [[UILabel alloc] initWithFrame:CGRectMake(10, CGRectGetMaxY(self.NESControllerView.frame), CGRectGetWidth(self.view.bounds)-20, 66)];
41 | nesLabel.text = @"Hit B, then A, then the enter button (right button in middle of NES controller) to finish Konami sequence.";
42 | nesLabel.numberOfLines = 0;
43 | [nesLabel setFont:[UIFont systemFontOfSize:15]];
44 | nesLabel.textAlignment = NSTextAlignmentCenter;
45 | [self.view addSubview:nesLabel];
46 | nesLabel.autoresizingMask = UIViewAutoresizingFlexibleBottomMargin;
47 | self.nesLabel = nesLabel;
48 | }
49 |
50 | // initially hidden. Shown when user has completed the Konami sequence up to the A+B+Enter part.
51 | self.NESControllerView.alpha = 0;
52 | self.NESControllerView.transform = CGAffineTransformMakeScale(.8, .8);
53 | self.nesLabel.alpha = 0;
54 |
55 | self.statusLabel.text = nil;
56 | }
57 |
58 | - (void)viewDidUnload
59 | {
60 | [self.view removeGestureRecognizer:self.konamiGestureRecognizer];
61 | _konamiGestureRecognizer = nil;
62 | [super viewDidUnload];
63 | }
64 |
65 | #pragma mark -
66 | #pragma mark DRKonamiGestureProtocol
67 |
68 | - (void)DRKonamiGestureRecognizerNeedsABEnterSequence:(DRKonamiGestureRecognizer*)gesture
69 | {
70 | [self setControllerHidden:NO animated:YES];
71 | }
72 |
73 | - (void)DRKonamiGestureRecognizer:(DRKonamiGestureRecognizer*)gesture didFinishNeedingABEnterSequenceWithError:(BOOL)error
74 | {
75 | [self setControllerHidden:YES animated:YES];
76 | }
77 |
78 | - (void)setControllerHidden:(BOOL)hidden animated:(BOOL)animated {
79 |
80 | [self OSSafeAnimateWithDuration:animated?.7:0 delay:0 usingSpringWithDamping:.5 initialSpringVelocity:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
81 |
82 | self.NESControllerView.alpha = hidden ? 0:1;
83 | self.NESControllerView.transform = hidden ? CGAffineTransformMakeScale(.7, .7) : CGAffineTransformIdentity;
84 | self.nesLabel.alpha = hidden ? 0:1;
85 |
86 | } completion:nil];
87 | }
88 |
89 | #pragma mark -
90 | #pragma mark Public
91 |
92 | - (IBAction)advancedModeSwitchValueChanged:(id)sender
93 | {
94 | NSAssert([sender isKindOfClass:[UISwitch class]] == YES, @"Invalid class.");
95 | UISwitch *theSwitch = (UISwitch *)sender;
96 |
97 | self.konamiGestureRecognizer.requiresABEnterToUnlock = [theSwitch isOn];
98 |
99 | [self setGuideString]; // call after setting requiresABEnterToUnlock
100 | }
101 |
102 | - (IBAction)aButtonWasPressed:(id)sender
103 | {
104 | [self.konamiGestureRecognizer AButtonAction];
105 | }
106 |
107 | - (IBAction)bButtonWasPressed:(id)sender
108 | {
109 | [self.konamiGestureRecognizer BButtonAction];
110 | }
111 |
112 | - (IBAction)enterButtonWasPressed:(id)sender
113 | {
114 | [self.konamiGestureRecognizer enterButtonAction];
115 | }
116 |
117 | - (IBAction)nesControllerWasPressed:(id)sender
118 | {
119 | [self.konamiGestureRecognizer cancelSequence];
120 | }
121 |
122 | #pragma mark -
123 | #pragma mark Private
124 |
125 | - (void)_konamiGestureRecognized:(DRKonamiGestureRecognizer*)gesture
126 | {
127 | if ( gesture.state == UIGestureRecognizerStateRecognized )
128 | {
129 | UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:@"Konami!" delegate:nil cancelButtonTitle:nil otherButtonTitles:@"Dismiss",nil];
130 | [alert show];
131 | }
132 | else if ( gesture.state == UIGestureRecognizerStateChanged )
133 | {
134 | DRKonamiGestureState konamiState = gesture.konamiState;
135 | NSInteger indexOfSubString = konamiState - DRKonamiGestureStateUp1 + 1;
136 |
137 | if ( indexOfSubString > 0 )
138 | {
139 | NSString *progressString = [konamiProgressString substringToIndex:indexOfSubString];
140 | self.statusLabel.text = progressString;
141 | }
142 | else
143 | {
144 | self.statusLabel.text = nil;
145 | }
146 | }
147 | else
148 | {
149 | self.statusLabel.text = nil;
150 | }
151 | }
152 |
153 | - (void)setGuideString
154 | {
155 | BOOL baaaaa = self.konamiGestureRecognizer.requiresABEnterToUnlock;
156 | self.guideLabel.text = [konamiProgressString substringToIndex:baaaaa?10:8];
157 | }
158 |
159 | // lets you use dynamics if available
160 | - (void)OSSafeAnimateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion NS_AVAILABLE_IOS(6_0)
161 | {
162 | if ( [[UIView class] respondsToSelector:@selector(animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:)] ) {
163 |
164 | [UIView animateWithDuration:duration delay:delay usingSpringWithDamping:dampingRatio initialSpringVelocity:velocity options:options animations:animations completion:completion];
165 |
166 | } else {
167 |
168 | [UIView animateWithDuration:duration delay:delay options:options animations:animations completion:completion];
169 |
170 | }
171 | }
172 |
173 | @end
174 |
--------------------------------------------------------------------------------
/Sources/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // DRKonamiCode
4 | //
5 | // Created by Danny Ricciotti on 3/4/12.
6 | //
7 |
8 | #import
9 |
10 | #import "DRAppDelegate.h"
11 |
12 | int main(int argc, char *argv[])
13 | {
14 | @autoreleasepool {
15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([DRAppDelegate class]));
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | DRKonamiCode is licensed under the MIT license
2 |
3 | The MIT License (MIT)
4 |
5 | Copyright (c) 2015 Daniel Ricciotti
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy
8 | of this software and associated documentation files (the "Software"), to deal
9 | in the Software without restriction, including without limitation the rights
10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 | copies of the Software, and to permit persons to whom the Software is
12 | furnished to do so, subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in
15 | all copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 | THE SOFTWARE.
24 |
--------------------------------------------------------------------------------