如何检测iPad上是否有外接键盘?

时间:2010-05-23 20:14:10

标签: ios ipad keyboard

有没有办法检测外接(蓝牙或usb)键盘是否连接到iPad?

12 个答案:

答案 0 :(得分:33)

间接和SDK安全的方法是使文本字段成为第一响应者。如果存在外部键盘,则不会发布UIKeyboardWillShowNotification本地通知。

  

更新:自iOS 9以来不再适用,但您可以使用键盘尺寸来确定是否涉及硬件或软件键盘。有关详细信息,请参阅 How to reliably detect if an external keyboard is connected on iOS 9?

您可以收听"GSEventHardwareKeyboardAttached"kGSEventHardwareKeyboardAvailabilityChangedNotification)Darwin通知,但这是一个私有API,因此如果您使用此应用,您的应用可能会被拒绝。要检查外部硬件是否存在,请使用私有GSEventIsHardwareKeyboardAttached()功能。

UIKit会监听并相应地设置UIKeyboardImpl.isInHardwareKeyboardMode属性,但这又是私有API。

答案 1 :(得分:28)

还有另一个层面。

  • 如果您没有inputAccessoryView,则不会收到通知,如上述说明所示。
  • 但是,如果您为文本视图设置了inputAccessoryView,那么当外部kbd存在时您仍会收到UIKeyboard通知 - 逻辑是您需要将视图设置为正确的位置,以便您需要通知中包含的动画信息。

幸运的是,事件中有足够的信息来确定是否会出现kbd,尽管它仍然有点参与。

如果我们检查通知字典,我们会看到以下信息:

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

那是在肖像;如果我们将设备旋转到PortraitUpsideDown,我们得到:

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

同样,在LandscapeLeft和LandscapeRight中,我们会得到不同的起点和终点位置。

嗯......这些数字是什么意思?您可以看到kbd在屏幕外启动,但它确实移动了一点。更糟糕的是,根据设备方向,kbd位置不同。

但是,我们确实有足够的信息来确定发生了什么:

  1. kbd从设备物理底部的屏幕外移动到与inputAccessoryView相同的高度(但被它遮挡)
  2. 所以在Portrait情况下,它从1024移动到980 - 我们必须有一个高度为44的inputAccessoryView,情况确实如此。
  3. 因此,如果结束y + inputAccessoryView height ==屏幕高度,则在Portrait中,则kbd不可见。你需要处理其他轮换,但这就是想法。

答案 2 :(得分:8)

在@ user721239上构建if条件确定键盘底部是否超出self.view的框架。 “convertRect”规范化任何方向的框架。

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

答案 3 :(得分:5)

即使在UITextView实例上使用inputAccessoryView设置为带有框架CGRectZero的UIView实例,也可以使用硬件键盘传递键盘通知。

答案 4 :(得分:4)

这是我用来从UIKeyboardWillShowNotification中的键盘userInfo获取高度的代码。适用于物理和虚拟键盘。

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;

答案 5 :(得分:3)

基于这个线程,我已经组装了两个静态方法,我可以通过键盘通知方法轻松调用它来处理键盘出现时正确调整视图大小(通常是UIScrollViews),无论类型如何(软件与硬件):

+ (void)keyboardWillShowHide:(NSNotification *)notification
                  inView:(UIView *)view
              adjustView:(UIView *)viewToAdjust
{
    // How much should we adjust the view's 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's 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;
}

答案 6 :(得分:2)

您可以使用以下内容同时计算连接硬件键盘时键盘/工具栏高度的高度。您需要订阅KeyboardWillShow通知:

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

然后像这样处理通知:

- (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 
    //  ....
}

您还可以处理KeyboardWillHide通知。当硬件和软件键盘的第一个响应者时,这将会激活。

- (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 
    //  ...
}

另外不要忘记删除观察者:

-(void) dealloc {
      [[NSNotificationCenter defaultCenter] removeObserver:self];
      [super dealloc];
}

答案 7 :(得分:1)

由于以前的答案中的大部分方法已被iOS 8和9弃用,我将键盘报告的帧与当前窗口相交以获得实际可见的键盘框架。然后你可以检查高度是否已经改变。

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

答案 8 :(得分:0)

以下代码为您提供了所有方向的键盘框架,无论您使用的是全屏视图还是拆分视图的详细视图。

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;

当iOS设备处于正常纵向模式且底部带有主页按钮时,通知提供的键盘框始终是硬件坐标,原点为屏幕的右上角。方法-convertRect:fromView将坐标从窗口坐标(=硬件)更改为本地视图坐标。

我发现使用蓝牙键盘,第一次屏幕旋转时会得到一个UIKeyboardDidShowNotification,但之后没有。使对接键盘与未对接键盘/分离键和BT键盘区分开来变得更加困难。

答案 9 :(得分:0)

这不是检测外部键盘是否存在的直接答案,但我这样做是为了检测在屏幕底部显示与键盘相关的视图所需的实际高度

CGRect keyboardFrame = [[[notification userInfo] objectForKey:@"UIKeyboardFrameEndUserInfoKey"] CGRectValue];
CGFloat keyboardRelatedViewsHeight = self.view.window.frame.size.height - keyboardFrame.origin.y;

答案 10 :(得分:0)

对于在 Xamarin.iOS 中查找的任何人

           NSNotificationCenter.DefaultCenter.AddObserver(UIKeyboard.WillShowNotification, OnKeyboardNotification);

然后添加 OnKeyboardNotification 方法,

 private void OnKeyboardNotification(NSNotification obj)
    {
            var window = UIApplication.SharedApplication.KeyWindow;
            var view = window.RootViewController.View;

            String eventName = (UIKeyboardExtensions.HardwareKeyboardConnected(obj, view)) ? "keyboard_hardware" : "keyboard_software";

    }

答案 11 :(得分:-3)

@ philosophistry的回答对我有用。在iOS 8上解决方案不那么复杂:

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

CGFloat deviceHeight = [UIScreen mainScreen].bounds.size.height;    
CGFloat keyboardHeight = deviceHeight - keyboardRect.origin.y;

NSLog(@"actualKeyboardHeight = %f", keyboardHeight);