mirror of
https://github.com/keymanapp/keyman.git
synced 2026-09-06 15:47:40 +00:00
Migrate KMTextField to Swift
This commit is contained in:
parent
6e8fe32680
commit
6de84cc35e
9 changed files with 377 additions and 394 deletions
|
|
@ -42,6 +42,7 @@
|
|||
98FFB3D41B67006F00289F0E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FFB3D31B67006F00289F0E /* WebKit.framework */; };
|
||||
98FFB3D51B67008000289F0E /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 98FFB3D31B67006F00289F0E /* WebKit.framework */; };
|
||||
C040E50E1F85FF8A00901EE4 /* KeyPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E50D1F85FF8A00901EE4 /* KeyPreviewView.swift */; };
|
||||
C040E5101F8606E300901EE4 /* KeymanTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E50F1F8606E300901EE4 /* KeymanTextField.swift */; };
|
||||
C040E5121F86107E00901EE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E5111F86107E00901EE4 /* AppDelegate.swift */; };
|
||||
C040E5141F86108900901EE4 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E5131F86108900901EE4 /* MainViewController.swift */; };
|
||||
C04514881F85D7F500D88416 /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04514871F85D7F500D88416 /* KeyboardViewController.swift */; };
|
||||
|
|
@ -65,13 +66,11 @@
|
|||
C06D37441F81F5C400F61AE0 /* KeyboardNameTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08C62121F67C31100268D03 /* KeyboardNameTableViewCell.swift */; };
|
||||
C06D37451F81F5C400F61AE0 /* KMManager.m in Sources */ = {isa = PBXBuildFile; fileRef = F273AB9815641EC500A47CEE /* KMManager.m */; };
|
||||
C06D37461F81F5C400F61AE0 /* PopoverView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0A5FF361F6682EB00BE740C /* PopoverView.swift */; };
|
||||
C06D37471F81F5C400F61AE0 /* KMTextField.m in Sources */ = {isa = PBXBuildFile; fileRef = F273AB9315641C3F00A47CEE /* KMTextField.m */; };
|
||||
C06D37481F81F5C400F61AE0 /* KMTextFieldDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = F273ABA21564419700A47CEE /* KMTextFieldDelegateProxy.m */; };
|
||||
C06D37491F81F5C400F61AE0 /* KMTextViewDelegateProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 6CBD0DE1151EC30300D70779 /* KMTextViewDelegateProxy.m */; };
|
||||
C06D374A1F81F5C400F61AE0 /* KMTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = 6C0A1406151EA8B3007FA4AD /* KMTextView.m */; };
|
||||
C06D374B1F81F5F400F61AE0 /* Keyman.h in Headers */ = {isa = PBXBuildFile; fileRef = F27FCB67157FFE0B00FBBA20 /* Keyman.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C06D374D1F81FFF900F61AE0 /* KMManager.h in Headers */ = {isa = PBXBuildFile; fileRef = F273AB9715641EC500A47CEE /* KMManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C06D374E1F81FFF900F61AE0 /* KMTextField.h in Headers */ = {isa = PBXBuildFile; fileRef = F273AB9215641C3F00A47CEE /* KMTextField.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C06D374F1F81FFF900F61AE0 /* KMTextFieldDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = F273ABA11564419700A47CEE /* KMTextFieldDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C06D37521F82001100F61AE0 /* KMTextView.h in Headers */ = {isa = PBXBuildFile; fileRef = 6C0A1405151EA8B3007FA4AD /* KMTextView.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
C06D37531F82001100F61AE0 /* KMTextViewDelegateProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 6CBD0DE0151EC30300D70779 /* KMTextViewDelegateProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
|
@ -188,6 +187,7 @@
|
|||
98FFB3D31B67006F00289F0E /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
|
||||
C034BBBD1F7CCE7D00021FF5 /* KeyboardMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardMenuView.swift; sourceTree = "<group>"; };
|
||||
C040E50D1F85FF8A00901EE4 /* KeyPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPreviewView.swift; sourceTree = "<group>"; };
|
||||
C040E50F1F8606E300901EE4 /* KeymanTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeymanTextField.swift; sourceTree = "<group>"; };
|
||||
C040E5111F86107E00901EE4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
C040E5131F86108900901EE4 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
C04514861F85D7F500D88416 /* SystemKeyboard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SystemKeyboard-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
|
|
@ -217,8 +217,6 @@
|
|||
F26071FF158F8C6000F37184 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||
F2607201158F8C9600F37184 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
F2607203158F8CA200F37184 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||
F273AB9215641C3F00A47CEE /* KMTextField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KMTextField.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
F273AB9315641C3F00A47CEE /* KMTextField.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = KMTextField.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
F273AB9715641EC500A47CEE /* KMManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = KMManager.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
F273AB9815641EC500A47CEE /* KMManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = KMManager.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
F273AB9A15641F0E00A47CEE /* CWLSynthesizeSingleton.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CWLSynthesizeSingleton.h; sourceTree = "<group>"; };
|
||||
|
|
@ -562,10 +560,9 @@
|
|||
F273AB9E156440CD00A47CEE /* UITextField */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
F273AB9215641C3F00A47CEE /* KMTextField.h */,
|
||||
F273AB9315641C3F00A47CEE /* KMTextField.m */,
|
||||
F273ABA11564419700A47CEE /* KMTextFieldDelegateProxy.h */,
|
||||
F273ABA21564419700A47CEE /* KMTextFieldDelegateProxy.m */,
|
||||
C040E50F1F8606E300901EE4 /* KeymanTextField.swift */,
|
||||
);
|
||||
name = UITextField;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -633,7 +630,6 @@
|
|||
C06D372F1F81F4E100F61AE0 /* KeymanEngine.h in Headers */,
|
||||
C06D374B1F81F5F400F61AE0 /* Keyman.h in Headers */,
|
||||
C06D374D1F81FFF900F61AE0 /* KMManager.h in Headers */,
|
||||
C06D374E1F81FFF900F61AE0 /* KMTextField.h in Headers */,
|
||||
C06D374F1F81FFF900F61AE0 /* KMTextFieldDelegateProxy.h in Headers */,
|
||||
C06D37521F82001100F61AE0 /* KMTextView.h in Headers */,
|
||||
C06D37531F82001100F61AE0 /* KMTextViewDelegateProxy.h in Headers */,
|
||||
|
|
@ -866,10 +862,10 @@
|
|||
C06D37421F81F5C400F61AE0 /* KeyboardPickerButton.swift in Sources */,
|
||||
C06D37431F81F5C400F61AE0 /* KeyboardPickerBarButtonItem.swift in Sources */,
|
||||
C06D37441F81F5C400F61AE0 /* KeyboardNameTableViewCell.swift in Sources */,
|
||||
C040E5101F8606E300901EE4 /* KeymanTextField.swift in Sources */,
|
||||
C06D37451F81F5C400F61AE0 /* KMManager.m in Sources */,
|
||||
C045148A1F85DF9100D88416 /* KeymanInputViewController.swift in Sources */,
|
||||
C06D37461F81F5C400F61AE0 /* PopoverView.swift in Sources */,
|
||||
C06D37471F81F5C400F61AE0 /* KMTextField.m in Sources */,
|
||||
C06D37481F81F5C400F61AE0 /* KMTextFieldDelegateProxy.m in Sources */,
|
||||
C06D37491F81F5C400F61AE0 /* KMTextViewDelegateProxy.m in Sources */,
|
||||
C06D374A1F81F5C400F61AE0 /* KMTextView.m in Sources */,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
//
|
||||
// A one-stop hub for:
|
||||
// - global settings and behaviour for KMTextView and KMTextField
|
||||
// - global settings and behaviour for KMTextView and KeymanTextField
|
||||
// - displaying the keyboard picker/downloader
|
||||
// - all interaction with the Keyman servers (polling for info, downloading keyboards, etc)
|
||||
//
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
// [[KMManager sharedInstance] setKeyboardWithID:kbID languageID:langID keyboardName:kbName languageName:langName font:kbFont, oskFont:nil];
|
||||
//
|
||||
//
|
||||
// NOTES: 1) The easiest way to use this SDK is to simply use KMTextViews and KMTextFields in place of their UIKit counterparts
|
||||
// NOTES: 1) The easiest way to use this SDK is to simply use KMTextViews and KeymanTextFields in place of their UIKit counterparts
|
||||
// 2) All keyboard downloading and picking can be handled by globe key on the keyboard, displaying a KMKeyboardPickerButton or a
|
||||
// KMKeyboardPickerBarButtonItem
|
||||
// - when tapped, these will display a UI for the user to navigate all available Keyman keyboards
|
||||
|
|
@ -191,7 +191,7 @@ typedef enum {
|
|||
|
||||
// Displays a list of available keyboards and allows a user to add/download new keyboards or remove existing ones
|
||||
// - it is recommended that you pass in your current UIViewController rather than the navigation controller
|
||||
// - to enable/disable the keyboard picker on the keyboard, see KMTextView/KMTextField class reference
|
||||
// - to enable/disable the keyboard picker on the keyboard, see KMTextView/KeymanTextField class reference
|
||||
- (void)showKeyboardPickerInViewController:(UIViewController *)viewController shouldAddKeyboard:(BOOL)shouldAddKeyboard;
|
||||
- (void)dismissKeyboardPicker:(UIViewController *)viewController;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@
|
|||
#import "KMManager.h"
|
||||
#import "KMManager+Internal.h"
|
||||
#import "KMURLProtocol.h"
|
||||
#import "KMTextField.h"
|
||||
#import "KMTextView.h"
|
||||
#import "UIView+Helpers.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
|
@ -904,8 +903,8 @@ CWL_SYNTHESIZE_SINGLETON_FOR_CLASS_WITH_ACCESSOR(KMManager, sharedInstance);
|
|||
id firstResponder = [[[UIApplication sharedApplication] keyWindow] findFirstResponder];
|
||||
if ([firstResponder isKindOfClass:[KMTextView class]])
|
||||
[(KMTextView *)firstResponder dismissKeyboard];
|
||||
else if ([firstResponder isKindOfClass:[KMTextField class]])
|
||||
[(KMTextField *)firstResponder dismissKeyboard];
|
||||
else if ([firstResponder isKindOfClass:[KeymanTextField class]])
|
||||
[(KeymanTextField *)firstResponder dismissKeyboard];
|
||||
}
|
||||
|
||||
KeyboardPickerViewController *vc = [[KeyboardPickerViewController alloc] init];
|
||||
|
|
|
|||
|
|
@ -1,34 +0,0 @@
|
|||
//
|
||||
// KMTextField.h
|
||||
// Keyman Engine
|
||||
//
|
||||
// Copyright (c) 2017 SIL International. All rights reserved.
|
||||
//
|
||||
// KMTextField requires iOS 6.0 or greater due to use of the UITextInput protocol
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "KMTextFieldDelegateProxy.h"
|
||||
|
||||
@interface KMTextField : UITextField <UITextFieldDelegate> {
|
||||
KMTextFieldDelegateProxy *delegateProxy_;
|
||||
NSTimer *selectionPollingTimer_;
|
||||
NSInteger lastSelectionPosition_;
|
||||
NSInteger lastSelectionLength_;
|
||||
UIViewController *viewController; // viewController should be set to main view controller to enable keyboard picker.
|
||||
BOOL shouldSetCustomFontOnKeyboardChange_; // if YES, sets Keyman custom font (if any) to KMTextField instance on keyboard change event, defaults to YES.
|
||||
BOOL isInputClickSoundEnabled_; // if YES, plays keyboard click sound whenever input received, defaults to YES.
|
||||
}
|
||||
|
||||
@property (nonatomic, strong) UIViewController *viewController;
|
||||
@property (nonatomic, assign) BOOL shouldSetCustomFontOnKeyboardChange;
|
||||
@property (nonatomic, assign) BOOL isInputClickSoundEnabled;
|
||||
|
||||
// Use this KMTextFieldDelegate instead of the normal UITextFieldDelegate.
|
||||
// - All of the normal UITextFieldDelegate methods are supported.
|
||||
- (void)setKeymanDelegate:(id<KMTextFieldDelegate>)keymanDelegate;
|
||||
|
||||
// Dismisses the keyboard if this textview is the first responder.
|
||||
// - Use this instead of [resignFirstResponder] as it also resigns the Keyman keyboard's responders.
|
||||
- (void)dismissKeyboard;
|
||||
|
||||
@end
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
//
|
||||
// KMTextField.m
|
||||
// Keyman Engine
|
||||
//
|
||||
// Created by Patrick Weekes on 12-05-16.
|
||||
// Updated by Serkan Kurt on 17/05/2013.
|
||||
// Copyright (c) 2017 SIL International. All rights reserved.
|
||||
//
|
||||
|
||||
#import "KMTextField.h"
|
||||
#import "KMManager+Internal.h"
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
@interface KMTextField ()
|
||||
@property (nonatomic, strong) KMTextFieldDelegateProxy *delegateProxy;
|
||||
@property (nonatomic, strong) NSTimer *selectionPollingTimer;
|
||||
@property (nonatomic, assign) NSInteger lastSelectionPosition;
|
||||
@property (nonatomic, assign) NSInteger lastSelectionLength;
|
||||
@property (nonatomic, assign) BOOL shouldUpdateKMText;
|
||||
@end
|
||||
|
||||
@implementation KMTextField
|
||||
|
||||
@synthesize delegateProxy = delegateProxy_;
|
||||
@synthesize selectionPollingTimer = selectionPollingTimer_;
|
||||
@synthesize lastSelectionPosition = lastSelectionPosition_;
|
||||
@synthesize lastSelectionLength = lastSelectionLength_;
|
||||
@synthesize viewController;
|
||||
@synthesize shouldSetCustomFontOnKeyboardChange;
|
||||
@synthesize isInputClickSoundEnabled;
|
||||
@synthesize shouldUpdateKMText;
|
||||
|
||||
#pragma mark - Object Admin
|
||||
|
||||
- (void)dealloc {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
[self.selectionPollingTimer invalidate];
|
||||
self.delegate = nil;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
return [self initWithFrame:CGRectZero];
|
||||
}
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame {
|
||||
shouldSetCustomFontOnKeyboardChange = YES;
|
||||
isInputClickSoundEnabled = YES;
|
||||
if (self = [super initWithFrame:frame]) {
|
||||
self.delegateProxy = [[KMTextFieldDelegateProxy alloc] init];
|
||||
self.delegate = self.delegateProxy;
|
||||
|
||||
if ([self respondsToSelector:@selector(inputAssistantItem)]) {
|
||||
UITextInputAssistantItem *inputAssistantItem = [self inputAssistantItem];
|
||||
inputAssistantItem.leadingBarButtonGroups = @[];
|
||||
inputAssistantItem.trailingBarButtonGroups = @[];
|
||||
}
|
||||
|
||||
[KMManager sharedInstance]; // Preload webview keyboard
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(textfieldTextDidChange:) name:UITextFieldTextDidChangeNotification object:self];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardChanged:) name:kKeymanKeyboardChangedNotification object:nil];
|
||||
|
||||
self.lastSelectionPosition = 0;
|
||||
self.lastSelectionLength = 0;
|
||||
|
||||
NSString *minVersionString = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"MinimumOSVersion"];
|
||||
if ([minVersionString hasPrefix:@"4"] && [KMManager sharedInstance].debugPrintingOn)
|
||||
[[KMManager sharedInstance] KMLog:@"KMTextField requires iOS 5.0 onwards. Try KMTextView instead or change your deployment target." checkDebugPrinting:NO];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Class Overrides
|
||||
|
||||
- (UIView *)inputView {
|
||||
[KMManager sharedInstance].webDelegate = self;
|
||||
return [KMManager inputView];
|
||||
}
|
||||
|
||||
// Prevent the delegate being set to anything but self
|
||||
- (void)setDelegate:(id<UITextFieldDelegate>)delegate {
|
||||
// Allow clearing of delegate
|
||||
if (!delegate) {
|
||||
[super setDelegate:nil];
|
||||
} else {
|
||||
if (delegate != self.delegateProxy)
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"KMTextField: 0x%x Trying to set KMTextField's delegate directly. Use -[setKeymanDelegate:] instead.", (uint)self] checkDebugPrinting:YES];
|
||||
[super setDelegate:self.delegateProxy];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Public Methods
|
||||
|
||||
- (void)setKeymanDelegate:(id<KMTextFieldDelegate>)keymanDelegate {
|
||||
self.delegateProxy.keymanDelegate = keymanDelegate;
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"KMTextField: 0x%x keymanDelegate set to: %@", (uint)self, keymanDelegate] checkDebugPrinting:YES];
|
||||
}
|
||||
|
||||
- (void)dismissKeyboard {
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"KMTextField: 0x%x Dismissing keyboard. Was first responder:%@", (uint)self, [self isFirstResponder]?@"YES":@"NO"] checkDebugPrinting:YES];
|
||||
|
||||
[self resignFirstResponder];
|
||||
[[KMManager inputView] endEditing:YES];
|
||||
}
|
||||
|
||||
- (void)setText:(NSString *)text {
|
||||
if (text == nil)
|
||||
[super setText:@""];
|
||||
else
|
||||
[super setText:text];
|
||||
|
||||
[KMManager setKMText:self.text];
|
||||
UITextRange *textRange = self.selectedTextRange;
|
||||
NSRange newRange = NSMakeRange([self offsetFromPosition:[self beginningOfDocument] toPosition:textRange.start], [self offsetFromPosition:textRange.start toPosition:textRange.end]);
|
||||
[KMManager setKMSelectionRange:newRange manually:NO];
|
||||
}
|
||||
|
||||
#pragma mark - KMWebViewDelegate
|
||||
|
||||
- (void)updatedFragment:(NSString *)fragment {
|
||||
if (fragment && [fragment rangeOfString:@"insertText"].location != NSNotFound) {
|
||||
if ([[KMManager sharedInstance] isSubKeysMenuVisible])
|
||||
return;
|
||||
|
||||
if (isInputClickSoundEnabled) {
|
||||
AudioServicesPlaySystemSound(0x450);
|
||||
isInputClickSoundEnabled = NO; // Disable input click sound for 0.1 second to ensure it plays for single key stroke.
|
||||
[self performSelector:@selector(enableInputClickSound) withObject:nil afterDelay:0.1f];
|
||||
}
|
||||
|
||||
NSRange range1 = [fragment rangeOfString:@"+dn="];
|
||||
NSRange range2 = [fragment rangeOfString:@"+s="];
|
||||
range1.location += range1.length;
|
||||
range1.length = range2.location - range1.location;
|
||||
NSInteger dn = [[fragment substringWithRange:range1] integerValue];
|
||||
|
||||
range2.location += range2.length;
|
||||
range2.length = [fragment length] - range2.location;
|
||||
NSString *s = [fragment substringWithRange:range2];
|
||||
|
||||
NSMutableString *mText = nil;
|
||||
NSArray *unicodes = nil;
|
||||
if ([s length])
|
||||
unicodes = [s componentsSeparatedByString: @","];
|
||||
NSScanner *scanner = nil;
|
||||
for(int i=0; i<[unicodes count]; i++) {
|
||||
scanner = [NSScanner scannerWithString:[unicodes objectAtIndex:i]];
|
||||
unsigned int unicode;
|
||||
[scanner scanHexInt:&unicode];
|
||||
if(mText == nil)
|
||||
mText = [NSMutableString stringWithFormat:@"%C", (unsigned short) unicode];
|
||||
else
|
||||
[mText appendString:[NSString stringWithFormat:@"%C", (unsigned short) unicode]];
|
||||
}
|
||||
|
||||
if (mText == nil)
|
||||
mText = [NSMutableString stringWithString:@""];
|
||||
NSString *text = [NSString stringWithString:mText];
|
||||
mText = nil;
|
||||
|
||||
UITextRange *textRange = self.selectedTextRange;
|
||||
NSRange selRange = NSMakeRange([self offsetFromPosition:[self beginningOfDocument] toPosition:textRange.start], [self offsetFromPosition:textRange.start toPosition:textRange.end]);
|
||||
if (dn <= 0) {
|
||||
if(selRange.length == 0)
|
||||
[self insertText:text];
|
||||
else {
|
||||
NSString *t = self.text;
|
||||
NSString *r = [t stringByReplacingCharactersInRange:selRange withString:text];
|
||||
self.text = r;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (![s length]) {
|
||||
for (int i=0;i<dn;i++)
|
||||
[self deleteBackward];
|
||||
}
|
||||
else {
|
||||
if(selRange.length == 0) {
|
||||
for (int i=0;i<dn;i++)
|
||||
[self deleteBackward];
|
||||
[self insertText:text];
|
||||
}
|
||||
else {
|
||||
NSString *t = self.text;
|
||||
NSString *r = [t stringByReplacingCharactersInRange:selRange withString:text];
|
||||
self.text = r;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (fragment && [fragment rangeOfString:@"hideKeyboard"].location != NSNotFound) {
|
||||
[self dismissKeyboard];
|
||||
}
|
||||
else if (fragment && [fragment rangeOfString:@"menuKeyUp"].location != NSNotFound) {
|
||||
if (viewController != nil)
|
||||
[[KMManager sharedInstance] showKeyboardPickerInViewController:viewController shouldAddKeyboard:NO];
|
||||
else
|
||||
[[KMManager sharedInstance] switchToNextKeyboard];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate Hooks
|
||||
|
||||
- (void)setSelectedTextRange:(UITextRange *)selectedTextRange {
|
||||
[super setSelectedTextRange:selectedTextRange];
|
||||
NSRange newRange = NSMakeRange([self offsetFromPosition:[self beginningOfDocument] toPosition:selectedTextRange.start], [self offsetFromPosition:selectedTextRange.start toPosition:selectedTextRange.end]);
|
||||
[KMManager setKMSelectionRange:newRange manually:NO];
|
||||
}
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
|
||||
{
|
||||
shouldUpdateKMText = YES; // Enable text update to catch copy/paste operations
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textfieldTextDidChange:(NSNotification *)notification {
|
||||
if (shouldUpdateKMText) { // Catches copy/paste operations
|
||||
[KMManager setKMText:self.text];
|
||||
UITextRange *textRange = self.selectedTextRange;
|
||||
NSRange newRange = NSMakeRange([self offsetFromPosition:[self beginningOfDocument] toPosition:textRange.start], [self offsetFromPosition:textRange.start toPosition:textRange.end]);
|
||||
[KMManager setKMSelectionRange:newRange manually:NO];
|
||||
shouldUpdateKMText = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldClear:(KMTextField *)textField {
|
||||
if (textField == self)
|
||||
[KMManager clearText];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
|
||||
int iosVersion = [[[UIDevice currentDevice] systemVersion] intValue];
|
||||
if (iosVersion < 7)
|
||||
return YES;
|
||||
|
||||
NSString *lrm = @"\u200e";
|
||||
NSString *rlm = @"\u202e";
|
||||
NSString *keyboardID = [KMManager sharedInstance].keyboardID;
|
||||
NSString *languageID = [KMManager sharedInstance].languageID;
|
||||
UITextWritingDirection textWD = [self baseWritingDirectionForPosition:[self beginningOfDocument] inDirection:UITextStorageDirectionForward];
|
||||
if ([[KMManager sharedInstance] isRTLKeyboardWithID:keyboardID languageID:languageID]) {
|
||||
if (textWD != UITextWritingDirectionRightToLeft) {
|
||||
if ([self.text rangeOfString:lrm].location == 0) {
|
||||
NSMutableString *mText = [self.text mutableCopy];
|
||||
[mText deleteCharactersInRange:NSMakeRange(0, 1)];
|
||||
[self setText:[NSString stringWithString:mText]];
|
||||
mText = nil;
|
||||
}
|
||||
|
||||
if (![self.text length] || [self.text rangeOfString:rlm].location != 0)
|
||||
[self setText:[NSString stringWithFormat:@"%@%@", rlm, self.text]];
|
||||
[self makeTextWritingDirectionRightToLeft:nil];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (textWD != UITextWritingDirectionLeftToRight) {
|
||||
if ([self.text rangeOfString:rlm].location == 0) {
|
||||
NSMutableString *mText = [self.text mutableCopy];
|
||||
[mText deleteCharactersInRange:NSMakeRange(0, 1)];
|
||||
[self setText:[NSString stringWithString:mText]];
|
||||
mText = nil;
|
||||
}
|
||||
|
||||
if (![self.text length] || [self.text rangeOfString:lrm].location != 0)
|
||||
[self setText:[NSString stringWithFormat:@"%@%@", lrm, self.text]];
|
||||
[self makeTextWritingDirectionLeftToRight:nil];
|
||||
}
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)textFieldDidBeginEditing:(KMTextField *)textField {
|
||||
[KMManager sharedInstance].webDelegate = self;
|
||||
|
||||
NSString *keyboardID = [[KMManager sharedInstance] keyboardID];
|
||||
NSString *languageID = [[KMManager sharedInstance] languageID];
|
||||
NSString *fontName = [[KMManager sharedInstance] fontNameForKeyboardWithID:keyboardID languageID:languageID];
|
||||
CGFloat fontSize = [self.font pointSize];
|
||||
if (fontName != nil)
|
||||
[self setFont:[UIFont fontWithName:fontName size:fontSize]];
|
||||
else
|
||||
[self setFont:[UIFont systemFontOfSize:fontSize]];
|
||||
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"TextField setFont: %@", [self font].familyName] checkDebugPrinting:YES];
|
||||
|
||||
// copy this textField's text to the webview
|
||||
[KMManager setKMText:self.text];
|
||||
UITextRange *textRange = self.selectedTextRange;
|
||||
NSRange newRange = NSMakeRange([self offsetFromPosition:[self beginningOfDocument] toPosition:textRange.start], [self offsetFromPosition:textRange.start toPosition:textRange.end]);
|
||||
[KMManager setKMSelectionRange:newRange manually:NO];
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"KMTextField: 0x%x Became first responder. Value: %@", (uint)self, [self.text length]?self.text:@"<blank>"] checkDebugPrinting:YES];
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldEndEditing:(KMTextField *)textField {
|
||||
if (textField == self)
|
||||
[self resignFirstResponder];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - Keyman notifications
|
||||
|
||||
- (void)keyboardChanged:(NSNotification *)notification {
|
||||
if (!self.shouldSetCustomFontOnKeyboardChange)
|
||||
return;
|
||||
|
||||
NSDictionary *kbInfo = [[notification userInfo] objectForKey:kKeymanKeyboardInfoKey];
|
||||
NSString *keyboardID = [kbInfo objectForKey:kKeymanKeyboardIdKey];
|
||||
NSString *languageID = [kbInfo objectForKey:kKeymanLanguageIdKey];
|
||||
NSString *fontName = [[KMManager sharedInstance] fontNameForKeyboardWithID:keyboardID languageID:languageID];
|
||||
CGFloat fontSize = [self.font pointSize];
|
||||
if (fontName != nil)
|
||||
[self setFont:[UIFont fontWithName:fontName size:fontSize]];
|
||||
else
|
||||
[self setFont:[UIFont systemFontOfSize:fontSize]];
|
||||
|
||||
if ([self isFirstResponder]) {
|
||||
[self resignFirstResponder];
|
||||
[self becomeFirstResponder];
|
||||
}
|
||||
|
||||
[[KMManager sharedInstance] KMLog:[NSString stringWithFormat:@"TextField setFont: %@", [self font].familyName] checkDebugPrinting:YES];
|
||||
}
|
||||
|
||||
#pragma mark - Private Methods
|
||||
|
||||
- (void)enableInputClickSound {
|
||||
isInputClickSoundEnabled = YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
//
|
||||
|
||||
#import "KMTextFieldDelegateProxy.h"
|
||||
#import "KMTextField.h"
|
||||
#import "KeymanEngine/KeymanEngine-Swift.h"
|
||||
|
||||
@implementation KMTextFieldDelegateProxy
|
||||
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
// NOTE: the return value from the textField's hook is ignored
|
||||
- (BOOL)textFieldShouldBeginEditing:(KMTextField *)textField {
|
||||
- (BOOL)textFieldShouldBeginEditing:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldShouldBeginEditing:)]) {
|
||||
[textField textFieldShouldBeginEditing:textField];
|
||||
}
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)textFieldDidBeginEditing:(KMTextField *)textField {
|
||||
- (void)textFieldDidBeginEditing:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldDidBeginEditing:)]) {
|
||||
[textField textFieldDidBeginEditing:textField];
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@
|
|||
}
|
||||
|
||||
// NOTE: the return value from the textField's hook is ignored
|
||||
- (BOOL)textFieldShouldEndEditing:(KMTextField *)textField {
|
||||
- (BOOL)textFieldShouldEndEditing:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldShouldEndEditing:)]) {
|
||||
[textField textFieldShouldEndEditing:textField];
|
||||
}
|
||||
|
|
@ -53,7 +53,7 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (void)textFieldDidEndEditing:(KMTextField *)textField {
|
||||
- (void)textFieldDidEndEditing:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldDidEndEditing:)]) {
|
||||
[textField textFieldDidEndEditing:textField];
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@
|
|||
}
|
||||
|
||||
// NOTE: the return value from the textField's hook is ignored
|
||||
- (BOOL)textField:(KMTextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
||||
- (BOOL)textField:(KeymanTextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
|
||||
if ([textField respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) {
|
||||
[textField textField:textField shouldChangeCharactersInRange:range replacementString:string];
|
||||
}
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
}
|
||||
|
||||
// NOTE: the return value from the textField's hook is ignored
|
||||
- (BOOL)textFieldShouldClear:(KMTextField *)textField {
|
||||
- (BOOL)textFieldShouldClear:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldShouldClear:)]) {
|
||||
[textField textFieldShouldClear:textField];
|
||||
}
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
}
|
||||
|
||||
// NOTE: the return value from the textField's hook is ignored
|
||||
- (BOOL)textFieldShouldReturn:(KMTextField *)textField {
|
||||
- (BOOL)textFieldShouldReturn:(KeymanTextField *)textField {
|
||||
if ([textField respondsToSelector:@selector(textFieldShouldReturn:)]) {
|
||||
[textField textFieldShouldReturn:textField];
|
||||
}
|
||||
|
|
|
|||
358
ios/engine/KMEI/KeymanEngine/Classes/KeymanTextField.swift
Normal file
358
ios/engine/KMEI/KeymanEngine/Classes/KeymanTextField.swift
Normal file
|
|
@ -0,0 +1,358 @@
|
|||
//
|
||||
// KeymanTextField.swift
|
||||
// KeymanEngine
|
||||
//
|
||||
// Created by Gabriel Wong on 2017-10-05.
|
||||
// Copyright © 2017 SIL International. All rights reserved.
|
||||
//
|
||||
|
||||
import AudioToolbox
|
||||
import UIKit
|
||||
|
||||
public class KeymanTextField: UITextField, UITextFieldDelegate {
|
||||
// viewController should be set to main view controller to enable keyboard picker.
|
||||
public var viewController: UIViewController?
|
||||
|
||||
// Sets Keyman custom font (if any) to KeymanTextField instance on keyboard change event
|
||||
public var shouldSetCustomFontOnKeyboardChange = true
|
||||
public var isInputClickSoundEnabled = true
|
||||
|
||||
private var delegateProxy: KMTextFieldDelegateProxy?
|
||||
private var shouldUpdateKMText = false
|
||||
|
||||
// MARK: - Object Admin
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
delegate = nil
|
||||
}
|
||||
|
||||
public convenience init() {
|
||||
self.init(frame: CGRect.zero)
|
||||
}
|
||||
|
||||
public override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
delegateProxy = KMTextFieldDelegateProxy()
|
||||
delegate = delegateProxy
|
||||
|
||||
if #available(iOS 9.0, *) {
|
||||
inputAssistantItem.leadingBarButtonGroups = []
|
||||
inputAssistantItem.trailingBarButtonGroups = []
|
||||
}
|
||||
|
||||
KMManager.sharedInstance() // Preload webview keyboard
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldTextDidChange),
|
||||
name: .UITextFieldTextDidChange, object: self)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged),
|
||||
name: NSNotification.Name.keymanKeyboardChanged, object: nil)
|
||||
}
|
||||
|
||||
public required init?(coder aDecoder: NSCoder) {
|
||||
super.init(coder: aDecoder)
|
||||
|
||||
delegateProxy = KMTextFieldDelegateProxy(self)
|
||||
delegate = delegateProxy
|
||||
|
||||
if #available(iOS 9.0, *) {
|
||||
inputAssistantItem.leadingBarButtonGroups = []
|
||||
inputAssistantItem.trailingBarButtonGroups = []
|
||||
}
|
||||
|
||||
KMManager.sharedInstance() // Preload webview keyboard
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.textFieldTextDidChange),
|
||||
name: .UITextFieldTextDidChange, object: self)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged),
|
||||
name: NSNotification.Name.keymanKeyboardChanged, object: nil)
|
||||
}
|
||||
|
||||
// MARK: - Class Overrides
|
||||
public override var inputView: UIView? {
|
||||
get {
|
||||
KMManager.sharedInstance().webDelegate = self
|
||||
return KMManager.inputView()
|
||||
}
|
||||
|
||||
set(inputView) {
|
||||
super.inputView = inputView
|
||||
}
|
||||
}
|
||||
|
||||
// Prevent the delegate being set to anything but the delegateProxy
|
||||
public override weak var delegate: UITextFieldDelegate? {
|
||||
get {
|
||||
return super.delegate
|
||||
}
|
||||
|
||||
set(delegate) {
|
||||
// Allow clearing of delegate
|
||||
guard let delegate = delegate else {
|
||||
super.delegate = nil
|
||||
return
|
||||
}
|
||||
|
||||
if delegate !== delegateProxy {
|
||||
KMManager.sharedInstance().kmLog(
|
||||
"Trying to set KeymanTextField's delegate directly. Use setKeymanDelegate() instead.",
|
||||
checkDebugPrinting: true)
|
||||
}
|
||||
super.delegate = delegateProxy
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public Methods
|
||||
|
||||
// Use this KMTextFieldDelegate instead of the normal UITextFieldDelegate.
|
||||
// All of the normal UITextFieldDelegate methods are supported.
|
||||
@objc public func setKeymanDelegate(_ keymanDelegate: KMTextFieldDelegate?) {
|
||||
delegateProxy?.keymanDelegate = keymanDelegate
|
||||
KMManager.sharedInstance().kmLog(
|
||||
"KeymanTextField: \(self.debugDescription) keymanDelegate set to: \(keymanDelegate.debugDescription)",
|
||||
checkDebugPrinting: true)
|
||||
}
|
||||
|
||||
// Dismisses the keyboard if this textview is the first responder.
|
||||
// - Use this instead of [resignFirstResponder] as it also resigns the Keyman keyboard's responders.
|
||||
@objc public func dismissKeyboard() {
|
||||
KMManager.sharedInstance().kmLog(
|
||||
"KeymanTextField: \(self.debugDescription) Dismissing keyboard. Was first responder:\(isFirstResponder)",
|
||||
checkDebugPrinting: true)
|
||||
resignFirstResponder()
|
||||
KMManager.inputView().endEditing(true)
|
||||
}
|
||||
|
||||
public override var text: String! {
|
||||
get {
|
||||
return super.text ?? ""
|
||||
}
|
||||
|
||||
set(text) {
|
||||
if let text = text {
|
||||
super.text = text
|
||||
} else {
|
||||
super.text = ""
|
||||
}
|
||||
|
||||
KMManager.setKMText(self.text)
|
||||
let textRange = selectedTextRange!
|
||||
let newRange = NSRange(location: offset(from: beginningOfDocument, to: textRange.start),
|
||||
length: offset(from: textRange.start, to: textRange.end))
|
||||
KMManager.setKMSelectionRange(newRange, manually: false)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - KMWebViewDelegate
|
||||
@objc public func updatedFragment(_ fragment: String) {
|
||||
if fragment.contains("insertText") {
|
||||
processInsertText(fragment)
|
||||
} else if fragment.contains("hideKeyboard") {
|
||||
dismissKeyboard()
|
||||
} else if fragment.contains("menuKeyUp") {
|
||||
if let viewController = viewController {
|
||||
KMManager.sharedInstance().showKeyboardPicker(in: viewController, shouldAddKeyboard: false)
|
||||
} else {
|
||||
KMManager.sharedInstance().switchToNextKeyboard()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func processInsertText(_ fragment: String) {
|
||||
if KMManager.sharedInstance().isSubKeysMenuVisible() {
|
||||
return
|
||||
}
|
||||
|
||||
if isInputClickSoundEnabled {
|
||||
AudioServicesPlaySystemSound(0x450)
|
||||
|
||||
// Disable input click sound for 0.1 second to ensure it plays for single key stroke.
|
||||
isInputClickSoundEnabled = false
|
||||
perform(#selector(self.enableInputClickSound), with: nil, afterDelay: 0.1)
|
||||
}
|
||||
|
||||
// TODO: Refactor duplicate logic in KeymanInputViewController and KMTextView
|
||||
let dnRange = fragment.range(of: "+dn=")!
|
||||
let sRange = fragment.range(of: "+s=")!
|
||||
|
||||
let dn = Int(fragment[dnRange.upperBound..<sRange.lowerBound])!
|
||||
let s = fragment[sRange.upperBound...]
|
||||
|
||||
let hexStrings: [String]
|
||||
if !s.isEmpty {
|
||||
hexStrings = s.components(separatedBy: ",")
|
||||
} else {
|
||||
hexStrings = []
|
||||
}
|
||||
|
||||
let codeUnits = hexStrings.map { hexString -> UInt16 in
|
||||
let scanner = Scanner(string: hexString)
|
||||
var codeUnit: UInt32 = 0
|
||||
scanner.scanHexInt32(&codeUnit)
|
||||
return UInt16(codeUnit)
|
||||
}
|
||||
|
||||
let text = String(utf16CodeUnits: codeUnits, count: codeUnits.count)
|
||||
|
||||
let textRange = selectedTextRange!
|
||||
let selRange = NSRange(location: offset(from: beginningOfDocument, to: textRange.start),
|
||||
length: offset(from: textRange.start, to: textRange.end))
|
||||
|
||||
if dn <= 0 {
|
||||
if selRange.length == 0 {
|
||||
insertText(text)
|
||||
} else {
|
||||
self.text = (self.text! as NSString).replacingCharacters(in: selRange, with: text)
|
||||
}
|
||||
} else {
|
||||
if s.isEmpty {
|
||||
for _ in 0..<dn {
|
||||
deleteBackward()
|
||||
}
|
||||
} else {
|
||||
if selRange.length == 0 {
|
||||
for _ in 0..<dn {
|
||||
deleteBackward()
|
||||
}
|
||||
insertText(text)
|
||||
} else {
|
||||
self.text = (self.text! as NSString).replacingCharacters(in: selRange, with: text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - UITextFieldDelegate Hooks
|
||||
public override var selectedTextRange: UITextRange? {
|
||||
didSet(range) {
|
||||
guard let range = range else {
|
||||
return
|
||||
}
|
||||
let newRange = NSRange(location: offset(from: beginningOfDocument, to: range.start),
|
||||
length: offset(from: range.start, to: range.end))
|
||||
KMManager.setKMSelectionRange(newRange, manually: false)
|
||||
}
|
||||
}
|
||||
|
||||
public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange,
|
||||
replacementString string: String) -> Bool {
|
||||
shouldUpdateKMText = true // Enable text update to catch copy/paste operations
|
||||
return true
|
||||
}
|
||||
|
||||
@objc public func textFieldTextDidChange(_ notification: Notification) {
|
||||
if shouldUpdateKMText {
|
||||
// Catches copy/paste operations
|
||||
KMManager.setKMText(text)
|
||||
let textRange = selectedTextRange!
|
||||
let newRange = NSRange(location: offset(from: beginningOfDocument, to: textRange.start),
|
||||
length: offset(from: textRange.start, to: textRange.end))
|
||||
KMManager.setKMSelectionRange(newRange, manually: false)
|
||||
shouldUpdateKMText = false
|
||||
}
|
||||
}
|
||||
|
||||
public func textFieldShouldClear(_ textField: UITextField) -> Bool {
|
||||
if textField == self {
|
||||
KMManager.clearText()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
|
||||
let leftToRightMark = "\u{200e}"
|
||||
let rightToLeftOverride = "\u{202e}"
|
||||
let keyboardID = KMManager.sharedInstance().keyboardID
|
||||
let languageID = KMManager.sharedInstance().languageID
|
||||
let textWD = baseWritingDirection(for: beginningOfDocument, in: .forward)
|
||||
|
||||
if KMManager.sharedInstance().isRTLKeyboard(withID: keyboardID, languageID: languageID) {
|
||||
if textWD != .rightToLeft {
|
||||
if text.hasPrefix(leftToRightMark) {
|
||||
text = String(text.utf16.dropFirst())
|
||||
}
|
||||
|
||||
if text.isEmpty || !text.hasPrefix(rightToLeftOverride) {
|
||||
text = "\(rightToLeftOverride)\(text!)"
|
||||
}
|
||||
makeTextWritingDirectionRightToLeft(nil)
|
||||
}
|
||||
} else {
|
||||
if textWD != .leftToRight {
|
||||
if text.hasPrefix(rightToLeftOverride) {
|
||||
text = String(text.utf16.dropFirst())
|
||||
}
|
||||
|
||||
if text.isEmpty || !text.hasPrefix(leftToRightMark) {
|
||||
text = "\(leftToRightMark)\(text!)"
|
||||
}
|
||||
makeTextWritingDirectionLeftToRight(nil)
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
KMManager.sharedInstance().webDelegate = self
|
||||
|
||||
let keyboardID = KMManager.sharedInstance().keyboardID
|
||||
let languageID = KMManager.sharedInstance().languageID
|
||||
let fontName = KMManager.sharedInstance().fontNameForKeyboard(withID: keyboardID, languageID: languageID)
|
||||
let fontSize = font?.pointSize ?? UIFont.systemFontSize
|
||||
if let fontName = fontName {
|
||||
font = UIFont(name: fontName, size: fontSize)
|
||||
} else {
|
||||
font = UIFont.systemFont(ofSize: fontSize)
|
||||
}
|
||||
|
||||
KMManager.sharedInstance().kmLog("TextField setFont: \(String(describing: font?.familyName))",
|
||||
checkDebugPrinting: true)
|
||||
|
||||
// copy this textField's text to the webview
|
||||
KMManager.setKMText(text)
|
||||
let textRange = selectedTextRange!
|
||||
let newRange = NSRange(location: offset(from: beginningOfDocument, to: textRange.start),
|
||||
length: offset(from: textRange.start, to: textRange.end))
|
||||
KMManager.setKMSelectionRange(newRange, manually: false)
|
||||
KMManager.sharedInstance().kmLog(
|
||||
"KeymanTextField: \(self.debugDescription) Became first responder. Value: \(String(describing: text))",
|
||||
checkDebugPrinting: true)
|
||||
}
|
||||
|
||||
public func textFieldShouldEndEditing(_ textField: UITextField) -> Bool {
|
||||
if textField == self {
|
||||
resignFirstResponder()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// MARK: - Keyman notifications
|
||||
@objc public func keyboardChanged(_ notification: Notification) {
|
||||
if !shouldSetCustomFontOnKeyboardChange {
|
||||
return
|
||||
}
|
||||
|
||||
let kbInfo = notification.userInfo?[kKeymanKeyboardInfoKey] as? [AnyHashable: Any]
|
||||
let keyboardID = kbInfo?[kKeymanKeyboardIdKey] as? String
|
||||
let languageID = kbInfo?[kKeymanLanguageIdKey] as? String
|
||||
let fontName = KMManager.sharedInstance().fontNameForKeyboard(withID: keyboardID, languageID: languageID)
|
||||
let fontSize = font?.pointSize ?? UIFont.systemFontSize
|
||||
if let fontName = fontName {
|
||||
font = UIFont(name: fontName, size: fontSize)
|
||||
} else {
|
||||
font = UIFont.systemFont(ofSize: fontSize)
|
||||
}
|
||||
|
||||
if isFirstResponder {
|
||||
resignFirstResponder()
|
||||
becomeFirstResponder()
|
||||
}
|
||||
KMManager.sharedInstance().kmLog(
|
||||
"KeymanTextField \(self.debugDescription) setFont: \(font!.familyName)", checkDebugPrinting: true)
|
||||
}
|
||||
|
||||
@objc public func enableInputClickSound() {
|
||||
isInputClickSoundEnabled = true
|
||||
}
|
||||
}
|
||||
|
|
@ -12,5 +12,4 @@
|
|||
#import "KMTextView.h"
|
||||
#import "KMTextViewDelegateProxy.h"
|
||||
|
||||
#import "KMTextField.h"
|
||||
#import "KMTextFieldDelegateProxy.h"
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import QuartzCore
|
|||
|
||||
class MainViewController: UIViewController, UIAlertViewDelegate, KMTextViewDelegate, KMTextFieldDelegate {
|
||||
var textView1: KMTextView!
|
||||
var textView2: KMTextField!
|
||||
var textView2: KeymanTextField!
|
||||
var textView3: UITextView!
|
||||
|
||||
deinit {
|
||||
|
|
@ -90,7 +90,7 @@ class MainViewController: UIViewController, UIAlertViewDelegate, KMTextViewDeleg
|
|||
|
||||
// Text Views/Fields
|
||||
textView1 = KMTextView()
|
||||
textView2 = KMTextField()
|
||||
textView2 = KeymanTextField()
|
||||
textView3 = UITextView()
|
||||
setTextViewStyle(textView1)
|
||||
setTextFieldStyle(textView2)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue