Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Keyboard dismissing when I select the "Bold" option from tool bar #159

Open
nastasiupta opened this issue Oct 30, 2023 · 16 comments
Open

Keyboard dismissing when I select the "Bold" option from tool bar #159

nastasiupta opened this issue Oct 30, 2023 · 16 comments

Comments

@nastasiupta
Copy link

nastasiupta commented Oct 30, 2023

I created a simple project, added the framework using SPM and using the SwiftUI example. If I tap somewhere and select the "Bold" option to write something bolded, the keyboard is dismissed... I have to tap again in the same place and start writing.
iOS version 17.1
Xcode version 15.0.1
Framework version 0.6.0

Note 1: This happens only when I activate the bold, underline, italic and strike, when i disable the effect, the keyboard remains. And if I tap again, the keyboard is dismissed.
Note 2: For other options (dots list etc) works fine.

@stevengharris
Copy link
Owner

Thanks very much for reporting this and the additional notes you supplied. I think it must be a regression (maybe for iOS 17?), but I should be able to take a look at it within the next couple of days.

@nastasiupta
Copy link
Author

@stevengharris Any ETA for this issue ?

@stevengharris
Copy link
Owner

I started to look at it, thinking I had a good idea how to fix it, but it turns out not to be as simple as I thought. The fact it's not happening with things like indent is a good clue, considering I'm conceptually doing the same thing (invoke a JavaScript function, modify the DOM, notify the Swift side that there has been a change). Maybe some kind of change in the underlying WKWebView to accommodate changes in UITextInteraction in iOS 17 (e.g., https://developer.apple.com/videos/play/wwdc2023/10058/), but considering I never do anything with UITextInteraction directly in the MarkupEditor, I'm not sure. So, the short answer is: no ETA, but I'm looking at it.

@stevengharris
Copy link
Owner

FWIW, the simulator shows this problem does not show up in iOS 16.

Also in iOS 17, when positioning the cursor in the middle of a word using the "loupe" (i.e., long press showing a magnifier above the touch point), the console spits out:

Error: this application, or a library it uses, has passed an invalid numeric value (NaN, or not-a-number) to CoreGraphics API and this value is being ignored. Please fix this problem.
If you want to see the backtrace, please set CG_NUMERICS_SHOW_BACKTRACE environmental variable.

And if you put CG_NUMERICS_SHOW_BACKTRACE in the environment, you get this backtrace:

  <CGPathAddLineToPoint+71>
   <+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadii:segments:smoothPillShapes:]+2718>
    <+[UIBezierPath _continuousRoundedRectBezierPath:withRoundedCorners:cornerRadius:segments:]+167>
     <+[UIBezierPath _roundedRectBezierPath:withRoundedCorners:cornerRadius:segments:legacyCorners:]+338>
      <-[_UITextMagnifiedLoupeView layoutSubviews]+2240>
       <-[UIView(CALayerDelegate) layoutSublayersOfLayer:]+2141>
        <_ZN2CA5Layer16layout_if_neededEPNS_11TransactionE+527>
         <_ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE+67>
          <_ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd+706>
           <_ZN2CA11Transaction6commitEv+728>
            <_UIApplicationFlushRunLoopCATransactionIfTooLate+70>
             <__processEventQueue+9465>
              <__eventFetcherSourceCallback+163>
               <__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__+17>
                <__CFRunLoopDoSource0+157>
                 <__CFRunLoopDoSources0+215>
                  <__CFRunLoopRun+919>
                   <CFRunLoopRunSpecific+557>
                    <GSEventRunModal+137>
                     <-[UIApplication _run]+972>
                      <UIApplicationMain+123>
                       <__swift_destroy_boxed_opaque_existential_1Tm+12707>
                        <$sSo21UIApplicationDelegateP5UIKitE4mainyyFZ+123>
                         <$s11SwiftUIDemo11AppDelegateC5$mainyyFZ+39>
                          <main+24>
                           109d023ee                            1179a43a6

The loupe positioning still works okay, but 🤔.

@stevengharris
Copy link
Owner

Some potentially related issues:

https://developer.apple.com/forums/thread/731700

simonbs/Runestone#314

Mostly just makes me think this is going to require some kind of weird hack to fix without Apple themselves fixing it. I will probably try to reproduce it using a very simple test case with only WKWebView and submit the problem as a formal Technical Support Incident.

