kif-framework/KIF

View on GitHub
Sources/KIF/Classes/KIFTypist.m

Summary

Maintainability
Test Coverage
//
//  KIFTypist.m
//  KIF
//
//  Created by Pete Hodgson on 8/12/12.
//  Licensed to Square, Inc. under one or more contributor license agreements.
//  See the LICENSE file distributed with this work for the terms under
//  which Square, Inc. licenses this file to you.

#import "KIFTypist.h"
#import "UIApplication-KIFAdditions.h"
#import "UIView-KIFAdditions.h"
#import "CGGeometry-KIFAdditions.h"
#import "UIAccessibilityElement-KIFAdditions.h"

@interface UIKeyboardTaskQueue: NSObject
- (void)waitUntilAllTasksAreFinished;
@end

@interface UIKeyboardImpl : NSObject
+ (UIKeyboardImpl *)sharedInstance;
- (void)addInputString:(NSString *)string;
- (void)deleteFromInput;
@property(readonly, nonatomic) UIKeyboardTaskQueue *taskQueue;
@property(getter=isInHardwareKeyboardMode) BOOL inHardwareKeyboardMode;
@property(retain) UIResponder<UIKeyInput> * delegate;
@end

static NSTimeInterval keystrokeDelay = 0.001f;

@interface KIFTypist()
@property (nonatomic, assign) BOOL keyboardHidden;
@end

@implementation KIFTypist

+ (KIFTypist *)sharedTypist
{
    static dispatch_once_t once;
    static KIFTypist *sharedObserver = nil;
    dispatch_once(&once, ^{
        sharedObserver = [[self alloc] init];
    });
    return sharedObserver;
}

+ (void)registerForNotifications {
    [[self sharedTypist] registerForNotifications];
}

- (instancetype)init
{
    if ((self = [super init])) {
        self.keyboardHidden = YES;
    }
    return self;
}

- (void)registerForNotifications
{
    // Instead of listening to keyboard will show/hide notifications, this is more robust. When keyboard is split
    // on a physical device, keyboard will show/hide notifications does not get fired, whereas this does.
    __weak KIFTypist *weakSelf = self;
    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidChangeFrameNotification
                                                      object:nil
                                                       queue:[NSOperationQueue mainQueue]
                                                  usingBlock:^(NSNotification *note) {
                                                      CGRect keyboardEndFrame =
                                                      [[note.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

                                                      CGRect screenRect = [[UIScreen mainScreen] bounds];

                                                      if (CGRectIntersectsRect(keyboardEndFrame, screenRect))
                                                      {
                                                          weakSelf.keyboardHidden = NO;
                                                      }
                                                      else
                                                      {
                                                          weakSelf.keyboardHidden = YES;
                                                      }
                                                  }];
}

+ (BOOL)keyboardHidden
{
    return [self sharedTypist].keyboardHidden;
}

+ (BOOL)enterCharacter:(NSString *)characterString;
{
    if ([characterString isEqualToString:@"\b"]) {
        [[UIKeyboardImpl sharedInstance] deleteFromInput];
    } else {
        [[UIKeyboardImpl sharedInstance] addInputString:characterString];
    }
    
    [[[UIKeyboardImpl sharedInstance] taskQueue] waitUntilAllTasksAreFinished];
    CFRunLoopRunInMode(kCFRunLoopDefaultMode, keystrokeDelay, false);
    return YES;
}

+ (NSTimeInterval)keystrokeDelay;
{
    return keystrokeDelay;
}

+ (void)setKeystrokeDelay:(NSTimeInterval)delay
{
    keystrokeDelay = delay;
}

+ (BOOL)hasHardwareKeyboard
{
    return [UIKeyboardImpl sharedInstance].inHardwareKeyboardMode;
}

+ (BOOL)hasKeyInputResponder
{
    return [UIKeyboardImpl sharedInstance].delegate != nil;
}


@end