【JetpackCompose】 TextField の singleLine は物理キーボードの Enter には無力

無力というか、ぱっと見で Enter の挙動について勘違いしてしまうかな、というものです。

JetpackCompose の TextField には singleLine という引数があって、1行しか表示したくない時に利用されます。

var value by remember { mutableStateOf("") }
TextField(
  value = value,
  onValueChange = { value = it },
  singleLine = true
)

この状態で、スマートフォンタブレットにて、ソフトウェアキーボードを使っている時は特に問題なく1行に収まると思うのですが、物理キーボードを接続してEnter キーを押すと改行されてしまい、1行ではなくなってしまいます。

これは正確には、物理キーボード入力でなくとも、改行コードが入ってくると singleLineが true でも改行されます。TextField は改行コードの面倒を見てくれる機能は持ち合わせていないのです。
issuetracker.google.com

なんとかするとすると、入力した文字列から改行をとるという感じになるのでしょうか。
例えば素朴にこんな感じですかね...

var value by remember { mutableStateOf("") }
TextField(
  value = value,
  onValueChange = {
    newValue ->
      value = newValue.filter { it != '\n' }
  },
  singleLine = true
)

一応これで改行は入り込まないですね。

見た目以外の問題として、物理キーボードで Enter が押されたら次の入力欄に移動したい、という要件もありそうです。

                    var id by remember { mutableStateOf("") }
                    var pass by remember { mutableStateOf("") }
                    val (idInputFocus, passInputFocus) = remember { FocusRequester.createRefs() }
                    Column {
                        TextField(
                            value = id,
                            onValueChange = { newValue ->
                                id = newValue.filter { it != '\n' }
                            },
                            modifier = Modifier
                                .onKeyEvent {
                                    if (it.nativeKeyEvent.keyCode == KEYCODE_ENTER) {
                                        passInputFocus.requestFocus()
                                    }
                                    true
                                }
                                .focusRequester(idInputFocus)
                                .focusProperties {
                                    next = passInputFocus
                                },
                        )
                        TextField(
                            value = pass,

これでよいのでしょうか?これではダメで、日本語入力中な場合は Enter で変換を確定するとonKeyEventに拾われてしまいます。なので TextFieldvalue には TextFieldValue を渡すことにして、composition の有無で IME が入力中としている文字列がない場合だけ Enter で次の TextField に進めるにようにしてみました。

                    var id by remember {
                        mutableStateOf(TextFieldValue(text = ""))
                    }
                    val (idInputFocus, passInputFocus) = remember { FocusRequester.createRefs() }
                    Column {
                        TextField(
                            value = id,
                            onValueChange = { newValue ->
                                id = newValue.copy(text = newValue.text.filter { it != '\n' } )
                            },
                            modifier = Modifier
                                .onKeyEvent {
                                    if (it.nativeKeyEvent.keyCode == KEYCODE_ENTER && id.composition == null) { // 入力中ではない
                                        passInputFocus.requestFocus()
                                    }
                                    true
                                }
                                .focusRequester(idInputFocus)
                                .focusProperties {
                                    next = passInputFocus
                                },
                        )
                        TextField(
...

面倒ですが、現時点ではこんな感じでしょうか...