diff --git a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj index 5b6b15ba92..876a56dbf4 100644 --- a/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj +++ b/ios/engine/KMEI/KeymanEngine.xcodeproj/project.pbxproj @@ -24,10 +24,7 @@ /* Begin PBXBuildFile section */ 1645D5952036C6FF0076C51B /* KeymanPackage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1645D5942036C6FF0076C51B /* KeymanPackage.swift */; }; 1645D5972036C9F80076C51B /* KMPKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1645D5962036C9F80076C51B /* KMPKeyboard.swift */; }; - 165C8B8D1FD8220600D4A78D /* Zip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 165C8B8B1FD8220600D4A78D /* Zip.framework */; }; 165EB3A12098993900040A69 /* KeyboardError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB3A02098993900040A69 /* KeyboardError.swift */; }; - 1687ACCE1FD8DE5300926D69 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCC1FD8DE5300926D69 /* XCGLogger.framework */; }; - 1687ACCF1FD8DE5300926D69 /* ObjcExceptionBridging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCD1FD8DE5300926D69 /* ObjcExceptionBridging.framework */; }; 6CD5DFAA150F6DC8007A5DDE /* icon.png in Resources */ = {isa = PBXBuildFile; fileRef = 6CD5DFA8150F6DC8007A5DDE /* icon.png */; }; 6CD5DFAB150F6DC8007A5DDE /* icon@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 6CD5DFA9150F6DC8007A5DDE /* icon@2x.png */; }; 988B36B61ADF67290008752C /* inuktitut_pirurvik-1.0.js in Resources */ = {isa = PBXBuildFile; fileRef = 988B36B51ADF67290008752C /* inuktitut_pirurvik-1.0.js */; }; @@ -81,7 +78,6 @@ 9A079E49223F176100581263 /* String+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = C075EB051F8EFF870041F4BD /* String+Helpers.swift */; }; 9A082559227589360051EBB0 /* Formatter+ISODateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A082558227589360051EBB0 /* Formatter+ISODateExtension.swift */; }; 9A08255A227589360051EBB0 /* Formatter+ISODateExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A082558227589360051EBB0 /* Formatter+ISODateExtension.swift */; }; - 9A0FC9FD22D66D9E00D33F86 /* Reachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A0FC9FC22D66D9E00D33F86 /* Reachability.framework */; }; 9A0FCA0422D7C49700D33F86 /* DeviceKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9A0FCA0522D7C49E00D33F86 /* Reachability.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 9A0FC9FC22D66D9E00D33F86 /* Reachability.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 9A0FCA0622D7C4E100D33F86 /* XCGLogger.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1687ACCC1FD8DE5300926D69 /* XCGLogger.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -104,11 +100,9 @@ 9A31E2CE224AE8B100D9A491 /* LexicalModelRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB083224170F700231FB9 /* LexicalModelRepository.swift */; }; 9A31E2CF224AE8B800D9A491 /* LexicalModelRepositoryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB0852241717C00231FB9 /* LexicalModelRepositoryDelegate.swift */; }; 9A31E2D0224AE8BF00D9A491 /* APILexicalModelRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB0812241704800231FB9 /* APILexicalModelRepository.swift */; }; - 9A3B14BB228F592F0052A11F /* LanguageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04C2A6C1F6B7D9A00BA42B6 /* LanguageViewController.swift */; }; 9A3B14BC228F59380052A11F /* LanguageDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C092D8381F6A70C8005C5485 /* LanguageDetailViewController.swift */; }; 9A3B14BD228F593C0052A11F /* LexicalModelPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB07F22416E5400231FB9 /* LexicalModelPickerViewController.swift */; }; 9A3B14BE228F59420052A11F /* LexicalModelInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A4609962241B39B00B0BFD1 /* LexicalModelInfoViewController.swift */; }; - 9A3B14BF228F59450052A11F /* KeyboardInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62141F67C8D500268D03 /* KeyboardInfoViewController.swift */; }; 9A3B14C0228F59490052A11F /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A60764322893A4E003BCFBA /* SettingsViewController.swift */; }; 9A3B14C1228F595A0052A11F /* KeyboardError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB3A02098993900040A69 /* KeyboardError.swift */; }; 9A3B14C3228F59C10052A11F /* KeyboardPickerButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C620F1F67BD4500268D03 /* KeyboardPickerButton.swift */; }; @@ -128,8 +122,6 @@ 9A5091B322B418CA0094B99C /* KeyboardInfoViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62141F67C8D500268D03 /* KeyboardInfoViewController.swift */; }; 9A5091B422B419B10094B99C /* LanguageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04C2A6C1F6B7D9A00BA42B6 /* LanguageViewController.swift */; }; 9A60764422893A4E003BCFBA /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A60764322893A4E003BCFBA /* SettingsViewController.swift */; }; - 9A862D2822B429FB005FE26D /* KeyboardNameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62121F67C31100268D03 /* KeyboardNameTableViewCell.swift */; }; - 9A862D2922B42A0C005FE26D /* LanguageDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C092D8381F6A70C8005C5485 /* LanguageDetailViewController.swift */; }; 9A9CB08022416E5400231FB9 /* LexicalModelPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB07F22416E5400231FB9 /* LexicalModelPickerViewController.swift */; }; 9A9CB0822241704800231FB9 /* APILexicalModelRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB0812241704800231FB9 /* APILexicalModelRepository.swift */; }; 9A9CB084224170F700231FB9 /* LexicalModelRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9A9CB083224170F700231FB9 /* LexicalModelRepository.swift */; }; @@ -214,11 +206,15 @@ CE24ECF021B763740052D291 /* KeymanResponder+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24ECEF21B763740052D291 /* KeymanResponder+Types.swift */; }; CE24ECF121B763740052D291 /* KeymanResponder+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24ECEF21B763740052D291 /* KeymanResponder+Types.swift */; }; CE24ECF221B763740052D291 /* KeymanResponder+Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE24ECEF21B763740052D291 /* KeymanResponder+Types.swift */; }; - CE2B1E4621B60E7C007D092E /* DeviceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; }; CE2B1E4721B60E89007D092E /* DeviceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; }; CE2B1E4821B60E8A007D092E /* DeviceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; }; CE2B1E4A21B60FB1007D092E /* DeviceKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CE67D961228A6F190029F2B5 /* KeyboardCommandStructs.swift in Sources */ = {isa = PBXBuildFile; fileRef = CE67D960228A6F190029F2B5 /* KeyboardCommandStructs.swift */; }; + CE808A48236697BE00713E6B /* DeviceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4521B60E7C007D092E /* DeviceKit.framework */; }; + CE808A4B236697D400713E6B /* ObjcExceptionBridging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCD1FD8DE5300926D69 /* ObjcExceptionBridging.framework */; }; + CE808A4D236697D500713E6B /* Reachability.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9A0FC9FC22D66D9E00D33F86 /* Reachability.framework */; }; + CE808A4F236697D800713E6B /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACCC1FD8DE5300926D69 /* XCGLogger.framework */; }; + CE808A532366980A00713E6B /* Zip.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 165C8B8B1FD8220600D4A78D /* Zip.framework */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -455,11 +451,11 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 9A0FC9FD22D66D9E00D33F86 /* Reachability.framework in Frameworks */, - 1687ACCE1FD8DE5300926D69 /* XCGLogger.framework in Frameworks */, - 1687ACCF1FD8DE5300926D69 /* ObjcExceptionBridging.framework in Frameworks */, - 165C8B8D1FD8220600D4A78D /* Zip.framework in Frameworks */, - CE2B1E4621B60E7C007D092E /* DeviceKit.framework in Frameworks */, + CE808A532366980A00713E6B /* Zip.framework in Frameworks */, + CE808A4F236697D800713E6B /* XCGLogger.framework in Frameworks */, + CE808A48236697BE00713E6B /* DeviceKit.framework in Frameworks */, + CE808A4D236697D500713E6B /* Reachability.framework in Frameworks */, + CE808A4B236697D400713E6B /* ObjcExceptionBridging.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -976,7 +972,7 @@ attributes = { DefaultBuildSystemTypeForWorkspace = Original; LastSwiftUpdateCheck = 1010; - LastUpgradeCheck = 1020; + LastUpgradeCheck = 1110; ORGANIZATIONNAME = "SIL International"; TargetAttributes = { 98F9D6961954112F0087AA43 = { @@ -1112,7 +1108,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftlint >/dev/null; then\n swiftlint --config ../../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi"; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint --config ../../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; }; /* End PBXShellScriptBuildPhase section */ @@ -1169,7 +1165,6 @@ 9A079E41223B602B00581263 /* LexicalModel.swift in Sources */, 9A3E832622EAC14A00D22D2A /* KeyboardSwitcherViewController.swift in Sources */, 9A3B14C0228F59490052A11F /* SettingsViewController.swift in Sources */, - 9A3B14BB228F592F0052A11F /* LanguageViewController.swift in Sources */, 9A31E2CE224AE8B100D9A491 /* LexicalModelRepository.swift in Sources */, 9A079E2E22361B8100581263 /* KeymanResponder+Types.swift in Sources */, 9A079DE12231A14D00581263 /* Storage.swift in Sources */, @@ -1182,7 +1177,6 @@ 9A31E2C9224AE88600D9A491 /* LanguagesAPICall.swift in Sources */, 9A3B14C1228F595A0052A11F /* KeyboardError.swift in Sources */, 9A079E2B22361A3200581263 /* KeymanWebViewController.swift in Sources */, - 9A862D2822B429FB005FE26D /* KeyboardNameTableViewCell.swift in Sources */, 9A31E2CD224AE8A700D9A491 /* NotificationObserver.swift in Sources */, 9A079E382238680700581263 /* KMPLexicalModel.swift in Sources */, 9A3B14BC228F59380052A11F /* LanguageDetailViewController.swift in Sources */, @@ -1194,10 +1188,8 @@ 9A3B14D3229370B20052A11F /* InstalledLanguagesViewController.swift in Sources */, 9A08255A227589360051EBB0 /* Formatter+ISODateExtension.swift in Sources */, 9A079E2A223619FC00581263 /* KeymanWebDelegate.swift in Sources */, - 9A3B14BF228F59450052A11F /* KeyboardInfoViewController.swift in Sources */, 9A31E2C3224AADBB00D9A491 /* NotificationName.swift in Sources */, 9A3B14C8228F59EE0052A11F /* TextView.swift in Sources */, - 9A862D2922B42A0C005FE26D /* LanguageDetailViewController.swift in Sources */, 9A079DDA2231A0B900581263 /* KeymanPackage.swift in Sources */, 9A079DE22231A15900581263 /* Manager.swift in Sources */, 9A079E47223DBF0100581263 /* SubKeysView.swift in Sources */, @@ -1544,9 +1536,10 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; + SUPPORTS_MACCATALYST = NO; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -1592,7 +1585,8 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; PROVISIONING_PROFILE_SPECIFIER = ""; SKIP_INSTALL = YES; - SWIFT_VERSION = 4.0; + SUPPORTS_MACCATALYST = NO; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; diff --git a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift index 4a0e81671f..15f565b4ed 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/InputViewController.swift @@ -83,7 +83,7 @@ open class InputViewController: UIInputViewController, KeymanWebDelegate { keymanWeb = KeymanWebViewController(storage: Storage.active) super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - addChildViewController(keymanWeb) + addChild(keymanWeb) } public required init?(coder aDecoder: NSCoder) { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift index 770f1b4668..f3c86cf529 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/KeymanWebViewController.swift @@ -128,9 +128,9 @@ class KeymanWebViewController: UIViewController { view.addGestureRecognizer(hold) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), - name: .UIKeyboardWillShow, object: nil) + name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), - name: .UIKeyboardWillHide, object: nil) + name: UIResponder.keyboardWillHideNotification, object: nil) reloadKeyboard() } @@ -142,6 +142,10 @@ class KeymanWebViewController: UIViewController { // Very useful for immediately adjusting the WebView's properties upon loading. override func viewDidAppear(_ animated: Bool) { fixLayout() + + // Initialize the keyboard's size/scale. In iOS 13 (at least), the system + // keyboard's width will be set at this stage, but not in viewWillAppear. + keyboardSize = view.bounds.size } } @@ -530,7 +534,7 @@ extension KeymanWebViewController: KeymanWebDelegate { delegate?.keyboardLoaded(keymanWeb) log.info("Loaded keyboard.") - + resizeKeyboard() setDeviceType(UIDevice.current.userInterfaceIdiom) @@ -735,7 +739,7 @@ extension KeymanWebViewController: UIGestureRecognizerDelegate { button.addTarget(self, action: #selector(subKeyButtonClick), for: .touchUpInside) // Detect the text width for subkeys. The 'as Any' silences an inappropriate warning from Swift. - let textSize = subKeyText.size(withAttributes: [NSAttributedStringKey.font: button.titleLabel?.font! as Any]) + let textSize = subKeyText.size(withAttributes: [NSAttributedString.Key.font: button.titleLabel?.font! as Any]) var displayText = subKeyText if textSize.width <= 0 && subKeyText.count > 0 { @@ -852,9 +856,10 @@ extension KeymanWebViewController { func resizeKeyboard() { fixLayout() - // Ensures the height is properly updated. + // Ensures the width and height are properly updated. // Note: System Keyboard init currently requires this for the keyboard to display properly // the first time. + setOskWidth(Int(kbSize.width)) setOskHeight(Int(kbSize.height)) } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift index d6c93e5820..4f73f2b32e 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardInfoViewController.swift @@ -136,12 +136,12 @@ class KeyboardInfoViewController: UITableViewController, UIAlertViewDelegate { private func showDeleteKeyboard() { let alertController = UIAlertController(title: title ?? "", message: "Would you like to delete this keyboard?", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) alertController.addAction(UIAlertAction(title: "Delete", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: deleteHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift index 1f671e2102..f2a9babfea 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardNameTableViewCell.swift @@ -13,7 +13,7 @@ private let cellSelectedTag = 4576 // arbitrary number class KeyboardNameTableViewCell: UITableViewCell, UIAlertViewDelegate { var indexPath: IndexPath? - override init(style: UITableViewCellStyle, reuseIdentifier: String?) { + override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) indentationLevel = 0 } @@ -23,7 +23,7 @@ class KeyboardNameTableViewCell: UITableViewCell, UIAlertViewDelegate { } func setKeyboardState(_ kbState: KeyboardState, selected isSelected: Bool, - defaultAccessoryType accessoryType: UITableViewCellAccessoryType) { + defaultAccessoryType accessoryType: UITableViewCell.AccessoryType) { if kbState != .downloading { accessoryView = nil } @@ -35,7 +35,7 @@ class KeyboardNameTableViewCell: UITableViewCell, UIAlertViewDelegate { let view = UIView(frame: CGRect(x: 0, y: 0, width: bounds.width, height: bounds.height)) view.tag = cellSelectedTag view.backgroundColor = UIColor.green - view.autoresizingMask = UIViewAutoresizing.flexibleWidth.union(.flexibleHeight) + view.autoresizingMask = UIView.AutoresizingMask.flexibleWidth.union(.flexibleHeight) addSubview(view) } } else { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerButton.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerButton.swift index 9bc4723c72..9d9ec2db4b 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerButton.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardPickerButton.swift @@ -41,7 +41,7 @@ public class KeyboardPickerButton: UIButton { } // Clear images if the developer sets a title - public override func setTitle(_ title: String?, for state: UIControlState) { + public override func setTitle(_ title: String?, for state: UIControl.State) { setImage(nil, for: state) super.setTitle(title, for: state) } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardSwitcherViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardSwitcherViewController.swift index 2b8d50795b..59873442e9 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardSwitcherViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/KeyboardSwitcherViewController.swift @@ -14,7 +14,7 @@ private let toolbarButtonTag = 100 class KeyboardSwitcherViewController: UITableViewController, UIAlertViewDelegate { public var userKeyboards: [InstallableKeyboard] = [InstallableKeyboard]() - public var accessoryType: UITableViewCellAccessoryType = .none + public var accessoryType: UITableViewCell.AccessoryType = .none override func viewDidLoad() { super.viewDidLoad() @@ -38,7 +38,7 @@ class KeyboardSwitcherViewController: UITableViewController, UIAlertViewDelegate } public func scroll(toSelectedKeyboard animated: Bool) { - let index = userKeyboards.index { kb in + let index = userKeyboards.firstIndex { kb in return Manager.shared.currentKeyboardID == kb.fullID } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift index ff4d73d1f6..84b6e6f97a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageDetailViewController.swift @@ -151,12 +151,12 @@ class LanguageDetailViewController: UITableViewController, UIAlertViewDelegate { let alertController = UIAlertController(title: "\(language.name): \(keyboard.name)", message: "Would you like to download this keyboard?", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) alertController.addAction(UIAlertAction(title: "Download", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: {_ in self.downloadHandler(keyboardIndex)} )) self.present(alertController, animated: true, completion: nil) @@ -170,7 +170,7 @@ class LanguageDetailViewController: UITableViewController, UIAlertViewDelegate { func showActivityView() { view.isUserInteractionEnabled = false - let indicatorView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) + let indicatorView = UIActivityIndicatorView(style: .whiteLarge) let activityView = UIView(frame: indicatorView.bounds.insetBy(dx: -10.0, dy: -10.0)) activityView.backgroundColor = UIColor(white: 0.5, alpha: 0.8) activityView.layer.cornerRadius = 6.0 @@ -195,9 +195,9 @@ class LanguageDetailViewController: UITableViewController, UIAlertViewDelegate { dismissActivityView() let alertController = UIAlertController(title: "Connection Error", message: "Could not reach Keyman server. Please try again later.", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: errorAcknowledgmentHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift index 095a5caf2e..d79878fb58 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageLMDetailViewController.swift @@ -124,12 +124,12 @@ class LanguageLMDetailViewController: UITableViewController, UIAlertViewDelegate let alertController = UIAlertController(title: "\(language.name): \(lexicalModel.name)", message: "Would you like to download this dictionary?", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) alertController.addAction(UIAlertAction(title: "Download", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: {_ in self.downloadHandler(lexicalModelIndex)} )) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift index d5fd73e204..dc0898a8b8 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LanguageViewController.swift @@ -213,12 +213,12 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { isUpdate = state != .needsDownload let alertController = UIAlertController(title: "\(language.name): \(keyboard.name)", message: "Would you like to download this keyboard?", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) alertController.addAction(UIAlertAction(title: "Download", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: {_ in self.downloadHandler(keyboardIndex)} )) self.present(alertController, animated: true, completion: nil) } @@ -257,7 +257,7 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { func showActivityView() { view.isUserInteractionEnabled = false - let indicatorView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) + let indicatorView = UIActivityIndicatorView(style: .whiteLarge) let activityView = UIView(frame: indicatorView.bounds.insetBy(dx: -10.0, dy: -10.0)) activityView.backgroundColor = UIColor(white: 0.5, alpha: 0.8) activityView.layer.cornerRadius = 6.0 @@ -313,9 +313,9 @@ class LanguageViewController: UITableViewController, UIAlertViewDelegate { dismissActivityView() let alertController = UIAlertController(title: "Connection Error", message: "Could not reach Keyman server. Please try again later.", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: errorAcknowledgmentHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift index 8c74837070..0bc6312c0e 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelInfoViewController.swift @@ -113,12 +113,12 @@ class LexicalModelInfoViewController: UITableViewController, UIAlertViewDelegate private func showDeleteLexicalModel() { let alertController = UIAlertController(title: title ?? "", message: "Would you like to delete this dictionary?", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) alertController.addAction(UIAlertAction(title: "Delete", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: deleteHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift index 909a741507..773f60db99 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/LanguagePicker/LexicalModelPickerViewController.swift @@ -106,7 +106,7 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega return true } - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle != .delete { return @@ -216,9 +216,9 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega navigationController?.setToolbarHidden(true, animated: true) let alertController = UIAlertController(title: title, message: notification.error.localizedDescription, - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: { _ in self.navigationController?.popToRootViewController(animated: true) })) @@ -271,7 +271,7 @@ class LexicalModelPickerViewController: UITableViewController, UIAlertViewDelega } private func scroll(toSelectedLexicalModel animated: Bool) { - let index = userLexicalModels.index { lm in + let index = userLexicalModels.firstIndex { lm in return Manager.shared.currentLexicalModelID == lm.fullID } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift index 4c0c09f5d1..89757bd9b0 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Manager.swift @@ -331,7 +331,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate { var userKeyboards = userDefaults.userKeyboards ?? [] // Update keyboard if it exists - if let index = userKeyboards.index(where: { $0.fullID == keyboard.fullID }) { + if let index = userKeyboards.firstIndex(where: { $0.fullID == keyboard.fullID }) { userKeyboards[index] = keyboard } else { userKeyboards.append(keyboard) @@ -396,7 +396,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate { var userLexicalModels = userDefaults.userLexicalModels ?? [] // Update lexical model if it exists - if let index = userLexicalModels.index(where: { $0.fullID == lexicalModel.fullID }) { + if let index = userLexicalModels.firstIndex(where: { $0.fullID == lexicalModel.fullID }) { userLexicalModels[index] = lexicalModel } else { userLexicalModels.append(lexicalModel) @@ -412,7 +412,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate { /// - Returns: The keyboard exists and was removed public func removeKeyboard(withFullID fullID: FullKeyboardID) -> Bool { // Remove keyboard from the list if it exists - let index = Storage.active.userDefaults.userKeyboards?.index { $0.fullID == fullID } + let index = Storage.active.userDefaults.userKeyboards?.firstIndex { $0.fullID == fullID } if let index = index { return removeKeyboard(at: index) } @@ -473,7 +473,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate { /// - Returns: The lexical model exists and was removed public func removeLexicalModel(withFullID fullID: FullLexicalModelID) -> Bool { // Remove lexical model from the list if it exists - let index = Storage.active.userDefaults.userLexicalModels?.index { $0.fullID == fullID } + let index = Storage.active.userDefaults.userLexicalModels?.firstIndex { $0.fullID == fullID } if let index = index { return removeLexicalModel(at: index) } @@ -555,7 +555,7 @@ public class Manager: NSObject, UIGestureRecognizerDelegate { /// - Returns: Index of the newly selected keyboard. public func switchToNextKeyboard() -> Int? { guard let userKeyboards = Storage.active.userDefaults.userKeyboards, - let index = userKeyboards.index(where: { self.currentKeyboardID == $0.fullID }) + let index = userKeyboards.firstIndex(where: { self.currentKeyboardID == $0.fullID }) else { return nil } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/ResourceDownloadStatusToolbar.swift b/ios/engine/KMEI/KeymanEngine/Classes/ResourceDownloadStatusToolbar.swift index 3704947c4b..c91d3afcbb 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/ResourceDownloadStatusToolbar.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/ResourceDownloadStatusToolbar.swift @@ -62,7 +62,7 @@ public class ResourceDownloadStatusToolbar: UIToolbar { * Creates the classic spinning-wheel 'activity in progress' indicator. */ private func setupActivityIndicator() -> UIActivityIndicatorView { - let indicatorView = UIActivityIndicatorView(activityIndicatorStyle: .gray) + let indicatorView = UIActivityIndicatorView(style: .gray) indicatorView.center = CGPoint(x: frame.width - indicatorView.frame.width, y: frame.height * 0.5) indicatorView.autoresizingMask = [.flexibleLeftMargin, .flexibleTopMargin, .flexibleBottomMargin] @@ -123,7 +123,7 @@ public class ResourceDownloadStatusToolbar: UIToolbar { actionButton = setupActionButton(text, for: target, onClick: callback) addSubview(actionButton!) - bringSubview(toFront: actionButton!) + bringSubviewToFront(actionButton!) // Automatically display if we're hidden and have access to our owning UINavigationController. if navigationController?.isToolbarHidden ?? false { diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift index 65cf3cf26a..3ea12ed4e1 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/InstalledLanguagesViewController.swift @@ -361,9 +361,9 @@ public class InstalledLanguagesViewController: UITableViewController, UIAlertVie navigationController?.setToolbarHidden(true, animated: true) let alertController = UIAlertController(title: title, message: "", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) self.present(alertController, animated: true, completion: nil) @@ -391,7 +391,7 @@ public class InstalledLanguagesViewController: UITableViewController, UIAlertVie func showActivityView() { view.isUserInteractionEnabled = false - let indicatorView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) + let indicatorView = UIActivityIndicatorView(style: .whiteLarge) let activityView = UIView(frame: indicatorView.bounds.insetBy(dx: -10.0, dy: -10.0)) activityView.backgroundColor = UIColor(white: 0.5, alpha: 0.8) activityView.layer.cornerRadius = 6.0 @@ -442,9 +442,9 @@ public class InstalledLanguagesViewController: UITableViewController, UIAlertVie dismissActivityView() let alertController = UIAlertController(title: "Connection Error", message: "Could not reach Keyman server. Please try again later.", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: errorAcknowledgmentHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift index 1757fff24f..b1c0b5a25a 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/Settings/LanguageSettingsViewController.swift @@ -283,7 +283,7 @@ class LanguageSettingsViewController: UITableViewController { return false } - override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, + override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { if let globalIndex = getKeyboardIndex(kb: (language.keyboards?[safe: indexPath.row])!) { @@ -336,7 +336,7 @@ class LanguageSettingsViewController: UITableViewController { return nil } - if let index = globalUserKeyboards.index(where: { $0.fullID == matchingFullID }) { + if let index = globalUserKeyboards.firstIndex(where: { $0.fullID == matchingFullID }) { guard index < globalUserKeyboards.count else { return nil } @@ -354,7 +354,7 @@ class LanguageSettingsViewController: UITableViewController { let userData = Storage.active.userDefaults // If user defaults for keyboards list does not exist, do nothing. - guard var globalUserKeyboards = userData.userKeyboards else { + guard let globalUserKeyboards = userData.userKeyboards else { log.error("no keyboards in the global keyboards list!") return } @@ -395,7 +395,7 @@ class LanguageSettingsViewController: UITableViewController { let userData = Storage.active.userDefaults if let globalUserLexicalModels = userData.userLexicalModels { - if let index = globalUserLexicalModels.index(where: { $0.fullID == matchingFullID }) { + if let index = globalUserLexicalModels.firstIndex(where: { $0.fullID == matchingFullID }) { guard index < globalUserLexicalModels.count else { return } diff --git a/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift b/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift index bf0b2d7890..f781e64e4d 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/SubKeysView.swift @@ -11,6 +11,7 @@ import UIKit class SubKeysView: UIView { private let borderRadius: CGFloat = 5.0 private let strokeWidth: CGFloat = 1.0 + private var baseKeyYDelta: CGFloat = 0.0 private var keyFrame = CGRect.zero private var adjX: CGFloat = 0.0 @@ -88,7 +89,14 @@ class SubKeysView: UIView { let baseHeight = keyFrame.size.height + marginY let viewHeight = baseHeight + containerHeight - marginY + strokeWidth var viewPosX = keyFrame.origin.x - (viewWidth - keyFrame.size.width) / 2.0 - let viewPosY = keyFrame.origin.y - (viewHeight - keyFrame.size.height + strokeWidth) + var viewPosY = keyFrame.origin.y - (viewHeight - keyFrame.size.height + strokeWidth) + + // Ensure that the system keyboard doesn't try to display off the top of the keyboard's view area. + if viewPosY < 0 && isSystemKeyboard { + baseKeyYDelta = viewPosY // We'll need this to adjust the visualization. + viewPosY = 0 + } + adjX = 0 adjY = 0 @@ -173,6 +181,10 @@ class SubKeysView: UIView { let viewTop = strokeWidth var viewBottom = viewHeight - strokeWidth * 0.75 - (CGFloat(rows - 1) * 0.25) + viewBottom += baseKeyYDelta + + let showBaseKeyPopup = (viewBottom > midY) + if scale == 3.0 { viewBottom -= CGFloat(3 - rows) * 0.4 } else if scale == 2.0 { @@ -198,16 +210,21 @@ class SubKeysView: UIView { context.move(to: CGPoint(x: viewMid, y: viewTop)) context.addArc(tangent1End: CGPoint(x: viewLeft, y: viewTop), tangent2End: CGPoint(x: viewLeft, y: midY), radius: r1) - context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), - tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1) - context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY), - tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2) - context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom), - tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0) - context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom), - tangent2End: CGPoint(x: keyRight, y: midY), radius: r0) - context.addArc(tangent1End: CGPoint(x: keyRight, y: midY), - tangent2End: CGPoint(x: viewRight, y: midY), radius: r2) + if showBaseKeyPopup { + context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), + tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1) + context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY), + tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2) + context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom), + tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0) + context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom), + tangent2End: CGPoint(x: keyRight, y: midY), radius: r0) + context.addArc(tangent1End: CGPoint(x: keyRight, y: midY), + tangent2End: CGPoint(x: viewRight, y: midY), radius: r2) + } else { + context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), + tangent2End: CGPoint(x: viewRight, y: midY), radius: r0) + } context.addArc(tangent1End: CGPoint(x: viewRight, y: midY), tangent2End: CGPoint(x: viewRight, y: viewTop), radius: r1) context.addArc(tangent1End: CGPoint(x: viewRight, y: viewTop), @@ -219,16 +236,21 @@ class SubKeysView: UIView { context.move(to: CGPoint(x: viewMid, y: viewTop)) context.addArc(tangent1End: CGPoint(x: viewLeft, y: viewTop), tangent2End: CGPoint(x: viewLeft, y: midY), radius: r1) - context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), - tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1) - context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY), - tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2) - context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom), - tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0) - context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom), - tangent2End: CGPoint(x: keyRight, y: midY), radius: r0) - context.addArc(tangent1End: CGPoint(x: keyRight, y: midY), - tangent2End: CGPoint(x: viewRight, y: midY), radius: r2) + if showBaseKeyPopup { + context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), + tangent2End: CGPoint(x: keyLeft, y: midY), radius: r1) + context.addArc(tangent1End: CGPoint(x: keyLeft, y: midY), + tangent2End: CGPoint(x: keyLeft, y: viewBottom), radius: r2) + context.addArc(tangent1End: CGPoint(x: keyLeft, y: viewBottom), + tangent2End: CGPoint(x: keyRight, y: viewBottom), radius: r0) + context.addArc(tangent1End: CGPoint(x: keyRight, y: viewBottom), + tangent2End: CGPoint(x: keyRight, y: midY), radius: r0) + context.addArc(tangent1End: CGPoint(x: keyRight, y: midY), + tangent2End: CGPoint(x: viewRight, y: midY), radius: r2) + } else { + context.addArc(tangent1End: CGPoint(x: viewLeft, y: midY), + tangent2End: CGPoint(x: viewRight, y: midY), radius: r0) + } context.addArc(tangent1End: CGPoint(x: viewRight, y: midY), tangent2End: CGPoint(x: viewRight, y: viewTop), radius: r1) context.addArc(tangent1End: CGPoint(x: viewRight, y: viewTop), diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift index 425c5506c9..523f4a0228 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextField.swift @@ -54,7 +54,7 @@ public class TextField: UITextField, KeymanResponder { self.inputView = Manager.shared.inputViewController.view NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldTextDidChange), - name: .UITextFieldTextDidChange, object: self) + name: UITextField.textDidChangeNotification, object: self) keyboardChangedObserver = NotificationCenter.default.addObserver(forName: Notifications.keyboardChanged, observer: self, function: TextField.keyboardChanged) diff --git a/ios/engine/KMEI/KeymanEngine/Classes/TextFieldDelegateProxy.swift b/ios/engine/KMEI/KeymanEngine/Classes/TextFieldDelegateProxy.swift index 6368d077ed..262ea880fd 100644 --- a/ios/engine/KMEI/KeymanEngine/Classes/TextFieldDelegateProxy.swift +++ b/ios/engine/KMEI/KeymanEngine/Classes/TextFieldDelegateProxy.swift @@ -50,7 +50,7 @@ class TextFieldDelegateProxy: NSObject, UITextFieldDelegate { } @available(iOS 10.0, *) - func textFieldDidEndEditing(_ textField: UITextField, reason: UITextFieldDidEndEditingReason) { + func textFieldDidEndEditing(_ textField: UITextField, reason: UITextField.DidEndEditingReason) { self.textField.textFieldDidEndEditing?(textField, reason: reason) keymanDelegate?.textFieldDidEndEditing?(textField, reason: reason) } diff --git a/ios/history.md b/ios/history.md index 50b0d21b12..3b9d561ea5 100644 --- a/ios/history.md +++ b/ios/history.md @@ -3,6 +3,13 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-14 12.0.54 stable +* Confine system keyboard popup-key positioning (#2317) +* Fix initialization of system keyboard width (#2318) + +## 2019-10-10 12.0.53 stable +* No actual code changes affecting iOS (KeymanWeb #2194) + ## 2019-10-08 12.0.52 stable * Fixes issue when installing dictionaries (#2193) diff --git a/ios/keyman/Keyman/Keyman-Info.plist b/ios/keyman/Keyman/Keyman-Info.plist index 4c0f7f99a4..9b8e9c9b59 100644 --- a/ios/keyman/Keyman/Keyman-Info.plist +++ b/ios/keyman/Keyman/Keyman-Info.plist @@ -56,6 +56,8 @@ UIFileSharingEnabled + UILaunchStoryboardName + LaunchScreen UIPrerenderedIcon UIRequiredDeviceCapabilities @@ -79,6 +81,8 @@ UISupportsDocumentBrowser + UIUserInterfaceStyle + Light UTExportedTypeDeclarations diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj index dd72e6f071..8e81b66515 100644 --- a/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj +++ b/ios/keyman/Keyman/Keyman.xcodeproj/project.pbxproj @@ -14,11 +14,8 @@ 162E2C9F2092D36800F40769 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 162E2C9E2092D36800F40769 /* UIDevice+Extensions.swift */; }; 165EB39A2097165B00040A69 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB3992097165B00040A69 /* UIColor+Extensions.swift */; }; 165EB39C2097181D00040A69 /* KMView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 165EB39B2097181D00040A69 /* KMView.swift */; }; - 1687ACCA1FD8269C00926D69 /* Zip.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 165C8B8F1FD8221800D4A78D /* Zip.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1687ACD41FD8DE8000926D69 /* ObjcExceptionBridging.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD11FD8DE7600926D69 /* ObjcExceptionBridging.framework */; }; - 1687ACD51FD8DE8000926D69 /* ObjcExceptionBridging.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD11FD8DE7600926D69 /* ObjcExceptionBridging.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1687ACD61FD8DE8000926D69 /* XCGLogger.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD01FD8DE7600926D69 /* XCGLogger.framework */; }; - 1687ACD71FD8DE8000926D69 /* XCGLogger.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 1687ACD01FD8DE7600926D69 /* XCGLogger.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 981AFA8F19EF44DE006706BF /* 724-info@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 9815725518E4F0930014DF0C /* 724-info@2x.png */; }; 981AFA9019EF44DE006706BF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 98ABADBC176935E400B62590 /* InfoPlist.strings */; }; 981AFA9619EF44DE006706BF /* MainViewController_iPhone.xib in Resources */ = {isa = PBXBuildFile; fileRef = 98ABADCE176935E500B62590 /* MainViewController_iPhone.xib */; }; @@ -117,7 +114,6 @@ 985EA9E819E64A580006C017 /* banner-Portrait@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 985EA9DD19E64A580006C017 /* banner-Portrait@3x.png */; }; 985EA9E919E64A580006C017 /* banner-Portrait~ipad.png in Resources */ = {isa = PBXBuildFile; fileRef = 985EA9DE19E64A580006C017 /* banner-Portrait~ipad.png */; }; 989E4DBC1B1EB85200A345FB /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 989E4DBA1B1EB85200A345FB /* Settings.bundle */; }; - 9A0FCA0022D7C22000D33F86 /* Reachability.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9A0FC9FF22D7C21F00D33F86 /* Reachability.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; C055F0B11F60E8D400140735 /* GetStartedViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C055F0B01F60E8D400140735 /* GetStartedViewController.swift */; }; C055F0B31F60F7A400140735 /* DropDownView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C055F0B21F60F7A400140735 /* DropDownView.swift */; }; C055F0B51F610FB200140735 /* DropDownListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C055F0B41F610FB200140735 /* DropDownListView.swift */; }; @@ -138,6 +134,7 @@ CE2B1E4C21B6112B007D092E /* DeviceKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE2B1E4B21B6112B007D092E /* DeviceKit.framework */; }; CE6138011FB99538009D0EF2 /* KeymanEngine.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = CE6137FF1FB99538009D0EF2 /* KeymanEngine.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; CE6138021FB999C8009D0EF2 /* KeymanEngine.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CE6138031FB999C8009D0EF2 /* KeymanEngine.framework */; }; + CE7C1AE2236925D800100C2C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CE7C1AE1236925D800100C2C /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -158,11 +155,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 9A0FCA0022D7C22000D33F86 /* Reachability.framework in Embed Frameworks */, - 1687ACCA1FD8269C00926D69 /* Zip.framework in Embed Frameworks */, - 1687ACD71FD8DE8000926D69 /* XCGLogger.framework in Embed Frameworks */, CE6138011FB99538009D0EF2 /* KeymanEngine.framework in Embed Frameworks */, - 1687ACD51FD8DE8000926D69 /* ObjcExceptionBridging.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -304,6 +297,7 @@ CE2B1E4B21B6112B007D092E /* DeviceKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DeviceKit.framework; path = ../../Carthage/Build/iOS/DeviceKit.framework; sourceTree = ""; }; CE6137FF1FB99538009D0EF2 /* KeymanEngine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KeymanEngine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; CE6138031FB999C8009D0EF2 /* KeymanEngine.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = KeymanEngine.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + CE7C1AE1236925D800100C2C /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -478,6 +472,7 @@ 98ABADA7176935E400B62590 = { isa = PBXGroup; children = ( + CE7C1AE1236925D800100C2C /* LaunchScreen.storyboard */, 9A0FC9FF22D7C21F00D33F86 /* Reachability.framework */, CE2B1E4B21B6112B007D092E /* DeviceKit.framework */, CE6137FF1FB99538009D0EF2 /* KeymanEngine.framework */, @@ -664,13 +659,13 @@ buildConfigurationList = 981AFADE19EF44DE006706BF /* Build configuration list for PBXNativeTarget "Keyman" */; buildPhases = ( 981AFA7A19EF44DE006706BF /* Sources */, + 1687ACCB1FD826D000926D69 /* Run Script */, 981AFA8319EF44DE006706BF /* Frameworks */, 981AFA8E19EF44DE006706BF /* Resources */, + 989E4DB91B1EB5C200A345FB /* Run Script */, 981AFADC19EF44DE006706BF /* Embed App Extensions */, - 989E4DB91B1EB5C200A345FB /* ShellScript */, 37BC8FF91DE83B40006AEBFF /* Headers */, C01AB5981F8343F7009B37D3 /* Embed Frameworks */, - 1687ACCB1FD826D000926D69 /* ShellScript */, ); buildRules = ( ); @@ -685,7 +680,7 @@ isa = PBXNativeTarget; buildConfigurationList = 98CD126819CA85710089385F /* Build configuration list for PBXNativeTarget "SWKeyboard" */; buildPhases = ( - CE06AA671F161422006D91C3 /* ShellScript */, + CE06AA671F161422006D91C3 /* Run Script */, 98CD125819CA85710089385F /* Sources */, 98CD125919CA85710089385F /* Frameworks */, 98CD125A19CA85710089385F /* Resources */, @@ -806,6 +801,7 @@ 982D148B19FF462A007D4629 /* 702-share-selected@3x.png in Resources */, 9845A7B21A43983300544E2E /* kmwb-navbar-Portrait.png in Resources */, 981AFABB19EF44DE006706BF /* 887-notepad-selected.png in Resources */, + CE7C1AE2236925D800100C2C /* LaunchScreen.storyboard in Resources */, 981AFABC19EF44DE006706BF /* 887-notepad@2x.png in Resources */, 981AFABE19EF44DE006706BF /* textsize_up.png in Resources */, 982D148F19FF462A007D4629 /* 711-trash-selected@3x.png in Resources */, @@ -863,7 +859,7 @@ /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ - 1687ACCB1FD826D000926D69 /* ShellScript */ = { + 1687ACCB1FD826D000926D69 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -875,6 +871,7 @@ "$(SRCROOT)/../../Carthage/Build/iOS/DeviceKit.framework", "$(SRCROOT)/../../Carthage/Build/iOS/Reachability.framework", ); + name = "Run Script"; outputPaths = ( "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Zip.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ObjcExceptionBridging.framework", @@ -887,13 +884,14 @@ shellScript = "echo \"-- Copying Frameworks --\"\n/usr/local/bin/carthage copy-frameworks\n\n\n"; showEnvVarsInLog = 0; }; - 989E4DB91B1EB5C200A345FB /* ShellScript */ = { + 989E4DB91B1EB5C200A345FB /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -901,13 +899,14 @@ shellScript = "verstr1=$(/usr/libexec/PlistBuddy -c \"Print CFBundleShortVersionString\" \"$SRCROOT/Keyman-Info.plist\")\nverstr2=$(/usr/libexec/PlistBuddy -c \"Print CFBundleVersion\" \"$SRCROOT/Keyman-Info.plist\")\n/usr/libexec/PlistBuddy \"$SRCROOT/Settings.bundle/Root.plist\" -c \"set PreferenceSpecifiers:0:DefaultValue $verstr1 (build $verstr2)\"\n\nif which swiftlint >/dev/null; then\n swiftlint --config ../../.swiftlint.yml\nelse\n echo \"warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint\"\nfi\n"; showEnvVarsInLog = 0; }; - CE06AA671F161422006D91C3 /* ShellScript */ = { + CE06AA671F161422006D91C3 /* Run Script */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( ); + name = "Run Script"; outputPaths = ( ); runOnlyForDeploymentPostprocessing = 0; @@ -985,7 +984,6 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Keyman/Keyman.entitlements; CODE_SIGN_STYLE = Manual; @@ -1007,7 +1005,7 @@ SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; @@ -1018,7 +1016,6 @@ buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Keyman/Keyman.entitlements; CODE_SIGN_STYLE = Manual; @@ -1039,7 +1036,7 @@ PROVISIONING_PROFILE_SPECIFIER = "XC iOS: Tavultesoft.Keyman"; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; WRAPPER_EXTENSION = app; }; @@ -1193,7 +1190,7 @@ SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1231,7 +1228,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_OBJC_BRIDGING_HEADER = ""; SWIFT_SWIFT3_OBJC_INFERENCE = Default; - SWIFT_VERSION = 4.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/ios/keyman/Keyman/Keyman.xcodeproj/xcshareddata/xcschemes/SWKeyboard.xcscheme b/ios/keyman/Keyman/Keyman.xcodeproj/xcshareddata/xcschemes/SWKeyboard.xcscheme index ebf89bc2e5..2ab38af804 100644 --- a/ios/keyman/Keyman/Keyman.xcodeproj/xcshareddata/xcschemes/SWKeyboard.xcscheme +++ b/ios/keyman/Keyman/Keyman.xcodeproj/xcshareddata/xcschemes/SWKeyboard.xcscheme @@ -1,6 +1,6 @@ - - - - Bool { + options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool { // .kmp package install, Keyman 10 onwards var destinationUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] destinationUrl.appendPathComponent("\(url.lastPathComponent).zip") @@ -36,7 +36,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { } func application(_ application: UIApplication, - didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]? = nil) -> Bool { + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool { #if DEBUG KeymanEngine.log.outputLevel = .debug log.outputLevel = .debug @@ -98,7 +98,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate { _overlayWindow!.autoresizingMask = [.flexibleWidth, .flexibleHeight] _overlayWindow!.autoresizesSubviews = true _overlayWindow!.backgroundColor = UIColor(white: 0.0, alpha: 0.75) - _overlayWindow!.windowLevel = UIWindowLevelStatusBar + 1 + _overlayWindow!.windowLevel = UIWindow.Level.statusBar + 1 _overlayWindow!.isUserInteractionEnabled = true _overlayWindow!.isHidden = true } @@ -133,9 +133,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate { public func showSimpleAlert(title: String, message: String) { let alertController = UIAlertController(title: title, message: message, - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: nil)) self.window?.rootViewController?.present(alertController, animated: true, completion: nil) diff --git a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift index 521beb65af..1bc2e0d3ea 100644 --- a/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift +++ b/ios/keyman/Keyman/Keyman/Classes/Extensions/UIView+Extensions.swift @@ -12,7 +12,7 @@ import UIKit extension UIView { func constrainEqually(to parent: UIView, - attribute: NSLayoutAttribute, + attribute: NSLayoutConstraint.Attribute, constant: CGFloat = 0) -> NSLayoutConstraint { let constraint = NSLayoutConstraint(item: self, @@ -25,7 +25,7 @@ extension UIView { return constraint } - func constrainEqually(to constant: CGFloat, attribute: NSLayoutAttribute) -> NSLayoutConstraint { + func constrainEqually(to constant: CGFloat, attribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint { let constraint = NSLayoutConstraint( item: self, attribute: attribute, diff --git a/ios/keyman/Keyman/Keyman/GetStartedViewController/GetStartedViewController.swift b/ios/keyman/Keyman/Keyman/GetStartedViewController/GetStartedViewController.swift index c5067e2dac..0053d428d8 100644 --- a/ios/keyman/Keyman/Keyman/GetStartedViewController/GetStartedViewController.swift +++ b/ios/keyman/Keyman/Keyman/GetStartedViewController/GetStartedViewController.swift @@ -26,7 +26,7 @@ class GetStartedViewController: UIViewController, UITableViewDelegate, UITableVi super.viewDidLoad() NotificationCenter.default.addObserver(self, selector: #selector(self.refreshTable), - name: NSNotification.Name.UIApplicationDidBecomeActive, object: nil) + name: UIApplication.didBecomeActiveNotification, object: nil) tableView.isScrollEnabled = false diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json deleted file mode 100644 index 8d740e45e3..0000000000 --- a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Contents.json +++ /dev/null @@ -1,152 +0,0 @@ -{ - "images" : [ - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "launch_iphonex_portrait@3x.png", - "minimum-system-version" : "11.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "2436h", - "filename" : "launch_iphoneX_landscape@3x.png", - "minimum-system-version" : "11.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "Default-HD-55.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "736h", - "filename" : "Default-Landscape-HD-55.png", - "minimum-system-version" : "8.0", - "orientation" : "landscape", - "scale" : "3x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "667h", - "filename" : "Default-HD-47.png", - "minimum-system-version" : "8.0", - "orientation" : "portrait", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default@2x.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "extent" : "full-screen", - "idiom" : "iphone", - "subtype" : "retina4", - "filename" : "Default-568h@2x.png", - "minimum-system-version" : "7.0", - "orientation" : "portrait", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait~ipad7.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape~ipad7.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait@2x~ipad7.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape@2x~ipad7.png", - "extent" : "full-screen", - "minimum-system-version" : "7.0", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default.png", - "extent" : "full-screen", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default@2x.png", - "extent" : "full-screen", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "iphone", - "filename" : "Default-568h@2x.png", - "extent" : "full-screen", - "subtype" : "retina4", - "scale" : "2x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait~ipad.png", - "extent" : "to-status-bar", - "scale" : "1x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape~ipad.png", - "extent" : "to-status-bar", - "scale" : "1x" - }, - { - "orientation" : "portrait", - "idiom" : "ipad", - "filename" : "Default-Portrait@2x~ipad.png", - "extent" : "to-status-bar", - "scale" : "2x" - }, - { - "orientation" : "landscape", - "idiom" : "ipad", - "filename" : "Default-Landscape@2x~ipad.png", - "extent" : "to-status-bar", - "scale" : "2x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png deleted file mode 100644 index 3c3847b020..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-568h@2x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-47.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-47.png deleted file mode 100644 index f8340e68d3..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-47.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-55.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-55.png deleted file mode 100644 index c8c8efefb9..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-HD-55.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape-HD-55.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape-HD-55.png deleted file mode 100644 index 286babbcab..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape-HD-55.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png deleted file mode 100644 index d8612fec14..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad7.png deleted file mode 100644 index 497bd0235c..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape@2x~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png deleted file mode 100644 index 5fc0fa344d..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad7.png deleted file mode 100644 index dd092e3f59..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Landscape~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png deleted file mode 100644 index ca6d2b4583..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad7.png deleted file mode 100644 index 3bb64588f8..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait@2x~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png deleted file mode 100644 index 5eeb72d57f..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad7.png deleted file mode 100644 index 3e1a2720ef..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default-Portrait~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default.png deleted file mode 100644 index 4d2c9c994e..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default@2x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default@2x.png deleted file mode 100644 index 5451a99063..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Default@2x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-568h@2x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-568h@2x.png deleted file mode 100644 index 3c3847b020..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-568h@2x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-47.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-47.png deleted file mode 100644 index f8340e68d3..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-47.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-55.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-55.png deleted file mode 100644 index c8c8efefb9..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-HD-55.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape-HD-55.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape-HD-55.png deleted file mode 100644 index 286babbcab..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape-HD-55.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape@2x~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape@2x~ipad7.png deleted file mode 100644 index 497bd0235c..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape@2x~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape~ipad7.png deleted file mode 100644 index dd092e3f59..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Landscape~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait@2x~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait@2x~ipad7.png deleted file mode 100644 index 3bb64588f8..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait@2x~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait~ipad7.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait~ipad7.png deleted file mode 100644 index 3e1a2720ef..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default-Portrait~ipad7.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default@2x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default@2x.png deleted file mode 100644 index 5451a99063..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/Launch Image Set/Default@2x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png deleted file mode 100644 index adb9dfe6c1..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphoneX_landscape@3x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png deleted file mode 100644 index 22a3ab1f62..0000000000 Binary files a/ios/keyman/Keyman/Keyman/Images.xcassets/LaunchImage.launchimage/launch_iphonex_portrait@3x.png and /dev/null differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/Contents.json b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/Contents.json new file mode 100644 index 0000000000..846a710b71 --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "gradient-footer@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/gradient-footer@2x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/gradient-footer@2x.png new file mode 100644 index 0000000000..53397ea9b6 Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/gradient-footer@2x.png differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/Contents.json b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/Contents.json new file mode 100644 index 0000000000..fb732f71ca --- /dev/null +++ b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/Contents.json @@ -0,0 +1,83 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "1x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ] + }, + { + "idiom" : "universal", + "scale" : "1x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ] + }, + { + "idiom" : "universal", + "scale" : "2x", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ] + }, + { + "idiom" : "universal", + "filename" : "keyman_logo@3x.png", + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "keyman_logo@3x-1.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "light" + } + ], + "scale" : "3x" + }, + { + "idiom" : "universal", + "filename" : "keyman_logo_dark@3x.png", + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x-1.png b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x-1.png new file mode 100644 index 0000000000..2b34ddf361 Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x-1.png differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x.png new file mode 100644 index 0000000000..2b34ddf361 Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x.png differ diff --git a/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo_dark@3x.png b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo_dark@3x.png new file mode 100644 index 0000000000..ac273a94c4 Binary files /dev/null and b/ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo_dark@3x.png differ diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift index 8d930f753a..994accfe2b 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/BookmarksViewController.swift @@ -51,12 +51,12 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie @IBAction func addBookmark(_ sender: Any) { let alertController = UIAlertController(title: "Add Bookmark", message: "", - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addTextField(configurationHandler: { (textField) in //listen for changes NotificationCenter.default.addObserver(self, selector: #selector(BookmarksViewController.handleTextFieldTextChangedNotification(notification:)), - name: NSNotification.Name.UITextFieldTextDidChange, object: textField) + name: UITextField.textDidChangeNotification, object: textField) textField.placeholder = "Title" textField.text = self.webBrowser?.webView?.stringByEvaluatingJavaScript(from: "document.title") textField.autocapitalizationType = .sentences @@ -69,7 +69,7 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie //listen for changes NotificationCenter.default.addObserver(self, selector: #selector(BookmarksViewController.handleTextFieldTextChangedNotification(notification:)), - name: NSNotification.Name.UITextFieldTextDidChange, object: textField) + name: UITextField.textDidChangeNotification, object: textField) textField.placeholder = "URL" textField.text = self.webBrowser?.webView?.request?.mainDocumentURL?.absoluteString textField.autocapitalizationType = .none @@ -79,11 +79,11 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie self.inputUrlField = textField }) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: nil)) let addAlertAction = UIAlertAction(title: "Add", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: {_ in self.addBookmarkHandler() }) alertController.addAction(addAlertAction) @@ -152,7 +152,7 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie let bookmark = bookmarks[indexPath.section] cell.textLabel?.text = bookmark[bookmarkTitleKey] cell.detailTextLabel?.text = bookmark[bookmarkUrlKey] - cell.accessoryType = UITableViewCellAccessoryType.none + cell.accessoryType = UITableViewCell.AccessoryType.none } func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool { @@ -160,7 +160,7 @@ class BookmarksViewController: UIViewController, UITableViewDelegate, UITableVie } func tableView(_ tableView: UITableView, - commit editingStyle: UITableViewCellEditingStyle, + commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { bookmarks.remove(at: indexPath.section) diff --git a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift index 350be29740..8641843ba5 100644 --- a/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift +++ b/ios/keyman/Keyman/Keyman/KMWebBrowser/WebBrowserViewController.swift @@ -82,7 +82,7 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView let refreshSize = CGSize(width: 18, height: 22) let refreshIcon = #imageLiteral(resourceName: "UIButtonBarRefresh.png").resize(to: refreshSize) .withRenderingMode(.alwaysOriginal) - refreshButton = UIButton(type: UIButtonType.system) + refreshButton = UIButton(type: UIButton.ButtonType.system) refreshButton.setImage(refreshIcon, for: .normal) refreshButton.frame = rightView.frame refreshButton.addTarget(self, action: #selector(self.refresh), for: .touchUpInside) @@ -92,7 +92,7 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView let stopSize = CGSize(width: 17, height: 17) let stopIcon = #imageLiteral(resourceName: "UIButtonBarStop.png").resize(to: stopSize) .withRenderingMode(.alwaysOriginal) - stopButton = UIButton(type: UIButtonType.system) + stopButton = UIButton(type: UIButton.ButtonType.system) stopButton.setImage(stopIcon, for: .normal) stopButton.frame = rightView.frame stopButton.addTarget(self, action: #selector(self.stop), for: .touchUpInside) @@ -190,7 +190,7 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView func webView(_ webView: UIWebView, shouldStartLoadWith request: URLRequest, - navigationType: UIWebViewNavigationType) -> Bool { + navigationType: UIWebView.NavigationType) -> Bool { updateAddress(request) return true } @@ -211,9 +211,9 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView updateButtons() let alertController = UIAlertController(title: "Cannot Open Page", message: error.localizedDescription, - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "OK", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: nil)) self.present(alertController, animated: true, completion: nil) } diff --git a/ios/keyman/Keyman/Keyman/MainViewController.swift b/ios/keyman/Keyman/Keyman/MainViewController.swift index ee96f2cc17..a0218c92f7 100644 --- a/ios/keyman/Keyman/Keyman/MainViewController.swift +++ b/ios/keyman/Keyman/Keyman/MainViewController.swift @@ -36,7 +36,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg private var getStartedVC: GetStartedViewController! private var infoView: InfoViewController! - private var popover: UIPopoverController? + private var popover: UIViewController? private var textSizeController: UISlider! private var dropdownItems: [UIBarButtonItem]! @@ -88,11 +88,11 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg // Setup Notifications NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow), - name: NSNotification.Name.UIKeyboardWillShow, object: nil) + name: UIResponder.keyboardWillShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardDidShow), - name: NSNotification.Name.UIKeyboardWillShow, object: nil) + name: UIResponder.keyboardDidShowNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide), - name: NSNotification.Name.UIKeyboardWillHide, object: nil) + name: UIResponder.keyboardWillHideNotification, object: nil) keyboardLoadedObserver = NotificationCenter.default.addObserver( forName: Notifications.keyboardLoaded, observer: self, @@ -307,7 +307,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg let vAdjPort: CGFloat = UIScreen.main.scale == 2.0 ? -3.6 : -2.6 let vAdjLscpe: CGFloat = -1.6 - let vAdj = UIInterfaceOrientationIsPortrait(orientation) ? vAdjPort : vAdjLscpe + let vAdj = orientation.isPortrait ? vAdjPort : vAdjLscpe let navBarHeight = self.navBarHeight() let y = (navBarHeight - icon.size.height) / 2.0 + vAdj @@ -593,9 +593,10 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg printText.font = textView.font let activityVC = UIActivityViewController(activityItems: [activityProvider, printText], applicationActivities: nil) - activityVC.excludedActivityTypes = [UIActivityType.assignToContact, UIActivityType.postToWeibo, - UIActivityType.saveToCameraRoll] - activityVC.completionWithItemsHandler = {(_ activityType: UIActivityType?, _ completed: Bool, + activityVC.excludedActivityTypes = [UIActivity.ActivityType.assignToContact, + UIActivity.ActivityType.postToWeibo, + UIActivity.ActivityType.saveToCameraRoll] + activityVC.completionWithItemsHandler = {(_ activityType: UIActivity.ActivityType?, _ completed: Bool, _ returnedItems: [Any]?, _ activityError: Error?) -> Void in self.textView.isUserInteractionEnabled = true } @@ -604,9 +605,11 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg if UIDevice.current.userInterfaceIdiom == .phone { present(activityVC, animated: true, completion: nil) } else { - popover = UIPopoverController(contentViewController: activityVC) - popover!.present(from: (navigationItem.rightBarButtonItems?[8])!, permittedArrowDirections: .any, - animated: true) + activityVC.modalPresentationStyle = UIModalPresentationStyle.popover + activityVC.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[12] + self.present(activityVC, animated: true) + + popover = activityVC } } @@ -674,7 +677,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg } else { let vc = UIViewController() vc.modalPresentationStyle = .popover - vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[6] + vc.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[8] vc.view = containerView vc.preferredContentSize = containerView.frame.size present(vc, animated: true, completion: nil) @@ -712,7 +715,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg let cancel = UIAlertAction(title: "Cancel", style: .default, handler: nil) alert.addAction(clear) alert.addAction(cancel) - alert.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[4] + alert.popoverPresentationController?.barButtonItem = navigationItem.rightBarButtonItems?[6] present(alert, animated: true, completion: nil) } @@ -723,7 +726,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg dismissGetStartedView(nil) overlayWindow.isHidden = false - let activityView = UIActivityIndicatorView(activityIndicatorStyle: .whiteLarge) + let activityView = UIActivityIndicatorView(style: .whiteLarge) let containerView = UIView(frame: activityView.bounds.insetBy(dx: -10.0, dy: -10.0)) containerView.backgroundColor = UIColor(white: 0.5, alpha: 0.8) containerView.layer.cornerRadius = 6.0 @@ -902,12 +905,12 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg dismissGetStartedView(nil) let alertController = UIAlertController(title: title, message: msg, - preferredStyle: UIAlertControllerStyle.alert) + preferredStyle: UIAlertController.Style.alert) alertController.addAction(UIAlertAction(title: "Cancel", - style: UIAlertActionStyle.cancel, + style: UIAlertAction.Style.cancel, handler: cbHandler)) alertController.addAction(UIAlertAction(title: "Install", - style: UIAlertActionStyle.default, + style: UIAlertAction.Style.default, handler: installHandler)) self.present(alertController, animated: true, completion: nil) diff --git a/ios/keyman/Keyman/Keyman/SetUpViewController/SetUpViewController.swift b/ios/keyman/Keyman/Keyman/SetUpViewController/SetUpViewController.swift index dd3585545d..806d450ac0 100644 --- a/ios/keyman/Keyman/Keyman/SetUpViewController/SetUpViewController.swift +++ b/ios/keyman/Keyman/Keyman/SetUpViewController/SetUpViewController.swift @@ -61,7 +61,9 @@ class SetUpViewController: UIViewController, UIWebViewDelegate { // Yes, .php.html. That's how `wget` is set to retrieve it, since Safari won't recognize the contents // without the .html ending, it seems. - let filePath = offlineHelpBundle.path(forResource: "installing-system-keyboard.php", ofType: "html", inDirectory: nil) + let filePath = offlineHelpBundle.path(forResource: "installing-system-keyboard.php", + ofType: "html", + inDirectory: nil) webView.loadRequest(URLRequest(url: URL.init(fileURLWithPath: filePath!))) } diff --git a/ios/keyman/Keyman/LaunchScreen.storyboard b/ios/keyman/Keyman/LaunchScreen.storyboard new file mode 100644 index 0000000000..9043205cb6 --- /dev/null +++ b/ios/keyman/Keyman/LaunchScreen.storyboard @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/keymanios.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/ios/keymanios.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings index 949b678982..3ddf867a10 100644 --- a/ios/keymanios.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings +++ b/ios/keymanios.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -3,6 +3,6 @@ BuildSystemType - Original + Latest diff --git a/ios/keymanios.xcworkspace/xcshareddata/xcschemes/KME-universal.xcscheme b/ios/keymanios.xcworkspace/xcshareddata/xcschemes/KME-universal.xcscheme index a5272b5f04..9586d7a832 100644 --- a/ios/keymanios.xcworkspace/xcshareddata/xcschemes/KME-universal.xcscheme +++ b/ios/keymanios.xcworkspace/xcshareddata/xcschemes/KME-universal.xcscheme @@ -1,6 +1,6 @@ - - - - + + - - - - - - + + - - start.offset) { + dn = start.offset; + } + if(start.node.nodeType != 3) { console.warn("Deletion of characters requested without available context!"); return; // No context to delete characters from. diff --git a/web/source/dom/designIFrame.ts b/web/source/dom/designIFrame.ts index b20b2cdbff..42045923fc 100644 --- a/web/source/dom/designIFrame.ts +++ b/web/source/dom/designIFrame.ts @@ -150,6 +150,11 @@ namespace com.keyman.dom { let start = this.getCarets().start; + // Bounds-check on the number of chars to delete. + if(dn > start.offset) { + dn = start.offset; + } + if(start.node.nodeType != 3) { console.warn("Deletion of characters requested without available context!"); return; // No context to delete characters from. diff --git a/web/source/dom/input.ts b/web/source/dom/input.ts index d432f5ce99..bd32120d1e 100644 --- a/web/source/dom/input.ts +++ b/web/source/dom/input.ts @@ -113,6 +113,10 @@ namespace com.keyman.dom { let curText = this.getTextBeforeCaret(); let caret = this.getCaret(); + if(dn > caret) { + dn = caret; + } + this.adjustDeadkeys(-dn); this.setTextBeforeCaret(curText.kmwSubstring(0, this.getCaret() - dn)); this.setCaret(caret - dn); diff --git a/web/source/dom/textarea.ts b/web/source/dom/textarea.ts index de9d82027f..0e0b68bc6d 100644 --- a/web/source/dom/textarea.ts +++ b/web/source/dom/textarea.ts @@ -141,6 +141,10 @@ namespace com.keyman.dom { let curText = this.getTextBeforeCaret(); let caret = this.getCaret(); + if(dn > caret) { + dn = caret; + } + this.adjustDeadkeys(-dn); this.setTextBeforeCaret(curText.kmwSubstring(0, this.getCaret() - dn)); this.setCaret(caret - dn); diff --git a/web/source/dom/touchAlias.ts b/web/source/dom/touchAlias.ts index e64948235b..954c521055 100644 --- a/web/source/dom/touchAlias.ts +++ b/web/source/dom/touchAlias.ts @@ -50,6 +50,9 @@ namespace com.keyman.dom { deleteCharsBeforeCaret(dn: number): void { if(dn > 0) { let curText = this.getTextBeforeCaret(); + if(this.getDeadkeyCaret() < dn) { + dn = this.getDeadkeyCaret(); + } this.adjustDeadkeys(-dn); this.root.setTextBeforeCaret(curText.kmwSubstring(0, this.root.getTextCaret() - dn)); } diff --git a/web/source/kmwdevice.ts b/web/source/kmwdevice.ts index 6be109c4d9..e08eab92f4 100644 --- a/web/source/kmwdevice.ts +++ b/web/source/kmwdevice.ts @@ -46,6 +46,7 @@ namespace com.keyman { detect() : void { var IEVersion = Device._GetIEVersion(); + var possMacSpoof = false; if(navigator && navigator.userAgent) { var agent=navigator.userAgent; @@ -70,7 +71,21 @@ namespace com.keyman { } else if(agent.indexOf('Linux') >= 0) { this.OS='Linux'; } else if(agent.indexOf('Macintosh') >= 0) { - this.OS='MacOSX'; + // Starting with 13.1, "Macintosh" can reflect iPads (by default) or iPhones + // (by user setting); a new "Request Desktop Website" setting for Safari will + // change the user agent string to match a desktop Mac. + let regex = /Intel Mac OS X (10(?:_\d+)+)/i; + let results = regex.exec(agent); + + // Match result: a version string with components separated by underscores. + if(results.length > 1 && results[1]) { + // Convert version string into a usable form. + let versionString = results[1].replace('_', '.'); + let version = new utils.Version(versionString); + + possMacSpoof = utils.Version.MAC_POSSIBLE_IPAD_ALIAS.compareTo(version) <= 0; + this.OS='MacOSX'; + } } else if(agent.indexOf('Windows NT') >= 0) { this.OS='Windows'; if(agent.indexOf('Touch') >= 0) { @@ -133,6 +148,30 @@ namespace com.keyman { } } } + + if(possMacSpoof && this.browser == 'safari') { + // Indistinguishable user agent string! We need a different test; fortunately, true macOS + // Safari doesn't support TouchEvents. (Chrome does, though! Hence the filter above.) + if(window['TouchEvent']) { + this.OS='iOS'; + this.formFactor='tablet'; + this.dyPortrait=this.dyLandscape=0; + + // It's currently impossible to differentiate between iPhone and iPad here + // except for by screen dimensions. + let aspectRatio = screen.height / screen.width; + if(aspectRatio < 1) { + aspectRatio = 1 / aspectRatio; + } + + // iPhones usually have a ratio of 16:9 (or 1.778) or higher, while iPads use 4:3 (or 1.333) + if(aspectRatio > 1.6) { + // Override - we'll treat this device as an iPhone. + this.formFactor = 'phone'; + this.dyPortrait=this.dyLandscape=25; + } + } + } } static _GetIEVersion() { diff --git a/web/source/text/kbdInterface.ts b/web/source/text/kbdInterface.ts index 4964c0962c..c7c3a9897b 100644 --- a/web/source/text/kbdInterface.ts +++ b/web/source/text/kbdInterface.ts @@ -842,7 +842,9 @@ namespace com.keyman.text { // We want to control exactly which deadkeys get removed. if(dn > 0) { context = this._BuildExtendedContext(dn, dn, outputTarget); - for(var i=0; i < context.deadContext.length; i++) { + let nulCount = 0; + + for(var i=0; i < context.valContext.length; i++) { var dk = context.deadContext[i]; if(dk) { @@ -851,8 +853,18 @@ namespace com.keyman.text { // Reduce our reported context size. dn--; + } else if(context.valContext[i] == "\uFFFE") { + // Count any `nul` sentinels that would contribute to our deletion count. + nulCount++; } } + + // Prevent attempts to delete nul sentinels, as they don't exist in the actual context. + // (Addresses regression from KMW v 12.0 paired with Developer bug through same version) + let contextLength = context.valContext.length - nulCount; + if(dn > contextLength) { + dn = contextLength; + } } // If a matched deadkey hasn't been deleted, we don't WANT to delete it. diff --git a/web/source/text/outputTarget.ts b/web/source/text/outputTarget.ts index fcdf05f068..ee6fe10ed7 100644 --- a/web/source/text/outputTarget.ts +++ b/web/source/text/outputTarget.ts @@ -329,6 +329,9 @@ namespace com.keyman.text { deleteCharsBeforeCaret(dn: number): void { if(dn >= 0) { + if(dn > this.caretIndex) { + dn = this.caretIndex; + } this.text = this.text.kmwSubstr(0, this.caretIndex - dn) + this.getTextAfterCaret(); this.caretIndex -= dn; } diff --git a/web/source/text/processor.ts b/web/source/text/processor.ts index 02801a2632..1683cd7678 100644 --- a/web/source/text/processor.ts +++ b/web/source/text/processor.ts @@ -149,9 +149,21 @@ namespace com.keyman.text { // kbdInterface.defaultBackspace(); // } } - } else if(Lkc.Lcode == 8) { //Only desktop UI, not touch devices. TODO: add repeat while mouse down for desktop UI - keyman.interface.defaultBackspace(); - return ''; + + // Only desktop UI, not touch devices. TODO: add repeat while mouse down for desktop UI + // + // Can easily occur from mnemonic keyboards, which create synthetic events without + // the appropriate kName value. + // + // Not strictly if `Lkc.vkCode` is properly maintained, but it's good to have an + // extra safety; this would have blocked the backspace bug as well. + } else if(Lkc.Lcode == 8) { + if(disableDOM) { + return '\b'; // the escape sequence for backspace. + } else { + keyman.interface.defaultBackspace(); + return ''; + } } // Translate numpad keystrokes into their non-numpad equivalents @@ -560,13 +572,26 @@ namespace com.keyman.text { mappingEvent[key] = Lkc[key]; } + // To facilitate storing relevant commands, we should probably reverse-lookup + // the actual keyname instead. mappingEvent.kName = 'K_xxxx'; mappingEvent.Ltarg = null; - var mappedChar: string = this.defaultKeyOutput(Lkc, (shifted ? 0x10 : 0), false, true); + var mappedChar: string = this.defaultKeyOutput(mappingEvent, (shifted ? 0x10 : 0), false, true); + + /* First, save a backup of the original code. This one won't needlessly trigger keyboard + * rules, but allows us to replicate/emulate commands after rule processing if needed. + * (Like backspaces) + */ + Lkc.vkCode = Lkc.Lcode; if(mappedChar) { - // FIXME; Warning - will return 96 for 'a', which is a keycode corresponding to Codes.keyCodes('K_NP1') - a numpad key. + // Will return 96 for 'a', which is a keycode corresponding to Codes.keyCodes('K_NP1') - a numpad key. + // That stated, we're in mnemonic mode - this keyboard's rules are based on the char codes. Lkc.Lcode = mappedChar.charCodeAt(0); - } // No 'else' - avoid blocking modifier keys, etc. + } else { + // Don't let command-type keys (like K_DEL, which will output '.' otherwise!) + // trigger keyboard rules. + delete Lkc.Lcode; + } } if(capsActive) { diff --git a/web/source/utils/version.ts b/web/source/utils/version.ts index 3d43ee7ea8..7b64b37e53 100644 --- a/web/source/utils/version.ts +++ b/web/source/utils/version.ts @@ -9,6 +9,8 @@ namespace com.keyman.utils { // as it results in unexpected, bug-like behavior for keyboard designers when it is unwanted. public static readonly NO_DEFAULT_KEYCAPS = new Version([12, 0]); + public static readonly MAC_POSSIBLE_IPAD_ALIAS = new Version([10, 15]); + private readonly components: number[] /** diff --git a/web/unit_tests/cases/element_interfaces.js b/web/unit_tests/cases/element_interfaces.js index 601469a6ba..e1ed36b69c 100644 --- a/web/unit_tests/cases/element_interfaces.js +++ b/web/unit_tests/cases/element_interfaces.js @@ -31,6 +31,7 @@ if(typeof InterfaceTests == 'undefined') { InterfaceTests.Input.resetWithText = function(pair, string) { pair.elem.value = string; + pair.wrapper.invalidateSelection(); pair.elem.setSelectionRange(0, 0); } @@ -76,6 +77,7 @@ if(typeof InterfaceTests == 'undefined') { InterfaceTests.TextArea.resetWithText = function(pair, string) { pair.elem.value = string; + pair.wrapper.invalidateSelection(); pair.elem.setSelectionRange(0, 0); } @@ -803,6 +805,14 @@ if(typeof InterfaceTests == 'undefined') { pair.wrapper.deleteCharsBeforeCaret(2); assert.equal(pair.wrapper.getText(), Apple.mixed.substr(0, 1) + Apple.mixed.substr(4), "Error deleting context chars from a mixed SMP string"); String.kmwEnableSupplementaryPlane(false); + + String.kmwEnableSupplementaryPlane(false); + testObj.resetWithText(pair, Apple.normal); + testObj.setCaret(pair, 4); + pair.wrapper.deleteCharsBeforeCaret(7); + assert.equal(pair.wrapper.getText(), "e", "Bounds-check on deletion range failed; context improperly deleted."); + String.kmwEnableSupplementaryPlane(false); + pair.wrapper.invalidateSelection(); } InterfaceTests.Tests.deleteCharsBeforeCaretWithSelection = function(testObj) { diff --git a/windows/src/desktop/history.md b/windows/src/desktop/history.md index ff1afe1a1a..2700822cc0 100644 --- a/windows/src/desktop/history.md +++ b/windows/src/desktop/history.md @@ -3,6 +3,10 @@ ## 13.0 alpha * Start version 13.0 +## 2019-11-12 12.0.53 stable +* Bug Fix: Address instability when exiting Keyman on some systems (#2324) +* Bug Fix: Keyman was not working with Skype, Windows Search on some systems (#2324) + ## 2019-10-20 12.0.52 stable * Upgrades from 11.0 and 12.0 were losing installed keyboards and settings (#2214) diff --git a/windows/src/engine/keyman/UfrmKeyman7Main.pas b/windows/src/engine/keyman/UfrmKeyman7Main.pas index 8c198f699f..c37b73fb95 100644 --- a/windows/src/engine/keyman/UfrmKeyman7Main.pas +++ b/windows/src/engine/keyman/UfrmKeyman7Main.pas @@ -442,6 +442,10 @@ begin begin olestrm := TOLEStream.Create(istrm); try + // In some situations, launching the app multiple times rapidly can + // cause the icon to be loaded multiple times. Make sure we reset the + // stream position before we try and read. + olestrm.Position := 0; Application.Icon.LoadFromStream(olestrm); finally olestrm.Free; diff --git a/windows/src/engine/keyman/keyman.dpr b/windows/src/engine/keyman/keyman.dpr index b2352c3a7e..2f9bed1197 100644 --- a/windows/src/engine/keyman/keyman.dpr +++ b/windows/src/engine/keyman/keyman.dpr @@ -1,7 +1,5 @@ program keyman; - - uses Forms, Dialogs, @@ -148,6 +146,11 @@ uses {$R VERSION.RES} {$R MANIFEST.RES} +// +// PEOPTFLAGS $140 turns on Data Execution Prevention +// +{$SETPEOPTFLAGS $140} + begin //InitTntEnvironment; //ShowMessage('Start'); diff --git a/windows/src/engine/keyman/main.pas b/windows/src/engine/keyman/main.pas index beb32bc105..14677a5987 100644 --- a/windows/src/engine/keyman/main.pas +++ b/windows/src/engine/keyman/main.pas @@ -181,6 +181,10 @@ begin if r.OpenKey(SRegKey_KeymanRoot_CU, True) then begin GrantPermissionToAllApplicationPackages(r.CurrentKey, KEY_READ); + // #1680 - on some systems, HKCU\Software\Keyman\Keyman Engine is not + // inheriting permissions from HKCU\Software\Keyman + if r.OpenKey('\' + SRegKey_KeymanEngineRoot_CU, True) then + GrantPermissionToAllApplicationPackages(r.CurrentKey, KEY_READ); end; finally r.Free; diff --git a/windows/src/engine/keyman32/Keyman32.cpp b/windows/src/engine/keyman32/Keyman32.cpp index 9f4948f35b..f146f3eae0 100644 --- a/windows/src/engine/keyman32/Keyman32.cpp +++ b/windows/src/engine/keyman32/Keyman32.cpp @@ -157,11 +157,13 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) case DLL_PROCESS_ATTACH: //if(!TestDebugProcess()) return FALSE; //if(!ShouldAttachToProcess()) return FALSE; + OutputThreadDebugString("DLL_PROCESS_ATTACH"); if(!Globals_InitProcess()) return FALSE; break; case DLL_PROCESS_DETACH: //if(!TestDebugProcess()) return FALSE; if (reserved == NULL) { + OutputThreadDebugString("DLL_PROCESS_DETACH not terminating"); // If reserved == NULL, that means the library is being unloaded, but // the process is not terminating. // @@ -180,15 +182,20 @@ BOOL __stdcall DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID reserved) // CloseTSF from here. This needs further investigation... UninitialiseProcess(FALSE); Globals_UninitProcess(); + } + else { + OutputThreadDebugString("DLL_PROCESS_DETACH terminating"); } break; case DLL_THREAD_ATTACH: //if(!TestDebugProcess()) return FALSE; + OutputThreadDebugString("DLL_THREAD_ATTACH"); Globals_InitThread(); break; case DLL_THREAD_DETACH: //if(!TestDebugProcess()) return FALSE; - UninitialiseProcess(FALSE); + OutputThreadDebugString("DLL_THREAD_DETACH"); + UninitialiseProcess(FALSE); Globals_UninitThread(); break; } @@ -214,8 +221,13 @@ BOOL UninitialiseProcess(BOOL Lock) if(_td->IndexStack) delete _td->IndexStack; _td->IndexStack = NULL; - } + if (_td->miniContext) delete _td->miniContext; + _td->miniContext = NULL; + + if (_td->msgbuf) delete _td->msgbuf; + _td->msgbuf = NULL; + } return TRUE; } @@ -512,6 +524,10 @@ extern "C" BOOL _declspec(dllexport) WINAPI Keyman_Exit(void) return FALSE; } +#ifndef _WIN64 + Hotkeys::Unload(); +#endif + *Globals::InitialisingThread() = 0; BOOL RetVal = TRUE; @@ -801,6 +817,7 @@ void LoadBaseLayoutSettings() { // I4552 // I4583 void RefreshKeyboards(BOOL Initialising) { + OutputThreadDebugString("RefreshKeyboards"); char sz[_MAX_FNAME]; char oldname[_MAX_FNAME]; RegistryReadOnly *reg2; @@ -828,7 +845,7 @@ void RefreshKeyboards(BOOL Initialising) _td->ActiveKeymanID = KEYMANID_NONKEYMAN; } - ReleaseKeyboards(TRUE); + ReleaseKeyboards(TRUE); /* Read the "keyboard off hotkey", simulate Alt+Gr, Hotkeys-Toggle flags */ @@ -938,13 +955,14 @@ void RefreshKeyboards(BOOL Initialising) _td->FInRefreshKeyboards = FALSE; } - void ReleaseKeyboards(BOOL Lock) { + OutputThreadDebugString("ReleaseKeyboards"); PKEYMAN64THREADDATA _td = ThreadGlobals(); - if(!_td || _td->lpKeyboards) return; + if(!_td || !_td->lpKeyboards) return; - if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); + + if(Lock) if(_td->lpActiveKeyboard && !_td->ForceFileName[0]) DeactivateDLLs(_td->lpActiveKeyboard); for(int i = 0; i < _td->nKeyboards; i++) { diff --git a/windows/src/engine/keyman32/hookutils.cpp b/windows/src/engine/keyman32/hookutils.cpp index 15c24283b9..6ccccae719 100644 --- a/windows/src/engine/keyman32/hookutils.cpp +++ b/windows/src/engine/keyman32/hookutils.cpp @@ -15,45 +15,48 @@ typedef BOOL IN CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam OPTIONAL ); +DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) { +#ifndef _DEBUG + UNREFERENCED_PARAMETER(Proc); +#endif -DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) -{ MINIDUMP_EXCEPTION_INFORMATION mei; char filename[MAX_PATH], temppath[MAX_PATH]; - if(GetTempPath(MAX_PATH, temppath) == 0 || - GetTempFileName(temppath, "kmc", 0, filename) == 0) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to generate temp file name"); - else - { + if (GetTempPath(MAX_PATH, temppath) == 0 || + GetTempFileName(temppath, "kmc", 0, filename) == 0) { + OutputThreadDebugString("Minidump failed to generate temp file name\n"); + } + else { HANDLE hFile = CreateFile(filename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL); - if(!hFile) - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump failed to create file %s", filename); - else - { + if (!hFile) { + OutputThreadDebugString("Minidump failed to create file "); + OutputThreadDebugString(filename); + } + else { mei.ClientPointers = TRUE; mei.ExceptionPointers = ep; mei.ThreadId = GetCurrentThreadId(); HMODULE hDbgHelp = LoadLibrary("dbghelp.dll"); - if(!hDbgHelp) - SendDebugMessage(0, sdmGlobal, 0, "dbghelp.dll not available"); - else - { + if (!hDbgHelp) { + OutputThreadDebugString("dbghelp.dll not available"); + } + else { PMiniDumpWriteDump mdwd = (PMiniDumpWriteDump) GetProcAddress(hDbgHelp, "MiniDumpWriteDump"); - if(!mdwd) - SendDebugMessage(0, sdmGlobal, 0, "MiniDumpWriteDump not available"); - else - { + if (!mdwd) { + OutputThreadDebugString("MiniDumpWriteDump not available"); + } + else { if (!(*mdwd)(GetCurrentProcess(), GetCurrentProcessId(), hFile, - (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), - &mei, NULL, NULL)) + (MINIDUMP_TYPE)(MiniDumpWithDataSegs | MiniDumpWithHandleData), + &mei, NULL, NULL)) { DebugLastError("MiniDumpWriteDump"); - else - { - SendDebugMessageFormat(0, sdmGlobal, 0, "Minidump written to %s", filename); + } + else { + OutputThreadDebugString("Minidump written to "); + OutputThreadDebugString(filename); HKEY hkey; if(RegCreateKeyEx(HKEY_CURRENT_USER, REGSZ_KeymanEngineDiag, 0, NULL, 0, KEY_ALL_ACCESS, - NULL, &hkey, NULL) == ERROR_SUCCESS) - { + NULL, &hkey, NULL) == ERROR_SUCCESS) { DWORD v = 0; RegSetValueEx(hkey, filename, 0, REG_DWORD, (PBYTE)&v, sizeof(DWORD)); RegCloseKey(hkey); @@ -66,23 +69,26 @@ DWORD ExceptionMessage(LPSTR Proc, LPEXCEPTION_POINTERS ep) } } - if(!ep || !ep->ExceptionRecord) - { - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT UNKNOWN EXCEPTION"); + if(!ep || !ep->ExceptionRecord) { + OutputThreadDebugString("CAUGHT UNKNOWN EXCEPTION"); return EXCEPTION_CONTINUE_SEARCH; } LPEXCEPTION_RECORD er = ep->ExceptionRecord; - while(er != NULL) - { - if(er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", - er->ExceptionCode, Proc, er->ExceptionAddress, - er->ExceptionInformation[0] == 0 ? "read from" : "write to", - er->ExceptionInformation[1]); - else - SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", - er->ExceptionCode, Proc, er->ExceptionAddress); + while(er != NULL) { + if (er->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + OutputThreadDebugString("EXCEPTION_ACCESS_VIOLATION in "); + OutputThreadDebugString(Proc); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d (ACCESS VIOLATION) IN %s AT %x; attempted to %s %x", + er->ExceptionCode, Proc, er->ExceptionAddress, + er->ExceptionInformation[0] == 0 ? "read from" : "write to", + er->ExceptionInformation[1]);*/ + } + else { + OutputThreadDebugString("CAUGHT EXCEPTION"); + /*SendDebugMessageFormat(0, sdmGlobal, 0, "CAUGHT EXCEPTION %d IN %s AT %x", + er->ExceptionCode, Proc, er->ExceptionAddress);*/ + } er = er->ExceptionRecord; } diff --git a/windows/src/engine/keyman32/hotkeys.cpp b/windows/src/engine/keyman32/hotkeys.cpp index a3363c49cc..cead296f8d 100644 --- a/windows/src/engine/keyman32/hotkeys.cpp +++ b/windows/src/engine/keyman32/hotkeys.cpp @@ -45,6 +45,18 @@ Hotkeys *Hotkeys::Instance() { // I4326 return g_Hotkeys; } +void Hotkeys::Unload() { + if (GetCurrentThreadId() != Globals::get_InitialisingThread()) { + OutputThreadDebugString("Unexpected: no other thread should be attempting to unload hotkeys"); + return; + } + + if (g_Hotkeys != NULL) { + delete g_Hotkeys; + g_Hotkeys = NULL; + } +} + void Hotkeys::Reload() { // I4326 // I4390 Hotkeys *hotkeys = Hotkeys::Instance(); // I4641 if(hotkeys == NULL) { diff --git a/windows/src/engine/keyman32/hotkeys.h b/windows/src/engine/keyman32/hotkeys.h index b011d20547..863be3636c 100644 --- a/windows/src/engine/keyman32/hotkeys.h +++ b/windows/src/engine/keyman32/hotkeys.h @@ -43,4 +43,5 @@ public: Hotkey *GetHotkey(DWORD hotkey); static void Reload(); // I4326 static Hotkeys *Instance(); // I4326 -}; + static void Unload(); + }; diff --git a/windows/src/engine/keyman32/K32_DBG.CPP b/windows/src/engine/keyman32/k32_dbg.cpp similarity index 98% rename from windows/src/engine/keyman32/K32_DBG.CPP rename to windows/src/engine/keyman32/k32_dbg.cpp index 7fcc025762..f78eb737fa 100644 --- a/windows/src/engine/keyman32/K32_DBG.CPP +++ b/windows/src/engine/keyman32/k32_dbg.cpp @@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) { } //WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL); return bufout[x]; -} \ No newline at end of file +} + +#ifdef _DEBUG +void _OutputThreadDebugString(char *s) { + char buf[256]; + sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s); + OutputDebugString(buf); +} +#endif diff --git a/windows/src/engine/keyman32/k32_globals.cpp b/windows/src/engine/keyman32/k32_globals.cpp index af59056a15..2a08e6c293 100644 --- a/windows/src/engine/keyman32/k32_globals.cpp +++ b/windows/src/engine/keyman32/k32_globals.cpp @@ -138,7 +138,11 @@ PKEYMAN64THREADDATA Globals_InitThread() void Globals_UninitThread() { - if(!Globals_ProcessInitialised()) return; + OutputThreadDebugString("Globals_UninitThread"); + if (!Globals_ProcessInitialised()) { + OutputThreadDebugString("Globals_UninitThread aborted without cleanup"); + return; + } CloseTSF(); // I3933 @@ -185,6 +189,7 @@ void Globals_UninitProcess() TlsFree(dwTlsIndex); dwTlsIndex = TLS_OUT_OF_INDEXES; LeaveCriticalSection(&csGlobals); + DeleteCriticalSection(&csGlobals); } PKEYMAN64THREADDATA ThreadGlobals() diff --git a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp index b50e0486e4..fee747f486 100644 --- a/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp +++ b/windows/src/engine/keyman32/k32_lowlevelkeyboardhook.cpp @@ -53,7 +53,7 @@ LRESULT CALLBACK kmnLowLevelKeyboardProc( __except(ExceptionMessage("kmnLowLevelKeyboardProc", GetExceptionInformation())) { } #endif - return res; + return res; } BOOL KeyLanguageSwitchPress(WPARAM wParam, BOOL extended, BOOL isUp, DWORD ShiftState); diff --git a/windows/src/engine/keyman32/keyboardoptions.cpp b/windows/src/engine/keyman32/keyboardoptions.cpp index 2e907c6460..1e0e0a8511 100644 --- a/windows/src/engine/keyman32/keyboardoptions.cpp +++ b/windows/src/engine/keyman32/keyboardoptions.cpp @@ -41,9 +41,10 @@ void LoadSharedKeyboardOptions(LPINTKEYBOARDINFO kp) void FreeKeyboardOptions(LPINTKEYBOARDINFO kp) { - assert(kp != NULL); - assert(kp->Keyboard != NULL); - assert(kp->KeyboardOptions != NULL); + // This is a cleanup routine; we don't want to precondition all calls to it + // so we do not assert + if (kp == NULL || kp->Keyboard == NULL || kp->KeyboardOptions == NULL) + return; for(DWORD i = 0; i < kp->Keyboard->cxStoreArray; i++) if(kp->KeyboardOptions[i].Value) diff --git a/windows/src/engine/keyman32/kmhook_callwndproc.cpp b/windows/src/engine/keyman32/kmhook_callwndproc.cpp index 4b72ab7bd6..7178ed5fea 100644 --- a/windows/src/engine/keyman32/kmhook_callwndproc.cpp +++ b/windows/src/engine/keyman32/kmhook_callwndproc.cpp @@ -66,6 +66,7 @@ LRESULT _kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam); LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { LRESULT res = 0; + #ifdef _DEBUG_EXCEPTION res = _kmnCallWndProc(nCode,wParam,lParam); #else @@ -77,7 +78,7 @@ LRESULT CALLBACK kmnCallWndProc(int nCode, WPARAM wParam, LPARAM lParam) { } #endif - return res; + return res; } // I3617 BOOL IsSysTrayWindow(HWND hwnd); diff --git a/windows/src/engine/keyman32/serialkeyeventclient.cpp b/windows/src/engine/keyman32/serialkeyeventclient.cpp index 3719b9409a..722903e6c3 100644 --- a/windows/src/engine/keyman32/serialkeyeventclient.cpp +++ b/windows/src/engine/keyman32/serialkeyeventclient.cpp @@ -149,6 +149,7 @@ public: }; void ISerialKeyEventClient::Startup() { + OutputThreadDebugString("ISerialKeyEventClient::Startup"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td) { _td->pSerialKeyEventClient = new SerialKeyEventClient(); @@ -156,6 +157,7 @@ void ISerialKeyEventClient::Startup() { } void ISerialKeyEventClient::Shutdown() { + OutputThreadDebugString("ISerialKeyEventClient::Shutdown"); PKEYMAN64THREADDATA _td = ThreadGlobals(); if (_td && _td->pSerialKeyEventClient) { delete _td->pSerialKeyEventClient; diff --git a/windows/src/global/delphi/general/klog.pas b/windows/src/global/delphi/general/klog.pas index 8f8198bf31..0915696743 100644 --- a/windows/src/global/delphi/general/klog.pas +++ b/windows/src/global/delphi/general/klog.pas @@ -133,7 +133,7 @@ begin end; writeln(FLogFile, Format('%12.12d ', [GetTickCount()])+FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Now) + ': ' + StringOfChar(' ', FMethodStack.Count*2) + msg); flush(FLogFile); - OutputDebugString(PChar(msg)); + OutputDebugString(PChar('KLog:' + msg + #13#10)); {$ENDIF} end; diff --git a/windows/src/global/inc/keyman64.h b/windows/src/global/inc/keyman64.h index ca8961501e..65e17b6db9 100644 --- a/windows/src/global/inc/keyman64.h +++ b/windows/src/global/inc/keyman64.h @@ -347,6 +347,13 @@ BOOL ShouldDebug_1(); // TSDMState state); #endif +#ifdef _DEBUG +#define OutputThreadDebugString(s) _OutputThreadDebugString(s) +void _OutputThreadDebugString(char *s); +#else +#define OutputThreadDebugString(s) +#endif + /* Keyboard selection functions */ void HandleRefresh(int code, LONG tag);