feat: add size, opacity and hidden-key settings for the PC keyboard (#1897)

This commit is contained in:
Kurt Himebauch authored and GitHub committed 2026-11-03 07:01:33 -05:00
commit 8eeea5ef5a
7 files changed
+131 -10

No files matched your search

@@ -51,6 +51,15 @@ val PC_KEY_ROWS: List<List<PcKey>> = listOf(
val PC_MODIFIERS: Set<Int> = setOf(42, 54, 29, 97, 56, 100, 125)
// Sticky modifiers are excluded: hiding a locked modifier would leave it pressed forever.
val PC_KEY_HIDDEN_GROUPS: Map<String, Set<Int>> = mapOf(
"function" to ((59..68).toSet() + setOf(1, 87, 88)),
"nav" to setOf(110, 111, 102, 107, 104, 109),
"arrows" to setOf(103, 105, 108, 106),
)
val PC_KEY_GROUP_IDS: Map<Int, String> = mapOf(0 to "function", 1 to "nav", 2 to "arrows")
val PC_KEYS: Map<Int, PcKey> = PC_KEY_ROWS.flatten().associateBy { it.code }
fun pcKeyLabel(context: Context, code: Int): String {
@@ -348,6 +348,32 @@ object SessionPrefs {
prefs(context).edit().putInt("hudOpacity", percent.coerceIn(HUD_OPACITY_RANGE)).apply()
}
const val PC_KEYBOARD_SIZE_DEFAULT = 47
val PC_KEYBOARD_SIZE_RANGE = 25..70
const val PC_KEYBOARD_OPACITY_DEFAULT = 100
val PC_KEYBOARD_OPACITY_RANGE = 30..100
fun pcKeyboardSize(context: Context): Int =
prefs(context).getInt("pcKeyboardSize", PC_KEYBOARD_SIZE_DEFAULT).takeIf { it in PC_KEYBOARD_SIZE_RANGE } ?: PC_KEYBOARD_SIZE_DEFAULT
fun setPcKeyboardSize(context: Context, percent: Int) {
prefs(context).edit().putInt("pcKeyboardSize", percent.coerceIn(PC_KEYBOARD_SIZE_RANGE)).apply()
}
fun pcKeyboardOpacity(context: Context): Int =
prefs(context).getInt("pcKeyboardOpacity", PC_KEYBOARD_OPACITY_DEFAULT).takeIf { it in PC_KEYBOARD_OPACITY_RANGE } ?: PC_KEYBOARD_OPACITY_DEFAULT
fun setPcKeyboardOpacity(context: Context, percent: Int) {
prefs(context).edit().putInt("pcKeyboardOpacity", percent.coerceIn(PC_KEYBOARD_OPACITY_RANGE)).apply()
}
fun pcKeyboardHiddenKeys(context: Context): Set<String> =
idList(prefs(context).getString("pcKeyboardHiddenKeys", null)).toSet()
fun setPcKeyboardHiddenKeys(context: Context, hidden: Set<String>) {
prefs(context).edit().putString("pcKeyboardHiddenKeys", hidden.joinToString(",")).apply()
}
fun droidDeckHudConfig(context: Context): String? = prefs(context).getString("__KEEP_droidDeckHud__", null)
fun setDroidDeckHudConfig(context: Context, config: String) {
@@ -17,7 +17,7 @@ object SettingsReset {
"storesInstallLanguage",
"hud", "hudDeck", "hudFps", "hudBattery", "hudGraph", "hudColor", "hudOpacity", "__KEEP_droidDeckHud__", "__KEEP_droidDeckHudPos__", "backHold", "backActionsInverted", "backDoubleTapMs", "touch", "osc", "shape", "steamController",
"gamepadLeft", "gamepadRight", "pipAutoEnter", "unfoldedControls", "unfoldedControlsWithController",
"stretch16x9", "picturePosition", "railLabels",
"stretch16x9", "picturePosition", "railLabels", "pcKeyboardSize", "pcKeyboardOpacity", "pcKeyboardHiddenKeys",
"gpuDriverMode", "androidDriver", "linuxDriver", "linuxDriver.steam", "linuxDriver.desktop",
"tuSysmem", "glThread", "noGlError", "zinkLazy", "mangoapp", "gpuClockPin", "gamescopeRealtime", "ramCapMb", "vramCapMb", "zramClient",
"directAudio", "mic", "wifiDiscovery", "clientCpusOverride", "clientCpus", "gameCpus",
@@ -1,6 +1,7 @@
package com.droiddeck.launcher.ui
import com.droiddeck.launcher.R
import com.droiddeck.launcher.input.PC_KEY_HIDDEN_GROUPS
import com.droiddeck.launcher.input.PC_KEY_ROWS
import com.droiddeck.launcher.input.PC_MODIFIERS
import com.droiddeck.launcher.input.PcKey
@@ -35,6 +36,7 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.key
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateMapOf
import androidx.compose.runtime.mutableStateOf
@@ -45,12 +47,14 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.key.nativeKeyCode
import androidx.compose.ui.input.key.onPreviewKeyEvent
import androidx.compose.ui.input.key.type
import androidx.compose.ui.input.key.KeyEventType
import androidx.compose.ui.input.key.key
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
@@ -98,10 +102,17 @@ fun PcKeyboard(
}
LaunchedEffect(Unit) { runCatching { firstKey.requestFocus() } }
val prefsContext = LocalContext.current
remember { PcKeyboardPrefs.load(prefsContext) }
val hiddenCodes = PcKeyboardPrefs.hiddenKeys.flatMap { PC_KEY_HIDDEN_GROUPS[it].orEmpty() }.toSet()
val rows = PC_KEY_ROWS.map { row -> row.filter { it.code !in hiddenCodes } }.filter { it.isNotEmpty() }
BoxWithConstraints(Modifier.fillMaxSize(), contentAlignment = Alignment.BottomCenter) {
val rowHeight = ((maxHeight * 0.47f - 24.dp - 3.dp * 6 - 10.dp) / 6).coerceIn(24.dp, 44.dp)
val rowHeight = ((maxHeight * (PcKeyboardPrefs.size / 100f) - 24.dp - 3.dp * rows.size - 10.dp) / rows.size)
.coerceIn(20.dp, 56.dp)
Box(
Modifier.fillMaxWidth()
.graphicsLayer { alpha = PcKeyboardPrefs.opacity / 100f }
.background(Color(0xE6101418), RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp))
.border(1.dp, pal.line2, RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp))
.pointerInput(Unit) { awaitEachGesture { awaitFirstDown().consume(); waitForUpOrCancellation()?.consume() } }
@@ -115,7 +126,7 @@ fun PcKeyboard(
Spacer(Modifier.width(8.dp))
HeaderButton(stringResource(R.string.pckb_hide), onClose)
}
PC_KEY_ROWS.forEachIndexed { r, row ->
rows.forEachIndexed { r, row ->
Row(horizontalArrangement = Arrangement.spacedBy(3.dp), modifier = Modifier.fillMaxWidth().height(rowHeight)) {
row.forEachIndexed { i, key ->
val state = mods[key.code] ?: MOD_OFF
@@ -126,11 +137,13 @@ fun PcKeyboard(
key.label.length == 1 && key.label[0].isLetter() && (shifted xor capsOn) -> key.label.uppercase()
else -> key.label
}
KeyCap(
label, key.weight, lit, locked = state == MOD_LOCKED,
modifier = if (r == 0 && i == 0) Modifier.focusRequester(firstKey) else Modifier,
onDown = { press(key) }, onUp = { release(key) },
)
key(key.code) {
KeyCap(
label, key.weight, lit, locked = state == MOD_LOCKED,
modifier = if (r == 0 && i == 0) Modifier.focusRequester(firstKey) else Modifier,
onDown = { press(key) }, onUp = { release(key) },
)
}
}
}
}
@@ -164,8 +177,11 @@ private fun RowScope.KeyCap(
awaitEachGesture {
awaitFirstDown().consume()
down = true; onDown()
waitForUpOrCancellation()?.consume()
down = false; onUp()
try {
waitForUpOrCancellation()?.consume()
} finally {
down = false; onUp()
}
}
}
.onPreviewKeyEvent { e ->
@@ -0,0 +1,38 @@
package com.droiddeck.launcher.ui
import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import com.droiddeck.launcher.input.PC_KEY_HIDDEN_GROUPS
import com.droiddeck.launcher.session.SessionPrefs
internal object PcKeyboardPrefs {
var size by mutableStateOf(SessionPrefs.PC_KEYBOARD_SIZE_DEFAULT)
private set
var opacity by mutableStateOf(SessionPrefs.PC_KEYBOARD_OPACITY_DEFAULT)
private set
var hiddenKeys by mutableStateOf(emptySet<String>())
private set
fun load(context: Context) {
size = SessionPrefs.pcKeyboardSize(context)
opacity = SessionPrefs.pcKeyboardOpacity(context)
hiddenKeys = SessionPrefs.pcKeyboardHiddenKeys(context).filter { it in PC_KEY_HIDDEN_GROUPS }.toSet()
}
fun setSize(context: Context, percent: Int) {
size = percent
SessionPrefs.setPcKeyboardSize(context, percent)
}
fun setOpacity(context: Context, percent: Int) {
opacity = percent
SessionPrefs.setPcKeyboardOpacity(context, percent)
}
fun toggleHiddenKey(context: Context, group: String, on: Boolean) {
hiddenKeys = if (on) hiddenKeys + group else hiddenKeys - group
SessionPrefs.setPcKeyboardHiddenKeys(context, hiddenKeys)
}
}
@@ -154,6 +154,7 @@ import com.droiddeck.launcher.gpu.SteamVr
import com.droiddeck.launcher.gpu.ScreenEffects
import com.droiddeck.launcher.session.SessionPrefs
import com.droiddeck.launcher.session.ComponentsManager
import com.droiddeck.launcher.input.PC_KEY_GROUP_IDS
import com.droiddeck.launcher.input.SecondScreenDisplay
import com.droiddeck.launcher.input.SecondScreenMode
import com.droiddeck.launcher.input.TouchGestureConfig.Companion.MOUSE_BEHAVIOR_CLICK
@@ -683,6 +684,28 @@ internal fun SessionDrawer(open: Boolean, requestedPage: SessionDrawerPage, cont
host.open = null; a.onKeyboard()
}
}
val keyboardContext = LocalContext.current
remember { PcKeyboardPrefs.load(keyboardContext) }
SliderRow(
stringResource(R.string.pckb_size), stringResource(R.string.pckb_size_hint),
PcKeyboardPrefs.size, SessionPrefs.PC_KEYBOARD_SIZE_RANGE, step = 1,
format = { "$it%" }, modifier = focus.track(page, "pckb-size"),
onChange = { PcKeyboardPrefs.setSize(keyboardContext, it) })
SliderRow(
stringResource(R.string.pckb_opacity), stringResource(R.string.pckb_opacity_hint),
PcKeyboardPrefs.opacity, SessionPrefs.PC_KEYBOARD_OPACITY_RANGE, step = 5,
format = { "$it%" }, modifier = focus.track(page, "pckb-opacity"),
onChange = { PcKeyboardPrefs.setOpacity(keyboardContext, it) })
MultiRow(
host, "pckb-hidden", stringResource(R.string.pckb_hidden_keys),
stringResource(R.string.pckb_hidden_keys_hint),
listOf(
0 to stringResource(R.string.pckb_group_function),
1 to stringResource(R.string.pckb_group_nav),
2 to stringResource(R.string.pckb_group_arrows),
),
PC_KEY_GROUP_IDS.filterValues { it in PcKeyboardPrefs.hiddenKeys }.keys,
onToggle = { id, on -> PcKeyboardPrefs.toggleHiddenKey(keyboardContext, PC_KEY_GROUP_IDS.getValue(id), on) })
}
}
SessionDrawerPage.SECOND_SCREEN -> {
+9
View File
@@ -1396,6 +1396,15 @@
<string name="proton_cancel_queued">Cancel queued</string>
<string name="pckb_android">Android keyboard</string>
<string name="pckb_hide">Hide ✕</string>
<string name="pckb_size">Size on screen</string>
<string name="pckb_size_hint">Share of the screen the keyboard takes, header included.</string>
<string name="pckb_opacity">Opacity</string>
<string name="pckb_opacity_hint">Lower it to see the game behind the keyboard.</string>
<string name="pckb_hidden_keys">Hidden keys</string>
<string name="pckb_hidden_keys_hint">Keys you rarely use stay off the keyboard.</string>
<string name="pckb_group_function">Esc and function row</string>
<string name="pckb_group_nav">Ins / Del / Home / End / PgUp / PgDn</string>
<string name="pckb_group_arrows">Arrow keys</string>
<string name="main_launch_named">Launch %1$s</string>
<string name="main_choose_screen">Choose a screen. Secondary: %1$s.</string>
<string name="main_secondary_gone">The secondary display is no longer available.</string>