How to determine if an external keyboard is present on the iPad?

Is there a way to determine if an external (bluetooth or USB) keyboard is connected to the iPad?

+46
ios ipad keyboard
May 23 '10 at 20:14
source share
11 answers

An indirect and secure SDK way is to make the text field the first responder. If an external keyboard is present, the local UIKeyboardWillShowNotification notification UIKeyboardWillShowNotification not published.

You can listen to the Darwin kGSEventHardwareKeyboardAvailabilityChangedNotification ( kGSEventHardwareKeyboardAvailabilityChangedNotification ) notification, but this is a private API, so your application will be rejected if you use it. To check for external hardware, use the private function GSEventIsHardwareKeyboardAttached() .

UIKit listens for this and sets the UIKeyboardImpl.isInHardwareKeyboardMode property accordingly, but again this is a private API.

+31
May 23 '10 at 20:31
source share

There is another level to this.

  • If you do not have an inputAccessoryView, you will not receive a notification as above.
  • However, if you have configured inputAccessoryView for the text view, you will still receive a UIKeyboard notification when external kbd is present - the logic is that you will need to animate your view in the right place so that you need the animation information contained in the notification.

Fortunately, in this case there is enough information to find out if kbd will be provided, although it is still a bit involved.

If we look at the notification dictionary, we will see this information:

 UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, 1024}, {768, 308}} UIKeyboardFrameEndUserInfoKey = NSRect: {{0, 980}, {768, 308}} 

It was in a portrait; if we rotate the device to PortraitUpsideDown, we get:

 UIKeyboardFrameBeginUserInfoKey = NSRect: {{0, -308}, {768, 308}} UIKeyboardFrameEndUserInfoKey = NSRect: {{0, -264}, {768, 308}} 

Similarly, in LandscapeLeft and LandscapeRight we get different start and end locations.

Hmm ... what do these numbers mean? You can see that kbd is turned off to start, but it is moving a bit. To make things worse, depending on the orientation of the device, the kbd locations are different.

However, we have enough information to find out what is happening:

  • kbd moves only from the screen on the physical bottom of the device to the same height as inputAccessoryView (but hides from it).
  • So, in the case of a portrait, it moves from 1024 to 980 - we should have an inputAccessoryView with a height of 44, which is really so.
  • Thus, in the portrait, if the end is y +, the height of the input_select height == screen height, then kbd is not displayed. You need to handle other rotations, but this is an idea.
+28
Apr 22 '11 at 23:13
source share

