Merge branch 'stable-12.0' into android-fix-left-deletions
|
|
@ -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";
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 21 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 79 KiB |
|
Before Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 84 KiB |
|
Before Width: | Height: | Size: 96 KiB |
21
ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
ios/keyman/Keyman/Keyman/Images.xcassets/Splash Gradient.imageset/gradient-footer@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
83
ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/Contents.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
BIN
ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x-1.png
vendored
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
ios/keyman/Keyman/Keyman/Images.xcassets/Splash.imageset/keyman_logo_dark@3x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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!)))
|
||||
}
|
||||
|
||||
|
|
|
|||
42
ios/keyman/Keyman/LaunchScreen.storyboard
Normal 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>
|
||||
|
|
@ -3,6 +3,6 @@
|
|||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildSystemType</key>
|
||||
<string>Original</string>
|
||||
<string>Latest</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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[]
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -43,4 +43,5 @@ public:
|
|||
Hotkey *GetHotkey(DWORD hotkey);
|
||||
static void Reload(); // I4326
|
||||
static Hotkeys *Instance(); // I4326
|
||||
};
|
||||
static void Unload();
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||