├── GestureKeyboard
├── graffiti_strokes.jpeg
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── Info.plist
├── AppDelegate.swift
├── ViewController.swift
└── Base.lproj
│ └── Main.storyboard
├── GestureKeyboard.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── project.pbxproj
├── .gitignore
├── CMUnistrokeGestureRecognizer
├── GestureKeyboard-Bridging-Header.h
├── CMUnistrokeRecognizer
│ ├── CMUnistrokeRecognizer.h
│ ├── CMUnistrokeRecognizerTypes.h
│ ├── CMUnistrokeRecognizerPrivate.h
│ ├── CMUnistrokeRecognizerTypes.c
│ └── CMUnistrokeRecognizer.c
├── CMUnistrokeGestureResult.h
├── CMUnistrokeGestureResult.m
├── CMUnistrokeGestureRecognizer-Prefix.pch
├── CMUnistrokeGestureRecognizer.h
└── CMUnistrokeGestureRecognizer.m
├── GestureKeyboardTests
├── Info.plist
└── GestureKeyboardTests.swift
├── GestureKeyboardExtension
├── Info.plist
└── KeyboardViewController.swift
└── graffiti.plist
/GestureKeyboard/graffiti_strokes.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/robterrell/graffiti-keyboard/HEAD/GestureKeyboard/graffiti_strokes.jpeg
--------------------------------------------------------------------------------
/GestureKeyboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | .DS_Store
3 | build/
4 | *.pbxuser
5 | !default.pbxuser
6 | *.mode1v3
7 | !default.mode1v3
8 | *.mode2v3
9 | !default.mode2v3
10 | *.perspectivev3
11 | !default.perspectivev3
12 | *.xcworkspace
13 | !default.xcworkspace
14 | xcuserdata
15 | profile
16 | *.moved-aside
17 | DerivedData
18 | .idea/
19 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/GestureKeyboard-Bridging-Header.h:
--------------------------------------------------------------------------------
1 | //
2 | // GestureKeyboard-Bridging-Header.h
3 | // GestureKeyboard
4 | //
5 | // Created by Rob Terrell on 6/8/14.
6 | // Copyright (c) 2014 TouchCentric. All rights reserved.
7 | //
8 |
9 | #import "CMUnistrokeGestureRecognizer.h"
10 | #import "CMUnistrokeGestureResult.h"
11 |
12 |
--------------------------------------------------------------------------------
/GestureKeyboardTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.touchcentric.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 |
24 |
25 |
--------------------------------------------------------------------------------
/GestureKeyboardTests/GestureKeyboardTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // GestureKeyboardTests.swift
3 | // GestureKeyboardTests
4 | //
5 | // Created by Rob Terrell on 6/7/14.
6 | // Copyright (c) 2014 TouchCentric. All rights reserved.
7 | //
8 |
9 | import XCTest
10 |
11 | class GestureKeyboardTests: XCTestCase {
12 |
13 | override func setUp() {
14 | super.setUp()
15 | // Put setup code here. This method is called before the invocation of each test method in the class.
16 | }
17 |
18 | override func tearDown() {
19 | // Put teardown code here. This method is called after the invocation of each test method in the class.
20 | super.tearDown()
21 | }
22 |
23 | func testExample() {
24 | // This is an example of a functional test case.
25 | XCTAssert(true, "Pass")
26 | }
27 |
28 | func testPerformanceExample() {
29 | // This is an example of a performance test case.
30 | self.measureBlock() {
31 | // Put the code you want to measure the time of here.
32 | }
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/GestureKeyboard/Images.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "ipad",
20 | "size" : "29x29",
21 | "scale" : "1x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "29x29",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "40x40",
31 | "scale" : "1x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "40x40",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "76x76",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "76x76",
46 | "scale" : "2x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/GestureKeyboard/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | },
18 | {
19 | "orientation" : "portrait",
20 | "idiom" : "ipad",
21 | "extent" : "full-screen",
22 | "minimum-system-version" : "7.0",
23 | "scale" : "1x"
24 | },
25 | {
26 | "orientation" : "landscape",
27 | "idiom" : "ipad",
28 | "extent" : "full-screen",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "1x"
31 | },
32 | {
33 | "orientation" : "portrait",
34 | "idiom" : "ipad",
35 | "extent" : "full-screen",
36 | "minimum-system-version" : "7.0",
37 | "scale" : "2x"
38 | },
39 | {
40 | "orientation" : "landscape",
41 | "idiom" : "ipad",
42 | "extent" : "full-screen",
43 | "minimum-system-version" : "7.0",
44 | "scale" : "2x"
45 | }
46 | ],
47 | "info" : {
48 | "version" : 1,
49 | "author" : "xcode"
50 | }
51 | }
--------------------------------------------------------------------------------
/GestureKeyboardExtension/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleDisplayName
8 | Graffiti
9 | CFBundleExecutable
10 | ${EXECUTABLE_NAME}
11 | CFBundleIdentifier
12 | ${PRODUCT_NAME}
13 | CFBundleInfoDictionaryVersion
14 | 6.0
15 | CFBundleName
16 | ${PRODUCT_NAME}
17 | CFBundlePackageType
18 | XPC!
19 | CFBundleShortVersionString
20 | 1.0
21 | CFBundleSignature
22 | ????
23 | CFBundleVersion
24 | 1
25 | NSExtension
26 |
27 | NSExtensionAttributes
28 |
29 | IsASCIICapable
30 |
31 | PrefersRightToLeft
32 |
33 | PrimaryLanguage
34 | en-US
35 | RequestsOpenAccess
36 |
37 |
38 | NSExtensionPointIdentifier
39 | com.apple.keyboard-service
40 | NSExtensionPrincipalClass
41 | ${PRODUCT_MODULE_NAME}.KeyboardViewController
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeRecognizer/CMUnistrokeRecognizer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeRecognizer.h
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 23/09/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #ifndef CMUnistrokeGestureRecognizer_h
30 | #define CMUnistrokeGestureRecognizer_h
31 |
32 | #include "CMUnistrokeRecognizerTypes.h"
33 |
34 | CMURResultRef
35 | unistrokeRecognizePathFromTemplates(CMURPathRef path, CMURTemplatesRef templates, CMUROptionsRef options);
36 |
37 | #endif
38 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeGestureResult.h:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeGestureResult.h
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 17/10/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #import
30 |
31 | @interface CMUnistrokeGestureResult : NSObject
32 |
33 | @property (nonatomic, strong, readonly) NSString *recognizedStrokeName;
34 | @property (nonatomic, assign, readonly) float recognizedStrokeScore;
35 |
36 | - (id)initWithName:(NSString *)name score:(float)score;
37 |
38 | @end
39 |
--------------------------------------------------------------------------------
/GestureKeyboard/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.touchcentric.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | ${PRODUCT_NAME}
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 |
35 | NSExtension
36 |
37 | NSExtensionAttributes
38 |
39 | IsASCIICapable
40 |
41 | PrefersRightToLeft
42 |
43 | PrimaryLanguage
44 | en-US
45 | RequestsOpenAccess
46 |
47 |
48 | NSExtensionPointIdentifier
49 | com.apple.keyboard-service
50 | NSExtensionPrincipalClass
51 | KeyboardViewController
52 |
53 |
54 |
55 |
56 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeGestureResult.m:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeGestureResult.m
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 17/10/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #import "CMUnistrokeGestureResult.h"
30 |
31 |
32 | #pragma mark - CMUnistrokeGestureResult class extension
33 |
34 | @interface CMUnistrokeGestureResult ()
35 |
36 | @property (nonatomic, strong, readwrite) NSString *recognizedStrokeName;
37 | @property (nonatomic, assign, readwrite) float recognizedStrokeScore;
38 |
39 | @end
40 |
41 |
42 | @implementation CMUnistrokeGestureResult
43 |
44 | - (id)initWithName:(NSString *)name score:(float)score
45 | {
46 | self = [super init];
47 | if (self) {
48 | self.recognizedStrokeName = name;
49 | self.recognizedStrokeScore = score;
50 | }
51 | return self;
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/GestureKeyboard/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // GestureKeyboard
4 | //
5 | // Created by Rob Terrell on 6/7/14.
6 | // Copyright (c) 2014 TouchCentric. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: NSDictionary?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(application: UIApplication) {
23 | // 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.
24 | // 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.
25 | }
26 |
27 | func applicationDidEnterBackground(application: UIApplication) {
28 | // 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.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(application: UIApplication) {
33 | // 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.
34 | }
35 |
36 | func applicationDidBecomeActive(application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeGestureRecognizer-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header for all source files of the 'CMUnistrokeGestureRecognizer' target in the 'CMUnistrokeGestureRecognizer' project
3 | //
4 | // Copyright (c) 2012 Chris Miles. All rights reserved.
5 | //
6 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in
16 | // all copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | // THE SOFTWARE.
25 | //
26 |
27 | #ifdef __OBJC__
28 | #import
29 | #import
30 |
31 | #ifdef DEBUG
32 | #define CMUGRLog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
33 | #define CMUGRALog(...) [[NSAssertionHandler currentHandler] handleFailureInFunction:[NSString stringWithCString:__PRETTY_FUNCTION__ encoding:NSUTF8StringEncoding] file:[NSString stringWithCString:__FILE__ encoding:NSUTF8StringEncoding] lineNumber:__LINE__ description:__VA_ARGS__]
34 | #else
35 | #define CMUGRLog(...) do { } while (0)
36 | #ifndef NS_BLOCK_ASSERTIONS
37 | #define NS_BLOCK_ASSERTIONS
38 | #endif
39 | #define CMUGRALog(...) NSLog(@"%s %@", __PRETTY_FUNCTION__, [NSString stringWithFormat:__VA_ARGS__])
40 | #endif
41 |
42 | #define CMUGRAssert(condition, ...) do { if (!(condition)) { ALog(__VA_ARGS__); }} while(0)
43 |
44 | #endif
45 |
--------------------------------------------------------------------------------
/GestureKeyboard/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // GestureKeyboard
4 | //
5 | // Created by Rob Terrell on 6/7/14.
6 | // Copyright (c) 2014 TouchCentric. All rights reserved.
7 | //
8 |
9 | // Note: this is the main view controller for the app -- NOT for the keyboard.
10 |
11 | import UIKit
12 |
13 | class ViewController: UIViewController {
14 |
15 | @IBOutlet var imageView : UIImageView
16 |
17 | @IBOutlet var label : UILabel
18 |
19 | var plist:String = NSBundle.mainBundle().pathForResource("graffiti", ofType: "plist")
20 |
21 | override func viewDidLoad() {
22 | super.viewDidLoad()
23 |
24 | var a = CMUnistrokeGestureRecognizer(target: self, action: "gotGesture:" )
25 | var dict = NSDictionary(contentsOfFile: plist) // COMPILER BUG: as Dictionary
26 | var keys:String[] = dict.allKeys as String[]
27 |
28 | for letter:String in keys {
29 | var path = UIBezierPath()
30 | var first = true
31 | var points = dict[letter] as String[]
32 | for p in points {
33 | var cgp = CGPointFromString(p)
34 | if (first) {
35 | path.moveToPoint(cgp)
36 | first = false
37 | } else {
38 | path.addLineToPoint(cgp)
39 | }
40 | }
41 | path.closePath();
42 | a.registerUnistrokeWithName( letter, bezierPath: path)
43 | }
44 |
45 |
46 | var drawView = UIView() as UIView
47 | drawView.frame = CGRectMake(0, 0, 120, 120)
48 | drawView.center = self.view.center
49 | drawView.center.y = drawView.center.y + 180
50 | drawView.backgroundColor = UIColor.darkGrayColor()
51 | // var drawViewBottomConstraint = NSLayoutConstraint(item: self.imageView, attribute: .Top, relatedBy: .Equal, toItem: drawView, attribute: .Bottom, multiplier: 1.0, constant: 0.0)
52 | // self.view.addConstraint( drawViewBottomConstraint )
53 |
54 | self.view.addSubview(drawView)
55 | self.view.addGestureRecognizer(a)
56 | }
57 |
58 | func gotGesture( r : CMUnistrokeGestureRecognizer ) {
59 | var path = r.strokePath
60 | var name = r.result.recognizedStrokeName
61 |
62 | println("gotGesture: \(name)")
63 |
64 | label.text = label.text + name;
65 |
66 |
67 | }
68 |
69 | override func didReceiveMemoryWarning() {
70 | super.didReceiveMemoryWarning()
71 | // Dispose of any resources that can be recreated.
72 | }
73 |
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeGestureRecognizer.h:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeGestureRecognizer.h
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 23/09/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #import
30 | #import
31 | #import "CMUnistrokeGestureResult.h"
32 |
33 |
34 | @protocol CMUnistrokeGestureRecognizerDelegate;
35 |
36 |
37 | #pragma mark - CMUnistrokeGestureRecognizer
38 |
39 | @interface CMUnistrokeGestureRecognizer : UIGestureRecognizer
40 |
41 | @property (nonatomic, weak) id unistrokeDelegate;
42 |
43 | /** Minimum score required to successfully register a gesture as recognized.
44 | i.e. recognition sensitivity.
45 | Expects a value between 0.0 and 1.0.
46 | */
47 | @property (nonatomic, assign) float minimumScoreThreshold;
48 |
49 | /** Enables the Protractor method for calculating difference between gestures.
50 | The Protractor method can be faster, but results may vary.
51 | Defaults to not enabled.
52 | */
53 | @property (nonatomic, assign) BOOL protactorMethodEnabled;
54 |
55 | /** Determines whether gesture rotations are normalised.
56 | When enabled, gestures will be normalised to the same angle before
57 | recognition is attempted.
58 | Defaults to enabled.
59 | */
60 | @property (nonatomic, assign) BOOL rotationNormalisationEnabled; // default: YES
61 |
62 | @property (nonatomic, strong, readonly) CMUnistrokeGestureResult *result;
63 | @property (nonatomic, strong, readonly) UIBezierPath *strokePath;
64 |
65 | - (void)registerUnistrokeWithName:(NSString *)name bezierPath:(UIBezierPath *)path;
66 | - (void)registerUnistrokeWithName:(NSString *)name bezierPath:(UIBezierPath *)bezierPath bidirectional:(BOOL)bidirectional;
67 | - (void)clearAllUnistrokes;
68 |
69 | @end
70 |
71 |
72 | #pragma mark - Protocols
73 |
74 | @protocol CMUnistrokeGestureRecognizerDelegate
75 |
76 | @optional
77 | - (void)unistrokeGestureRecognizer:(CMUnistrokeGestureRecognizer *)unistrokeGestureRecognizer isEvaluatingStrokePath:(UIBezierPath *)strokePath;
78 | - (void)unistrokeGestureRecognizerDidFailToRecognize:(CMUnistrokeGestureRecognizer *)unistrokeGestureRecognizer;
79 |
80 | @end
81 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeRecognizer/CMUnistrokeRecognizerTypes.h:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeRecognizerTypes.h
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 8/10/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #ifndef CMUnistrokeGestureRecognizer_Types_h
30 | #define CMUnistrokeGestureRecognizer_Types_h
31 |
32 | /*
33 | GLKVector2, from the GLKit framework, is used to represent points so we
34 | can take advantage of the high performance GLKit math functions.
35 | */
36 | #include
37 |
38 |
39 | typedef struct _CMURResult {
40 | char *name;
41 | float score;
42 | } CMURResult;
43 |
44 | typedef struct _CMUROptions {
45 | bool useProtractor;
46 | bool rotationNormalisationDisabled;
47 | } CMUROptions;
48 |
49 | typedef struct _CMUROptions *CMUROptionsRef;
50 | typedef struct _CMURPath *CMURPathRef;
51 | typedef struct _CMURResult *CMURResultRef;
52 | typedef struct _CMURTemplates *CMURTemplatesRef;
53 |
54 |
55 | /*
56 | CMURTemplates functions
57 | */
58 |
59 | CMURTemplatesRef
60 | CMURTemplatesNew(void);
61 |
62 | void
63 | CMURTemplatesDelete(CMURTemplatesRef templates);
64 |
65 | void
66 | CMURTemplatesAdd(CMURTemplatesRef templates, const char *name, CMURPathRef path, CMUROptionsRef options);
67 |
68 |
69 | /*
70 | CMURPath functions
71 | */
72 |
73 | CMURPathRef
74 | CMURPathNew(void);
75 |
76 | CMURPathRef
77 | CMURPathNewWithSize(unsigned int size);
78 |
79 | CMURPathRef
80 | CMURPathNewWithPoints(GLKVector2 *points, unsigned int pointsLength);
81 |
82 | CMURPathRef
83 | CMURPathCopy(CMURPathRef sourcePath);
84 |
85 | void
86 | CMURPathDelete(CMURPathRef path);
87 |
88 | void
89 | CMURPathAddPoint(CMURPathRef path, float x, float y);
90 |
91 | void
92 | CMURPathReverse(CMURPathRef path);
93 |
94 |
95 | /*
96 | CMURResult functions
97 | */
98 |
99 | CMURResultRef
100 | CMURResultNew(char *name, float score);
101 |
102 | void
103 | CMURResultDelete(CMURResultRef result);
104 |
105 |
106 | /*
107 | CMUROptions functions
108 | */
109 |
110 | CMUROptionsRef
111 | CMUROptionsNew(void);
112 |
113 | void
114 | CMUROptionsDelete(CMUROptionsRef options);
115 |
116 |
117 | #endif /* CMUnistrokeGestureRecognizer_Types_h */
118 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeRecognizer/CMUnistrokeRecognizerPrivate.h:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeRecognizerPrivate.h
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 24/09/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #ifndef CMUnistrokeGestureRecognizer_Private_h
30 | #define CMUnistrokeGestureRecognizer_Private_h
31 |
32 | #include "CMUnistrokeRecognizerTypes.h"
33 |
34 |
35 | struct _CMURPath {
36 | unsigned int length; // number of points
37 | GLKVector2 *pointList;
38 | unsigned int pointListSize; // size of array
39 | };
40 |
41 | struct _CMURTemplate {
42 | char *name;
43 | CMURPathRef path;
44 | CMURPathRef vector;
45 | };
46 | typedef struct _CMURTemplate *CMURTemplateRef;
47 |
48 | typedef struct _CMURTemplates {
49 | unsigned int length; // number of templates
50 | CMURTemplateRef *templateList;
51 | unsigned int templateListSize; // size of array
52 | } CMURTemplates;
53 |
54 | typedef struct {
55 | float x;
56 | float y;
57 | float width;
58 | float height;
59 | } CMURRectangle;
60 |
61 |
62 | /*
63 | CMURTemplate functions
64 | */
65 |
66 | CMURTemplateRef
67 | CMURTemplateNew(const char *name, CMURPathRef path);
68 |
69 | void
70 | CMURTemplateDelete(CMURTemplateRef template);
71 |
72 |
73 | /*
74 | Recognizer helper functions
75 | */
76 |
77 | CMURTemplateRef
78 | unistrokeRecognizerResampledNormalisedTemplate(const char *name, CMURPathRef path, CMUROptionsRef options);
79 |
80 | CMURPathRef
81 | unistrokeRecognizerResample(CMURPathRef path, unsigned int sampleSize);
82 |
83 | float
84 | unistrokeRecognizerIndicativeAngle(CMURPathRef path);
85 |
86 | float
87 | unistrokeRecognizerDistanceAtBestAngle(CMURPathRef path, CMURTemplateRef template, float radiansA, float radiansB, float radiansDelta);
88 |
89 | GLKVector2
90 | unistrokeRecognizerCentroid(CMURPathRef path);
91 |
92 | CMURPathRef
93 | unistrokeRecognizerRotateBy(CMURPathRef path, float radians);
94 |
95 | CMURRectangle
96 | unistrokeRecognizerBoundingBox(CMURPathRef path);
97 |
98 | void
99 | unistrokeRecognizerScaleTo(CMURPathRef path, float size);
100 |
101 | void
102 | unistrokeRecognizerTranslateTo(CMURPathRef path, GLKVector2 k);
103 |
104 | float
105 | unistrokeRecognizerDistanceAtAngle(CMURPathRef path, CMURTemplateRef template, float radians);
106 |
107 | float
108 | unistrokeRecognizerPathDistance(CMURPathRef pathA, CMURPathRef pathB);
109 |
110 | float
111 | unistrokeRecognizerPathLength(CMURPathRef path);
112 |
113 | CMURPathRef
114 | unistrokeRecognizerVectorize(CMURPathRef path);
115 |
116 | float
117 | unistrokeRecognizerOptimalCosineDistance(CMURPathRef vector1, CMURPathRef vector2);
118 |
119 | #endif
120 |
--------------------------------------------------------------------------------
/GestureKeyboard/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/graffiti.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | a
6 |
7 | {0.5, 4.5}
8 | {2.5, 0.5}
9 | {4.5, 4.5}
10 |
11 | b
12 |
13 | {1.0, 0.5}
14 | {1.0, 4.5}
15 | {1.5, 0.75}
16 | {3.0, 0.5}
17 | {3.5, 1.5}
18 | {2.5, 2}
19 | {1.5, 2.5}
20 | {3.0, 3.0}
21 | {3.5, 4}
22 | {3.0, 4.5}
23 | {2.0, 4.5)
24 |
25 | c
26 |
27 | {4.0, 1.0}
28 | {1.0, 1.0}
29 | {1.0, 4.0}
30 | {4.0, 4.0}
31 |
32 | d
33 |
34 | {1.0, 0.75}
35 | {1.0, 4.5}
36 | {1.25, 1.0}
37 | {3.0, 0.5}
38 | {4.0, 1.0}
39 | {4.5, 2.5}
40 | {4.0, 3.5}
41 | {2.5, 4.5}
42 | {1.0, 4.5)
43 |
44 | e
45 |
46 | {4.0, 1.0}
47 | {3.0, 0.5}
48 | {2.0, 0.5}
49 | {1.0, 1.5}
50 | {2.5, 2.5}
51 | {1.0, 3.5}
52 | {2.0, 4.5}
53 | {3.0, 4.5}
54 | {4.0, 4.0}
55 |
56 | f
57 |
58 | {1.0, 4.0}
59 | {1.0, 1.0}
60 | {4.0, 1.0}
61 |
62 | g
63 |
64 | {4.0, 1.5}
65 | {3.0, 0.5}
66 | {2.0, 0.5}
67 | {1.0, 1.5}
68 | {1.0, 3.5}
69 | {2.0, 4.5}
70 | {4.0, 4.5}
71 | {4.0, 3.0}
72 | {3.0, 3.0}
73 |
74 | h
75 |
76 | {1.0, 0.5}
77 | {1.0, 4.0}
78 | {1.1, 2.0}
79 | {3.0, 2.0}
80 | {4.0, 3.0}
81 |
82 | i
83 |
84 | {3.0, 0.5}
85 | {3.2, 1.0}
86 | {3.0, 1.5}
87 | {3.2, 2.0}
88 | {3.0, 2.5}
89 | {3.2, 3.0}
90 | {3.0, 3.5}
91 | {3.2, 4.0}
92 | {3.0, 4.5}
93 |
94 | j
95 |
96 | {4.0, 0.5}
97 | {4.0, 4.5}
98 | {1.0, 4.5}
99 |
100 | k
101 |
102 | {4.0, 1.0}
103 | {1.0, 4.0}
104 | {1.0, 1.0}
105 | {4.0, 4.0}
106 |
107 | l
108 |
109 | {1.0, 1.0}
110 | {1.1, 4.0}
111 | {4.0, 4.0}
112 |
113 | m
114 |
115 | {1.0, 4.0}
116 | {1.0, 1.0}
117 | {2.5, 2.0}
118 | {4.0, 1.0}
119 | {4.0, 4.0}
120 |
121 | n
122 |
123 | {1.0, 4.0}
124 | {1.1, 1.0}
125 | {4.0, 4.0}
126 | {4.0, 1.0}
127 |
128 | o
129 |
130 | {2.0, 1.0}
131 | {1.0, 2.0}
132 | {1.0, 3.0}
133 | {2.0, 4.0}
134 | {3.0, 4.0}
135 | {4.0, 3.0}
136 | {4.0, 2.0}
137 | {3.0, 1.0}
138 |
139 | p
140 |
141 | {0.8, 1.0}
142 | {1.0, 4.5}
143 | {1.0, 1.0}
144 | {2.0, 1.0}
145 | {3.0, 2.0}
146 | {2.0, 3.0}
147 | {1.0, 3.0}
148 |
149 |
150 |
151 | {1.5, 3.0}
152 | {2.0, 3.1}
153 | {2.5, 3.1}
154 | {3.0, 3.0}
155 | {3.5, 3.0}
156 | {4.0, 3.1}
157 |
158 | delete
159 |
160 | {3.5, 3.2}
161 | {3.0, 3.1}
162 | {2.5, 3.0}
163 | {2.0, 3.1}
164 | {1.5, 3.0}
165 |
166 |
167 |
168 |
--------------------------------------------------------------------------------
/GestureKeyboardExtension/KeyboardViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // KeyboardViewController.swift
3 | // GestureKeyboardExtension
4 | //
5 | // Created by Rob Terrell on 6/8/14.
6 | // Copyright (c) 2014 TouchCentric. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | class KeyboardViewController: UIInputViewController {
12 |
13 | @IBOutlet var nextKeyboardButton: UIButton
14 | var drawView : UIView = UIView()
15 |
16 | init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: NSBundle?) {
17 | super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
18 | NSLog("Keyboard View Controller init")
19 | }
20 |
21 | override func updateViewConstraints() {
22 | super.updateViewConstraints()
23 |
24 | // Add custom view sizing constraints here
25 | }
26 | override func viewDidAppear(animated: Bool) {
27 | NSLog("viewDidAppear \(self.drawView.frame), \(self.drawView.superview.frame)")
28 | self.drawView.center = self.view.center
29 | }
30 |
31 | override func viewDidLoad() {
32 | NSLog("Keyboard View Conroller viewDidLoad")
33 |
34 | super.viewDidLoad()
35 |
36 | NSLog("Keyboard View Conroller view \(self.view)")
37 |
38 | // Perform custom UI setup here
39 | self.nextKeyboardButton = UIButton.buttonWithType(.System) as UIButton
40 | self.nextKeyboardButton.setTitle(NSLocalizedString("Next Keyboard!", comment: "Title for 'Next Keyboard' button"), forState: .Normal)
41 | self.nextKeyboardButton.sizeToFit()
42 | self.nextKeyboardButton.setTranslatesAutoresizingMaskIntoConstraints(false)
43 | self.nextKeyboardButton.addTarget(self, action: "advanceToNextInputMode", forControlEvents: .TouchUpInside)
44 |
45 | self.view.addSubview(self.nextKeyboardButton)
46 |
47 | var nextKeyboardButtonLeftSideConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Left, relatedBy: .Equal, toItem: self.view, attribute: .Left, multiplier: 1.0, constant: 0.0)
48 | var nextKeyboardButtonBottomConstraint = NSLayoutConstraint(item: self.nextKeyboardButton, attribute: .Bottom, relatedBy: .Equal, toItem: self.view, attribute: .Bottom, multiplier: 1.0, constant: 7.0)
49 | self.view.addConstraints([nextKeyboardButtonLeftSideConstraint, nextKeyboardButtonBottomConstraint])
50 |
51 | drawView.frame = CGRectMake(0, 0, 180, 180)
52 | drawView.backgroundColor = UIColor.darkGrayColor()
53 | drawView.center = self.view.center
54 | drawView.layer.cornerRadius = 5.0
55 | self.view.addSubview(drawView)
56 |
57 | var drawViewVertConstraint = NSLayoutConstraint(item: self.drawView, attribute: .CenterY, relatedBy: .Equal, toItem: self.drawView.superview, attribute: .CenterY, multiplier: 1.0, constant: 0.0)
58 |
59 | var drawViewHorizConstraint = NSLayoutConstraint(item: self.drawView, attribute: .CenterX, relatedBy: .Equal, toItem: self.nextKeyboardButton.superview, attribute: .CenterX, multiplier: 1.0, constant: 0.0)
60 |
61 | self.view.addConstraints( [drawViewVertConstraint, drawViewHorizConstraint] )
62 |
63 | var a = CMUnistrokeGestureRecognizer(target: self, action: "gotGesture:" )
64 |
65 | var plist = NSBundle.mainBundle().pathForResource("graffiti", ofType: "plist")
66 | var dict = NSDictionary(contentsOfFile: plist) // COMPILER BUG: as Dictionary
67 | var keys:String[] = dict.allKeys as String[]
68 |
69 | for letter:String in keys {
70 | var path = UIBezierPath()
71 | var first = true
72 | var points = dict[letter] as String[]
73 | for p in points {
74 | var cgp = CGPointFromString(p)
75 | if (first) {
76 | path.moveToPoint(cgp)
77 | first = false
78 | } else {
79 | path.addLineToPoint(cgp)
80 | }
81 | }
82 | path.closePath();
83 | a.registerUnistrokeWithName( letter, bezierPath: path)
84 | }
85 |
86 | drawView.addGestureRecognizer(a)
87 |
88 | }
89 |
90 | func gotGesture( r : CMUnistrokeGestureRecognizer ) {
91 | var path = r.strokePath
92 | var name = r.result.recognizedStrokeName
93 |
94 | println("gotGesture \(name)")
95 |
96 | var doc : UIKeyInput = self.textDocumentProxy as UIKeyInput
97 |
98 | if name == "delete" {
99 | doc.deleteBackward()
100 | } else {
101 | doc.insertText(name)
102 | }
103 | }
104 |
105 | override func didReceiveMemoryWarning() {
106 | super.didReceiveMemoryWarning()
107 | // Dispose of any resources that can be recreated
108 | }
109 |
110 | override func textWillChange(textInput: UITextInput) {
111 | // The app is about to change the document's contents. Perform any preparation here.
112 | }
113 |
114 | override func textDidChange(textInput: UITextInput) {
115 | // The app has just changed the document's contents, the document context has been updated.
116 |
117 | var textColor: UIColor
118 | var proxy = self.textDocumentProxy as UITextDocumentProxy
119 | if proxy.keyboardAppearance == UIKeyboardAppearance.Dark {
120 | textColor = UIColor.whiteColor()
121 | } else {
122 | textColor = UIColor.blackColor()
123 | }
124 | self.nextKeyboardButton.setTitleColor(textColor, forState: .Normal)
125 | }
126 |
127 | }
128 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeRecognizer/CMUnistrokeRecognizerTypes.c:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeRecognizerTypes.c
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 8/10/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #include
30 | #include
31 |
32 | #include "CMUnistrokeRecognizerTypes.h"
33 | #include "CMUnistrokeRecognizerPrivate.h"
34 |
35 | #define kDefaultPathArraySize 32
36 | #define kDefaultTemplatesArraySize 4
37 |
38 |
39 | #pragma mark - struct CMURTemplates
40 |
41 | CMURTemplatesRef
42 | CMURTemplatesNew(void)
43 | {
44 | CMURTemplatesRef templates = malloc(sizeof(CMURTemplates));
45 |
46 | templates->templateListSize = kDefaultTemplatesArraySize;
47 | templates->templateList = malloc(kDefaultTemplatesArraySize * sizeof(CMURTemplateRef));
48 | templates->length = 0;
49 |
50 | return templates;
51 | }
52 |
53 | void
54 | CMURTemplatesDelete(CMURTemplatesRef templates)
55 | {
56 | if (NULL == templates) return;
57 |
58 | if (templates->templateList) {
59 | for (unsigned int i=0; i < templates->length; i++) {
60 | CMURTemplateDelete(templates->templateList[i]);
61 | }
62 | free(templates->templateList);
63 | templates->templateList = NULL;
64 | }
65 | templates->length = 0;
66 | templates->templateListSize = 0;
67 |
68 | free(templates);
69 | }
70 |
71 | void
72 | CMURTemplatesAdd(CMURTemplatesRef templates, const char *name, CMURPathRef path, CMUROptionsRef options)
73 | {
74 | if (templates->length >= templates->templateListSize) {
75 | templates->templateListSize *= 2;
76 | templates->templateList = realloc(templates->templateList, templates->templateListSize * sizeof(CMURTemplateRef));
77 | }
78 |
79 | CMURTemplateRef template = unistrokeRecognizerResampledNormalisedTemplate(name, path, options);
80 | template->vector = unistrokeRecognizerVectorize(template->path);
81 |
82 | templates->templateList[templates->length++] = template;
83 | }
84 |
85 |
86 | #pragma mark - CMURPath
87 |
88 | CMURPathRef
89 | CMURPathNew(void)
90 | {
91 | return CMURPathNewWithSize(kDefaultPathArraySize);
92 | }
93 |
94 | CMURPathRef
95 | CMURPathNewWithSize(unsigned int size)
96 | {
97 | CMURPathRef path = malloc(sizeof(struct _CMURPath));
98 | path->length = 0;
99 | path->pointListSize = size;
100 | path->pointList = malloc(path->pointListSize * sizeof(GLKVector2));
101 | return path;
102 | }
103 |
104 | CMURPathRef
105 | CMURPathNewWithPoints(GLKVector2 *points, unsigned int pointsLength)
106 | {
107 | CMURPathRef path = CMURPathNewWithSize(pointsLength);
108 | for (unsigned int i=0; ipointList[i] = points[i];
110 | }
111 | path->length = pointsLength;
112 | return path;
113 | }
114 |
115 | CMURPathRef
116 | CMURPathCopy(CMURPathRef sourcePath)
117 | {
118 | CMURPathRef copiedPath = CMURPathNewWithPoints(sourcePath->pointList, sourcePath->length);
119 | return copiedPath;
120 | }
121 |
122 | void
123 | CMURPathDelete(CMURPathRef path)
124 | {
125 | if (NULL == path) return;
126 |
127 | if (path->pointList) {
128 | free(path->pointList);
129 | path->pointList = NULL;
130 | }
131 | path->length = 0;
132 | path->pointListSize = 0;
133 |
134 | free(path);
135 | }
136 |
137 | void
138 | CMURPathAddPoint(CMURPathRef path, float x, float y)
139 | {
140 | if (path->length >= path->pointListSize) {
141 | path->pointListSize *= 2;
142 | path->pointList = realloc(path->pointList, path->pointListSize * sizeof(GLKVector2));
143 | }
144 |
145 | GLKVector2 vector = GLKVector2Make(x, y);
146 | path->pointList[path->length++] = vector;
147 | }
148 |
149 | void
150 | CMURPathReverse(CMURPathRef path)
151 | {
152 | for (unsigned int i=0; ilength/2; i++) {
153 | unsigned int indexA = i;
154 | unsigned int indexB = path->length-i-1;
155 |
156 | GLKVector2 pointA = path->pointList[indexA];
157 | GLKVector2 pointB = path->pointList[indexB];
158 |
159 | path->pointList[indexB] = pointA;
160 | path->pointList[indexA] = pointB;
161 | }
162 | }
163 |
164 |
165 | #pragma mark - CMURTemplate
166 |
167 | CMURTemplateRef
168 | CMURTemplateNew(const char *name, CMURPathRef path)
169 | {
170 | CMURTemplateRef template = malloc(sizeof(struct _CMURTemplate));
171 |
172 | size_t nameSize = strlen(name);
173 | template->name = calloc(nameSize+1, sizeof(char));
174 | strncpy(template->name, name, nameSize);
175 |
176 | template->path = CMURPathCopy(path);
177 | template->vector = NULL;
178 |
179 | return template;
180 | }
181 |
182 | void
183 | CMURTemplateDelete(CMURTemplateRef template)
184 | {
185 | if (NULL == template) return;
186 |
187 | if (template->path) {
188 | CMURPathDelete(template->path);
189 | template->path = NULL;
190 | }
191 | if (template->name) {
192 | free(template->name);
193 | template->name = NULL;
194 | }
195 | if (template->vector) {
196 | CMURPathDelete(template->vector);
197 | template->vector = NULL;
198 | }
199 | }
200 |
201 |
202 | #pragma mark - Result
203 |
204 | CMURResultRef
205 | CMURResultNew(char *name, float score)
206 | {
207 | CMURResultRef result = malloc(sizeof(struct _CMURResult));
208 |
209 | if (name) {
210 | size_t nameSize = strlen(name);
211 | result->name = calloc(nameSize+1, sizeof(char));
212 | strncpy(result->name, name, nameSize);
213 | }
214 | else {
215 | result->name = NULL;
216 | }
217 |
218 | result->score = score;
219 |
220 | return result;
221 | }
222 |
223 | void
224 | CMURResultDelete(CMURResultRef result)
225 | {
226 | if (NULL == result) return;
227 |
228 | if (result->name) {
229 | free(result->name);
230 | result->name = NULL;
231 | }
232 | result->score = 0.0f;
233 |
234 | free(result);
235 | }
236 |
237 |
238 | #pragma mark - Options
239 |
240 | CMUROptionsRef
241 | CMUROptionsNew(void)
242 | {
243 | CMUROptionsRef options = calloc(1, sizeof(struct _CMUROptions));
244 | return options;
245 | }
246 |
247 | void
248 | CMUROptionsDelete(CMUROptionsRef options)
249 | {
250 | if (NULL == options) return;
251 |
252 | free(options);
253 | }
254 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeGestureRecognizer.m:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeGestureRecognizer.m
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 23/09/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | #import "CMUnistrokeGestureRecognizer.h"
30 | #import "CMUnistrokeRecognizer.h"
31 | #import
32 |
33 | static void
34 | CMURCGPathApplierFunc(void *info, const CGPathElement *element);
35 |
36 |
37 | #pragma mark - CMUnistrokeGestureRecognizer class extension
38 |
39 | @interface CMUnistrokeGestureRecognizer () {
40 | CMUROptionsRef _options;
41 | CMURTemplatesRef _unistrokeTemplates;
42 | }
43 | @property (nonatomic, strong, readwrite) CMUnistrokeGestureResult *result;
44 | @property (nonatomic, strong, readwrite) UIBezierPath *strokePath;
45 | @property (nonatomic, strong) UITouch *trackedTouch;
46 | @end
47 |
48 |
49 | #pragma mark - CMUnistrokeGestureRecognizer implementation
50 |
51 | @implementation CMUnistrokeGestureRecognizer
52 |
53 | @dynamic protactorMethodEnabled;
54 | @dynamic rotationNormalisationEnabled;
55 |
56 |
57 | - (id)initWithTarget:(id)target action:(SEL)action
58 | {
59 | self = [super initWithTarget:target action:action];
60 | if (self) {
61 | _unistrokeTemplates = CMURTemplatesNew();
62 |
63 | _options = CMUROptionsNew();
64 | _options->useProtractor = false;
65 | _options->rotationNormalisationDisabled = false;
66 | }
67 | return self;
68 | }
69 |
70 | - (void)dealloc
71 | {
72 | if (_options) {
73 | CMUROptionsDelete(_options); _options = NULL;
74 | }
75 | if (_unistrokeTemplates) {
76 | CMURTemplatesDelete(_unistrokeTemplates); _unistrokeTemplates = NULL;
77 | }
78 | }
79 |
80 |
81 | #pragma mark - Touches
82 |
83 | - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
84 | {
85 | [super touchesBegan:touches withEvent:event];
86 |
87 | self.result = nil;
88 |
89 | self.trackedTouch = [touches anyObject];
90 | self.strokePath = [[UIBezierPath alloc] init];
91 |
92 | self.state = UIGestureRecognizerStatePossible;
93 |
94 | CGPoint location = [self.trackedTouch locationInView:self.view];
95 | [self.strokePath moveToPoint:location];
96 | }
97 |
98 | - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
99 | {
100 | [super touchesMoved:touches withEvent:event];
101 |
102 | if ([touches containsObject:self.trackedTouch]) {
103 | CGPoint location = [self.trackedTouch locationInView:self.view];
104 | [self.strokePath addLineToPoint:location];
105 |
106 | id unistrokeDelegate = self.unistrokeDelegate;
107 | if ([unistrokeDelegate respondsToSelector:@selector(unistrokeGestureRecognizer:isEvaluatingStrokePath:)]) {
108 | [unistrokeDelegate unistrokeGestureRecognizer:self isEvaluatingStrokePath:self.strokePath];
109 | }
110 | }
111 | }
112 |
113 | - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
114 | {
115 | [super touchesEnded:touches withEvent:event];
116 |
117 | [self recognizeUnistroke];
118 | }
119 |
120 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
121 | {
122 | [super touchesCancelled:touches withEvent:event];
123 |
124 | [self recognizeUnistroke];
125 | }
126 |
127 |
128 | #pragma mark - Reset
129 |
130 | - (void)reset
131 | {
132 | [super reset];
133 |
134 | self.strokePath = nil;
135 | self.trackedTouch = nil;
136 | }
137 |
138 |
139 | #pragma mark - Unistroke recognizer options
140 |
141 | - (void)setProtactorMethodEnabled:(BOOL)protactorMethodEnabled
142 | {
143 | _options->useProtractor = protactorMethodEnabled;
144 | }
145 |
146 | - (BOOL)protactorMethodEnabled
147 | {
148 | return _options->useProtractor;
149 | }
150 |
151 | - (void)setRotationNormalisationEnabled:(BOOL)rotationNormalisationEnabled
152 | {
153 | _options->rotationNormalisationDisabled = (! rotationNormalisationEnabled);
154 | }
155 |
156 | - (BOOL)rotationNormalisationEnabled
157 | {
158 | return (! _options->rotationNormalisationDisabled);
159 | }
160 |
161 |
162 | #pragma mark - Recognize Unistroke
163 |
164 | - (void)recognizeUnistroke
165 | {
166 | if ([self isUnistrokeRecognized]) {
167 | self.state = UIGestureRecognizerStateRecognized;
168 | }
169 | else {
170 | self.state = UIGestureRecognizerStateFailed;
171 |
172 | id unistrokeDelegate = self.unistrokeDelegate;
173 | if ([unistrokeDelegate respondsToSelector:@selector(unistrokeGestureRecognizerDidFailToRecognize:)]) {
174 | [unistrokeDelegate unistrokeGestureRecognizerDidFailToRecognize:self];
175 | }
176 | }
177 | }
178 |
179 | - (BOOL)isUnistrokeRecognized
180 | {
181 | CMURPathRef path = [self pathFromBezierPath:self.strokePath];
182 | CMURResultRef result = unistrokeRecognizePathFromTemplates(path, _unistrokeTemplates, _options);
183 | CMURPathDelete(path);
184 |
185 | BOOL isRecognized;
186 | if (result && result->score >= self.minimumScoreThreshold) {
187 | isRecognized = YES;
188 | self.result = [[CMUnistrokeGestureResult alloc] initWithName:[NSString stringWithCString:result->name encoding:NSUTF8StringEncoding] score:result->score];
189 | NSLog(@"Recognized: result->score = %f result->name = '%s'", result->score, result->name);
190 | //NSLog(@"Path: %@", self.strokePath);
191 | }
192 | else {
193 | isRecognized = NO;
194 | self.result = nil;
195 | NSLog(@"NOT Recognized");
196 | //NSLog(@"Path: %@", self.strokePath);
197 | }
198 |
199 | CMURResultDelete(result);
200 |
201 | return isRecognized;
202 | }
203 |
204 | - (CMURPathRef)pathFromBezierPath:(UIBezierPath *)bezierPath
205 | {
206 | CMURPathRef path = CMURPathNew();
207 | CGPathApply(bezierPath.CGPath, path, CMURCGPathApplierFunc);
208 |
209 | return path;
210 | }
211 |
212 |
213 | #pragma mark - Stroke templates
214 |
215 | - (void)registerUnistrokeWithName:(NSString *)name bezierPath:(UIBezierPath *)bezierPath
216 | {
217 | [self registerUnistrokeWithName:name bezierPath:bezierPath bidirectional:NO];
218 | }
219 |
220 | - (void)registerUnistrokeWithName:(NSString *)name bezierPath:(UIBezierPath *)bezierPath bidirectional:(BOOL)bidirectional
221 | {
222 | CMURPathRef path = [self pathFromBezierPath:bezierPath];
223 | CMURTemplatesAdd(_unistrokeTemplates, [name cStringUsingEncoding:NSUTF8StringEncoding], path, _options);
224 |
225 | if (bidirectional) {
226 | CMURPathReverse(path);
227 | CMURTemplatesAdd(_unistrokeTemplates, [name cStringUsingEncoding:NSUTF8StringEncoding], path, _options);
228 | }
229 |
230 | CMURPathDelete(path);
231 | }
232 |
233 | - (void)clearAllUnistrokes
234 | {
235 | if (_unistrokeTemplates) {
236 | CMURTemplatesDelete(_unistrokeTemplates);
237 | }
238 | _unistrokeTemplates = CMURTemplatesNew();
239 | }
240 |
241 | @end
242 |
243 |
244 | static void
245 | CMURCGPathApplierFunc(void *info, const CGPathElement *element)
246 | {
247 | CMURPathRef path = (CMURPathRef)info;
248 |
249 | CGPoint *points = element->points;
250 | CGPathElementType type = element->type;
251 |
252 | switch(type) {
253 | case kCGPathElementMoveToPoint: // contains 1 point
254 | CMURPathAddPoint(path, (float)points[0].x, (float)points[0].y);
255 | break;
256 |
257 | case kCGPathElementAddLineToPoint: // contains 1 point
258 | CMURPathAddPoint(path, (float)points[0].x, (float)points[0].y);
259 | break;
260 |
261 | case kCGPathElementAddQuadCurveToPoint: // contains 2 points
262 | CMURPathAddPoint(path, (float)points[0].x, (float)points[0].y);
263 | CMURPathAddPoint(path, (float)points[1].x, (float)points[1].y);
264 | break;
265 |
266 | case kCGPathElementAddCurveToPoint: // contains 3 points
267 | CMURPathAddPoint(path, (float)points[0].x, (float)points[0].y);
268 | CMURPathAddPoint(path, (float)points[1].x, (float)points[1].y);
269 | CMURPathAddPoint(path, (float)points[2].x, (float)points[2].y);
270 | break;
271 |
272 | case kCGPathElementCloseSubpath: // contains no point
273 | break;
274 | }
275 | }
276 |
--------------------------------------------------------------------------------
/CMUnistrokeGestureRecognizer/CMUnistrokeRecognizer/CMUnistrokeRecognizer.c:
--------------------------------------------------------------------------------
1 | //
2 | // CMUnistrokeRecognizer.c
3 | // CMUnistrokeGestureRecognizer
4 | //
5 | // Created by Chris Miles on 23/09/12.
6 | // Copyright (c) 2012 Chris Miles. All rights reserved.
7 | //
8 | // MIT Licensed (http://opensource.org/licenses/mit-license.php):
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining a copy
11 | // of this software and associated documentation files (the "Software"), to deal
12 | // in the Software without restriction, including without limitation the rights
13 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | // copies of the Software, and to permit persons to whom the Software is
15 | // furnished to do so, subject to the following conditions:
16 | //
17 | // The above copyright notice and this permission notice shall be included in
18 | // all copies or substantial portions of the Software.
19 | //
20 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | // THE SOFTWARE.
27 | //
28 |
29 | /**
30 | * Parts based on JavaScript implemention of the $1 Unistroke Recognizer:
31 | *
32 | * Copyright (c) 2007-2011, Jacob O. Wobbrock, Andrew D. Wilson and Yang Li.
33 | * All rights reserved.
34 | *
35 | * Redistribution and use in source and binary forms, with or without
36 | * modification, are permitted provided that the following conditions are met:
37 | * * Redistributions of source code must retain the above copyright
38 | * notice, this list of conditions and the following disclaimer.
39 | * * Redistributions in binary form must reproduce the above copyright
40 | * notice, this list of conditions and the following disclaimer in the
41 | * documentation and/or other materials provided with the distribution.
42 | * * Neither the names of the University of Washington nor Microsoft,
43 | * nor the names of its contributors may be used to endorse or promote
44 | * products derived from this software without specific prior written
45 | * permission.
46 | *
47 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
48 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
49 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
50 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Jacob O. Wobbrock OR Andrew D. Wilson
51 | * OR Yang Li BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
52 | * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
55 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
57 | **/
58 |
59 | #include "CMUnistrokeRecognizer.h"
60 | #include "CMUnistrokeRecognizerPrivate.h"
61 | #include
62 | #include
63 |
64 | #ifndef DEBUG
65 | #define NDEBUG 1
66 | #endif
67 | #include
68 |
69 |
70 | #define kDefaultPathSampleSize 64
71 |
72 | static const float BoundingBoxSize = 250.0f;
73 | static const float theta = 0.7853981634f; // 45°
74 | static const float thetaThreshold = 0.034906585f; // 2°
75 |
76 |
77 | CMURResultRef
78 | unistrokeRecognizePathFromTemplates(CMURPathRef path, CMURTemplatesRef templates, CMUROptionsRef options)
79 | {
80 | float b = MAXFLOAT;
81 | CMURTemplateRef bestTemplate = NULL;
82 |
83 | if (path->length < 2) {
84 | return NULL;
85 | }
86 |
87 | CMURPathRef resampledPath = unistrokeRecognizerResample(path, kDefaultPathSampleSize);
88 | CMURPathRef normalisedPath;
89 |
90 | if (options && options->rotationNormalisationDisabled) {
91 | normalisedPath = CMURPathCopy(resampledPath);
92 | }
93 | else {
94 | float radians = unistrokeRecognizerIndicativeAngle(resampledPath);
95 | normalisedPath = unistrokeRecognizerRotateBy(resampledPath, -radians);
96 | }
97 |
98 | unistrokeRecognizerScaleTo(normalisedPath, BoundingBoxSize);
99 | GLKVector2 origin = GLKVector2Make(0.0f, 0.0f);
100 | unistrokeRecognizerTranslateTo(normalisedPath, origin);
101 |
102 | bool useProtractor = (options && options->useProtractor);
103 |
104 | CMURPathRef vector = NULL;
105 | if (useProtractor) vector = unistrokeRecognizerVectorize(normalisedPath);
106 |
107 | for (unsigned int i=0; ilength; i++) {
108 | CMURTemplateRef template = templates->templateList[i];
109 |
110 | float d;
111 | if (useProtractor) {
112 | // Protractor (faster)
113 | d = unistrokeRecognizerOptimalCosineDistance(template->vector, vector);
114 | }
115 | else {
116 | // Golden Section Search (original $1)
117 | d = unistrokeRecognizerDistanceAtBestAngle(normalisedPath, template, -theta, theta, thetaThreshold);
118 | }
119 |
120 | if (d < b) {
121 | b = d;
122 | bestTemplate = template;
123 | }
124 | }
125 |
126 | CMURResultRef result = NULL;
127 | if (bestTemplate) {
128 | float score;
129 | if (useProtractor) {
130 | score = 1.0f - b;
131 | }
132 | else {
133 | score = 1.0f - b / (0.5f * sqrtf(BoundingBoxSize*BoundingBoxSize + BoundingBoxSize*BoundingBoxSize));
134 | }
135 | result = CMURResultNew(bestTemplate->name, score);
136 | }
137 |
138 | CMURPathDelete(normalisedPath);
139 | CMURPathDelete(resampledPath);
140 | if (vector) CMURPathDelete(vector);
141 |
142 | return result;
143 | }
144 |
145 | CMURTemplateRef
146 | unistrokeRecognizerResampledNormalisedTemplate(const char *name, CMURPathRef path, CMUROptionsRef options)
147 | {
148 | CMURPathRef resampledPath = unistrokeRecognizerResample(path, kDefaultPathSampleSize);
149 | CMURPathRef normalisedPath;
150 |
151 | if (options && options->rotationNormalisationDisabled) {
152 | normalisedPath = CMURPathCopy(resampledPath);
153 | }
154 | else {
155 | float radians = unistrokeRecognizerIndicativeAngle(resampledPath);
156 | normalisedPath = unistrokeRecognizerRotateBy(resampledPath, -radians);
157 | }
158 |
159 | unistrokeRecognizerScaleTo(normalisedPath, BoundingBoxSize);
160 | GLKVector2 origin = GLKVector2Make(0.0f, 0.0f);
161 | unistrokeRecognizerTranslateTo(normalisedPath, origin);
162 |
163 | CMURTemplateRef template = CMURTemplateNew(name, normalisedPath);
164 |
165 | CMURPathDelete(resampledPath);
166 | CMURPathDelete(normalisedPath);
167 |
168 | return template;
169 | }
170 |
171 | CMURPathRef
172 | unistrokeRecognizerResample(CMURPathRef path, unsigned int sampleSize)
173 | {
174 | float I = unistrokeRecognizerPathLength(path) / (float)(sampleSize -1 );
175 | float D = 0;
176 |
177 | CMURPathRef newPath = CMURPathNewWithSize(sampleSize);
178 | CMURPathAddPoint(newPath, path->pointList[0].x, path->pointList[0].y);
179 |
180 | unsigned int i = 1; // points index
181 |
182 | GLKVector2 prevPoint = path->pointList[0];
183 | GLKVector2 currentPoint = path->pointList[1];
184 |
185 | while (i < path->length) {
186 | float d = GLKVector2Distance(prevPoint, currentPoint);
187 | if (D + d >= I) {
188 | float x = prevPoint.x + ((I - D) / d) * (currentPoint.x - prevPoint.x);
189 | float y = prevPoint.y + ((I - D) / d) * (currentPoint.y - prevPoint.y);
190 | CMURPathAddPoint(newPath, x, y);
191 |
192 | prevPoint.x = x;
193 | prevPoint.y = y;
194 | D = 0.0f;
195 | }
196 | else {
197 | D += d;
198 | i++;
199 | prevPoint = path->pointList[i-1];
200 | currentPoint = path->pointList[i];
201 | }
202 | }
203 |
204 | // sometimes we fall a rounding-error short of adding the last point, so add it if so
205 | if (newPath->length == sampleSize - 1) {
206 | CMURPathAddPoint(newPath, path->pointList[path->length - 1].x, path->pointList[path->length - 1].y);
207 | }
208 |
209 | return newPath;
210 | }
211 |
212 | float
213 | unistrokeRecognizerIndicativeAngle(CMURPathRef path)
214 | {
215 | GLKVector2 centroid = unistrokeRecognizerCentroid(path);
216 | float angle = atan2f(centroid.y - path->pointList[0].y, centroid.x - path->pointList[0].x); // for -pi <= angle <= pi
217 | return angle;
218 | }
219 |
220 | float
221 | unistrokeRecognizerDistanceAtBestAngle(CMURPathRef path, CMURTemplateRef template, float radiansA, float radiansB, float radiansDelta)
222 | {
223 | static float phi = 0.0f;
224 |
225 | if (phi == 0.0f) phi = 0.5f * (-1.0f + sqrtf(5.0f));
226 |
227 | float x1 = phi * radiansA + (1.0f - phi) * radiansB;
228 | float f1 = unistrokeRecognizerDistanceAtAngle(path, template, x1);
229 | float x2 = (1.0f - phi) * radiansA + phi * radiansB;
230 | float f2 = unistrokeRecognizerDistanceAtAngle(path, template, x2);
231 | while (fabsf(radiansB - radiansA) > radiansDelta) {
232 | if (f1 < f2) {
233 | radiansB = x2;
234 | x2 = x1;
235 | f2 = f1;
236 | x1 = phi * radiansA + (1.0f - phi) * radiansB;
237 | f1 = unistrokeRecognizerDistanceAtAngle(path, template, x1);
238 | }
239 | else {
240 | radiansA = x1;
241 | x1 = x2;
242 | f1 = f2;
243 | x2 = (1.0f - phi) * radiansA + phi * radiansB;
244 | f2 = unistrokeRecognizerDistanceAtAngle(path, template, x2);
245 | }
246 | }
247 | return fminf(f1, f2);
248 | }
249 |
250 | GLKVector2
251 | unistrokeRecognizerCentroid(CMURPathRef path)
252 | {
253 | float sumX = 0;
254 | float sumY = 0;
255 |
256 | for (unsigned int i=0; i < path->length; i++) {
257 | sumX += path->pointList[i].x;
258 | sumY += path->pointList[i].y;
259 | }
260 |
261 | GLKVector2 centroid = GLKVector2Make(sumX / (float)path->length, sumY / (float)path->length);
262 | return centroid;
263 | }
264 |
265 | CMURPathRef
266 | unistrokeRecognizerRotateBy(CMURPathRef path, float radians)
267 | {
268 | CMURPathRef newPath = NULL;
269 |
270 | if (path->length > 0) {
271 | GLKVector2 centroid = unistrokeRecognizerCentroid(path);
272 | float cos = cosf(radians);
273 | float sin = sinf(radians);
274 |
275 | newPath = CMURPathNewWithSize(path->length);
276 | for (unsigned int i=0; i < path->length; i++) {
277 | GLKVector2 point = path->pointList[i];
278 | float x = (point.x - centroid.x) * cos - (point.y - centroid.y) * sin + centroid.x;
279 | float y = (point.x - centroid.x) * sin + (point.y - centroid.y) * cos + centroid.y;
280 | CMURPathAddPoint(newPath, x, y);
281 | }
282 | }
283 |
284 | return newPath;
285 | }
286 |
287 | CMURRectangle
288 | unistrokeRecognizerBoundingBox(CMURPathRef path)
289 | {
290 | float minX = MAXFLOAT;
291 | float minY = MAXFLOAT;
292 | float maxX = -MAXFLOAT;
293 | float maxY = -MAXFLOAT;
294 |
295 | for (unsigned int i=0; i < path->length; i++) {
296 | if (path->pointList[i].x < minX) minX = path->pointList[i].x;
297 | if (path->pointList[i].x > maxX) maxX = path->pointList[i].x;
298 | if (path->pointList[i].y < minY) minY = path->pointList[i].y;
299 | if (path->pointList[i].y > maxY) maxY = path->pointList[i].y;
300 | }
301 |
302 | CMURRectangle result;
303 | result.x = minX;
304 | result.y = minY;
305 | result.width = maxX - minX;
306 | result.height = maxY - minY;
307 |
308 | return result;
309 | }
310 |
311 | void
312 | unistrokeRecognizerScaleTo(CMURPathRef path, float size)
313 | {
314 | CMURRectangle box = unistrokeRecognizerBoundingBox(path);
315 |
316 | for (unsigned int i=0; i < path->length; i++) {
317 | path->pointList[i].x *= size / box.width;
318 | path->pointList[i].y *= size / box.height;
319 | }
320 | }
321 |
322 | void
323 | unistrokeRecognizerTranslateTo(CMURPathRef path, GLKVector2 k)
324 | {
325 | GLKVector2 centroid = unistrokeRecognizerCentroid(path);
326 |
327 | for (unsigned int i=0; i < path->length; i++) {
328 | path->pointList[i].x += k.x - centroid.x;
329 | path->pointList[i].y += k.y - centroid.y;
330 | }
331 | }
332 |
333 | float
334 | unistrokeRecognizerDistanceAtAngle(CMURPathRef path, CMURTemplateRef template, float radians)
335 | {
336 | CMURPathRef rotatedPath = unistrokeRecognizerRotateBy(path, radians);
337 |
338 | assert(rotatedPath != NULL);
339 | if (rotatedPath == NULL) return MAXFLOAT;
340 |
341 | float d = unistrokeRecognizerPathDistance(rotatedPath, template->path);
342 | CMURPathDelete(rotatedPath);
343 | return d;
344 | }
345 |
346 | float
347 | unistrokeRecognizerPathDistance(CMURPathRef pathA, CMURPathRef pathB)
348 | {
349 | float d = 0.0f;
350 |
351 | assert(pathA->length == pathB->length);
352 |
353 | for (unsigned int i=0; i < pathA->length; i++) {
354 | float distance = GLKVector2Distance(pathA->pointList[i], pathB->pointList[i]);
355 | if (! isnan(distance)) d += distance;
356 | }
357 |
358 | return d / (float)pathA->length;
359 | }
360 |
361 | float
362 | unistrokeRecognizerPathLength(CMURPathRef path)
363 | {
364 | float d = 0.0f;
365 | for (unsigned int i=1; i < path->length; i++)
366 | d += GLKVector2Distance(path->pointList[i - 1], path->pointList[i]);
367 | return d;
368 | }
369 |
370 |
371 | /*
372 | Functions for Protractor
373 | */
374 |
375 | CMURPathRef
376 | unistrokeRecognizerVectorize(CMURPathRef path)
377 | {
378 | float sum = 0.0f;
379 | CMURPathRef vector = CMURPathNew();
380 | for (unsigned int i=0; i < path->length; i++) {
381 | float x = path->pointList[i].x;
382 | float y = path->pointList[i].y;
383 | CMURPathAddPoint(vector, x, y);
384 | sum += path->pointList[i].x * path->pointList[i].x + path->pointList[i].y * path->pointList[i].y;
385 | }
386 | float magnitude = sqrtf(sum);
387 | float invMagnitude = 1.0f / magnitude;
388 |
389 | for (unsigned int i=0; i < vector->length; i++) {
390 | vector->pointList[i] = GLKVector2MultiplyScalar(vector->pointList[i], invMagnitude);
391 | }
392 | return vector;
393 | }
394 |
395 | float
396 | unistrokeRecognizerOptimalCosineDistance(CMURPathRef vector1, CMURPathRef vector2)
397 | {
398 | assert(vector1->length == vector2->length);
399 |
400 | float a = 0.0f;
401 | float b = 0.0f;
402 | for (unsigned int i = 0; i < vector1->length; i++)
403 | {
404 | a += vector1->pointList[i].x * vector2->pointList[i].x + vector1->pointList[i].y * vector2->pointList[i].y;
405 | b += vector1->pointList[i].x * vector2->pointList[i].y - vector1->pointList[i].y * vector2->pointList[i].x;
406 | }
407 | float angle = atanf(b / a);
408 | float z = a * cosf(angle) + b * sinf(angle);
409 | float distance = acosf(z);
410 | return distance;
411 | }
412 |
--------------------------------------------------------------------------------
/GestureKeyboard.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | D460B2B81943CF7600A5D298 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D460B2B71943CF7600A5D298 /* AppDelegate.swift */; };
11 | D460B2BA1943CF7600A5D298 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D460B2B91943CF7600A5D298 /* ViewController.swift */; };
12 | D460B2BD1943CF7600A5D298 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = D460B2BB1943CF7600A5D298 /* Main.storyboard */; };
13 | D460B2BF1943CF7600A5D298 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D460B2BE1943CF7600A5D298 /* Images.xcassets */; };
14 | D460B2CB1943CF7700A5D298 /* GestureKeyboardTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D460B2CA1943CF7700A5D298 /* GestureKeyboardTests.swift */; };
15 | D460B2E01944C09900A5D298 /* CMUnistrokeGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = D460B2D71944C09900A5D298 /* CMUnistrokeGestureRecognizer.m */; };
16 | D460B2E11944C09900A5D298 /* CMUnistrokeGestureResult.m in Sources */ = {isa = PBXBuildFile; fileRef = D460B2D91944C09900A5D298 /* CMUnistrokeGestureResult.m */; };
17 | D460B2E21944C09900A5D298 /* CMUnistrokeRecognizer.c in Sources */ = {isa = PBXBuildFile; fileRef = D460B2DB1944C09900A5D298 /* CMUnistrokeRecognizer.c */; };
18 | D460B2E31944C09900A5D298 /* CMUnistrokeRecognizerTypes.c in Sources */ = {isa = PBXBuildFile; fileRef = D460B2DE1944C09900A5D298 /* CMUnistrokeRecognizerTypes.c */; };
19 | D460B2E81944D69900A5D298 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E71944D69900A5D298 /* Foundation.framework */; };
20 | D460B2EA1944D6A100A5D298 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E91944D6A100A5D298 /* GLKit.framework */; };
21 | D460B2EC1944D6A600A5D298 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2EB1944D6A600A5D298 /* UIKit.framework */; };
22 | D460B2EE1944D6F300A5D298 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2ED1944D6F300A5D298 /* CoreGraphics.framework */; };
23 | D49E3281194528EE001B9BB1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E71944D69900A5D298 /* Foundation.framework */; };
24 | D49E3282194528F2001B9BB1 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E91944D6A100A5D298 /* GLKit.framework */; };
25 | D49E3283194528F5001B9BB1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2EB1944D6A600A5D298 /* UIKit.framework */; };
26 | D49E3284194528FA001B9BB1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2ED1944D6F300A5D298 /* CoreGraphics.framework */; };
27 | D49E328E19454F84001B9BB1 /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D49E328D19454F84001B9BB1 /* KeyboardViewController.swift */; };
28 | D49E329219454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = D49E328919454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex */; };
29 | D49E3298194552C1001B9BB1 /* CMUnistrokeGestureResult.m in Sources */ = {isa = PBXBuildFile; fileRef = D460B2D91944C09900A5D298 /* CMUnistrokeGestureResult.m */; };
30 | D49E3299194552C6001B9BB1 /* CMUnistrokeGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = D460B2D71944C09900A5D298 /* CMUnistrokeGestureRecognizer.m */; };
31 | D49E329A194552CB001B9BB1 /* CMUnistrokeRecognizer.c in Sources */ = {isa = PBXBuildFile; fileRef = D460B2DB1944C09900A5D298 /* CMUnistrokeRecognizer.c */; };
32 | D49E329B194552DA001B9BB1 /* CMUnistrokeRecognizerTypes.c in Sources */ = {isa = PBXBuildFile; fileRef = D460B2DE1944C09900A5D298 /* CMUnistrokeRecognizerTypes.c */; };
33 | D49E329C1946BAE2001B9BB1 /* GLKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E91944D6A100A5D298 /* GLKit.framework */; };
34 | D49E329D1946BAE7001B9BB1 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2E71944D69900A5D298 /* Foundation.framework */; };
35 | D49E329E1946BAEE001B9BB1 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2ED1944D6F300A5D298 /* CoreGraphics.framework */; };
36 | D49E329F1946BAFC001B9BB1 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D460B2EB1944D6A600A5D298 /* UIKit.framework */; };
37 | D49E32B41946E176001B9BB1 /* graffiti_strokes.jpeg in Resources */ = {isa = PBXBuildFile; fileRef = D49E32B31946E176001B9BB1 /* graffiti_strokes.jpeg */; };
38 | D4B4ABBD1947520800052189 /* graffiti.plist in Resources */ = {isa = PBXBuildFile; fileRef = D4B4ABBC1947520800052189 /* graffiti.plist */; };
39 | /* End PBXBuildFile section */
40 |
41 | /* Begin PBXContainerItemProxy section */
42 | D460B2C51943CF7700A5D298 /* PBXContainerItemProxy */ = {
43 | isa = PBXContainerItemProxy;
44 | containerPortal = D460B2AA1943CF7600A5D298 /* Project object */;
45 | proxyType = 1;
46 | remoteGlobalIDString = D460B2B11943CF7600A5D298;
47 | remoteInfo = GestureKeyboard;
48 | };
49 | D49E328F19454F84001B9BB1 /* PBXContainerItemProxy */ = {
50 | isa = PBXContainerItemProxy;
51 | containerPortal = D460B2AA1943CF7600A5D298 /* Project object */;
52 | proxyType = 1;
53 | remoteGlobalIDString = D49E328819454F84001B9BB1;
54 | remoteInfo = GestureKeyboardExtension;
55 | };
56 | D49E329319454F84001B9BB1 /* PBXContainerItemProxy */ = {
57 | isa = PBXContainerItemProxy;
58 | containerPortal = D460B2AA1943CF7600A5D298 /* Project object */;
59 | proxyType = 1;
60 | remoteGlobalIDString = D49E328819454F84001B9BB1;
61 | remoteInfo = GestureKeyboardExtension;
62 | };
63 | /* End PBXContainerItemProxy section */
64 |
65 | /* Begin PBXCopyFilesBuildPhase section */
66 | D49E329119454F84001B9BB1 /* Embed App Extensions */ = {
67 | isa = PBXCopyFilesBuildPhase;
68 | buildActionMask = 2147483647;
69 | dstPath = "";
70 | dstSubfolderSpec = 13;
71 | files = (
72 | D49E329219454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex in Embed App Extensions */,
73 | );
74 | name = "Embed App Extensions";
75 | runOnlyForDeploymentPostprocessing = 0;
76 | };
77 | /* End PBXCopyFilesBuildPhase section */
78 |
79 | /* Begin PBXFileReference section */
80 | D460B2B21943CF7600A5D298 /* GestureKeyboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = GestureKeyboard.app; sourceTree = BUILT_PRODUCTS_DIR; };
81 | D460B2B61943CF7600A5D298 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
82 | D460B2B71943CF7600A5D298 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
83 | D460B2B91943CF7600A5D298 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
84 | D460B2BC1943CF7600A5D298 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
85 | D460B2BE1943CF7600A5D298 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; };
86 | D460B2C41943CF7700A5D298 /* GestureKeyboardTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = GestureKeyboardTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
87 | D460B2C91943CF7700A5D298 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
88 | D460B2CA1943CF7700A5D298 /* GestureKeyboardTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GestureKeyboardTests.swift; sourceTree = ""; };
89 | D460B2D51944C09900A5D298 /* CMUnistrokeGestureRecognizer-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "CMUnistrokeGestureRecognizer-Prefix.pch"; sourceTree = ""; };
90 | D460B2D61944C09900A5D298 /* CMUnistrokeGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMUnistrokeGestureRecognizer.h; sourceTree = ""; };
91 | D460B2D71944C09900A5D298 /* CMUnistrokeGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CMUnistrokeGestureRecognizer.m; sourceTree = ""; };
92 | D460B2D81944C09900A5D298 /* CMUnistrokeGestureResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMUnistrokeGestureResult.h; sourceTree = ""; };
93 | D460B2D91944C09900A5D298 /* CMUnistrokeGestureResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CMUnistrokeGestureResult.m; sourceTree = ""; };
94 | D460B2DB1944C09900A5D298 /* CMUnistrokeRecognizer.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CMUnistrokeRecognizer.c; sourceTree = ""; };
95 | D460B2DC1944C09900A5D298 /* CMUnistrokeRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMUnistrokeRecognizer.h; sourceTree = ""; };
96 | D460B2DD1944C09900A5D298 /* CMUnistrokeRecognizerPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMUnistrokeRecognizerPrivate.h; sourceTree = ""; };
97 | D460B2DE1944C09900A5D298 /* CMUnistrokeRecognizerTypes.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = CMUnistrokeRecognizerTypes.c; sourceTree = ""; };
98 | D460B2DF1944C09900A5D298 /* CMUnistrokeRecognizerTypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CMUnistrokeRecognizerTypes.h; sourceTree = ""; };
99 | D460B2E61944D35A00A5D298 /* GestureKeyboard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "GestureKeyboard-Bridging-Header.h"; path = "../CMUnistrokeGestureRecognizer/GestureKeyboard-Bridging-Header.h"; sourceTree = ""; };
100 | D460B2E71944D69900A5D298 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
101 | D460B2E91944D6A100A5D298 /* GLKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GLKit.framework; path = System/Library/Frameworks/GLKit.framework; sourceTree = SDKROOT; };
102 | D460B2EB1944D6A600A5D298 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
103 | D460B2ED1944D6F300A5D298 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
104 | D49E328919454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
105 | D49E328C19454F84001B9BB1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
106 | D49E328D19454F84001B9BB1 /* KeyboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardViewController.swift; sourceTree = ""; };
107 | D49E32B31946E176001B9BB1 /* graffiti_strokes.jpeg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = graffiti_strokes.jpeg; path = GestureKeyboard/graffiti_strokes.jpeg; sourceTree = ""; };
108 | D4B4ABBC1947520800052189 /* graffiti.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = graffiti.plist; sourceTree = ""; };
109 | /* End PBXFileReference section */
110 |
111 | /* Begin PBXFrameworksBuildPhase section */
112 | D460B2AF1943CF7600A5D298 /* Frameworks */ = {
113 | isa = PBXFrameworksBuildPhase;
114 | buildActionMask = 2147483647;
115 | files = (
116 | D460B2E81944D69900A5D298 /* Foundation.framework in Frameworks */,
117 | D460B2EE1944D6F300A5D298 /* CoreGraphics.framework in Frameworks */,
118 | D460B2EC1944D6A600A5D298 /* UIKit.framework in Frameworks */,
119 | D460B2EA1944D6A100A5D298 /* GLKit.framework in Frameworks */,
120 | );
121 | runOnlyForDeploymentPostprocessing = 0;
122 | };
123 | D460B2C11943CF7700A5D298 /* Frameworks */ = {
124 | isa = PBXFrameworksBuildPhase;
125 | buildActionMask = 2147483647;
126 | files = (
127 | D49E3284194528FA001B9BB1 /* CoreGraphics.framework in Frameworks */,
128 | D49E3282194528F2001B9BB1 /* GLKit.framework in Frameworks */,
129 | D49E3283194528F5001B9BB1 /* UIKit.framework in Frameworks */,
130 | D49E3281194528EE001B9BB1 /* Foundation.framework in Frameworks */,
131 | );
132 | runOnlyForDeploymentPostprocessing = 0;
133 | };
134 | D49E328619454F84001B9BB1 /* Frameworks */ = {
135 | isa = PBXFrameworksBuildPhase;
136 | buildActionMask = 2147483647;
137 | files = (
138 | D49E329F1946BAFC001B9BB1 /* UIKit.framework in Frameworks */,
139 | D49E329E1946BAEE001B9BB1 /* CoreGraphics.framework in Frameworks */,
140 | D49E329D1946BAE7001B9BB1 /* Foundation.framework in Frameworks */,
141 | D49E329C1946BAE2001B9BB1 /* GLKit.framework in Frameworks */,
142 | );
143 | runOnlyForDeploymentPostprocessing = 0;
144 | };
145 | /* End PBXFrameworksBuildPhase section */
146 |
147 | /* Begin PBXGroup section */
148 | D460B2A91943CF7600A5D298 = {
149 | isa = PBXGroup;
150 | children = (
151 | D4B4ABBC1947520800052189 /* graffiti.plist */,
152 | D49E32B31946E176001B9BB1 /* graffiti_strokes.jpeg */,
153 | D460B2ED1944D6F300A5D298 /* CoreGraphics.framework */,
154 | D460B2EB1944D6A600A5D298 /* UIKit.framework */,
155 | D460B2E91944D6A100A5D298 /* GLKit.framework */,
156 | D460B2E71944D69900A5D298 /* Foundation.framework */,
157 | D460B2D41944C09900A5D298 /* CMUnistrokeGestureRecognizer */,
158 | D460B2B41943CF7600A5D298 /* GestureKeyboard */,
159 | D460B2C71943CF7700A5D298 /* GestureKeyboardTests */,
160 | D49E328A19454F84001B9BB1 /* GestureKeyboardExtension */,
161 | D460B2B31943CF7600A5D298 /* Products */,
162 | );
163 | sourceTree = "";
164 | };
165 | D460B2B31943CF7600A5D298 /* Products */ = {
166 | isa = PBXGroup;
167 | children = (
168 | D460B2B21943CF7600A5D298 /* GestureKeyboard.app */,
169 | D460B2C41943CF7700A5D298 /* GestureKeyboardTests.xctest */,
170 | D49E328919454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex */,
171 | );
172 | name = Products;
173 | sourceTree = "";
174 | };
175 | D460B2B41943CF7600A5D298 /* GestureKeyboard */ = {
176 | isa = PBXGroup;
177 | children = (
178 | D460B2E61944D35A00A5D298 /* GestureKeyboard-Bridging-Header.h */,
179 | D460B2B71943CF7600A5D298 /* AppDelegate.swift */,
180 | D460B2B91943CF7600A5D298 /* ViewController.swift */,
181 | D460B2BB1943CF7600A5D298 /* Main.storyboard */,
182 | D460B2BE1943CF7600A5D298 /* Images.xcassets */,
183 | D460B2B51943CF7600A5D298 /* Supporting Files */,
184 | );
185 | path = GestureKeyboard;
186 | sourceTree = "";
187 | };
188 | D460B2B51943CF7600A5D298 /* Supporting Files */ = {
189 | isa = PBXGroup;
190 | children = (
191 | D460B2B61943CF7600A5D298 /* Info.plist */,
192 | );
193 | name = "Supporting Files";
194 | sourceTree = "";
195 | };
196 | D460B2C71943CF7700A5D298 /* GestureKeyboardTests */ = {
197 | isa = PBXGroup;
198 | children = (
199 | D460B2CA1943CF7700A5D298 /* GestureKeyboardTests.swift */,
200 | D460B2C81943CF7700A5D298 /* Supporting Files */,
201 | );
202 | path = GestureKeyboardTests;
203 | sourceTree = "";
204 | };
205 | D460B2C81943CF7700A5D298 /* Supporting Files */ = {
206 | isa = PBXGroup;
207 | children = (
208 | D460B2C91943CF7700A5D298 /* Info.plist */,
209 | );
210 | name = "Supporting Files";
211 | sourceTree = "";
212 | };
213 | D460B2D41944C09900A5D298 /* CMUnistrokeGestureRecognizer */ = {
214 | isa = PBXGroup;
215 | children = (
216 | D460B2D51944C09900A5D298 /* CMUnistrokeGestureRecognizer-Prefix.pch */,
217 | D460B2D61944C09900A5D298 /* CMUnistrokeGestureRecognizer.h */,
218 | D460B2D71944C09900A5D298 /* CMUnistrokeGestureRecognizer.m */,
219 | D460B2D81944C09900A5D298 /* CMUnistrokeGestureResult.h */,
220 | D460B2D91944C09900A5D298 /* CMUnistrokeGestureResult.m */,
221 | D460B2DA1944C09900A5D298 /* CMUnistrokeRecognizer */,
222 | );
223 | path = CMUnistrokeGestureRecognizer;
224 | sourceTree = "";
225 | };
226 | D460B2DA1944C09900A5D298 /* CMUnistrokeRecognizer */ = {
227 | isa = PBXGroup;
228 | children = (
229 | D460B2DB1944C09900A5D298 /* CMUnistrokeRecognizer.c */,
230 | D460B2DC1944C09900A5D298 /* CMUnistrokeRecognizer.h */,
231 | D460B2DD1944C09900A5D298 /* CMUnistrokeRecognizerPrivate.h */,
232 | D460B2DE1944C09900A5D298 /* CMUnistrokeRecognizerTypes.c */,
233 | D460B2DF1944C09900A5D298 /* CMUnistrokeRecognizerTypes.h */,
234 | );
235 | path = CMUnistrokeRecognizer;
236 | sourceTree = "";
237 | };
238 | D49E328A19454F84001B9BB1 /* GestureKeyboardExtension */ = {
239 | isa = PBXGroup;
240 | children = (
241 | D49E328D19454F84001B9BB1 /* KeyboardViewController.swift */,
242 | D49E328B19454F84001B9BB1 /* Supporting Files */,
243 | );
244 | path = GestureKeyboardExtension;
245 | sourceTree = "";
246 | };
247 | D49E328B19454F84001B9BB1 /* Supporting Files */ = {
248 | isa = PBXGroup;
249 | children = (
250 | D49E328C19454F84001B9BB1 /* Info.plist */,
251 | );
252 | name = "Supporting Files";
253 | sourceTree = "";
254 | };
255 | /* End PBXGroup section */
256 |
257 | /* Begin PBXNativeTarget section */
258 | D460B2B11943CF7600A5D298 /* GestureKeyboard */ = {
259 | isa = PBXNativeTarget;
260 | buildConfigurationList = D460B2CE1943CF7700A5D298 /* Build configuration list for PBXNativeTarget "GestureKeyboard" */;
261 | buildPhases = (
262 | D460B2AE1943CF7600A5D298 /* Sources */,
263 | D460B2AF1943CF7600A5D298 /* Frameworks */,
264 | D460B2B01943CF7600A5D298 /* Resources */,
265 | D49E329119454F84001B9BB1 /* Embed App Extensions */,
266 | );
267 | buildRules = (
268 | );
269 | dependencies = (
270 | D49E329019454F84001B9BB1 /* PBXTargetDependency */,
271 | D49E329419454F84001B9BB1 /* PBXTargetDependency */,
272 | );
273 | name = GestureKeyboard;
274 | productName = GestureKeyboard;
275 | productReference = D460B2B21943CF7600A5D298 /* GestureKeyboard.app */;
276 | productType = "com.apple.product-type.application";
277 | };
278 | D460B2C31943CF7700A5D298 /* GestureKeyboardTests */ = {
279 | isa = PBXNativeTarget;
280 | buildConfigurationList = D460B2D11943CF7700A5D298 /* Build configuration list for PBXNativeTarget "GestureKeyboardTests" */;
281 | buildPhases = (
282 | D460B2C01943CF7700A5D298 /* Sources */,
283 | D460B2C11943CF7700A5D298 /* Frameworks */,
284 | D460B2C21943CF7700A5D298 /* Resources */,
285 | );
286 | buildRules = (
287 | );
288 | dependencies = (
289 | D460B2C61943CF7700A5D298 /* PBXTargetDependency */,
290 | );
291 | name = GestureKeyboardTests;
292 | productName = GestureKeyboardTests;
293 | productReference = D460B2C41943CF7700A5D298 /* GestureKeyboardTests.xctest */;
294 | productType = "com.apple.product-type.bundle.unit-test";
295 | };
296 | D49E328819454F84001B9BB1 /* GestureKeyboardExtension */ = {
297 | isa = PBXNativeTarget;
298 | buildConfigurationList = D49E329519454F84001B9BB1 /* Build configuration list for PBXNativeTarget "GestureKeyboardExtension" */;
299 | buildPhases = (
300 | D49E328519454F84001B9BB1 /* Sources */,
301 | D49E328619454F84001B9BB1 /* Frameworks */,
302 | D49E328719454F84001B9BB1 /* Resources */,
303 | );
304 | buildRules = (
305 | );
306 | dependencies = (
307 | );
308 | name = GestureKeyboardExtension;
309 | productName = GestureKeyboardExtension;
310 | productReference = D49E328919454F84001B9BB1 /* com.touchcentric.GestureKeyboard.GestureKeyboardExtension.appex */;
311 | productType = "com.apple.product-type.app-extension";
312 | };
313 | /* End PBXNativeTarget section */
314 |
315 | /* Begin PBXProject section */
316 | D460B2AA1943CF7600A5D298 /* Project object */ = {
317 | isa = PBXProject;
318 | attributes = {
319 | LastUpgradeCheck = 0600;
320 | ORGANIZATIONNAME = TouchCentric;
321 | TargetAttributes = {
322 | D460B2B11943CF7600A5D298 = {
323 | CreatedOnToolsVersion = 6.0;
324 | };
325 | D460B2C31943CF7700A5D298 = {
326 | CreatedOnToolsVersion = 6.0;
327 | TestTargetID = D460B2B11943CF7600A5D298;
328 | };
329 | D49E328819454F84001B9BB1 = {
330 | CreatedOnToolsVersion = 6.0;
331 | };
332 | };
333 | };
334 | buildConfigurationList = D460B2AD1943CF7600A5D298 /* Build configuration list for PBXProject "GestureKeyboard" */;
335 | compatibilityVersion = "Xcode 3.2";
336 | developmentRegion = English;
337 | hasScannedForEncodings = 0;
338 | knownRegions = (
339 | en,
340 | Base,
341 | );
342 | mainGroup = D460B2A91943CF7600A5D298;
343 | productRefGroup = D460B2B31943CF7600A5D298 /* Products */;
344 | projectDirPath = "";
345 | projectRoot = "";
346 | targets = (
347 | D460B2B11943CF7600A5D298 /* GestureKeyboard */,
348 | D460B2C31943CF7700A5D298 /* GestureKeyboardTests */,
349 | D49E328819454F84001B9BB1 /* GestureKeyboardExtension */,
350 | );
351 | };
352 | /* End PBXProject section */
353 |
354 | /* Begin PBXResourcesBuildPhase section */
355 | D460B2B01943CF7600A5D298 /* Resources */ = {
356 | isa = PBXResourcesBuildPhase;
357 | buildActionMask = 2147483647;
358 | files = (
359 | D460B2BD1943CF7600A5D298 /* Main.storyboard in Resources */,
360 | D460B2BF1943CF7600A5D298 /* Images.xcassets in Resources */,
361 | D49E32B41946E176001B9BB1 /* graffiti_strokes.jpeg in Resources */,
362 | D4B4ABBD1947520800052189 /* graffiti.plist in Resources */,
363 | );
364 | runOnlyForDeploymentPostprocessing = 0;
365 | };
366 | D460B2C21943CF7700A5D298 /* Resources */ = {
367 | isa = PBXResourcesBuildPhase;
368 | buildActionMask = 2147483647;
369 | files = (
370 | );
371 | runOnlyForDeploymentPostprocessing = 0;
372 | };
373 | D49E328719454F84001B9BB1 /* Resources */ = {
374 | isa = PBXResourcesBuildPhase;
375 | buildActionMask = 2147483647;
376 | files = (
377 | );
378 | runOnlyForDeploymentPostprocessing = 0;
379 | };
380 | /* End PBXResourcesBuildPhase section */
381 |
382 | /* Begin PBXSourcesBuildPhase section */
383 | D460B2AE1943CF7600A5D298 /* Sources */ = {
384 | isa = PBXSourcesBuildPhase;
385 | buildActionMask = 2147483647;
386 | files = (
387 | D460B2BA1943CF7600A5D298 /* ViewController.swift in Sources */,
388 | D460B2E21944C09900A5D298 /* CMUnistrokeRecognizer.c in Sources */,
389 | D460B2E31944C09900A5D298 /* CMUnistrokeRecognizerTypes.c in Sources */,
390 | D460B2E01944C09900A5D298 /* CMUnistrokeGestureRecognizer.m in Sources */,
391 | D460B2B81943CF7600A5D298 /* AppDelegate.swift in Sources */,
392 | D460B2E11944C09900A5D298 /* CMUnistrokeGestureResult.m in Sources */,
393 | );
394 | runOnlyForDeploymentPostprocessing = 0;
395 | };
396 | D460B2C01943CF7700A5D298 /* Sources */ = {
397 | isa = PBXSourcesBuildPhase;
398 | buildActionMask = 2147483647;
399 | files = (
400 | D460B2CB1943CF7700A5D298 /* GestureKeyboardTests.swift in Sources */,
401 | );
402 | runOnlyForDeploymentPostprocessing = 0;
403 | };
404 | D49E328519454F84001B9BB1 /* Sources */ = {
405 | isa = PBXSourcesBuildPhase;
406 | buildActionMask = 2147483647;
407 | files = (
408 | D49E329B194552DA001B9BB1 /* CMUnistrokeRecognizerTypes.c in Sources */,
409 | D49E329A194552CB001B9BB1 /* CMUnistrokeRecognizer.c in Sources */,
410 | D49E328E19454F84001B9BB1 /* KeyboardViewController.swift in Sources */,
411 | D49E3299194552C6001B9BB1 /* CMUnistrokeGestureRecognizer.m in Sources */,
412 | D49E3298194552C1001B9BB1 /* CMUnistrokeGestureResult.m in Sources */,
413 | );
414 | runOnlyForDeploymentPostprocessing = 0;
415 | };
416 | /* End PBXSourcesBuildPhase section */
417 |
418 | /* Begin PBXTargetDependency section */
419 | D460B2C61943CF7700A5D298 /* PBXTargetDependency */ = {
420 | isa = PBXTargetDependency;
421 | target = D460B2B11943CF7600A5D298 /* GestureKeyboard */;
422 | targetProxy = D460B2C51943CF7700A5D298 /* PBXContainerItemProxy */;
423 | };
424 | D49E329019454F84001B9BB1 /* PBXTargetDependency */ = {
425 | isa = PBXTargetDependency;
426 | target = D49E328819454F84001B9BB1 /* GestureKeyboardExtension */;
427 | targetProxy = D49E328F19454F84001B9BB1 /* PBXContainerItemProxy */;
428 | };
429 | D49E329419454F84001B9BB1 /* PBXTargetDependency */ = {
430 | isa = PBXTargetDependency;
431 | target = D49E328819454F84001B9BB1 /* GestureKeyboardExtension */;
432 | targetProxy = D49E329319454F84001B9BB1 /* PBXContainerItemProxy */;
433 | };
434 | /* End PBXTargetDependency section */
435 |
436 | /* Begin PBXVariantGroup section */
437 | D460B2BB1943CF7600A5D298 /* Main.storyboard */ = {
438 | isa = PBXVariantGroup;
439 | children = (
440 | D460B2BC1943CF7600A5D298 /* Base */,
441 | );
442 | name = Main.storyboard;
443 | sourceTree = "";
444 | };
445 | /* End PBXVariantGroup section */
446 |
447 | /* Begin XCBuildConfiguration section */
448 | D460B2CC1943CF7700A5D298 /* Debug */ = {
449 | isa = XCBuildConfiguration;
450 | buildSettings = {
451 | ALWAYS_SEARCH_USER_PATHS = NO;
452 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
453 | CLANG_CXX_LIBRARY = "libc++";
454 | CLANG_ENABLE_MODULES = NO;
455 | CLANG_ENABLE_OBJC_ARC = YES;
456 | CLANG_WARN_BOOL_CONVERSION = YES;
457 | CLANG_WARN_CONSTANT_CONVERSION = YES;
458 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
459 | CLANG_WARN_EMPTY_BODY = YES;
460 | CLANG_WARN_ENUM_CONVERSION = YES;
461 | CLANG_WARN_INT_CONVERSION = YES;
462 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
463 | CLANG_WARN_UNREACHABLE_CODE = YES;
464 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
465 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
466 | COPY_PHASE_STRIP = NO;
467 | ENABLE_STRICT_OBJC_MSGSEND = YES;
468 | GCC_C_LANGUAGE_STANDARD = "compiler-default";
469 | GCC_DYNAMIC_NO_PIC = NO;
470 | GCC_OPTIMIZATION_LEVEL = 0;
471 | GCC_PREPROCESSOR_DEFINITIONS = (
472 | "DEBUG=1",
473 | "$(inherited)",
474 | );
475 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
476 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
477 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
478 | GCC_WARN_UNDECLARED_SELECTOR = YES;
479 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
480 | GCC_WARN_UNUSED_FUNCTION = YES;
481 | GCC_WARN_UNUSED_VARIABLE = YES;
482 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
483 | METAL_ENABLE_DEBUG_INFO = YES;
484 | ONLY_ACTIVE_ARCH = YES;
485 | PRODUCT_MODULE_NAME = GestureKeyboard;
486 | SDKROOT = iphoneos8.0;
487 | SWIFT_OBJC_BRIDGING_HEADER = "CMUnistrokeGestureRecognizer/GestureKeyboard-Bridging-Header.h";
488 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
489 | TARGETED_DEVICE_FAMILY = "1,2";
490 | };
491 | name = Debug;
492 | };
493 | D460B2CD1943CF7700A5D298 /* Release */ = {
494 | isa = XCBuildConfiguration;
495 | buildSettings = {
496 | ALWAYS_SEARCH_USER_PATHS = NO;
497 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
498 | CLANG_CXX_LIBRARY = "libc++";
499 | CLANG_ENABLE_MODULES = NO;
500 | CLANG_ENABLE_OBJC_ARC = YES;
501 | CLANG_WARN_BOOL_CONVERSION = YES;
502 | CLANG_WARN_CONSTANT_CONVERSION = YES;
503 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
504 | CLANG_WARN_EMPTY_BODY = YES;
505 | CLANG_WARN_ENUM_CONVERSION = YES;
506 | CLANG_WARN_INT_CONVERSION = YES;
507 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
508 | CLANG_WARN_UNREACHABLE_CODE = YES;
509 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
510 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
511 | COPY_PHASE_STRIP = YES;
512 | ENABLE_NS_ASSERTIONS = NO;
513 | ENABLE_STRICT_OBJC_MSGSEND = YES;
514 | GCC_C_LANGUAGE_STANDARD = "compiler-default";
515 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
516 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
517 | GCC_WARN_UNDECLARED_SELECTOR = YES;
518 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
519 | GCC_WARN_UNUSED_FUNCTION = YES;
520 | GCC_WARN_UNUSED_VARIABLE = YES;
521 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
522 | METAL_ENABLE_DEBUG_INFO = NO;
523 | ONLY_ACTIVE_ARCH = YES;
524 | PRODUCT_MODULE_NAME = GestureKeyboard;
525 | SDKROOT = iphoneos8.0;
526 | SWIFT_OBJC_BRIDGING_HEADER = "CMUnistrokeGestureRecognizer/GestureKeyboard-Bridging-Header.h";
527 | TARGETED_DEVICE_FAMILY = "1,2";
528 | VALIDATE_PRODUCT = YES;
529 | };
530 | name = Release;
531 | };
532 | D460B2CF1943CF7700A5D298 /* Debug */ = {
533 | isa = XCBuildConfiguration;
534 | buildSettings = {
535 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
536 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
537 | INFOPLIST_FILE = GestureKeyboard/Info.plist;
538 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
539 | PRODUCT_NAME = "$(TARGET_NAME)";
540 | };
541 | name = Debug;
542 | };
543 | D460B2D01943CF7700A5D298 /* Release */ = {
544 | isa = XCBuildConfiguration;
545 | buildSettings = {
546 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
547 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage;
548 | INFOPLIST_FILE = GestureKeyboard/Info.plist;
549 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
550 | PRODUCT_NAME = "$(TARGET_NAME)";
551 | };
552 | name = Release;
553 | };
554 | D460B2D21943CF7700A5D298 /* Debug */ = {
555 | isa = XCBuildConfiguration;
556 | buildSettings = {
557 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/GestureKeyboard.app/GestureKeyboard";
558 | FRAMEWORK_SEARCH_PATHS = (
559 | "$(SDKROOT)/Developer/Library/Frameworks",
560 | "$(inherited)",
561 | );
562 | GCC_PREPROCESSOR_DEFINITIONS = (
563 | "DEBUG=1",
564 | "$(inherited)",
565 | );
566 | INFOPLIST_FILE = GestureKeyboardTests/Info.plist;
567 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
568 | METAL_ENABLE_DEBUG_INFO = YES;
569 | PRODUCT_NAME = "$(TARGET_NAME)";
570 | TEST_HOST = "$(BUNDLE_LOADER)";
571 | };
572 | name = Debug;
573 | };
574 | D460B2D31943CF7700A5D298 /* Release */ = {
575 | isa = XCBuildConfiguration;
576 | buildSettings = {
577 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/GestureKeyboard.app/GestureKeyboard";
578 | FRAMEWORK_SEARCH_PATHS = (
579 | "$(SDKROOT)/Developer/Library/Frameworks",
580 | "$(inherited)",
581 | );
582 | INFOPLIST_FILE = GestureKeyboardTests/Info.plist;
583 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
584 | METAL_ENABLE_DEBUG_INFO = NO;
585 | PRODUCT_NAME = "$(TARGET_NAME)";
586 | TEST_HOST = "$(BUNDLE_LOADER)";
587 | };
588 | name = Release;
589 | };
590 | D49E329619454F84001B9BB1 /* Debug */ = {
591 | isa = XCBuildConfiguration;
592 | buildSettings = {
593 | CLANG_ENABLE_MODULES = NO;
594 | GCC_C_LANGUAGE_STANDARD = gnu99;
595 | GCC_PREPROCESSOR_DEFINITIONS = (
596 | "DEBUG=1",
597 | "$(inherited)",
598 | );
599 | INFOPLIST_FILE = GestureKeyboardExtension/Info.plist;
600 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
601 | METAL_ENABLE_DEBUG_INFO = YES;
602 | PRODUCT_NAME = "com.touchcentric.GestureKeyboard.$(TARGET_NAME:rfc1034identifier)";
603 | SKIP_INSTALL = YES;
604 | };
605 | name = Debug;
606 | };
607 | D49E329719454F84001B9BB1 /* Release */ = {
608 | isa = XCBuildConfiguration;
609 | buildSettings = {
610 | CLANG_ENABLE_MODULES = NO;
611 | GCC_C_LANGUAGE_STANDARD = gnu99;
612 | INFOPLIST_FILE = GestureKeyboardExtension/Info.plist;
613 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
614 | METAL_ENABLE_DEBUG_INFO = NO;
615 | PRODUCT_NAME = "com.touchcentric.GestureKeyboard.$(TARGET_NAME:rfc1034identifier)";
616 | SKIP_INSTALL = YES;
617 | };
618 | name = Release;
619 | };
620 | /* End XCBuildConfiguration section */
621 |
622 | /* Begin XCConfigurationList section */
623 | D460B2AD1943CF7600A5D298 /* Build configuration list for PBXProject "GestureKeyboard" */ = {
624 | isa = XCConfigurationList;
625 | buildConfigurations = (
626 | D460B2CC1943CF7700A5D298 /* Debug */,
627 | D460B2CD1943CF7700A5D298 /* Release */,
628 | );
629 | defaultConfigurationIsVisible = 0;
630 | defaultConfigurationName = Release;
631 | };
632 | D460B2CE1943CF7700A5D298 /* Build configuration list for PBXNativeTarget "GestureKeyboard" */ = {
633 | isa = XCConfigurationList;
634 | buildConfigurations = (
635 | D460B2CF1943CF7700A5D298 /* Debug */,
636 | D460B2D01943CF7700A5D298 /* Release */,
637 | );
638 | defaultConfigurationIsVisible = 0;
639 | defaultConfigurationName = Release;
640 | };
641 | D460B2D11943CF7700A5D298 /* Build configuration list for PBXNativeTarget "GestureKeyboardTests" */ = {
642 | isa = XCConfigurationList;
643 | buildConfigurations = (
644 | D460B2D21943CF7700A5D298 /* Debug */,
645 | D460B2D31943CF7700A5D298 /* Release */,
646 | );
647 | defaultConfigurationIsVisible = 0;
648 | defaultConfigurationName = Release;
649 | };
650 | D49E329519454F84001B9BB1 /* Build configuration list for PBXNativeTarget "GestureKeyboardExtension" */ = {
651 | isa = XCConfigurationList;
652 | buildConfigurations = (
653 | D49E329619454F84001B9BB1 /* Debug */,
654 | D49E329719454F84001B9BB1 /* Release */,
655 | );
656 | defaultConfigurationIsVisible = 0;
657 | defaultConfigurationName = Release;
658 | };
659 | /* End XCConfigurationList section */
660 | };
661 | rootObject = D460B2AA1943CF7600A5D298 /* Project object */;
662 | }
663 |
--------------------------------------------------------------------------------