0

I would like to create a custom text editor view in Android, with customizable key controls, meaning that I need to handle all software keyboard key events.

To do this, I can extend View and override its onKeyDown event. However, I would also like to preserve the user's full software keyboard functionality, e.g. suggestions and glide-typing, which seems to only work if I properly override onCreateInputConnection like so:

override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
    outAttrs.inputType = InputType.TYPE_CLASS_TEXT
    return object : BaseInputConnection(this, true) { ... }
}

Unfortunately, the InputConnection seems to eat all the key events and block the key listener methods like onKeyDown from being called, whereas I would like to listen to key events and use an InputConnection (to allow full soft keyboard functionality) at the same time.

The only workaround I have found is using a TextWatcher to listen to text change events, but I don't feel this is as flexible or simple as I need it to be; I need full and direct access to all key presses.

I believe this is possible because this is exactly how an input element in a WebView works: I can listen to its key events and the user can input text with suggestions or glide-typing at the same time. In fact, I am considering using a WebView after all, but I don't see why it shouldn't be possible to do this without one.

How can I implement this behavior in Android, in either a View or a Composable?

Skanderbeg
  • 15
  • 1
  • 3

1 Answers1

0

KeyEvents don't exist when using a soft keyboard. Almost every soft keyboard uses InputConnection.commitText() to send characters or even words at a time. KeyEvents are only really generated by hardware keyboards, bluetooth keyboards, and physical keys like volume.

If you want to look for changes to text, implement the commitText() function and see what's sent over there. There's one or two other functions like deleteSurroundingText you'd need to override as well to get delete presses.

Gabe Sechan
  • 90,003
  • 9
  • 87
  • 127
  • Actually, like I wrote in the question, soft keyboards do send key events to the `onKeyDown` method if you extend `View` directly instead of `EditText`. I have tested this on the Samsung Keyboard, Gboard, and some others. The key events only don't get sent if you provide an `InputConnection`, which is the issue. On the other hand, a `WebView` does everything I want, but I wish I didn't have to use one. – Skanderbeg Apr 08 '22 at 17:59
  • @Skanderbeg No, they don't. I spent 4 years of my life writing one. They only do under VERY SPECIFIC circumstances (involving an input type of null), if ever (and many of them don't bother writing this fallback path, as needing it means the view implementing the other half of the connection is badly broken). Something in the framework *might* translate something into keyevents under specific circumstances, but in that case expect half the info, including timing fields, to be wrong. Softkeyboards, as a rule, do NOT send key events. It's not a concept in that world. – Gabe Sechan Apr 08 '22 at 18:19
  • @Skanderbeg Actually, you can see in https://android.googlesource.com/platform/frameworks/base/+/a5408e6/core/java/android/webkit/WebViewClassic.java. where the webview is using inputConnection.commitText and faking the key events from it in their InputConnection code. Of course because of that most of the fields are wrong, because they view has no idea if shift is being held, or how long a key was pressed, because it doesn't get that info. – Gabe Sechan Apr 08 '22 at 18:29
  • I guess webviews had me fooled this whole time. Thank you so much, I learned a lot from your comments and the code you linked. – Skanderbeg Apr 09 '22 at 22:09