Previous to iOS 9, the most reliable method of determining whether an external keyboard is connected was to listen for UIKeyboardWillShowNotification
and make a
If you make the toolbar irrelevant then the keyboard doesn't show up. Do this by blanking out its left and right groups (at least on iOS 12.4):
textField.inputAssistantItem.leadingBarButtonGroups = []
textField.inputAssistantItem.trailingBarButtonGroups = []
...and in case it helps here is a swifty way to observe:
// Watch for a soft keyboard to show up
let observer = NotificationCenter.default.addObserver(forName: UIWindow.keyboardWillShowNotification, object: nil, queue: nil) { notification in
print("no external keyboard")
}
// Stop observing shortly after, since the keyboard should have shown by now
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
NotificationCenter.default.removeObserver(observer)
}
You could try checking for peripherals that are advertising services using Core Bluetooth
CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
[centralManager scanForPeripheralsWithServices:nil options:nil];
And you should implement the delegate:
- (void)centralManager:(CBCentralManager * _Nonnull)central
didDiscoverPeripheral:(CBPeripheral * _Nonnull)peripheral
advertisementData:(NSDictionary<NSString *,
id> * _Nonnull)advertisementData
RSSI:(NSNumber * _Nonnull)RSSI{
}
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
}
}