UIResponder:未调用 keyCommands;确认是FirstResponder

UIResponder: keyCommands not called; confirmed isFirstResponder

我的应用有一个密码视图,在概念上类似于 iOS 解锁屏幕。这是我在新的 UIWindow 中呈现的 UIViewController。工作正常。我正在添加使用硬件键盘键入密码的功能。 keyCommands 方法不会被调用,因此按键不会被识别,直到用户在屏幕上的任何地方至少点击一次。这是一个全屏 UIWindow/UIViewController,所以大概是 UIWindow/UIViewController 中的一个点击。一旦点击发生, keyCommands 将按预期调用,并且一切正常。我不想要求用户在输入密码之前先点击屏幕。

知道这里发生了什么,特别是为什么用户需要点击屏幕(以及如何避免这种要求)?

我已经通过包含重复的 NSTimer 调用来验证 UIViewController 是 firstResponder。

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    [self becomeFirstResponder];
    [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) { //This is just debugging code!
        [self confirmFirstResponder];
    }];
}

-(BOOL)canBecomeFirstResponder {
    return YES;
}

-(void)confirmFirstResponder { //Caveman debugging at its finest
    if ([self isFirstResponder]) {
        NSLog(@"I'm first responder!"); //This is always logged repeatedly
    } else {
        NSLog(@"I'm NOT THE FIRST RESPONDER!!!!"); //This is never logged
    }
}

-(NSArray<UIKeyCommand *> *)keyCommands {
    NSLog(@"keyCommands fired"); //This is not fired until user taps the screen, then presses a key on the hardware keyboard
    NSArray<UIKeyCommand *> *commands = @[
        [UIKeyCommand commandWithTitle:@"1" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"1" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"2" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"2" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"3" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"3" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"4" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"4" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"5" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"5" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"6" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"6" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"7" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"7" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"8" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"8" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"9" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"9" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"0" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"0" modifierFlags:0 propertyList:nil],
        [UIKeyCommand commandWithTitle:@"Delete" image:nil action:@selector(buttonPressedWithKeyCommand:) input:@"\b" modifierFlags:0 propertyList:nil]
    ];
    return commands;
}

下面是创建 UIWindow 的代码:

-(void)displayNewWindowWithViewController:(UIViewController *)vc {
    UINavigationController *nav=[[UINavigationController alloc] initWithRootViewController:vc]; //vc is the UIViewController containing the code above
    nav.navigationBarHidden=YES; //I have no recollection why I'm wrapping the vc in a UINavigationController...
    self.modalWindow = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.modalWindow.backgroundColor = [UIColor whiteColor];
    self.modalWindow.clipsToBounds = NO;
    self.modalWindow.rootViewController = nav;
    self.modalWindow.windowLevel=99;
    [self makeKeyAndVisible:self.modalWindow];
}

-(void)makeKeyAndVisible:(UIWindow *)window {
    window.backgroundColor = [UIColor clearColor];
    window.frame=CGRectMake(0, [UIScreen mainScreen].bounds.size.height, window.frame.size.width, window.frame.size.height);
    [window makeKeyAndVisible];
    window.frame=CGRectMake(0, 0, window.frame.size.width, window.frame.size.height);
}

除了我要问的硬件键盘代码外,我在将近七年前在这里写了所有内容。所以我不记得……任何事情的具体逻辑。我确实知道我使用了 UIWindow 因为这是一个安全视图,它绝对必须覆盖所有其他视图,包括应用程序可能在它可见时添加的一些视图。不管理想与否,它一直在完美地工作。如果需要进行实质性的重构以使硬件键盘在这里工作,则硬件键盘功能将被删除。

即使使用 makeKeyandVisible 指令,新的 UIWindow 在捕获键盘事件方面也不完全是“关键 window”。我通过将相同的代码临时添加到应用程序主 UIWindow 上的 UIViewController 来验证这一点。它收到键盘事件,直到我点击屏幕(新的 UIWindow)。

我改变了这个:

[window makeKeyAndVisible]

对此:

window.hidden = NO;
dispatch_async(dispatch_get_main_queue(), ^{
    [window makeKeyWindow];
});

然后键盘突然被我的新 UIWindow 完全捕获了。

我不太确定发生了什么。原来的 [window makeKeyAndVisible] 肯定是 运行ning 在主线程上(通过 [NSThread isMainThread] 验证)。但是把它扔到另一个 运行 循环中就可以了。去图吧。