diff --git a/ios/README.md b/ios/README.md index 33fa33d..2dcadcb 100644 --- a/ios/README.md +++ b/ios/README.md @@ -35,7 +35,10 @@ finish GL work before suspension. Touch and coalesced Pencil samples become the standard AX pointer events; additional fingers are ignored during a stroke. Two-finger pan becomes scroll input. Hardware keys retain modifier flags for framework accelerators. -`axSetTextInput` shows or hides the keyboard for an active text control. +`axSetTextInput` shows or hides the keyboard for an active text control. While the +on-screen keyboard covers the bottom of the window, the backend slides the +whole app view up by the covered height, with the keyboard's own animation, +and back down when it hides. Pointer coordinates are unaffected. The event queue accepts worker-thread posts and coalesces paint/resize events by target. Timers run on the main run loop and are cancelled when their owner diff --git a/ios/ios_window.m b/ios/ios_window.m index e6a0aa9..34e9394 100644 --- a/ios/ios_window.m +++ b/ios/ios_window.m @@ -209,6 +209,26 @@ - (void)viewDidLoad { scroll.allowedTouchTypes = @[@(UITouchTypeIndirectPointer)]; scroll.allowedScrollTypesMask = UIScrollTypeMaskAll; [ios_view addGestureRecognizer:scroll]; + for (NSNotificationName name in @[UIKeyboardWillChangeFrameNotification, UIKeyboardWillHideNotification]) + [NSNotificationCenter.defaultCenter addObserver:self selector:@selector(keyboard:) name:name object:nil]; +} +// The app slides up by the part of the window the on-screen keyboard covers. +// A view transform keeps the drawable size, and locationInView: still reports +// touches in the view's own coordinates. +- (void)keyboard:(NSNotification *)note { + CGFloat cover = 0; + if (note.name != UIKeyboardWillHideNotification) { + CGRect end = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; + id screen = self.view.window.screen.coordinateSpace; + CGRect kb = screen ? [self.view convertRect:end fromCoordinateSpace:screen] : CGRectZero; + CGRect hidden = CGRectIntersection(kb, self.view.bounds); + if (!CGRectIsNull(hidden) && CGRectGetMaxY(kb) >= CGRectGetMaxY(self.view.bounds)) cover = hidden.size.height; + } + IOS_TRACE("keyboard cover=%.1f", cover); + double duration = [note.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; + UIViewAnimationOptions curve = (UIViewAnimationOptions)[note.userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16; + [UIView animateWithDuration:duration delay:0 options:curve | UIViewAnimationOptionBeginFromCurrentState + animations:^{ ios_view.transform = CGAffineTransformMakeTranslation(0, -cover); } completion:nil]; } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated];