Dirk Hoffmann
03/13/2021, 10:41 AMtheapache64
03/13/2021, 11:15 AMModifier.keyEvent
to track the key presses.KeyEvent
has flags to identify simltns key presses.Control + Space
Igor Demin
03/13/2021, 11:55 AMimport androidx.compose.desktop.Window
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.text.BasicTextField
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.key.plus
import androidx.compose.ui.input.key.shortcuts
import androidx.compose.ui.text.TextLayoutResult
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.round
fun main() = Window {
var value: TextFieldValue by remember { mutableStateOf(TextFieldValue("")) }
var textLayoutResult: TextLayoutResult? by remember { mutableStateOf(null) }
var isPopupShowed: Boolean by remember { mutableStateOf(false) }
fun TextLayoutResult.currentCursor() = getCursorRect(
value.selection.end.coerceAtMost(layoutInput.text.length)
).topRight.round()
val popupCoordinates by remember {
derivedStateOf { textLayoutResult?.currentCursor() }
}
Box {
BasicTextField(
value,
{ value = it },
modifier = Modifier.shortcuts {
on(Key.CtrlLeft + Key.Spacebar) {
isPopupShowed = !isPopupShowed
}
},
onTextLayout = {
textLayoutResult = it
}
)
if (popupCoordinates != null && isPopupShowed) {
Box(Modifier.offset { popupCoordinates!! }) {
Box(Modifier.requiredSize(100.dp, 25.dp).background(Color.Red))
}
}
}
}
1. You can use desktop-only Modifier.shortcuts
instead of onKeyEvent
2. There is an issue - shortcuts/onKeyEvent don't intercept keys, they will be dispatched to the BasicTextField (when we press ctrl-space we will show popup and type "space" in the field). Probably it is a bug.
3. You can't use just TextField
for now. It doesn't have the ability to set onTextLayout
. You have to use BasicTextField
4. You can't use Popup
too, because it will intercept all key events (we fill fix this in the future). But you can use simple Box(Modifier.offset)
for now.Dirk Hoffmann
03/13/2021, 11:57 AMtheapache64
03/13/2021, 12:10 PMIgor Demin
03/13/2021, 12:10 PMisCtrlPressed
in the common code, keys is not my expertise š.
In this case, I think it is better to use onKeyEvent
@Andrew Rudenko [JB] probably can tell more about cases when we should use Modifier.shortcuts
Andrew Rudenko [JB]
03/13/2021, 12:32 PMModifier.shortcuts
There is an issue - shortcuts/onKeyEvent don't intercept keys, they will be dispatched to the BasicTextField (when we press ctrl-space we will show popup and type "space" in the field). Probably it is a bug.you can intercept events with
Modifier.onPreviewKeyEvent
Dirk Hoffmann
03/13/2021, 1:03 PMval isCtrlSpacePressed = keyEvent.type == KeyEventType.KeyDown && keyEvent.isCtrlPressed && keyEvent.nativeKeyEvent.keyCode == NativeKeyEvent.VK_SPACE
if(isCtrlSpacePressed) {
isPopupShowed = !isPopupShowed
true
on pressing Ctrl. space there are more than on keyEvent coming ...
and only one of them makes the if true
so no wonder the space is propagated ...
still would be curious on your prepared answer šAndrew Rudenko [JB]
03/13/2021, 1:09 PMBasicTextField(
value,
onValueChange = { value = it },
modifier = Modifier.onPreviewKeyEvent {
if ((it.key == Key.Spacebar || it.utf16CodePoint == ' '.toInt()) && it.isCtrlPressed) {
if (it.type == KeyEventType.KeyDown) {
println("fancy stuff")
}
true
} else {
false
}
}
)
I understand that it could be confusing, but that's how it's currently working...Dirk Hoffmann
03/13/2021, 1:10 PM