How to reliably detect if an external keyboard is connected on iOS 9?
iOS 14 SDK finally brings public API for that: GCKeyboard
. To check if external keyboard is connected:
let isKeyboardConnected = GCKeyboard.coalesced != nil
Notes:
import GameController
- you might need to enclose it in
if #available(iOS 14.0, *)
After going back to the original question, I've found a solution that works.
It seems that when the regular virtual keyboard is displayed the keyboard frame is within the dimensions of the screen. However when a physical keyboard is connected and the keyboard toolbar is displayed, the keyboard frame is located offscreen. We can check if the keyboard frame is offscreen to determine if the keyboard toolbar is showing.
Objective-C
- (void) keyboardWillShow:(NSNotification *)notification {
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;
if ((keyboard.origin.y + keyboard.size.height) > height) {
self.hasKeyboard = YES;
}
}
Swift
@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)
let height = self.view.frame.size.height
if (keyboard.origin.y + keyboard.size.height) > height {
self.hasKeyboard = true
}
}
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.