iOS get Keyboard Window

10,284

Solution 1

I also had this problem and found the solution.

Below is the code which will work for iOS 8.0 and also for below versions.

I have tested it on iOS 7 and 8.0 (Xcode Version 6.0.1)

- (void)addButtonToKeyboard
{
    // create custom button
    self.doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.doneButton.frame = CGRectMake(0, 163+44, 106, 53);
    self.doneButton.adjustsImageWhenHighlighted = NO;
    [self.doneButton setTag:67123];
    [self.doneButton setImage:[UIImage imageNamed:@"doneup1.png"] forState:UIControlStateNormal];
    [self.doneButton setImage:[UIImage imageNamed:@"donedown1.png"] forState:UIControlStateHighlighted];

    [self.doneButton addTarget:self action:@selector(doneButton:) forControlEvents:UIControlEventTouchUpInside];

    // locate keyboard view
    int windowCount = [[[UIApplication sharedApplication] windows] count];
    if (windowCount < 2) {
        return;
    }

    UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];
    UIView* keyboard;

    for(int i = 0 ; i < [tempWindow.subviews count] ; i++)
    {
        keyboard = [tempWindow.subviews objectAtIndex:i];
        // keyboard found, add the button

        if([[keyboard description] hasPrefix:@"<UIPeripheralHost"] == YES){
            UIButton* searchbtn = (UIButton*)[keyboard viewWithTag:67123];
            if (searchbtn == nil)//to avoid adding again and again as per my requirement (previous and next button on keyboard)
                [keyboard addSubview:self.doneButton];

        }//This code will work on iOS 8.0
        else if([[keyboard description] hasPrefix:@"<UIInputSetContainerView"] == YES){

            for(int i = 0 ; i < [keyboard.subviews count] ; i++)
            {
                UIView* hostkeyboard = [keyboard.subviews objectAtIndex:i];

                if([[hostkeyboard description] hasPrefix:@"<UIInputSetHost"] == YES){
                    UIButton* donebtn = (UIButton*)[hostkeyboard viewWithTag:67123];
                    if (donebtn == nil)//to avoid adding again and again as per my requirement (previous and next button on keyboard)
                        [hostkeyboard addSubview:self.doneButton];
                }
            }
        }
    }
}

>

    -(void) removedSearchButtonFromKeypad{

    int windowCount = [[[UIApplication sharedApplication] windows] count];
    if (windowCount < 2) {
        return;
    }

    UIWindow* tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:1];

    for(int i = 0 ; i < [tempWindow.subviews count] ; i++)
    {
        UIView* keyboard = [tempWindow.subviews objectAtIndex:i];

        if([[keyboard description] hasPrefix:@"<UIPeripheralHost"] == YES){
            [self removeButton:keyboard];

        }else if([[keyboard description] hasPrefix:@"<UIInputSetContainerView"] == YES){

            for(int i = 0 ; i < [keyboard.subviews count] ; i++)
            {
                UIView* hostkeyboard = [keyboard.subviews objectAtIndex:i];

                if([[hostkeyboard description] hasPrefix:@"<UIInputSetHost"] == YES){
                    [self removeButton:hostkeyboard];
                }
            }
        }
    }
}


-(void) removeButton:(UIView*)keypadView{
    UIButton* donebtn = (UIButton*)[keypadView viewWithTag:67123];
    if(donebtn){
        [donebtn removeFromSuperview];
        donebtn = nil;
    }
}

Hope this helps.

Solution 2

What i use to get the window for the keyboard is

- (void)findKeyboardWindow
{
    for (UIWindow *window in [[UIApplication sharedApplication] windows])
    {
        if ([NSStringFromClass([window class]) isEqualToString:@"UITextEffectsWindow"])
        {
            _keyboardWindow = window;
            break;
        }
    }
}

From my logs on iOS8 this contains one view

UIInputSetContainerView: 0x190d4430; frame = (0 0; 320 568); autoresize = W+H; layer = CALayer: 0x190d4630

