Merge branch 'stable-12.0' into android-fix-left-deletions

This commit is contained in:
Darcy Wong 2019-11-13 16:45:16 +07:00
commit a3f2ec720d
95 changed files with 601 additions and 396 deletions

View file

@ -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";

View file

@ -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) {

View file

@ -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))
}

View file

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

View file

@ -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 {

View file

@ -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)
}

View file

@ -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
}

View file

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

View file

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

View file

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

View file

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

View file

@ -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
}

View file

@ -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
}

View file

@ -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 {

View file

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

View file

@ -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
}

View file

@ -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),

View file

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

View file

@ -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)
}

View file

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

View file

@ -56,6 +56,8 @@
</dict>
<key>UIFileSharingEnabled</key>
<true/>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIPrerenderedIcon</key>
<true/>
<key>UIRequiredDeviceCapabilities</key>
@ -79,6 +81,8 @@
</array>
<key>UISupportsDocumentBrowser</key>
<false/>
<key>UIUserInterfaceStyle</key>
<string>Light</string>
<key>UTExportedTypeDeclarations</key>
<array>
<dict>

View file

@ -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 = "<group>"; };
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 = "<group>"; };
/* 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;

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1110"
wasCreatedForAppExtension = "YES"
version = "2.0">
<BuildAction
@ -30,14 +30,13 @@
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = ""
selectedLauncherIdentifier = "Xcode.IDEFoundation.Launcher.PosixSpawn"
launchStyle = "0"
askForAppToLaunch = "Yes"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
@ -53,8 +52,6 @@
ReferencedContainer = "container:Keyman.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View file

@ -31,11 +31,11 @@ class ActivityItemProvider: UIActivityItemProvider {
override var item: Any {
switch activityType {
case UIActivityType.mail?:
case UIActivity.ActivityType.mail?:
return htmlMail(withText: text, font: font)
case UIActivityType.postToFacebook?:
case UIActivity.ActivityType.postToFacebook?:
return "\(text)\n\n\(fbText)"
case UIActivityType.postToTwitter?:
case UIActivity.ActivityType.postToTwitter?:
return text.prefix(140)
default:
return text

View file

@ -21,7 +21,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var navigationController: UINavigationController?
func application(_ app: UIApplication, open url: URL,
options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> 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)

View file

@ -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,

View file

@ -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

View file

@ -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"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

View file

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View file

@ -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"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

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

View file

@ -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)
}

View file

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

View file

@ -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!)))
}

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15400" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_0" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15404"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="320" height="548"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="Splash" translatesAutoresizingMaskIntoConstraints="NO" id="Qmt-Eh-ovK">
<rect key="frame" x="67" y="232" width="186" height="83"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
</imageView>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="Splash Gradient" translatesAutoresizingMaskIntoConstraints="NO" id="6cA-fn-Wvu">
<rect key="frame" x="0.0" y="535" width="320" height="15"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
</imageView>
</subviews>
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
</view>
<modalPageSheetSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52.232142857142854" y="373.91304347826087"/>
</scene>
</scenes>
<resources>
<image name="Splash" width="95.333335876464844" height="19.666666030883789"/>
<image name="Splash Gradient" width="320" height="7.5"/>
</resources>
</document>

View file

@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
<string>Latest</string>
</dict>
</plist>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1110"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -38,8 +36,8 @@
ReferencedContainer = "container:engine/KMEI/KeymanEngine.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -60,8 +58,6 @@
ReferencedContainer = "container:engine/KMEI/KeymanEngine.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1020"
LastUpgradeVersion = "1110"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
@ -38,8 +36,8 @@
ReferencedContainer = "container:keyman/Keyman/Keyman.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
<Testables>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
@ -61,8 +59,6 @@
ReferencedContainer = "container:keyman/Keyman/Keyman.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"

View file

@ -55,7 +55,7 @@ while [[ $# -gt 0 ]] ; do
DO_KEYMANAPP=false
;;
-no-codesign)
CODE_SIGN="CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO $DEV_TEAM"
CODE_SIGN="CODE_SIGN_IDENTITY= CODE_SIGNING_REQUIRED=NO $DEV_TEAM CODE_SIGN_ENTITLEMENTS= CODE_SIGNING_ALLOWED=NO"
DO_ARCHIVE=false
;;
-no-archive)

View file

@ -144,6 +144,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.

View file

@ -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.

View file

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

View file

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

View file

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

View file

@ -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() {

View file

@ -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.

View file

@ -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;
}

View file

@ -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) {

View file

@ -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[]
/**

View file

@ -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) {

View file

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

View file

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

View file

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

View file

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

View file

@ -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++)
{

View file

@ -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;
}

View file

@ -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) {

View file

@ -43,4 +43,5 @@ public:
Hotkey *GetHotkey(DWORD hotkey);
static void Reload(); // I4326
static Hotkeys *Instance(); // I4326
};
static void Unload();
};

View file

@ -304,4 +304,12 @@ char *Debug_UnicodeString(PWSTR s, int x) {
}
//WideCharToMultiByte(CP_ACP, 0, buf, -1, bufout, 128, NULL, NULL);
return bufout[x];
}
}
#ifdef _DEBUG
void _OutputThreadDebugString(char *s) {
char buf[256];
sprintf_s(buf, "[%d]: %s\n", GetCurrentThreadId(), s);
OutputDebugString(buf);
}
#endif

View file

@ -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()

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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