简体   繁体   English

如何可靠地检测是否在 iOS 9 上连接了外接键盘?

[英]How to reliably detect if an external keyboard is connected on iOS 9?

Previous to iOS 9, the most reliable method of determining whether an external keyboard is connected was to listen for UIKeyboardWillShowNotification and make a text field the first responder, as discussed in this question .在 iOS 9 之前,确定是否连接外部键盘的最可靠方法是侦听UIKeyboardWillShowNotification并使文本字段成为第一响应者,如本问题中所述。 The notification would fire when using the virtual keyboard, but would not fire when using an external keyboard.使用虚拟键盘时会触发通知,但不会在使用外部键盘时触发。

However this behavior has now changed with iOS 9. UIKeyboardWillShowNotification also fires when an external keyboard is connected, since the new keyboard toolbar is now shown.然而,这种行为现在已经随着 iOS 9 改变。当连接外部键盘时, UIKeyboardWillShowNotification也会触发,因为现在显示了新的键盘工具栏。

It is still possible to detect the keyboard height and make a judgement whether it is the smaller toolbar or the larger virtual keyboard that is being shown.仍然可以检测键盘高度并判断显示的是较小的工具栏还是较大的虚拟键盘。 However this method is not reliable since the keyboard height has changed between the various beta and can't be counted on to stay the same over time.然而,这种方法并不可靠,因为键盘高度在各个测试版之间发生了变化,并且不能指望随着时间的推移保持不变。

Is there a more reliable method that can be used with iOS 9?有没有更可靠的方法可以与 iOS 9 一起使用?

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目标-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
    }
}

iOS 14 SDK finally brings public API for that: GCKeyboard . iOS 14 SDK 终于为此带来了公共 API: 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, *)您可能需要将其包含在if #available(iOS 14.0, *)

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:此代码支持 iOS 8 和 iOS 9,inputAccessoryView,具有双重保护的常量,为未来 iOS 版本的新变化做好准备并支持新设备:

#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.请注意,硬件键盘可能存在但未使用。

I am using a variation on Sarah Elan's answer.我正在使用莎拉·埃兰 (Sarah Elan) 的答案的变体。 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.但这里有另一种方法来确定它是否是您拥有的 ios9 外部键盘“撤消”栏,而不是全尺寸键盘。

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;
}

Private API solution: (have to grab the private header file - use RuntimeViewer).私有 API 解决方案:(必须获取私有头文件 - 使用 RuntimeViewer)。

Works nicely for enterprise apps, where you don't have AppStore restrictions.适用于没有 AppStore 限制的企业应用程序。

#import "UIKit/UIKeyboardImpl.h"

+ (BOOL)isHardwareKeyboardMode
{
   UIKeyboardImpl *kbi = [UIKeyboardImpl sharedInstance];
   BOOL externalKeyboard = kbi.inHardwareKeyboardMode;
   NSLog(@"Using external keyboard? %@", externalKeyboard?@"YES":@"NO");
   return externalKeyboard;
}

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):通过消隐其左右组来执行此操作(至少在 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)
}
  1. None of the answers here worked for me.这里没有一个答案对我有用。 I have iPad Air with iOS 13.x.我有带 iOS 13.x 的 iPad Air。

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.请注意,连接外部键盘时,屏幕键盘的高度约为 50-60 像素。 See the working demo here: https://youtu.be/GKi-g0HOQUc在此处查看工作演示: 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.因此,在您的事件keyboardWillShow ,只需获取键盘高度并查看它是否在 50-60 左右,如果是,则我们可以假设连接了外部键盘。

@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
        }
    }

In iOS 15 when a hardware Keyboard is present and you are supporting earlier versions of iOS that do not support an explicit indication that an external keyboard IS present, the Keyboard height and width obtained via:在 iOS 15 中,当存在硬件键盘并且您支持不支持明确指示存在外部键盘的早期版本 iOS 时,键盘高度和宽度通过以下方式获得:

CGRect kbEndFrame = [[[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue];

both have a value of 0两者的值为 0

Therefore you can detect external hardware via:因此,您可以通过以下方式检测外部硬件:

if(kbEndFrame.size.height == 0)
    // External/virtual KB exists
else
    // Virtual on screen KB exists

You could try checking for peripherals that are advertising services using Core Bluetooth您可以尝试使用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{

}

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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM