Previous to iOS 9, the most reliable method of determining whether an external keyboard is connected was to listen for UIKeyboardWillShowNotification
and make a
I am using a variation on Sarah Elan's answer. I was having issues with her approach in certain views. I never quite got to the bottom of what caused the problem. But here is another way to determine if it is an ios9 external keyboard 'undo' bar that you have, rather than the full sized keyboard.
It is probably not very forward compatible since if they change the size of the undo bar, this brakes. But, it got the job done. I welcome criticism as there must be a better way...
//... somewhere ...
#define HARDWARE_KEYBOARD_SIZE_IOS9 55
//
+ (BOOL) isExternalKeyboard:(NSNotification*)keyboardNotification {
NSDictionary* info = [keyboardNotification userInfo];
CGRect keyboardEndFrame;
[[info valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
CGRect keyboardBeginFrame;
[[info valueForKey:UIKeyboardFrameBeginUserInfoKey] getValue:&keyboardBeginFrame];
CGFloat diff = keyboardEndFrame.origin.y - keyboardBeginFrame.origin.y;
return fabs(diff) == HARDWARE_KEYBOARD_SIZE_IOS9;
}
This code supports iOS 8 and iOS 9, inputAccessoryView, has double-protected constant to be ready for new changes in future versions of iOS and to support new devices:
#define gThresholdForHardwareKeyboardToolbar 160.f // it's minimum height of the software keyboard on non-retina iPhone in landscape mode
- (bool)isHardwareKeyboardUsed:(NSNotification*)keyboardNotification {
NSDictionary* info = [keyboardNotification userInfo];
CGRect keyboardEndFrame;
[[info valueForKey:UIKeyboardFrameEndUserInfoKey] getValue:&keyboardEndFrame];
float height = [[UIScreen mainScreen] bounds].size.height - keyboardEndFrame.origin.y;
return height < gThresholdForHardwareKeyboardToolbar;
}
Note, a hardware keyboard may present but not used.
You can subscribe notification when the external device is connected:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceConnected:) name:EAAccessoryDidConnectNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceDisconnected:) name:EAAccessoryDidDisconnectNotification object:nil];
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
Or just retrieve the list of attached devices:
EAAccessoryManager* accessoryManager = [EAAccessoryManager sharedAccessoryManager];
if (accessoryManager)
{
NSArray* connectedAccessories = [accessoryManager connectedAccessories];
NSLog(@"ConnectedAccessories = %@", connectedAccessories);
}
Private API solution: (have to grab the private header file - use RuntimeViewer).
Works nicely for enterprise apps, where you don't have AppStore restrictions.
#import "UIKit/UIKeyboardImpl.h"
+ (BOOL)isHardwareKeyboardMode
{
UIKeyboardImpl *kbi = [UIKeyboardImpl sharedInstance];
BOOL externalKeyboard = kbi.inHardwareKeyboardMode;
NSLog(@"Using external keyboard? %@", externalKeyboard?@"YES":@"NO");
return externalKeyboard;
}
iOS 14 SDK finally brings public API for that: GCKeyboard
. To check if external keyboard is connected:
let isKeyboardConnected = GCKeyboard.coalescedKeyboard != nil
Notes:
import GameController
if #available(iOS 14.0, *)
I was able to do it, I reckon, by checking the height of the keyboard. That's it! Notice when an external keyboard is connected, the onscreen keyboard is about 50-60px in height. See the working demo here: https://youtu.be/GKi-g0HOQUc
So in your event keyboardWillShow
, just get the keyboard height and see if it's around 50-60, if so, then we can assume that there's an external keyboard connected.
@objc func keyboardWillShow(_ notification: NSNotification) {
guard let userInfo = notification.userInfo else {return}
let keyboardScreenEndFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue
let keyboard = self.view.convert(keyboardScreenEndFrame, from: self.view.window)
// If with keyboard, the onscreen keyboard height is 55.
// otherwise, the onscreen keyboard has >= 408px in height.
// The 66 digit came from a Stackoverflow comment that the keyboard height is sometimes around that number.
if keyboard.size.height <= 66 {
hasExternalKeyboard = true
} else {
hasExternalKeyboard = false
}
}