@nastasiupta
Copy link
Author

We can give it a try. Let me know after you solve this, and I will test it out :D

@nastasiupta
Copy link
Author

@stevengharris also, another issue I noticed on a freshly installed app, when the MarkupEditorView begins editing, the UIPasteBoard permission is triggered and it ask to allow the paste action...

@stevengharris
Copy link
Owner

I had thought that was all taken care of in #78, but, again, maybe something changed for iOS 17. I will check it out and raise a separate issue for it if needed.

@nastasiupta
Copy link
Author

@stevengharris any update on this issue?

@stevengharris
Copy link
Owner

I have not had the time to dig in further. If you would open a separate issue for the UIPasteboard permission problem with any details to reproduce, it will help me track it. Thx.

@nastasiupta
Copy link
Author

@stevengharris any update on this issue ?

@stevengharris
Copy link
Owner

No, I think I will have to dig into UITextInteraction to fix it but have not had the time.

@kaimatachi
Copy link

Hello @stevengharris,
I have the same issue as described above. Do you maybe have a fix or a workaround for this ?

@stevengharris
Copy link
Owner

Unfortunately, no. I spent some time trying to sort out UITextInteraction, and am not sure it is a path to fixing the issue, which seems to be in WKWebView itself. Anyway, sorry, but I haven't been able to make any progress on it. Do you know if it is still a problem on iOS 18?

@kaimatachi
Copy link

Yes it is still an issue on iOS 18.

@stevengharris
Copy link
Owner

It occurred to me that maybe a workaround would be to force the keyboard to show after bold/italic etc, although doing so takes some swizzling. This was discussed a long time ago in this issue/comment #88 (comment). As Gavin notes in the comment, I once had commented-out code in MarkupWKWebView to do this, but I removed it completely when I did what I felt was a proper job on getting focus. Here is the old code I just resurrected from git (no idea if it works, but putting it here for my own purposes and in case someone wants to take a closer look themselves). The idea would be to restore this code in working form to MarkupWKWebView and then call showKeyboard(), perhaps inside the evaluateJavaScript closure of MarkupWKWebView.bold(handler:), italic, etc.

typealias NewClosureType = @convention(c) (Any, Selector, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Voi
func setKeyboardRequiresUserInteraction(_ value: Bool) {
    guard
        let WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
        print("Cannot find the WKContentView class")
        return
    }
    let ios13Selector: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:")
    if let method = class_getInstanceMethod(WKContentViewClass, ios13Selector) {
        swizzleAutofocusMethod(method, ios13Selector, value)
    }

func unsetKeyboardRequiresUserInteraction() {
    guard
        let WKContentViewClass: AnyClass = NSClassFromString("WKContentView") else {
        print("Cannot find the WKContentView class")
        return
    }
    let ios13Selector: Selector = sel_getUid("_elementDidFocus:userIsInteracting:blurPreviousNode:activityStateChanges:userObject:")
    if let method = class_getInstanceMethod(WKContentViewClass, ios13Selector) {
        unswizzleAutofocusMethod(method, ios13Selector)
    }

func swizzleAutofocusMethod(_ method: Method, _ selector: Selector, _ value: Bool) {
    print("swizzling")
    let originalImp: IMP = method_getImplementation(method)
    let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self)
    let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
        original(me, selector, arg0, !value, arg2, arg3, arg4)
    }
    let imp: IMP = imp_implementationWithBlock(block)
    method_setImplementation(method, imp)

func unswizzleAutofocusMethod(_ method: Method, _ selector: Selector) {
    print("unswizzling")
    let originalImp: IMP = method_getImplementation(method)
    let original: NewClosureType = unsafeBitCast(originalImp, to: NewClosureType.self)
    let block : @convention(block) (Any, UnsafeRawPointer, Bool, Bool, Bool, Any?) -> Void = { (me, arg0, arg1, arg2, arg3, arg4) in
        original(me, selector, arg0, arg1, arg2, arg3, arg4)
    }
    let imp: IMP = imp_implementationWithBlock(block)
    method_setImplementation(method, imp)

public func showKeyboard() {
    setKeyboardRequiresUserInteraction(false)
    becomeFirstResponder()
    unsetKeyboardRequiresUserInteraction()
}

Since it's clear this problem isn't going to go away on the WKWebView end even in iOS 18, I will try to circle back around to this approach as a workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants