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);