Based on @ user721239, the if condition determines whether the bottom of the keyboard is outside the scope of self.view. "convertRect" normalizes the frame for any orientation.

 - (void)keyboardWillShow:(NSNotification *)notification { keyboardFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; keyboardFrame = [self.view convertRect:keyboardFrame fromView:nil]; // convert orientation keyboardSize = keyboardFrame.size; //NSLog(@"keyboardFrame.origin.y = %f", keyboardFrame.origin.y); //NSLog(@"keyboardFrame.size.height = %f", keyboardFrame.size.height); BOOL hardwareKeyboardPresent = FALSE;; if ((keyboardFrame.origin.y + keyboardFrame.size.height) > (self.view.frame.size.height+self.navigationController.navigationBar.frame.size.height)) { hardwareKeyboardPresent = TRUE; } //NSLog(@"bottomOfKeyboard = %f", bottomOfKeyboard); //NSLog(@"self.view.frame.size.height = %f", self.view.frame.size.height); 
+7
Feb 26 '14 at 18:08
source share

Even using inputAccessoryView on a UITextView instance installed on a UIView instance with a frame, CGRectZero works to get delivery of keyboard notifications that work with a hardware keyboard.

+5
Mar 04 2018-12-12T00:
source share

This is the code I use to get the height from the userInfo keyboard in UIKeyboardWillShowNotification . Works with both physical and virtual keyboards.

 NSValue* aValue = [userInfo objectForKey:UIKeyboardFrameEndUserInfoKey]; CGRect keyboardRect = [aValue CGRectValue]; CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height; CGFloat deviceWidth = [UIScreen mainScreen].bounds.size.width; CGFloat newKeyboardHeight; if (interfaceOrientation == UIInterfaceOrientationPortrait) newKeyboardHeight = deviceHeight - keyboardRect.origin.y; else if (interfaceOrientation == UIInterfaceOrientationPortraitUpsideDown) newKeyboardHeight = keyboardRect.size.height + keyboardRect.origin.y; else if (interfaceOrientation == UIInterfaceOrientationLandscapeLeft) newKeyboardHeight = deviceWidth - keyboardRect.origin.x; else newKeyboardHeight = keyboardRect.size.width + keyboardRect.origin.x; 
+4
Sep 13 '12 at 23:40
source share

Based on this thread, I put together two static methods that I can easily call from keyboard notification methods to handle the correct resizing of views (usually UIScrollViews) when the keyboard appears, regardless of type (software and hardware):

 + (void)keyboardWillShowHide:(NSNotification *)notification inView:(UIView *)view adjustView:(UIView *)viewToAdjust { // How much should we adjust the view frame by? CGFloat yOffset = [SMKeyboardUtil keyboardOffsetForKeyboardNotification:notification inView:view]; CGRect viewFrame = viewToAdjust.frame; viewFrame.size.height -= yOffset; // Get the animation parameters being used to show the keyboard. We'll use the same animation parameters as we // resize our view. UIViewAnimationCurve animationCurve; NSTimeInterval animationDuration; [notification.userInfo[UIKeyboardAnimationCurveUserInfoKey] getValue:&animationCurve]; [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] getValue:&animationDuration]; // Resize the view frame to subtract/add the height of the keyboard (and any inputAccessoryView) [UIView beginAnimations:@"animate resiz view" context:nil]; [UIView setAnimationDuration:animationDuration]; [UIView setAnimationCurve:animationCurve]; [viewToAdjust setFrame:viewFrame]; [UIView commitAnimations]; } + (CGFloat)keyboardOffsetForKeyboardNotification:(NSNotification *)notification inView:(UIView *)view { NSAssert(notification.userInfo[UIKeyboardFrameBeginUserInfoKey], @"Invalid keyboard notification"); // Get the frame of keyboard from the notification CGRect keyboardFrameBeginRaw = [notification.userInfo[UIKeyboardFrameBeginUserInfoKey] CGRectValue]; CGRect keyboardFrameEndRaw = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; // Because the frame we get from the notification is raw screen coordinates, without accounting for device orientation, // we need to convert the frame to be relative to our view. CGRect keyboardFrameBegin = [view convertRect:keyboardFrameBeginRaw fromView:nil]; CGRect keyboardFrameEnd = [view convertRect:keyboardFrameEndRaw fromView:nil]; // We could examine the size of the frame, but this does not account for hardware keyboards. Instead, // we need to need the delta between the start and end positions to determine how much to modify // the size of our view. return keyboardFrameBegin.origin.y - keyboardFrameEnd.origin.y; } 
+3
Jul 12 '13 at 20:05
source share

You can use the following, which also calculates the height for the height of the keyboard / toolbar when connecting a hardware keyboard. You will need to sign up for a KeyboardWillShow notification:

 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; 

then process the notification as follows:

 - (void)keyboardWillShow:(NSNotification *)notification { // Information we want to determine from notification BOOL isHardwareKB = NO; CGFloat keyboardHeight; // Notification info NSDictionary* userInfo = [notification userInfo]; CGRect keyboardFrame = [[userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect keyboard = [self.view convertRect:keyboardFrame fromView:self.view.window]; CGFloat height = self.view.frame.size.height; // Determine if hardware keyboard fired this notification if ((keyboard.origin.y + keyboard.size.height) > height) { isHardwareKB = YES; keyboardHeight = height - keyboard.origin.y; // toolbar height } else { isHardwareKB = NO; // As this value can change depending on rotation keyboardHeight = MIN(keyboardFrame.size.width, keyboardFrame.size.height); } // adjust view ui constraints ext ext depending on keyboard height // .... } 

You can also handle KeyboardWillHide notification. It will be a fire when the first responder will be for both the hardware and software keyboard.

 - (void)keyboardWillShow:(NSNotification *)notification { // Information we want to determine from notification BOOL isHardwareKB; // this is irrelevant since it is hidden CGFloat keyboardHeight = 0; // height is now 0 // Do any view layout logic here for keyboard height = 0 // ... } 

Also do not forget to remove the observer:

 -(void) dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; [super dealloc]; } 
+2
May 26 '16 at 6:23
source share

Since most of the methods of the previous answers are deprecated with iOS 8 and 9, I cross the frame with the keyboard message with the current window to get the real visible frame of the keyboard. Then you can simply check if the height has changed.

 CGRect reportedKeyboardFrameRaw = [[[notification userInfo] valueForKey: UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect reportedKeyboardFrame = [self.view.window convertRect: reportedKeyboardFrameRaw fromWindow:nil]; CGRect visibleKeyboardFrame = CGRectIntersection(reportedKeyboardFrame, self.view.window.frame); if (reportedKeyboardFrame.size.height != visibleKeyboardFrame.size.height) { // External keyboard present! } 
+1
Apr 11 '16 at 15:54
source share

The following code gives you a keyboard frame for all orientations, whether you use full-screen mode or a detailed view of a split view.

 NSDictionary* info = [aNotification userInfo]; CGRect frame = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGRect keyboardEndFrame = [self.view convertRect:frame fromView:nil]; // The raw frame values are physical device coordinate. CGSize keyboardSize = keyboardEndFrame.size; 

The keyboard frame set by the notification is always in terms of hardware coordinates, and the source is in the upper right corner of the screen when the iOS device is in normal portrait mode with the home button at the bottom. The -convertRect: fromView method changes coordinates from window coordinates (= hardware) to local coordinates of the view.

I found that with a Bluetooth keyboard you get one UIKeyboardDidShowNotification the first time there is a screen rotation, but not one after that. It makes it harder to distinguish a docked keyboard from unlocked / split and BT keyboards.

0
Apr 26 '13 at 13:46 on
source share

This is not a direct answer for detecting the presence of an external keyboard, but I am doing this to determine the actual height required to display the keyboard related views (s) at the bottom of the screen.

 CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue]; CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y; 
0
Apr 13 '16 at 9:39
source share

The answer to @philosophistry worked for me. The solution on iOS 8 is less complicated:

 CGRect keyboardRect = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height; CGFloat keyboardHeight = deviceHeight - keyboardRect.origin.y; NSLog(@"actualKeyboardHeight = %f", keyboardHeight); 
-3
Dec 11 '14 at 7:11
source share



All Articles