├── ExtraKeyboard.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ │ └── mahsa.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── mahsa.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ └── xcschememanagement.plist ├── ExtraKeyboard ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── ExtraKeyboard │ ├── extraKeyBoard.h │ ├── extraKeyBoard.m │ └── extraKeyBoard.xib ├── GrowingTextView │ ├── containerView.h │ ├── containerView.m │ ├── customTextView.h │ └── customTextView.m ├── Info.plist ├── TextInputView │ ├── TextInPutView.h │ ├── TextInPutView.m │ ├── TextInPutView.xib │ └── smile.png ├── ViewController.h ├── ViewController.m └── main.m ├── ExtraKeyboardTests ├── ExtraKeyboardTests.m └── Info.plist ├── ExtraKeyboardUITests ├── ExtraKeyboardUITests.m └── Info.plist └── README.md /ExtraKeyboard.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 50; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1941CCB621059EAC00583D7C /* extraKeyBoard.m in Sources */ = {isa = PBXBuildFile; fileRef = 1941CCB521059EAC00583D7C /* extraKeyBoard.m */; }; 11 | 1941CCB821059F3800583D7C /* smile.png in Resources */ = {isa = PBXBuildFile; fileRef = 1941CCB721059F3700583D7C /* smile.png */; }; 12 | 19DDF1072104929900C06A1D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF1062104929900C06A1D /* AppDelegate.m */; }; 13 | 19DDF10A2104929900C06A1D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF1092104929900C06A1D /* ViewController.m */; }; 14 | 19DDF10D2104929900C06A1D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 19DDF10B2104929900C06A1D /* Main.storyboard */; }; 15 | 19DDF10F2104929A00C06A1D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19DDF10E2104929A00C06A1D /* Assets.xcassets */; }; 16 | 19DDF1122104929A00C06A1D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 19DDF1102104929A00C06A1D /* LaunchScreen.storyboard */; }; 17 | 19DDF1152104929A00C06A1D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF1142104929A00C06A1D /* main.m */; }; 18 | 19DDF11F2104929A00C06A1D /* ExtraKeyboardTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF11E2104929A00C06A1D /* ExtraKeyboardTests.m */; }; 19 | 19DDF12A2104929A00C06A1D /* ExtraKeyboardUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF1292104929A00C06A1D /* ExtraKeyboardUITests.m */; }; 20 | 19DDF13C210492F500C06A1D /* customTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF138210492F500C06A1D /* customTextView.m */; }; 21 | 19DDF13D210492F500C06A1D /* containerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF139210492F500C06A1D /* containerView.m */; }; 22 | 19DDF1422104931200C06A1D /* TextInPutView.m in Sources */ = {isa = PBXBuildFile; fileRef = 19DDF1402104931200C06A1D /* TextInPutView.m */; }; 23 | 19DDF1432104931200C06A1D /* TextInPutView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 19DDF1412104931200C06A1D /* TextInPutView.xib */; }; 24 | 19DDF14E2104962B00C06A1D /* extraKeyBoard.xib in Resources */ = {isa = PBXBuildFile; fileRef = 19DDF1452104962A00C06A1D /* extraKeyBoard.xib */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 19DDF11B2104929A00C06A1D /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 19DDF0FA2104929800C06A1D /* Project object */; 31 | proxyType = 1; 32 | remoteGlobalIDString = 19DDF1012104929900C06A1D; 33 | remoteInfo = ExtraKeyboard; 34 | }; 35 | 19DDF1262104929A00C06A1D /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 19DDF0FA2104929800C06A1D /* Project object */; 38 | proxyType = 1; 39 | remoteGlobalIDString = 19DDF1012104929900C06A1D; 40 | remoteInfo = ExtraKeyboard; 41 | }; 42 | /* End PBXContainerItemProxy section */ 43 | 44 | /* Begin PBXFileReference section */ 45 | 1941CCB421059EAB00583D7C /* extraKeyBoard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = extraKeyBoard.h; sourceTree = ""; }; 46 | 1941CCB521059EAC00583D7C /* extraKeyBoard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = extraKeyBoard.m; sourceTree = ""; }; 47 | 1941CCB721059F3700583D7C /* smile.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = smile.png; sourceTree = ""; }; 48 | 19DDF1022104929900C06A1D /* ExtraKeyboard.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ExtraKeyboard.app; sourceTree = BUILT_PRODUCTS_DIR; }; 49 | 19DDF1052104929900C06A1D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 50 | 19DDF1062104929900C06A1D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 51 | 19DDF1082104929900C06A1D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 52 | 19DDF1092104929900C06A1D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 53 | 19DDF10C2104929900C06A1D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 54 | 19DDF10E2104929A00C06A1D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 55 | 19DDF1112104929A00C06A1D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 56 | 19DDF1132104929A00C06A1D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 57 | 19DDF1142104929A00C06A1D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 58 | 19DDF11A2104929A00C06A1D /* ExtraKeyboardTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExtraKeyboardTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 59 | 19DDF11E2104929A00C06A1D /* ExtraKeyboardTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtraKeyboardTests.m; sourceTree = ""; }; 60 | 19DDF1202104929A00C06A1D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 61 | 19DDF1252104929A00C06A1D /* ExtraKeyboardUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExtraKeyboardUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 62 | 19DDF1292104929A00C06A1D /* ExtraKeyboardUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtraKeyboardUITests.m; sourceTree = ""; }; 63 | 19DDF12B2104929A00C06A1D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 64 | 19DDF138210492F500C06A1D /* customTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = customTextView.m; sourceTree = ""; }; 65 | 19DDF139210492F500C06A1D /* containerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = containerView.m; sourceTree = ""; }; 66 | 19DDF13A210492F500C06A1D /* customTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = customTextView.h; sourceTree = ""; }; 67 | 19DDF13B210492F500C06A1D /* containerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = containerView.h; sourceTree = ""; }; 68 | 19DDF13F2104931200C06A1D /* TextInPutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TextInPutView.h; sourceTree = ""; }; 69 | 19DDF1402104931200C06A1D /* TextInPutView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TextInPutView.m; sourceTree = ""; }; 70 | 19DDF1412104931200C06A1D /* TextInPutView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = TextInPutView.xib; sourceTree = ""; }; 71 | 19DDF1452104962A00C06A1D /* extraKeyBoard.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = extraKeyBoard.xib; sourceTree = ""; }; 72 | /* End PBXFileReference section */ 73 | 74 | /* Begin PBXFrameworksBuildPhase section */ 75 | 19DDF0FF2104929900C06A1D /* Frameworks */ = { 76 | isa = PBXFrameworksBuildPhase; 77 | buildActionMask = 2147483647; 78 | files = ( 79 | ); 80 | runOnlyForDeploymentPostprocessing = 0; 81 | }; 82 | 19DDF1172104929A00C06A1D /* Frameworks */ = { 83 | isa = PBXFrameworksBuildPhase; 84 | buildActionMask = 2147483647; 85 | files = ( 86 | ); 87 | runOnlyForDeploymentPostprocessing = 0; 88 | }; 89 | 19DDF1222104929A00C06A1D /* Frameworks */ = { 90 | isa = PBXFrameworksBuildPhase; 91 | buildActionMask = 2147483647; 92 | files = ( 93 | ); 94 | runOnlyForDeploymentPostprocessing = 0; 95 | }; 96 | /* End PBXFrameworksBuildPhase section */ 97 | 98 | /* Begin PBXGroup section */ 99 | 19DDF0F92104929800C06A1D = { 100 | isa = PBXGroup; 101 | children = ( 102 | 19DDF1042104929900C06A1D /* ExtraKeyboard */, 103 | 19DDF11D2104929A00C06A1D /* ExtraKeyboardTests */, 104 | 19DDF1282104929A00C06A1D /* ExtraKeyboardUITests */, 105 | 19DDF1032104929900C06A1D /* Products */, 106 | ); 107 | sourceTree = ""; 108 | }; 109 | 19DDF1032104929900C06A1D /* Products */ = { 110 | isa = PBXGroup; 111 | children = ( 112 | 19DDF1022104929900C06A1D /* ExtraKeyboard.app */, 113 | 19DDF11A2104929A00C06A1D /* ExtraKeyboardTests.xctest */, 114 | 19DDF1252104929A00C06A1D /* ExtraKeyboardUITests.xctest */, 115 | ); 116 | name = Products; 117 | sourceTree = ""; 118 | }; 119 | 19DDF1042104929900C06A1D /* ExtraKeyboard */ = { 120 | isa = PBXGroup; 121 | children = ( 122 | 19DDF1442104938E00C06A1D /* ExtraKeyboard */, 123 | 19DDF13E210492F900C06A1D /* TextInputView */, 124 | 19DDF137210492A200C06A1D /* GrowingTextView */, 125 | 19DDF1052104929900C06A1D /* AppDelegate.h */, 126 | 19DDF1062104929900C06A1D /* AppDelegate.m */, 127 | 19DDF1082104929900C06A1D /* ViewController.h */, 128 | 19DDF1092104929900C06A1D /* ViewController.m */, 129 | 19DDF10B2104929900C06A1D /* Main.storyboard */, 130 | 19DDF10E2104929A00C06A1D /* Assets.xcassets */, 131 | 19DDF1102104929A00C06A1D /* LaunchScreen.storyboard */, 132 | 19DDF1132104929A00C06A1D /* Info.plist */, 133 | 19DDF1142104929A00C06A1D /* main.m */, 134 | ); 135 | path = ExtraKeyboard; 136 | sourceTree = ""; 137 | }; 138 | 19DDF11D2104929A00C06A1D /* ExtraKeyboardTests */ = { 139 | isa = PBXGroup; 140 | children = ( 141 | 19DDF11E2104929A00C06A1D /* ExtraKeyboardTests.m */, 142 | 19DDF1202104929A00C06A1D /* Info.plist */, 143 | ); 144 | path = ExtraKeyboardTests; 145 | sourceTree = ""; 146 | }; 147 | 19DDF1282104929A00C06A1D /* ExtraKeyboardUITests */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 19DDF1292104929A00C06A1D /* ExtraKeyboardUITests.m */, 151 | 19DDF12B2104929A00C06A1D /* Info.plist */, 152 | ); 153 | path = ExtraKeyboardUITests; 154 | sourceTree = ""; 155 | }; 156 | 19DDF137210492A200C06A1D /* GrowingTextView */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | 19DDF13B210492F500C06A1D /* containerView.h */, 160 | 19DDF139210492F500C06A1D /* containerView.m */, 161 | 19DDF13A210492F500C06A1D /* customTextView.h */, 162 | 19DDF138210492F500C06A1D /* customTextView.m */, 163 | ); 164 | path = GrowingTextView; 165 | sourceTree = ""; 166 | }; 167 | 19DDF13E210492F900C06A1D /* TextInputView */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | 19DDF13F2104931200C06A1D /* TextInPutView.h */, 171 | 1941CCB721059F3700583D7C /* smile.png */, 172 | 19DDF1402104931200C06A1D /* TextInPutView.m */, 173 | 19DDF1412104931200C06A1D /* TextInPutView.xib */, 174 | ); 175 | path = TextInputView; 176 | sourceTree = ""; 177 | }; 178 | 19DDF1442104938E00C06A1D /* ExtraKeyboard */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | 1941CCB421059EAB00583D7C /* extraKeyBoard.h */, 182 | 1941CCB521059EAC00583D7C /* extraKeyBoard.m */, 183 | 19DDF1452104962A00C06A1D /* extraKeyBoard.xib */, 184 | ); 185 | path = ExtraKeyboard; 186 | sourceTree = ""; 187 | }; 188 | /* End PBXGroup section */ 189 | 190 | /* Begin PBXNativeTarget section */ 191 | 19DDF1012104929900C06A1D /* ExtraKeyboard */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 19DDF12E2104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboard" */; 194 | buildPhases = ( 195 | 19DDF0FE2104929900C06A1D /* Sources */, 196 | 19DDF0FF2104929900C06A1D /* Frameworks */, 197 | 19DDF1002104929900C06A1D /* Resources */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | ); 203 | name = ExtraKeyboard; 204 | productName = ExtraKeyboard; 205 | productReference = 19DDF1022104929900C06A1D /* ExtraKeyboard.app */; 206 | productType = "com.apple.product-type.application"; 207 | }; 208 | 19DDF1192104929A00C06A1D /* ExtraKeyboardTests */ = { 209 | isa = PBXNativeTarget; 210 | buildConfigurationList = 19DDF1312104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboardTests" */; 211 | buildPhases = ( 212 | 19DDF1162104929A00C06A1D /* Sources */, 213 | 19DDF1172104929A00C06A1D /* Frameworks */, 214 | 19DDF1182104929A00C06A1D /* Resources */, 215 | ); 216 | buildRules = ( 217 | ); 218 | dependencies = ( 219 | 19DDF11C2104929A00C06A1D /* PBXTargetDependency */, 220 | ); 221 | name = ExtraKeyboardTests; 222 | productName = ExtraKeyboardTests; 223 | productReference = 19DDF11A2104929A00C06A1D /* ExtraKeyboardTests.xctest */; 224 | productType = "com.apple.product-type.bundle.unit-test"; 225 | }; 226 | 19DDF1242104929A00C06A1D /* ExtraKeyboardUITests */ = { 227 | isa = PBXNativeTarget; 228 | buildConfigurationList = 19DDF1342104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboardUITests" */; 229 | buildPhases = ( 230 | 19DDF1212104929A00C06A1D /* Sources */, 231 | 19DDF1222104929A00C06A1D /* Frameworks */, 232 | 19DDF1232104929A00C06A1D /* Resources */, 233 | ); 234 | buildRules = ( 235 | ); 236 | dependencies = ( 237 | 19DDF1272104929A00C06A1D /* PBXTargetDependency */, 238 | ); 239 | name = ExtraKeyboardUITests; 240 | productName = ExtraKeyboardUITests; 241 | productReference = 19DDF1252104929A00C06A1D /* ExtraKeyboardUITests.xctest */; 242 | productType = "com.apple.product-type.bundle.ui-testing"; 243 | }; 244 | /* End PBXNativeTarget section */ 245 | 246 | /* Begin PBXProject section */ 247 | 19DDF0FA2104929800C06A1D /* Project object */ = { 248 | isa = PBXProject; 249 | attributes = { 250 | LastUpgradeCheck = 0940; 251 | ORGANIZATIONNAME = Mahsa; 252 | TargetAttributes = { 253 | 19DDF1012104929900C06A1D = { 254 | CreatedOnToolsVersion = 9.4; 255 | }; 256 | 19DDF1192104929A00C06A1D = { 257 | CreatedOnToolsVersion = 9.4; 258 | TestTargetID = 19DDF1012104929900C06A1D; 259 | }; 260 | 19DDF1242104929A00C06A1D = { 261 | CreatedOnToolsVersion = 9.4; 262 | TestTargetID = 19DDF1012104929900C06A1D; 263 | }; 264 | }; 265 | }; 266 | buildConfigurationList = 19DDF0FD2104929800C06A1D /* Build configuration list for PBXProject "ExtraKeyboard" */; 267 | compatibilityVersion = "Xcode 9.3"; 268 | developmentRegion = en; 269 | hasScannedForEncodings = 0; 270 | knownRegions = ( 271 | en, 272 | Base, 273 | ); 274 | mainGroup = 19DDF0F92104929800C06A1D; 275 | productRefGroup = 19DDF1032104929900C06A1D /* Products */; 276 | projectDirPath = ""; 277 | projectRoot = ""; 278 | targets = ( 279 | 19DDF1012104929900C06A1D /* ExtraKeyboard */, 280 | 19DDF1192104929A00C06A1D /* ExtraKeyboardTests */, 281 | 19DDF1242104929A00C06A1D /* ExtraKeyboardUITests */, 282 | ); 283 | }; 284 | /* End PBXProject section */ 285 | 286 | /* Begin PBXResourcesBuildPhase section */ 287 | 19DDF1002104929900C06A1D /* Resources */ = { 288 | isa = PBXResourcesBuildPhase; 289 | buildActionMask = 2147483647; 290 | files = ( 291 | 19DDF1122104929A00C06A1D /* LaunchScreen.storyboard in Resources */, 292 | 19DDF10F2104929A00C06A1D /* Assets.xcassets in Resources */, 293 | 19DDF1432104931200C06A1D /* TextInPutView.xib in Resources */, 294 | 19DDF10D2104929900C06A1D /* Main.storyboard in Resources */, 295 | 1941CCB821059F3800583D7C /* smile.png in Resources */, 296 | 19DDF14E2104962B00C06A1D /* extraKeyBoard.xib in Resources */, 297 | ); 298 | runOnlyForDeploymentPostprocessing = 0; 299 | }; 300 | 19DDF1182104929A00C06A1D /* Resources */ = { 301 | isa = PBXResourcesBuildPhase; 302 | buildActionMask = 2147483647; 303 | files = ( 304 | ); 305 | runOnlyForDeploymentPostprocessing = 0; 306 | }; 307 | 19DDF1232104929A00C06A1D /* Resources */ = { 308 | isa = PBXResourcesBuildPhase; 309 | buildActionMask = 2147483647; 310 | files = ( 311 | ); 312 | runOnlyForDeploymentPostprocessing = 0; 313 | }; 314 | /* End PBXResourcesBuildPhase section */ 315 | 316 | /* Begin PBXSourcesBuildPhase section */ 317 | 19DDF0FE2104929900C06A1D /* Sources */ = { 318 | isa = PBXSourcesBuildPhase; 319 | buildActionMask = 2147483647; 320 | files = ( 321 | 19DDF10A2104929900C06A1D /* ViewController.m in Sources */, 322 | 1941CCB621059EAC00583D7C /* extraKeyBoard.m in Sources */, 323 | 19DDF1152104929A00C06A1D /* main.m in Sources */, 324 | 19DDF1422104931200C06A1D /* TextInPutView.m in Sources */, 325 | 19DDF13C210492F500C06A1D /* customTextView.m in Sources */, 326 | 19DDF13D210492F500C06A1D /* containerView.m in Sources */, 327 | 19DDF1072104929900C06A1D /* AppDelegate.m in Sources */, 328 | ); 329 | runOnlyForDeploymentPostprocessing = 0; 330 | }; 331 | 19DDF1162104929A00C06A1D /* Sources */ = { 332 | isa = PBXSourcesBuildPhase; 333 | buildActionMask = 2147483647; 334 | files = ( 335 | 19DDF11F2104929A00C06A1D /* ExtraKeyboardTests.m in Sources */, 336 | ); 337 | runOnlyForDeploymentPostprocessing = 0; 338 | }; 339 | 19DDF1212104929A00C06A1D /* Sources */ = { 340 | isa = PBXSourcesBuildPhase; 341 | buildActionMask = 2147483647; 342 | files = ( 343 | 19DDF12A2104929A00C06A1D /* ExtraKeyboardUITests.m in Sources */, 344 | ); 345 | runOnlyForDeploymentPostprocessing = 0; 346 | }; 347 | /* End PBXSourcesBuildPhase section */ 348 | 349 | /* Begin PBXTargetDependency section */ 350 | 19DDF11C2104929A00C06A1D /* PBXTargetDependency */ = { 351 | isa = PBXTargetDependency; 352 | target = 19DDF1012104929900C06A1D /* ExtraKeyboard */; 353 | targetProxy = 19DDF11B2104929A00C06A1D /* PBXContainerItemProxy */; 354 | }; 355 | 19DDF1272104929A00C06A1D /* PBXTargetDependency */ = { 356 | isa = PBXTargetDependency; 357 | target = 19DDF1012104929900C06A1D /* ExtraKeyboard */; 358 | targetProxy = 19DDF1262104929A00C06A1D /* PBXContainerItemProxy */; 359 | }; 360 | /* End PBXTargetDependency section */ 361 | 362 | /* Begin PBXVariantGroup section */ 363 | 19DDF10B2104929900C06A1D /* Main.storyboard */ = { 364 | isa = PBXVariantGroup; 365 | children = ( 366 | 19DDF10C2104929900C06A1D /* Base */, 367 | ); 368 | name = Main.storyboard; 369 | sourceTree = ""; 370 | }; 371 | 19DDF1102104929A00C06A1D /* LaunchScreen.storyboard */ = { 372 | isa = PBXVariantGroup; 373 | children = ( 374 | 19DDF1112104929A00C06A1D /* Base */, 375 | ); 376 | name = LaunchScreen.storyboard; 377 | sourceTree = ""; 378 | }; 379 | /* End PBXVariantGroup section */ 380 | 381 | /* Begin XCBuildConfiguration section */ 382 | 19DDF12C2104929A00C06A1D /* Debug */ = { 383 | isa = XCBuildConfiguration; 384 | buildSettings = { 385 | ALWAYS_SEARCH_USER_PATHS = NO; 386 | CLANG_ANALYZER_NONNULL = YES; 387 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 388 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 389 | CLANG_CXX_LIBRARY = "libc++"; 390 | CLANG_ENABLE_MODULES = YES; 391 | CLANG_ENABLE_OBJC_ARC = YES; 392 | CLANG_ENABLE_OBJC_WEAK = YES; 393 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 394 | CLANG_WARN_BOOL_CONVERSION = YES; 395 | CLANG_WARN_COMMA = YES; 396 | CLANG_WARN_CONSTANT_CONVERSION = YES; 397 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 398 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 399 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 400 | CLANG_WARN_EMPTY_BODY = YES; 401 | CLANG_WARN_ENUM_CONVERSION = YES; 402 | CLANG_WARN_INFINITE_RECURSION = YES; 403 | CLANG_WARN_INT_CONVERSION = YES; 404 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 405 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 406 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 407 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 408 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 409 | CLANG_WARN_STRICT_PROTOTYPES = YES; 410 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 411 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 412 | CLANG_WARN_UNREACHABLE_CODE = YES; 413 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 414 | CODE_SIGN_IDENTITY = "iPhone Developer"; 415 | COPY_PHASE_STRIP = NO; 416 | DEBUG_INFORMATION_FORMAT = dwarf; 417 | ENABLE_STRICT_OBJC_MSGSEND = YES; 418 | ENABLE_TESTABILITY = YES; 419 | GCC_C_LANGUAGE_STANDARD = gnu11; 420 | GCC_DYNAMIC_NO_PIC = NO; 421 | GCC_NO_COMMON_BLOCKS = YES; 422 | GCC_OPTIMIZATION_LEVEL = 0; 423 | GCC_PREPROCESSOR_DEFINITIONS = ( 424 | "DEBUG=1", 425 | "$(inherited)", 426 | ); 427 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 428 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 429 | GCC_WARN_UNDECLARED_SELECTOR = YES; 430 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 431 | GCC_WARN_UNUSED_FUNCTION = YES; 432 | GCC_WARN_UNUSED_VARIABLE = YES; 433 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 434 | MTL_ENABLE_DEBUG_INFO = YES; 435 | ONLY_ACTIVE_ARCH = YES; 436 | SDKROOT = iphoneos; 437 | }; 438 | name = Debug; 439 | }; 440 | 19DDF12D2104929A00C06A1D /* Release */ = { 441 | isa = XCBuildConfiguration; 442 | buildSettings = { 443 | ALWAYS_SEARCH_USER_PATHS = NO; 444 | CLANG_ANALYZER_NONNULL = YES; 445 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; 446 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; 447 | CLANG_CXX_LIBRARY = "libc++"; 448 | CLANG_ENABLE_MODULES = YES; 449 | CLANG_ENABLE_OBJC_ARC = YES; 450 | CLANG_ENABLE_OBJC_WEAK = YES; 451 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 452 | CLANG_WARN_BOOL_CONVERSION = YES; 453 | CLANG_WARN_COMMA = YES; 454 | CLANG_WARN_CONSTANT_CONVERSION = YES; 455 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 456 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 457 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 458 | CLANG_WARN_EMPTY_BODY = YES; 459 | CLANG_WARN_ENUM_CONVERSION = YES; 460 | CLANG_WARN_INFINITE_RECURSION = YES; 461 | CLANG_WARN_INT_CONVERSION = YES; 462 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 463 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 464 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 465 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 466 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 467 | CLANG_WARN_STRICT_PROTOTYPES = YES; 468 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 469 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; 470 | CLANG_WARN_UNREACHABLE_CODE = YES; 471 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 472 | CODE_SIGN_IDENTITY = "iPhone Developer"; 473 | COPY_PHASE_STRIP = NO; 474 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 475 | ENABLE_NS_ASSERTIONS = NO; 476 | ENABLE_STRICT_OBJC_MSGSEND = YES; 477 | GCC_C_LANGUAGE_STANDARD = gnu11; 478 | GCC_NO_COMMON_BLOCKS = YES; 479 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 480 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 481 | GCC_WARN_UNDECLARED_SELECTOR = YES; 482 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 483 | GCC_WARN_UNUSED_FUNCTION = YES; 484 | GCC_WARN_UNUSED_VARIABLE = YES; 485 | IPHONEOS_DEPLOYMENT_TARGET = 11.4; 486 | MTL_ENABLE_DEBUG_INFO = NO; 487 | SDKROOT = iphoneos; 488 | VALIDATE_PRODUCT = YES; 489 | }; 490 | name = Release; 491 | }; 492 | 19DDF12F2104929A00C06A1D /* Debug */ = { 493 | isa = XCBuildConfiguration; 494 | buildSettings = { 495 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 496 | CODE_SIGN_STYLE = Automatic; 497 | DEVELOPMENT_TEAM = BNTDTT947L; 498 | INFOPLIST_FILE = ExtraKeyboard/Info.plist; 499 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 500 | LD_RUNPATH_SEARCH_PATHS = ( 501 | "$(inherited)", 502 | "@executable_path/Frameworks", 503 | ); 504 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboard; 505 | PRODUCT_NAME = "$(TARGET_NAME)"; 506 | TARGETED_DEVICE_FAMILY = "1,2"; 507 | }; 508 | name = Debug; 509 | }; 510 | 19DDF1302104929A00C06A1D /* Release */ = { 511 | isa = XCBuildConfiguration; 512 | buildSettings = { 513 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 514 | CODE_SIGN_STYLE = Automatic; 515 | DEVELOPMENT_TEAM = BNTDTT947L; 516 | INFOPLIST_FILE = ExtraKeyboard/Info.plist; 517 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 518 | LD_RUNPATH_SEARCH_PATHS = ( 519 | "$(inherited)", 520 | "@executable_path/Frameworks", 521 | ); 522 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboard; 523 | PRODUCT_NAME = "$(TARGET_NAME)"; 524 | TARGETED_DEVICE_FAMILY = "1,2"; 525 | }; 526 | name = Release; 527 | }; 528 | 19DDF1322104929A00C06A1D /* Debug */ = { 529 | isa = XCBuildConfiguration; 530 | buildSettings = { 531 | BUNDLE_LOADER = "$(TEST_HOST)"; 532 | CODE_SIGN_STYLE = Automatic; 533 | INFOPLIST_FILE = ExtraKeyboardTests/Info.plist; 534 | LD_RUNPATH_SEARCH_PATHS = ( 535 | "$(inherited)", 536 | "@executable_path/Frameworks", 537 | "@loader_path/Frameworks", 538 | ); 539 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboardTests; 540 | PRODUCT_NAME = "$(TARGET_NAME)"; 541 | TARGETED_DEVICE_FAMILY = "1,2"; 542 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExtraKeyboard.app/ExtraKeyboard"; 543 | }; 544 | name = Debug; 545 | }; 546 | 19DDF1332104929A00C06A1D /* Release */ = { 547 | isa = XCBuildConfiguration; 548 | buildSettings = { 549 | BUNDLE_LOADER = "$(TEST_HOST)"; 550 | CODE_SIGN_STYLE = Automatic; 551 | INFOPLIST_FILE = ExtraKeyboardTests/Info.plist; 552 | LD_RUNPATH_SEARCH_PATHS = ( 553 | "$(inherited)", 554 | "@executable_path/Frameworks", 555 | "@loader_path/Frameworks", 556 | ); 557 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboardTests; 558 | PRODUCT_NAME = "$(TARGET_NAME)"; 559 | TARGETED_DEVICE_FAMILY = "1,2"; 560 | TEST_HOST = "$(BUILT_PRODUCTS_DIR)/ExtraKeyboard.app/ExtraKeyboard"; 561 | }; 562 | name = Release; 563 | }; 564 | 19DDF1352104929A00C06A1D /* Debug */ = { 565 | isa = XCBuildConfiguration; 566 | buildSettings = { 567 | CODE_SIGN_STYLE = Automatic; 568 | INFOPLIST_FILE = ExtraKeyboardUITests/Info.plist; 569 | LD_RUNPATH_SEARCH_PATHS = ( 570 | "$(inherited)", 571 | "@executable_path/Frameworks", 572 | "@loader_path/Frameworks", 573 | ); 574 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboardUITests; 575 | PRODUCT_NAME = "$(TARGET_NAME)"; 576 | TARGETED_DEVICE_FAMILY = "1,2"; 577 | TEST_TARGET_NAME = ExtraKeyboard; 578 | }; 579 | name = Debug; 580 | }; 581 | 19DDF1362104929A00C06A1D /* Release */ = { 582 | isa = XCBuildConfiguration; 583 | buildSettings = { 584 | CODE_SIGN_STYLE = Automatic; 585 | INFOPLIST_FILE = ExtraKeyboardUITests/Info.plist; 586 | LD_RUNPATH_SEARCH_PATHS = ( 587 | "$(inherited)", 588 | "@executable_path/Frameworks", 589 | "@loader_path/Frameworks", 590 | ); 591 | PRODUCT_BUNDLE_IDENTIFIER = MM.ExtraKeyboardUITests; 592 | PRODUCT_NAME = "$(TARGET_NAME)"; 593 | TARGETED_DEVICE_FAMILY = "1,2"; 594 | TEST_TARGET_NAME = ExtraKeyboard; 595 | }; 596 | name = Release; 597 | }; 598 | /* End XCBuildConfiguration section */ 599 | 600 | /* Begin XCConfigurationList section */ 601 | 19DDF0FD2104929800C06A1D /* Build configuration list for PBXProject "ExtraKeyboard" */ = { 602 | isa = XCConfigurationList; 603 | buildConfigurations = ( 604 | 19DDF12C2104929A00C06A1D /* Debug */, 605 | 19DDF12D2104929A00C06A1D /* Release */, 606 | ); 607 | defaultConfigurationIsVisible = 0; 608 | defaultConfigurationName = Release; 609 | }; 610 | 19DDF12E2104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboard" */ = { 611 | isa = XCConfigurationList; 612 | buildConfigurations = ( 613 | 19DDF12F2104929A00C06A1D /* Debug */, 614 | 19DDF1302104929A00C06A1D /* Release */, 615 | ); 616 | defaultConfigurationIsVisible = 0; 617 | defaultConfigurationName = Release; 618 | }; 619 | 19DDF1312104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboardTests" */ = { 620 | isa = XCConfigurationList; 621 | buildConfigurations = ( 622 | 19DDF1322104929A00C06A1D /* Debug */, 623 | 19DDF1332104929A00C06A1D /* Release */, 624 | ); 625 | defaultConfigurationIsVisible = 0; 626 | defaultConfigurationName = Release; 627 | }; 628 | 19DDF1342104929A00C06A1D /* Build configuration list for PBXNativeTarget "ExtraKeyboardUITests" */ = { 629 | isa = XCConfigurationList; 630 | buildConfigurations = ( 631 | 19DDF1352104929A00C06A1D /* Debug */, 632 | 19DDF1362104929A00C06A1D /* Release */, 633 | ); 634 | defaultConfigurationIsVisible = 0; 635 | defaultConfigurationName = Release; 636 | }; 637 | /* End XCConfigurationList section */ 638 | }; 639 | rootObject = 19DDF0FA2104929800C06A1D /* Project object */; 640 | } 641 | -------------------------------------------------------------------------------- /ExtraKeyboard.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ExtraKeyboard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ExtraKeyboard.xcodeproj/project.xcworkspace/xcuserdata/mahsa.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engmahsa/iOS-ExtraKeyboard/72e5fb3d20491dac557eafd224c3748fad8122af/ExtraKeyboard.xcodeproj/project.xcworkspace/xcuserdata/mahsa.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /ExtraKeyboard.xcodeproj/xcuserdata/mahsa.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 8 | 18 | 19 | 20 | 22 | 34 | 35 | 36 | 38 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /ExtraKeyboard.xcodeproj/xcuserdata/mahsa.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | ExtraKeyboard.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /ExtraKeyboard/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // ExtraKeyboard 4 | // 5 | // Created by Mahsa on. 6 | // 7 | 8 | #import 9 | 10 | @interface AppDelegate : UIResponder 11 | 12 | @property (strong, nonatomic) UIWindow *window; 13 | 14 | 15 | @end 16 | 17 | -------------------------------------------------------------------------------- /ExtraKeyboard/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // ExtraKeyboard 4 | // 5 | // Created by Mahsa. 6 | 7 | #import "AppDelegate.h" 8 | 9 | @interface AppDelegate () 10 | 11 | @end 12 | 13 | @implementation AppDelegate 14 | 15 | 16 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 17 | // Override point for customization after application launch. 18 | return YES; 19 | } 20 | 21 | 22 | - (void)applicationWillResignActive:(UIApplication *)application { 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 invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | 34 | - (void)applicationWillEnterForeground:(UIApplication *)application { 35 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 36 | } 37 | 38 | 39 | - (void)applicationDidBecomeActive:(UIApplication *)application { 40 | // 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. 41 | } 42 | 43 | 44 | - (void)applicationWillTerminate:(UIApplication *)application { 45 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 46 | } 47 | 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /ExtraKeyboard/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /ExtraKeyboard/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /ExtraKeyboard/Base.lproj/LaunchScreen.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 | -------------------------------------------------------------------------------- /ExtraKeyboard/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 | -------------------------------------------------------------------------------- /ExtraKeyboard/ExtraKeyboard/extraKeyBoard.h: -------------------------------------------------------------------------------- 1 | 2 | // extraKeyBoard.h 3 | // testTexting 4 | // 5 | // Created by Mahsa. 6 | 7 | #import 8 | 9 | 10 | @interface extraKeyBoard : UIView 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /ExtraKeyboard/ExtraKeyboard/extraKeyBoard.m: -------------------------------------------------------------------------------- 1 | // 2 | // extraKeyBoard.m 3 | // testTexting 4 | // 5 | // Created by Mahsa . 6 | 7 | #import "extraKeyBoard.h" 8 | 9 | 10 | 11 | 12 | @implementation extraKeyBoard 13 | 14 | 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ExtraKeyboard/ExtraKeyboard/extraKeyBoard.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /ExtraKeyboard/GrowingTextView/containerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // containerView.h 3 | // customTextView 4 | // 5 | // Created by Mahsa 6 | 7 | #import 8 | #import "customTextView.h" 9 | 10 | 11 | @class containerView; 12 | @class customTextView; 13 | 14 | @protocol containerViewcustomDelegate 15 | @optional 16 | 17 | - (void)customTextView:(containerView *)customTextView willChangeHeight:(float)height; 18 | - (void)textViewPressed; 19 | 20 | @end 21 | 22 | @interface containerView : UIView 23 | 24 | //real class properties 25 | @property int maxNumberOfLines; 26 | @property int minNumberOfLines; 27 | @property (nonatomic, strong) UITextView *internalTextView; 28 | 29 | //uitextview properties 30 | @property(unsafe_unretained) NSObject *customDelegate; 31 | 32 | @property(nonatomic,strong) NSString *text; 33 | @property(nonatomic,strong) UIFont *font; 34 | @property(nonatomic,strong) UIColor *textColor; 35 | @property(nonatomic) NSTextAlignment textAlignment; 36 | @property(nonatomic) NSRange selectedRange; 37 | @property(nonatomic,getter=isEditable) BOOL editable; 38 | @property (nonatomic) UIReturnKeyType returnKeyType; 39 | @property (nonatomic) UIKeyboardType keyboardType; 40 | @property (assign) UIEdgeInsets contentInset; 41 | @property (nonatomic) BOOL isScrollable; 42 | @property(nonatomic) BOOL enablesReturnKeyAutomatically; 43 | 44 | - (BOOL)becomeFirstResponder; 45 | 46 | @end 47 | 48 | -------------------------------------------------------------------------------- /ExtraKeyboard/GrowingTextView/containerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // containerView.m 3 | // customTextView 4 | // 5 | // Created by Mahsa. 6 | 7 | 8 | #import "containerView.h" 9 | #import "customTextView.h" 10 | @interface containerView () { 11 | 12 | customTextView *internalTextView; 13 | int minHeight; 14 | int maxHeight; 15 | int maxNumberOfLines; 16 | int minNumberOfLines; 17 | BOOL animateHeightChange; 18 | NSTimeInterval animationDuration; 19 | NSTextAlignment textAlignment; 20 | NSRange selectedRange; 21 | BOOL editable; 22 | UIDataDetectorTypes dataDetectorTypes; 23 | UIReturnKeyType returnKeyType; 24 | UIKeyboardType keyboardType; 25 | UIEdgeInsets contentInset; 26 | } 27 | 28 | @end 29 | 30 | @interface containerView(private) 31 | -(void)commonInitialiser; 32 | -(void)resizeTextView:(NSInteger)newSizeH; 33 | @end 34 | 35 | @implementation containerView 36 | @synthesize internalTextView; 37 | @synthesize customDelegate; 38 | @synthesize font; 39 | @synthesize textColor; 40 | @synthesize textAlignment; 41 | @synthesize selectedRange; 42 | @synthesize editable; 43 | @synthesize returnKeyType; 44 | 45 | 46 | - (id)initWithCoder:(NSCoder *)aDecoder 47 | { 48 | if ((self = [super initWithCoder:aDecoder])) { 49 | [self commonInitialiser]; 50 | } 51 | return self; 52 | } 53 | 54 | - (id) initWithFrame:(CGRect)frame { 55 | if ((self = [super initWithFrame:frame])) { 56 | [self commonInitialiser]; 57 | } 58 | return self; 59 | } 60 | -(void)commonInitialiser { 61 | [self commonInitialiser:nil]; 62 | } 63 | 64 | -(void)commonInitialiser:(NSTextContainer *)textContainer 65 | { 66 | // Initialization code 67 | CGRect tmpFrame = self.frame; 68 | tmpFrame.origin.y = 0; 69 | tmpFrame.origin.x = 0; 70 | internalTextView = [[customTextView alloc] initWithFrame:tmpFrame textContainer:textContainer]; 71 | internalTextView.delegate = self; 72 | internalTextView.textInternalViewDelegate = self; 73 | internalTextView.scrollEnabled = NO; 74 | internalTextView.font = [UIFont systemFontOfSize:16]; 75 | internalTextView.contentInset = UIEdgeInsetsZero; 76 | internalTextView.showsHorizontalScrollIndicator = NO; 77 | internalTextView.text = @"-"; 78 | internalTextView.contentMode = UIViewContentModeRedraw; 79 | [self addSubview:internalTextView]; 80 | 81 | minHeight = self.internalTextView.frame.size.height; 82 | minNumberOfLines = 1; 83 | animateHeightChange = YES; 84 | animationDuration = 0.1f; 85 | internalTextView.text = @""; 86 | [self setMaxNumberOfLines:3]; 87 | } 88 | 89 | -(CGSize)sizeThatFits:(CGSize)size 90 | { 91 | if (self.text.length == 0) { 92 | size.height = minHeight; 93 | } 94 | return size; 95 | } 96 | 97 | -(void)layoutSubviews 98 | { 99 | [super layoutSubviews]; 100 | 101 | CGRect tmpRect = self.bounds; 102 | tmpRect.origin.y = 0; 103 | tmpRect.origin.x = contentInset.left; 104 | tmpRect.size.width -= contentInset.left + contentInset.right; 105 | 106 | internalTextView.frame = tmpRect; 107 | } 108 | 109 | -(void)setContentInset:(UIEdgeInsets)inset 110 | { 111 | contentInset = inset; 112 | CGRect tmpRect = self.frame; 113 | tmpRect.origin.y = inset.top - inset.bottom; 114 | tmpRect.origin.x = inset.left; 115 | tmpRect.size.width -= inset.left + inset.right; 116 | internalTextView.frame = tmpRect; 117 | [self setMaxNumberOfLines:maxNumberOfLines]; 118 | [self setMinNumberOfLines:minNumberOfLines]; 119 | } 120 | 121 | -(UIEdgeInsets)contentInset 122 | { 123 | return contentInset; 124 | } 125 | 126 | -(void) setMaxNumberOfLines:(int)n 127 | { 128 | if(n == 0 && maxHeight > 0) return; 129 | NSString *saveText = internalTextView.text; 130 | NSString *newText = @"-"; 131 | internalTextView.delegate = nil; 132 | internalTextView.hidden = YES; 133 | 134 | for (int i = 1; i < n; ++i) 135 | newText = [newText stringByAppendingString:@"\n|W|"]; 136 | 137 | internalTextView.text = newText; 138 | maxHeight = [self calculateHeight]; 139 | internalTextView.text = saveText; 140 | internalTextView.hidden = NO; 141 | internalTextView.delegate = self; 142 | 143 | [self sizeToFit]; 144 | 145 | maxNumberOfLines = n; 146 | } 147 | 148 | -(int)maxNumberOfLines 149 | { 150 | return maxNumberOfLines; 151 | } 152 | 153 | - (void)setMaxHeight:(int)height 154 | { 155 | maxHeight = height; 156 | maxNumberOfLines = 0; 157 | } 158 | 159 | -(void)setMinNumberOfLines:(int)m 160 | { 161 | if(m == 0 && minHeight > 0) return; 162 | NSString *saveText = internalTextView.text, *newText = @"-"; 163 | internalTextView.delegate = nil; 164 | internalTextView.hidden = YES; 165 | 166 | for (int i = 1; i < m; ++i) 167 | newText = [newText stringByAppendingString:@"\n|W|"]; 168 | 169 | internalTextView.text = newText; 170 | minHeight = [self calculateHeight]; 171 | internalTextView.text = saveText; 172 | internalTextView.hidden = NO; 173 | internalTextView.delegate = self; 174 | [self sizeToFit]; 175 | minNumberOfLines = m; 176 | } 177 | 178 | -(int)minNumberOfLines 179 | { 180 | return minNumberOfLines; 181 | } 182 | 183 | - (void)setMinHeight:(int)height 184 | { 185 | minHeight = height; 186 | minNumberOfLines = 0; 187 | } 188 | 189 | - (void)textViewDidChange:(UITextView *)textView 190 | { 191 | [self refreshHeight]; 192 | } 193 | 194 | - (void)refreshHeight 195 | { 196 | [self.internalTextView setFont:[UIFont systemFontOfSize:16]]; 197 | NSInteger newSizeH = [self calculateHeight]; 198 | if (newSizeH < minHeight || !internalTextView.hasText) { 199 | newSizeH = minHeight; 200 | } 201 | else if (maxHeight && newSizeH > maxHeight) { 202 | newSizeH = maxHeight; 203 | } 204 | 205 | if (internalTextView.frame.size.height != newSizeH) 206 | { 207 | if (newSizeH >= maxHeight) 208 | { 209 | if(!internalTextView.scrollEnabled){ 210 | internalTextView.scrollEnabled = YES; 211 | [internalTextView flashScrollIndicators]; 212 | } 213 | 214 | } else { 215 | internalTextView.scrollEnabled = NO; 216 | } 217 | 218 | if (newSizeH <= maxHeight) 219 | { 220 | if(animateHeightChange) { 221 | [UIView beginAnimations:@"" context:nil]; 222 | [UIView setAnimationDuration:animationDuration]; 223 | [UIView setAnimationDelegate:self]; 224 | [UIView setAnimationBeginsFromCurrentState:YES]; 225 | [self resizeTextView:newSizeH]; 226 | [UIView commitAnimations]; 227 | } else { 228 | [self resizeTextView:newSizeH]; 229 | } 230 | } 231 | } 232 | } 233 | 234 | - (CGFloat)calculateHeight 235 | { 236 | if ([self respondsToSelector:@selector(snapshotViewAfterScreenUpdates:)]) 237 | { 238 | CGRect frame = self.internalTextView.bounds; 239 | UIEdgeInsets textContainerInsets = self.internalTextView.textContainerInset; 240 | UIEdgeInsets contentInsets = self.internalTextView.contentInset; 241 | 242 | CGFloat leftRightPadding = textContainerInsets.left + textContainerInsets.right + self.internalTextView.textContainer.lineFragmentPadding * 2 + contentInsets.left + contentInsets.right; 243 | CGFloat topBottomPadding = textContainerInsets.top + textContainerInsets.bottom + contentInsets.top + contentInsets.bottom; 244 | 245 | frame.size.width -= leftRightPadding; 246 | frame.size.height -= topBottomPadding; 247 | 248 | //////use attributed text instead of normal text if you want to parse some special character in text 249 | NSAttributedString *textToMeasure = self.internalTextView.attributedText; 250 | NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init]; 251 | [paragraphStyle setLineBreakMode:NSLineBreakByWordWrapping]; 252 | 253 | CGRect size = [textToMeasure boundingRectWithSize:CGSizeMake(CGRectGetWidth(frame), MAXFLOAT) options:NSStringDrawingUsesLineFragmentOrigin context:nil]; 254 | 255 | CGFloat measuredHeight = ceilf(CGRectGetHeight(size) + topBottomPadding); 256 | return measuredHeight; 257 | } 258 | else 259 | { 260 | return self.internalTextView.contentSize.height; 261 | } 262 | 263 | } 264 | 265 | -(void)resizeTextView:(NSInteger)newSizeH 266 | { 267 | if ([customDelegate respondsToSelector:@selector(customTextView:willChangeHeight:)]) { 268 | [customDelegate customTextView:self willChangeHeight:newSizeH]; 269 | } 270 | 271 | CGRect internalTextViewFrame = self.frame; 272 | internalTextViewFrame.size.height = newSizeH; 273 | self.frame = internalTextViewFrame; 274 | 275 | internalTextViewFrame.origin.y = contentInset.top - contentInset.bottom; 276 | internalTextViewFrame.origin.x = contentInset.left; 277 | 278 | if(!CGRectEqualToRect(internalTextView.frame, internalTextViewFrame)) internalTextView.frame = internalTextViewFrame; 279 | } 280 | 281 | - (BOOL)becomeFirstResponder 282 | { 283 | [super becomeFirstResponder]; 284 | return [self.internalTextView becomeFirstResponder]; 285 | } 286 | 287 | -(BOOL)resignFirstResponder 288 | { 289 | [super resignFirstResponder]; 290 | return [internalTextView resignFirstResponder]; 291 | } 292 | 293 | -(BOOL)isFirstResponder 294 | { 295 | return [self.internalTextView isFirstResponder]; 296 | } 297 | 298 | -(void)setText:(NSString *)newText 299 | { 300 | internalTextView.text = newText; 301 | } 302 | 303 | -(NSString*) text 304 | { 305 | return internalTextView.text; 306 | } 307 | 308 | -(void)setFont:(UIFont *)afont 309 | { 310 | internalTextView.font= afont; 311 | 312 | [self setMaxNumberOfLines:maxNumberOfLines]; 313 | [self setMinNumberOfLines:minNumberOfLines]; 314 | } 315 | 316 | -(UIFont *)font 317 | { 318 | return internalTextView.font; 319 | } 320 | 321 | -(void)setTextColor:(UIColor *)color 322 | { 323 | internalTextView.textColor = color; 324 | } 325 | 326 | -(UIColor*)textColor{ 327 | return internalTextView.textColor; 328 | } 329 | 330 | -(void)setBackgroundColor:(UIColor *)backgroundColor 331 | { 332 | [super setBackgroundColor:backgroundColor]; 333 | internalTextView.backgroundColor = backgroundColor; 334 | } 335 | 336 | -(UIColor*)backgroundColor 337 | { 338 | return internalTextView.backgroundColor; 339 | } 340 | 341 | -(void)setTextAlignment:(NSTextAlignment)aligment 342 | { 343 | internalTextView.textAlignment = aligment; 344 | } 345 | 346 | -(NSTextAlignment)textAlignment 347 | { 348 | return internalTextView.textAlignment; 349 | } 350 | 351 | -(void)setSelectedRange:(NSRange)range 352 | { 353 | internalTextView.selectedRange = range; 354 | } 355 | 356 | -(NSRange)selectedRange 357 | { 358 | return internalTextView.selectedRange; 359 | } 360 | 361 | - (void)setIsScrollable:(BOOL)isScrollable 362 | { 363 | internalTextView.scrollEnabled = isScrollable; 364 | } 365 | 366 | - (BOOL)isScrollable 367 | { 368 | return internalTextView.scrollEnabled; 369 | } 370 | 371 | -(void)setEditable:(BOOL)beditable 372 | { 373 | internalTextView.editable = beditable; 374 | } 375 | 376 | -(BOOL)isEditable 377 | { 378 | return internalTextView.editable; 379 | } 380 | 381 | -(void)setReturnKeyType:(UIReturnKeyType)keyType 382 | { 383 | internalTextView.returnKeyType = keyType; 384 | } 385 | 386 | -(UIReturnKeyType)returnKeyType 387 | { 388 | return internalTextView.returnKeyType; 389 | } 390 | 391 | - (void)setKeyboardType:(UIKeyboardType)keyType 392 | { 393 | internalTextView.keyboardType = keyType; 394 | } 395 | 396 | - (UIKeyboardType)keyboardType 397 | { 398 | return internalTextView.keyboardType; 399 | } 400 | 401 | - (void)setEnablesReturnKeyAutomatically:(BOOL)enablesReturnKeyAutomatically 402 | { 403 | internalTextView.enablesReturnKeyAutomatically = enablesReturnKeyAutomatically; 404 | } 405 | 406 | - (BOOL)enablesReturnKeyAutomatically 407 | { 408 | return internalTextView.enablesReturnKeyAutomatically; 409 | } 410 | 411 | -(UIDataDetectorTypes)dataDetectorTypes 412 | { 413 | return internalTextView.dataDetectorTypes; 414 | } 415 | 416 | - (BOOL)hasText{ 417 | return [internalTextView hasText]; 418 | } 419 | 420 | - (void)scrollRangeToVisible:(NSRange)range 421 | { 422 | [internalTextView scrollRangeToVisible:range]; 423 | } 424 | 425 | -(BOOL)textView:(UITextView *)textView shouldInteractWithURL:(NSURL *)URL inRange:(NSRange)characterRange interaction:(UITextItemInteraction)interaction { 426 | return YES; 427 | } 428 | 429 | - (BOOL)canBecomeFirstResponder 430 | { 431 | return YES; 432 | } 433 | 434 | -(void)pastHappendOnTextView{ 435 | 436 | [self refreshHeight]; 437 | } 438 | 439 | -(void)setResponder:(UIResponder *)responder 440 | { 441 | ((customTextView*)self.internalTextView).inputNextResponder = responder; 442 | 443 | } 444 | 445 | -(void)internalTtextFieldPressed 446 | { 447 | [self.customDelegate textViewPressed]; 448 | } 449 | @end 450 | -------------------------------------------------------------------------------- /ExtraKeyboard/GrowingTextView/customTextView.h: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // Created by Mahsa . 4 | // 5 | 6 | #import 7 | 8 | @protocol customTextViewDelegate 9 | 10 | -(void)pastHappendOnTextView; 11 | -(void)internalTtextFieldPressed; 12 | 13 | @end 14 | 15 | @interface customTextView : UITextView 16 | @property (nonatomic, weak) UIResponder *inputNextResponder; 17 | @property(nonatomic,weak)id textInternalViewDelegate; 18 | 19 | 20 | 21 | @end 22 | 23 | 24 | -------------------------------------------------------------------------------- /ExtraKeyboard/GrowingTextView/customTextView.m: -------------------------------------------------------------------------------- 1 | // 2 | // MMTextInternalView.m 3 | // customTextView 4 | // 5 | // Created by Mahsa . 6 | 7 | #import "customTextView.h" 8 | 9 | @interface customTextView () 10 | 11 | @end 12 | 13 | @implementation customTextView 14 | @synthesize textInternalViewDelegate; 15 | @synthesize inputNextResponder; 16 | 17 | -(void)setText:(NSString *)text 18 | { 19 | BOOL originalValue = self.scrollEnabled; 20 | [self setScrollEnabled:YES]; 21 | [super setText:text]; 22 | self.font = [UIFont systemFontOfSize:16]; 23 | [self setScrollEnabled:originalValue]; 24 | } 25 | 26 | - (void)setScrollable:(BOOL)isScrollable 27 | { 28 | [super setScrollEnabled:isScrollable]; 29 | } 30 | 31 | -(void)setContentSize:(CGSize)contentSize 32 | { 33 | if(self.contentSize.height > contentSize.height) 34 | { 35 | UIEdgeInsets insets = self.contentInset; 36 | insets.bottom = 0; 37 | insets.top = 0; 38 | self.contentInset = insets; 39 | } 40 | 41 | [super setContentSize:contentSize]; 42 | } 43 | 44 | - (BOOL)canBecomeFirstResponder 45 | { 46 | return YES; 47 | } 48 | 49 | - (BOOL)becomeFirstResponder 50 | { 51 | return [super becomeFirstResponder]; 52 | } 53 | 54 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender 55 | { 56 | if (inputNextResponder != nil) 57 | return NO; 58 | if (action == @selector(copy:)) 59 | return YES; 60 | else if (action == @selector(paste:)) 61 | return YES; 62 | 63 | return [super canPerformAction:action withSender:sender]; 64 | } 65 | 66 | - (UIResponder *)nextResponder { 67 | if (inputNextResponder != nil) 68 | return inputNextResponder; 69 | else 70 | return [super nextResponder]; 71 | } 72 | - (void)copy:(id)sender 73 | { 74 | NSLog(@"copy : %@" , [UIPasteboard generalPasteboard]); 75 | 76 | if (!self.selectedTextRange.isEmpty) { 77 | 78 | [[UIPasteboard generalPasteboard] setString:self.attributedText.string]; 79 | 80 | }else{ 81 | //////if nothing selected naturally copy nothing... 82 | [[UIPasteboard generalPasteboard] setString:@""]; 83 | } 84 | } 85 | 86 | - (void)paste:(id)sender 87 | { 88 | NSRange range = self.selectedRange; 89 | NSMutableAttributedString *strAtr = [[NSMutableAttributedString alloc] init]; 90 | 91 | NSString *pastString = [[UIPasteboard generalPasteboard] string]; 92 | 93 | if (pastString.length == 0) { 94 | 95 | 96 | //////nothing to past... :) 97 | 98 | }else{ 99 | 100 | if (range.length > 0) { 101 | 102 | NSAttributedString *pastStr = [[NSAttributedString alloc] initWithString:pastString]; 103 | 104 | [strAtr appendAttributedString:pastStr]; 105 | 106 | range.location = range.location + range.length; 107 | range.length = 0; 108 | 109 | }else{ 110 | 111 | NSAttributedString *pastStr = [[NSAttributedString alloc] initWithString:pastString]; 112 | 113 | [strAtr appendAttributedString:pastStr]; 114 | 115 | range.location = pastStr.length; 116 | range.length = 0; 117 | } 118 | 119 | } 120 | 121 | BOOL shouldChangeCursewrToEnd = NO; 122 | if (self.selectedRange.location == self.attributedText.length) { 123 | 124 | shouldChangeCursewrToEnd = YES; 125 | } 126 | 127 | self.attributedText = strAtr; 128 | 129 | if (shouldChangeCursewrToEnd) { 130 | 131 | self.selectedRange = NSMakeRange(strAtr.string.length, 0); 132 | }else{ 133 | self.selectedRange = range; 134 | } 135 | 136 | [self.textInternalViewDelegate pastHappendOnTextView]; 137 | } 138 | 139 | - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event{ 140 | [super touchesCancelled:touches withEvent:event]; 141 | NSLog(@"touchesCancelled"); 142 | [self.textInternalViewDelegate internalTtextFieldPressed]; 143 | 144 | } 145 | 146 | @end 147 | -------------------------------------------------------------------------------- /ExtraKeyboard/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ExtraKeyboard/TextInputView/TextInPutView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TextInPutView.h 3 | // Created by Mahsa 4 | // 5 | 6 | #import 7 | #import "ViewController.h" 8 | #import "containerView.h" 9 | 10 | @protocol TextInputViewDelegete 11 | - (void)didExtraKeyboardButtonPress; 12 | @end 13 | 14 | @interface TextInPutView : UIView 15 | 16 | - (void)initialize; 17 | @property (nonatomic , weak) id customDelegate; 18 | @property (weak, nonatomic) IBOutlet containerView *textView; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /ExtraKeyboard/TextInputView/TextInPutView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TextInPutView.m 3 | // Created by Mahsa. 4 | 5 | #import "TextInPutView.h" 6 | #import 7 | 8 | 9 | @implementation TextInPutView 10 | 11 | -(void)initialize { 12 | 13 | self.textView.isScrollable = NO; 14 | self.textView.contentInset = UIEdgeInsetsMake(0, 5, 0, 5); 15 | self.textView.clipsToBounds = YES; 16 | self.textView.layer.cornerRadius = 8.0f; 17 | self.textView.layer.borderWidth = 1.0; 18 | [self.textView.layer setBorderColor:[[[UIColor grayColor] colorWithAlphaComponent:0.5] CGColor]]; 19 | self.textView.minNumberOfLines = 1; 20 | self.textView.maxNumberOfLines = 6; 21 | self.textView.returnKeyType = UIReturnKeyDefault; 22 | self.textView.font = [UIFont systemFontOfSize:16]; 23 | self.textView.internalTextView.scrollIndicatorInsets = UIEdgeInsetsMake(5, 0, 5, 0); 24 | self.textView.backgroundColor = [UIColor whiteColor]; 25 | } 26 | 27 | - (BOOL)canBecomeFirstResponder 28 | { 29 | return YES; 30 | } 31 | 32 | - (BOOL)becomeFirstResponder 33 | { 34 | return [super becomeFirstResponder]; 35 | } 36 | 37 | - (BOOL)canPerformAction:(SEL)action withSender:(id)sender 38 | { 39 | 40 | if (action == @selector(copy:)) 41 | return YES; 42 | else if (action == @selector(paste:)) 43 | return YES; 44 | 45 | return [super canPerformAction:action withSender:sender]; 46 | } 47 | - (IBAction)sendButtonPressed:(id)sender { 48 | NSLog(@"Send Message"); 49 | } 50 | - (IBAction)extraKeyBoardPressed:(id)sender { 51 | if ([self.customDelegate respondsToSelector:@selector(didExtraKeyboardButtonPress)]) { 52 | 53 | [self.customDelegate didExtraKeyboardButtonPress]; 54 | } 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /ExtraKeyboard/TextInputView/TextInPutView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 37 | 38 | 39 | 40 | 41 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /ExtraKeyboard/TextInputView/smile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/engmahsa/iOS-ExtraKeyboard/72e5fb3d20491dac557eafd224c3748fad8122af/ExtraKeyboard/TextInputView/smile.png -------------------------------------------------------------------------------- /ExtraKeyboard/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // ExtraKeyboard 4 | // 5 | // Created by Mahsa . 6 | // 7 | 8 | #import 9 | 10 | @interface ViewController : UIViewController 11 | 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /ExtraKeyboard/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // 4 | // Created by Mahsa . 5 | // 6 | 7 | #import "ViewController.h" 8 | #import "TextInPutView.h" 9 | #import "containerView.h" 10 | #import "extraKeyBoard.h" 11 | 12 | #define ExtraKeyboardHeight 215 13 | #define TextInputViewHeight 44 14 | 15 | @interface ViewController () < containerViewcustomDelegate , TextInputViewDelegete> { 16 | TextInPutView *inputView; 17 | UIView *keyboardView; 18 | CGRect tempKeyboardFrame; 19 | CGFloat tempKeyboardHeight; 20 | 21 | BOOL isExtraKeybard; 22 | } 23 | 24 | @property (nonatomic, retain) UIView *TextInputViewNib; 25 | @property (nonatomic, strong) containerView *txtField; 26 | @property(nonatomic,strong) extraKeyBoard * extraView; 27 | @property (nonatomic, retain) UIView *ExtraKeyBoardFromNib; 28 | @property (nonatomic, retain) UIView *stickerKeyBoardFromNib; 29 | @end 30 | 31 | @implementation ViewController 32 | 33 | - (void)viewDidLoad { 34 | [super viewDidLoad]; 35 | [self registerXibFiles]; 36 | [self initialiValues]; 37 | } 38 | 39 | -(void)viewWillAppear:(BOOL)animated 40 | { 41 | [super viewWillAppear:animated]; 42 | [self addObservers]; 43 | 44 | } 45 | 46 | -(void)viewDidDisappear:(BOOL)animated 47 | { 48 | [super viewDidDisappear:animated]; 49 | [[NSNotificationCenter defaultCenter] removeObserver:self name:@"TapOnView" object:nil]; 50 | } 51 | 52 | -(void)viewWillDisappear:(BOOL)animated 53 | { 54 | [super viewWillDisappear:animated]; 55 | keyboardView = self.txtField.internalTextView.inputAccessoryView.superview; 56 | } 57 | 58 | -(void)addObservers 59 | { 60 | [[NSNotificationCenter defaultCenter] addObserver:self 61 | selector:@selector(keyboardWillHide:) 62 | name:UIKeyboardWillHideNotification 63 | object:nil]; 64 | [[NSNotificationCenter defaultCenter] addObserver:self 65 | selector:@selector(keyboardWillShow:) 66 | name:UIKeyboardWillShowNotification 67 | object:nil]; 68 | [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(closeKeyboard) name:@"TapOnView" object:nil]; 69 | } 70 | 71 | -(void)closeKeyboard { 72 | 73 | dispatch_async(dispatch_get_main_queue(), ^{ 74 | 75 | [self.view endEditing:YES]; 76 | 77 | self.txtField.internalTextView.inputView = nil; 78 | [self.txtField.internalTextView reloadInputViews]; 79 | }); 80 | } 81 | - (void)initialiValues { 82 | 83 | isExtraKeybard = NO; 84 | keyboardView = self.txtField.internalTextView.inputAccessoryView.superview; 85 | } 86 | 87 | -(void)registerExtraKeyBoardxibFile{ 88 | 89 | NSArray *nibViews = [[NSBundle mainBundle] loadNibNamed:@"extraKeyBoard" 90 | owner:self 91 | options:nil]; 92 | self.extraView = [ nibViews objectAtIndex: 0]; 93 | self.ExtraKeyBoardFromNib =[[UIView alloc] init]; 94 | self.ExtraKeyBoardFromNib = self.extraView; 95 | ////// we need it because sometimes textView inputaccessoryview is empty... 96 | /* DO NOT MISS THE INPUT ACCESSORY*/ 97 | [self.txtField.internalTextView setInputAccessoryView:[[UIView alloc] init]]; 98 | 99 | } 100 | 101 | -(BOOL)isKeyboardFisrtResponder 102 | { 103 | if ([self.txtField.internalTextView isFirstResponder]) { 104 | return YES; 105 | } 106 | return NO; 107 | } 108 | 109 | -(void)registerXibFiles{ 110 | 111 | if (self.TextInputViewNib) { 112 | [self.TextInputViewNib removeFromSuperview]; 113 | self.TextInputViewNib = nil; 114 | } 115 | 116 | NSArray* nbViews = [[NSBundle mainBundle] loadNibNamed:@"TextInPutView" 117 | owner:self 118 | options:nil]; 119 | 120 | TextInPutView *inputTextView = [ nbViews objectAtIndex: 0]; 121 | 122 | self.TextInputViewNib =[[UIView alloc] init]; 123 | [inputTextView initialize]; 124 | self.TextInputViewNib = inputTextView; 125 | ((TextInPutView*)self.TextInputViewNib).customDelegate = self; 126 | 127 | self.txtField = inputTextView.textView; 128 | 129 | 130 | ((TextInPutView*)self.TextInputViewNib).textView.customDelegate = self ; 131 | CGRect toolBarFrame = self.TextInputViewNib.frame; 132 | UIDeviceOrientation nextOrientation = [[UIDevice currentDevice] orientation]; 133 | UIInterfaceOrientation sori = [UIApplication sharedApplication].statusBarOrientation; 134 | if (nextOrientation == UIDeviceOrientationFaceUp && self.view.frame.size.width > self.view.frame.size.height && sori == UIInterfaceOrientationPortrait) { 135 | 136 | toolBarFrame.origin.y = self.view.frame.size.width - TextInputViewHeight; 137 | toolBarFrame.size.width =self.view.frame.size.height; 138 | toolBarFrame.size.height = TextInputViewHeight; 139 | 140 | }else if ((nextOrientation == UIDeviceOrientationLandscapeLeft || nextOrientation == UIDeviceOrientationLandscapeRight) && self.view.frame.size.width < self.view.frame.size.height){ 141 | 142 | toolBarFrame.origin.y = self.view.frame.size.width - TextInputViewHeight; 143 | toolBarFrame.size.width =self.view.frame.size.height; 144 | toolBarFrame.size.height = TextInputViewHeight; 145 | } 146 | else{ 147 | 148 | toolBarFrame.origin.y = self.view.frame.size.height - TextInputViewHeight; 149 | toolBarFrame.size.width =self.view.frame.size.width; 150 | toolBarFrame.size.height = TextInputViewHeight; 151 | } 152 | self.TextInputViewNib.frame = toolBarFrame; 153 | [self.view addSubview:self.TextInputViewNib]; 154 | inputTextView = nil; 155 | [((TextInPutView*)self.TextInputViewNib).textView becomeFirstResponder]; 156 | } 157 | 158 | -(void) keyboardWillShow:(NSNotification *)note{ 159 | 160 | CGRect keyboardBounds; 161 | [[note.userInfo valueForKey:UIKeyboardFrameEndUserInfoKey] getValue: &keyboardBounds]; 162 | NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; 163 | NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; 164 | keyboardBounds = [self.view convertRect:keyboardBounds toView:nil]; 165 | CGRect containerFrame = self.TextInputViewNib.frame; 166 | tempKeyboardHeight = CGRectGetHeight(keyboardBounds); 167 | 168 | containerFrame.origin.y = self.view.bounds.size.height - (keyboardBounds.size.height + containerFrame.size.height); 169 | [UIView beginAnimations:nil context:NULL]; 170 | [UIView setAnimationBeginsFromCurrentState:YES]; 171 | [UIView setAnimationDuration:[duration doubleValue]]; 172 | [UIView setAnimationCurve:[curve intValue]]; 173 | 174 | self.TextInputViewNib.frame = containerFrame; 175 | [UIView commitAnimations]; 176 | } 177 | 178 | -(void) keyboardWillHide:(NSNotification *)note{ 179 | 180 | NSNumber *duration = [note.userInfo objectForKey:UIKeyboardAnimationDurationUserInfoKey]; 181 | NSNumber *curve = [note.userInfo objectForKey:UIKeyboardAnimationCurveUserInfoKey]; 182 | CGRect containerFrame = self.TextInputViewNib.frame; 183 | containerFrame.origin.y = self.view.bounds.size.height - containerFrame.size.height; 184 | [UIView beginAnimations:nil context:NULL]; 185 | [UIView setAnimationBeginsFromCurrentState:YES]; 186 | [UIView setAnimationDuration:[duration doubleValue]]; 187 | [UIView setAnimationCurve:[curve intValue]]; 188 | self.TextInputViewNib.frame = containerFrame; 189 | [UIView commitAnimations]; 190 | 191 | 192 | 193 | } 194 | 195 | - (void)customTextView:(containerView *)customTextView willChangeHeight:(float)height 196 | { 197 | float diff = (customTextView.frame.size.height - height); 198 | 199 | CGRect r = self.TextInputViewNib.frame; 200 | r.size.height -= diff; 201 | r.origin.y += diff; 202 | self.TextInputViewNib.frame = r; 203 | } 204 | 205 | -(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation 206 | { 207 | return YES; 208 | } 209 | 210 | - (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator { 211 | 212 | [UIView animateWithDuration:0.1 animations:^{ 213 | [((TextInPutView*)self.TextInputViewNib).textView resignFirstResponder]; 214 | }]; 215 | 216 | UIInterfaceOrientation sori = [UIApplication sharedApplication].statusBarOrientation; 217 | /* handle textInPutView position in rotation 218 | */ 219 | if (size.height == self.view.frame.size.height ) { 220 | 221 | double refW = self.view.frame.size.height; 222 | double refH = self.view.frame.size.width; 223 | 224 | if (sori == UIInterfaceOrientationPortrait) { 225 | refW = self.view.frame.size.width; 226 | refH = self.view.frame.size.height; 227 | } 228 | 229 | [self.TextInputViewNib removeFromSuperview]; 230 | CGRect toolBarFrame = self.TextInputViewNib.frame; 231 | toolBarFrame.origin.y = refW - toolBarFrame.size.height; 232 | toolBarFrame.size.width =refH; 233 | self.TextInputViewNib.frame = toolBarFrame; 234 | 235 | [self.view addSubview:self.TextInputViewNib]; 236 | 237 | } 238 | 239 | else 240 | { 241 | [self.TextInputViewNib removeFromSuperview]; 242 | CGRect toolBarFrame = self.TextInputViewNib.frame; 243 | toolBarFrame.origin.y = self.view.frame.size.width - toolBarFrame.size.height; 244 | toolBarFrame.size.width =self.view.frame.size.height; 245 | self.TextInputViewNib.frame = toolBarFrame; 246 | [self.view addSubview:self.TextInputViewNib]; 247 | 248 | } 249 | } 250 | 251 | 252 | -(void)extraKeyBoardPressed{ 253 | 254 | [self registerExtraKeyBoardxibFile]; 255 | 256 | if (!isExtraKeybard) { 257 | self.txtField.internalTextView.inputView = self.ExtraKeyBoardFromNib; 258 | [self.ExtraKeyBoardFromNib removeFromSuperview]; 259 | [self.txtField.internalTextView reloadInputViews]; 260 | [self.txtField.internalTextView becomeFirstResponder]; 261 | CGRect toolBarFrame = self.TextInputViewNib.frame; 262 | toolBarFrame.origin.y = self.view.frame.size.height - (self.TextInputViewNib.frame.size.height + ExtraKeyboardHeight); 263 | toolBarFrame.size.width = self.view.frame.size.width; 264 | 265 | self.TextInputViewNib.frame = toolBarFrame; 266 | isExtraKeybard = YES; 267 | } else { 268 | self.txtField.internalTextView.inputView = nil; 269 | [self.txtField.internalTextView reloadInputViews]; 270 | isExtraKeybard =NO; 271 | } 272 | } 273 | 274 | - (void)didExtraKeyboardButtonPress { 275 | 276 | [self extraKeyBoardPressed]; 277 | } 278 | 279 | - (void)textViewPressed { 280 | 281 | self.txtField.internalTextView.inputView = nil; 282 | [self.txtField.internalTextView reloadInputViews]; 283 | isExtraKeybard = NO; 284 | } 285 | @end 286 | -------------------------------------------------------------------------------- /ExtraKeyboard/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ExtraKeyboard 4 | // 5 | // Created by Mahsa on 7/22/18. 6 | // Copyright © 2018 Mahsa. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /ExtraKeyboardTests/ExtraKeyboardTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExtraKeyboardTests.m 3 | // ExtraKeyboardTests 4 | // 5 | // Created by Mahsa . 6 | // 7 | 8 | #import 9 | 10 | @interface ExtraKeyboardTests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation ExtraKeyboardTests 15 | 16 | - (void)setUp { 17 | [super setUp]; 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | } 20 | 21 | - (void)tearDown { 22 | // Put teardown code here. This method is called after the invocation of each test method in the class. 23 | [super tearDown]; 24 | } 25 | 26 | - (void)testExample { 27 | // This is an example of a functional test case. 28 | // Use XCTAssert and related functions to verify your tests produce the correct results. 29 | } 30 | 31 | - (void)testPerformanceExample { 32 | // This is an example of a performance test case. 33 | [self measureBlock:^{ 34 | // Put the code you want to measure the time of here. 35 | }]; 36 | } 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /ExtraKeyboardTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /ExtraKeyboardUITests/ExtraKeyboardUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExtraKeyboardUITests.m 3 | // ExtraKeyboardUITests 4 | // 5 | // Created by Mahsa. 6 | // 7 | 8 | #import 9 | 10 | @interface ExtraKeyboardUITests : XCTestCase 11 | 12 | @end 13 | 14 | @implementation ExtraKeyboardUITests 15 | 16 | - (void)setUp { 17 | [super setUp]; 18 | 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | 21 | // In UI tests it is usually best to stop immediately when a failure occurs. 22 | self.continueAfterFailure = NO; 23 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 24 | [[[XCUIApplication alloc] init] launch]; 25 | 26 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 27 | } 28 | 29 | - (void)tearDown { 30 | // Put teardown code here. This method is called after the invocation of each test method in the class. 31 | [super tearDown]; 32 | } 33 | 34 | - (void)testExample { 35 | // Use recording to get started writing UI tests. 36 | // Use XCTAssert and related functions to verify your tests produce the correct results. 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /ExtraKeyboardUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS-ExtraKeyboard 2 | Customize the standard iOS keyboard to any style you want. 3 | You can create some custom views and use it instead of standard iOS keyboard view. For example in some messaging applications you may need to switch to sticker keyboard or you may want to load your gallery asset in related area .So you can use the code to switch different custom views .I’ve also assign textView to the keyboard to make more similar view to a messaging app. 4 | ![Text](https://user-images.githubusercontent.com/11373016/43132011-bcab41ec-8f4f-11e8-8b73-3c7d8f515227.gif) 5 | --------------------------------------------------------------------------------