Skip to content

Commit

Permalink
Fix Input methods on JBR, disable input methods when we lose focus
Browse files Browse the repository at this point in the history
1. Fixes JetBrains/compose-multiplatform#2628
2. Doesn't show input methods popup if there is no focused TextField (only on Windows for now, on macOs, Swing seems has a bug: JetBrains/compose-multiplatform#3839)

## Testing
Tested manually on Windows/macOs/Linux, OpenJDK/JBR, Accessibility enabled/disabled
  • Loading branch information
igordmn committed Oct 19, 2023
1 parent 54577e1 commit 7ebb7dc
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ import org.jetbrains.skiko.*
* Provides a base implementation for integrating a Compose scene with AWT/Swing.
* It allows setting Compose content by [setContent], this content should be drawn on [component].
*
* This bridge contain 2 components that should be added to the view hirarachy:
* [component] the main visible Swing component, on which Compose will be shown
* [invisibleComponent] service component used to bypass Swing issues:
* - for forcing refocus on input methods change
*
* Inheritors should call [attachComposeToComponent], so events that came to [component] will be transferred to [ComposeScene]
*/
internal abstract class ComposeBridge(
Expand All @@ -66,7 +71,10 @@ internal abstract class ComposeBridge(
mainOwnerProvider = { scene.mainOwner }
)

private val _invisibleComponent = InvisibleComponent()

abstract val component: JComponent
val invisibleComponent: Component get() = _invisibleComponent

abstract val renderApi: GraphicsApi

Expand All @@ -86,16 +94,30 @@ internal abstract class ComposeBridge(

private var window: Window? = null

private fun refocus() {
if (component.isFocusOwner) {
_invisibleComponent.requestFocusTemporary()
component.requestFocus()
}
}

private val platformComponent: PlatformComponent = object : PlatformComponent {
override fun enableInput(inputMethodRequests: InputMethodRequests) {
currentInputMethodRequests = inputMethodRequests
component.enableInputMethods(true)
val focusGainedEvent = FocusEvent(focusComponentDelegate, FocusEvent.FOCUS_GAINED)
component.inputContext.dispatchEvent(focusGainedEvent)
// Without resetting the focus, Swing won't update the status (doesn't show/hide popup)
// enableInputMethods is design to used per-Swing component level at init stage,
// not dynamically
refocus()
}

override fun disableInput() {
currentInputMethodRequests = null
component.enableInputMethods(false)
// Without resetting the focus, Swing won't update the status (doesn't show/hide popup)
// enableInputMethods is design to used per-Swing component level at init stage,
// not dynamically
refocus()
}

override val locationOnScreen: Point
Expand Down Expand Up @@ -181,6 +203,7 @@ internal abstract class ComposeBridge(

@OptIn(ExperimentalComposeUiApi::class)
protected fun attachComposeToComponent() {
component.enableInputMethods(false)
component.addInputMethodListener(object : InputMethodListener {
override fun caretPositionChanged(event: InputMethodEvent?) {
if (isDisposed) return
Expand Down Expand Up @@ -393,6 +416,12 @@ internal abstract class ComposeBridge(
override val touchSlop: Float get() = with(platformComponent.density) { 18.dp.toPx() }
}
}

private class InvisibleComponent : Component() {
fun requestFocusTemporary(): Boolean {
return super.requestFocus(true)
}
}
}

private fun ComposeScene.onMouseEvent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class ComposePanel @ExperimentalComposeUiApi constructor(
if (bridge != null) {
bridge!!.dispose()
super.remove(bridge!!.component)
super.remove(bridge!!.invisibleComponent)
bridge = null
}
}
Expand Down Expand Up @@ -187,6 +188,7 @@ class ComposePanel @ExperimentalComposeUiApi constructor(
if (bridge == null) {
bridge = createComposeBridge()
initContent()
super.add(bridge!!.invisibleComponent, Integer.valueOf(1))
super.add(bridge!!.component, Integer.valueOf(1))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,13 @@ internal class ComposeWindowDelegate(

init {
layout = null
super.add(bridge.invisibleComponent, 1)
super.add(bridge.component, 1)
}

fun dispose() {
super.remove(bridge.component)
super.remove(bridge.invisibleComponent)
}
}

Expand Down

0 comments on commit 7ebb7dc

Please sign in to comment.