Which contains another view

UIInputSetHostView: 0x190d4820; frame = (0 352; 320 216); layer = CALayer: 0x190d49c0

Since those dimensions are 216.0f height i guess that is the keyboard. Was this what you where looking for?

Solution 3

On iOS 13, we can get keyboard window like this:

let windows = UIApplication.shared.windows
if let keyboardWindow = windows.first(where: { NSStringFromClass($0.classForCoder) == "UIRemoteKeyboardWindow" }) {
  return
}
Share:
10,284
SaifDeen
Author by

SaifDeen

Updated on June 05, 2022

Comments

  • SaifDeen
    SaifDeen almost 2 years

    So in iOS 7 I always got the Keyboard Window like this:

    - (UIView *)keyboardView
    {
        UIWindow* tempWindow;
    
        //Because we cant get access to the UIKeyboard throught the SDK we will just use UIView.
        //UIKeyboard is a subclass of UIView anyways
        UIView* keyboard;
    
        NSLog(@"windows %d", [[[UIApplication sharedApplication]windows]count]);
    
        //Check each window in our application
        for(int c = 0; c < [[[UIApplication sharedApplication] windows] count]; c ++)
        {
            //Get a reference of the current window
            tempWindow = [[[UIApplication sharedApplication] windows] objectAtIndex:c];
    
            //Get a reference of the current view
            for(int i = 0; i < [tempWindow.subviews count]; i++)
            {
                keyboard = [tempWindow.subviews objectAtIndex:i];
                NSLog(@"view: %@, on index: %d, class: %@", [keyboard description], i, [[tempWindow.subviews objectAtIndex:i] class]);
                if([[keyboard description] hasPrefix:@"(lessThen)UIKeyboard"] == YES)
                {
                    //If we get to this point, then our UIView "keyboard" is referencing our keyboard.
                    return keyboard;
                }
            }
    
            for(UIView* potentialKeyboard in tempWindow.subviews)
                // if the real keyboard-view is found, remember it.
                if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0) {
                    if([[potentialKeyboard description] hasPrefix:@"<UILayoutContainerView"] == YES)
                        keyboard = potentialKeyboard;
                }
                else if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 3.2) {
                    if([[potentialKeyboard description] hasPrefix:@"<UIPeripheralHost"] == YES)
                        keyboard = potentialKeyboard;
                }
                else {
                    if([[potentialKeyboard description] hasPrefix:@"<UIKeyboard"] == YES)
                        keyboard = potentialKeyboard;
                }
        }
    
    
        NSLog(@"view: %@, on index: %d", [keyboard description]);
        return keyboard;
    }
    

    But in the iOS 8 beta 1 & 2 the window/view that is returned is the main App window. Any idea what is the the problem in my code? On my test device with iOS 7 it works great...

  • gregthegeek
    gregthegeek over 9 years
    Pure awesomeness! You saved me lots of extra hassle. And what's more... Our original code must have been from same boilerplate example, because this almost dropped right in place. Nice! Thanks!
  • iAnurag
    iAnurag over 9 years
    I have used the same code for adding done button, it worked for me, but when default keyboard appeares I can see that done button behind the keyboard even If I have removed it from superview. plz help. Thanks
  • Manjit Singh
    Manjit Singh over 9 years
    please tell me how to remove the done button and predictive text bar from the keyboard.
  • iGW
    iGW over 9 years
    I have edited my code which supports removing done button from the keyboard. Please have a look on the complete code.
  • Manjit Singh
    Manjit Singh over 9 years
    please see this question am doing same like this stackoverflow.com/questions/26213708/…
  • iGW
    iGW over 9 years
    I have not yet upload the app to the app store with this code. Have you found any restriction?
  • Gustavo Barbosa
    Gustavo Barbosa over 9 years
    This is the best solution!
  • Developer
    Developer almost 9 years
    Yes! I am able to add the button but not able to interact with that. I can see only image which I placed on the keyboard.