From 6fcdd39541957d843e17ef16da14b0d5da1b89cd Mon Sep 17 00:00:00 2001 From: movte Date: Sun, 22 Feb 2026 21:54:38 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat(=E6=89=8B=E6=9F=84=E6=98=A0=E5=B0=84):?= =?UTF-8?q?=20=E6=94=AF=E6=8C=81=E5=88=9B=E5=BB=BA=E5=A4=9A=E4=B8=AA?= =?UTF-8?q?=E6=89=8B=E6=9F=84=E6=98=A0=E5=B0=84=E9=85=8D=E7=BD=AE=20#718?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../zalithlauncher/setting/AllSettings.kt | 5 + .../ui/control/gamepad/GamepadEvents.kt | 4 +- .../ui/control/gamepad/GamepadMappingList.kt | 125 ++++++ .../ui/control/gamepad/_MMKV.kt | 5 + .../content/settings/GamepadSettingsScreen.kt | 361 +++++++++++++----- .../screens/content/settings/layouts/List.kt | 2 +- .../ui/screens/game/GameScreen.kt | 1 + .../game/elements/GameMenuSubscreen.kt | 39 +- .../viewmodel/GamepadRemapperViewModel.kt | 2 +- .../viewmodel/GamepadViewModel.kt | 184 +++++---- .../src/main/res/values-zh-rCN/strings.xml | 8 + .../src/main/res/values-zh-rTW/strings.xml | 8 + .../src/main/res/values/strings.xml | 8 + 13 files changed, 572 insertions(+), 180 deletions(-) create mode 100644 ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadMappingList.kt diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/setting/AllSettings.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/setting/AllSettings.kt index 0bb5c5cd3..04a435a9f 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/setting/AllSettings.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/setting/AllSettings.kt @@ -233,6 +233,11 @@ object AllSettings : SettingsRegistry() { */ val gamepadDeadZoneScale = intSetting("gamepadDeadZoneScale", 100, 50..200) + /** + * 手柄映射配置 + */ + val gamepadMappingConfig = stringSetting("gamepadMappingConfig", "default") + /** * 摇杆控制模式 */ diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadEvents.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadEvents.kt index 3a2cd6693..18776c90b 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadEvents.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadEvents.kt @@ -213,7 +213,7 @@ fun GamepadKeyListener( lastPressKey.remove(event.code) } } else { - gamepadViewModel.findByCode(event.code, inGame)?.let { targets -> + gamepadViewModel.currentMapping?.findByCode(event.code, inGame)?.let { targets -> val currentEvents = targets.map { guessEvent(it) } lastPressKey[event.code] = currentEvents currentOnKeyEvent(currentEvents, true) @@ -227,7 +227,7 @@ fun GamepadKeyListener( lastPressDpad.remove(event.direction) } } else { - gamepadViewModel.findByDpad(event.direction, inGame)?.let { targets -> + gamepadViewModel.currentMapping?.findByDpad(event.direction, inGame)?.let { targets -> val currentEvents = targets.map { guessEvent(it) } lastPressDpad[event.direction] = currentEvents currentOnKeyEvent(currentEvents, true) diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadMappingList.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadMappingList.kt new file mode 100644 index 000000000..b6e69475c --- /dev/null +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/GamepadMappingList.kt @@ -0,0 +1,125 @@ +package com.movtery.zalithlauncher.ui.control.gamepad + +import android.os.Parcelable +import kotlinx.parcelize.IgnoredOnParcel +import kotlinx.parcelize.Parcelize + +@Parcelize +class GamepadMappingList( + val name: String, + val list: MutableList +) : Parcelable { + /** + * 手柄与键盘按键映射绑定 + */ + @IgnoredOnParcel + private val allKeyMappings = mutableMapOf() + @IgnoredOnParcel + private val allDpadMappings = mutableMapOf() + + /** + * 便于记录目标键盘映射的数据类 + */ + data class TargetKeys( + val inGame: Set, + val inMenu: Set + ) { + fun getKeys(isInGame: Boolean) = if (isInGame) inGame else inMenu + } + + fun load() { + allKeyMappings.clear() + allDpadMappings.clear() + + list.forEach { mapping -> + addInMappingsMap(mapping) + } + } + + private fun addInMappingsMap(mapping: GamepadMapping) { + val target = TargetKeys(mapping.targetsInGame, mapping.targetsInMenu) + mapping.dpadDirection?.let { + allDpadMappings[it] = target + } ?: run { + allKeyMappings[mapping.key] = target + } + } + + /** + * 重置手柄与键盘按键映射绑定 + */ + fun resetMapping(gamepadMap: GamepadMap, inGame: Boolean) = + applyMapping(gamepadMap, inGame, useDefault = true) + + /** + * 为指定手柄映射设置目标键盘映射 + */ + fun saveMapping(gamepadMap: GamepadMap, targets: Set, inGame: Boolean) = + applyMapping(gamepadMap, inGame, customTargets = targets) + + /** + * 保存或重置手柄与键盘按键映射绑定 + * @param gamepadMap 手柄映射对象 + * @param inGame 是否为游戏内映射(true 为游戏内,false 为菜单内) + * @param customTargets 自定义目标键 + * @param useDefault 是否使用默认按键 + */ + private fun applyMapping( + gamepadMap: GamepadMap, + inGame: Boolean, + customTargets: Set? = null, + useDefault: Boolean = false + ) { + val dpad = gamepadMap.dpadDirection + val existing = if (dpad != null) allDpadMappings[dpad] else allKeyMappings[gamepadMap.gamepad] + + val (targetsInGame, targetsInMenu) = if (inGame) { + val newTargets = customTargets ?: if (useDefault) gamepadMap.defaultKeysInGame else emptySet() + newTargets to (existing?.inMenu ?: emptySet()) + } else { + (existing?.inGame ?: emptySet()) to (customTargets ?: if (useDefault) gamepadMap.defaultKeysInMenu else emptySet()) + } + + val mapping = GamepadMapping( + key = gamepadMap.gamepad, + dpadDirection = dpad, + targetsInGame = targetsInGame, + targetsInMenu = targetsInMenu + ) + addInMappingsMap(mapping) + if ( + list.removeIf { mapping0 -> + mapping0.key == mapping.key + } + ) { + list.add(mapping) + } + save() + } + + /** + * 根据手柄按键键值获取对应的键盘映射代码 + * @return 若未找到,则返回null + */ + fun findByCode(key: Int, inGame: Boolean) = + allKeyMappings[key]?.getKeys(inGame) + + /** + * 根据手柄方向键获取对应的键盘映射代码 + * @return 若未找到,则返回null + */ + fun findByDpad(dir: DpadDirection, inGame: Boolean) = + allDpadMappings[dir]?.getKeys(inGame) + + /** + * 根据手柄映射获取对应的键盘映射代码 + * @return 若未找到,则返回null + */ + fun findByMap(map: GamepadMap, inGame: Boolean) = + (map.dpadDirection?.let { allDpadMappings[it] } ?: allKeyMappings[map.gamepad]) + ?.getKeys(inGame) + + fun save() { + keyMappingListMMKV().encode(name, this) + } +} \ No newline at end of file diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/_MMKV.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/_MMKV.kt index 3aaed8d78..df715673a 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/_MMKV.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/control/gamepad/_MMKV.kt @@ -30,4 +30,9 @@ fun remapperMMKV(): MMKV = MMKV.mmkvWithID("GamepadRemapper", MMKV.MULTI_PROCESS */ fun keyMappingMMKV(): MMKV = MMKV.mmkvWithID("GamepadKeyMapping", MMKV.MULTI_PROCESS_MODE) +/** + * 手柄按键映射配置列表保存 MMKV + */ +fun keyMappingListMMKV(): MMKV = MMKV.mmkvWithID("GamepadKeyMappingList", MMKV.MULTI_PROCESS_MODE) + diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt index 702c10798..129672652 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt @@ -60,6 +60,8 @@ import com.movtery.zalithlauncher.ui.base.BaseScreen import com.movtery.zalithlauncher.ui.components.AnimatedLazyColumn import com.movtery.zalithlauncher.ui.components.CheckChip import com.movtery.zalithlauncher.ui.components.LittleTextLabel +import com.movtery.zalithlauncher.ui.components.SimpleAlertDialog +import com.movtery.zalithlauncher.ui.components.SimpleEditDialog import com.movtery.zalithlauncher.ui.control.GamepadBindingKeyboard import com.movtery.zalithlauncher.ui.control.gamepad.GamepadMap import com.movtery.zalithlauncher.ui.control.gamepad.JoystickMode @@ -73,6 +75,9 @@ import com.movtery.zalithlauncher.ui.screens.content.settings.layouts.ListSettin import com.movtery.zalithlauncher.ui.screens.content.settings.layouts.SettingsCard import com.movtery.zalithlauncher.ui.screens.content.settings.layouts.SettingsCardColumn import com.movtery.zalithlauncher.ui.screens.content.settings.layouts.SwitchSettingsCard +import com.movtery.zalithlauncher.utils.logging.Logger.lWarning +import com.movtery.zalithlauncher.utils.string.isEmptyOrBlank +import com.movtery.zalithlauncher.viewmodel.GAMEPAD_CONFIG_NAME_LENGTH import com.movtery.zalithlauncher.viewmodel.GamepadViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -84,6 +89,14 @@ private sealed interface BindKeyOperation { data class OnBind(val map: GamepadMap) : BindKeyOperation } +private sealed interface CreateNewConfigOperation { + data object None : CreateNewConfigOperation + /** 创建新的映射配置 */ + data object Create : CreateNewConfigOperation + /** 删除当前映射配置 */ + data object Delete : CreateNewConfigOperation +} + @Composable fun GamepadSettingsScreen( key: NestedNavKey.Settings, @@ -92,7 +105,10 @@ fun GamepadSettingsScreen( ) { val viewModel: GamepadViewModel = viewModel() - var operation by remember { mutableStateOf(BindKeyOperation.None) } + var bindKeyOperation by remember { mutableStateOf(BindKeyOperation.None) } + var createConfigOperation by remember { + mutableStateOf(CreateNewConfigOperation.None) + } /** * 编辑手柄按键绑定:true为游戏内,false为菜单内 @@ -104,14 +120,53 @@ fun GamepadSettingsScreen( */ var refreshed by remember { mutableStateOf(false) } + val currentMapping = remember(refreshed) { + viewModel.currentMapping + } + /** + * 根据当前是否拥有配置,决定是否可以展示绑定页 + */ + val canShowBind = remember(currentMapping) { + currentMapping != null + } + BindKeyOperation( - operation = operation, - changeOperation = { operation = it }, + operation = bindKeyOperation, + changeOperation = { bindKeyOperation = it }, viewModel = viewModel, editKeyInGame = editKeyInGame, onRefresh = { refreshed = refreshed.not() } ) + CreateNewConfigOperation( + operation = createConfigOperation, + onChange = { createConfigOperation = it }, + checkContains = { name -> + viewModel.containsConfig(name) + }, + onCreateConfig = { name -> + viewModel.createNewConfig( + name = name, + onContainsConfig = { + lWarning("There is already a configuration with the same name") + }, + onFinished = { + refreshed = refreshed.not() + } + ) + }, + onDeleteCurrent = { + if (currentMapping != null) { + viewModel.deleteConfig( + name = currentMapping.name, + onFinished = { + refreshed = refreshed.not() + } + ) + } + } + ) + BaseScreen( Triple(key, mainScreenKey, false), Triple(NormalNavKey.Settings.Gamepad, settingsScreenKey, false) @@ -217,119 +272,176 @@ fun GamepadSettingsScreen( } animatedItem(scope) { yOffset -> - Row( + SettingsCardColumn( modifier = Modifier .fillMaxWidth() - .padding(horizontal = 8.dp) - .offset { IntOffset(x = 0, y = yOffset.roundToPx()) }, - horizontalArrangement = Arrangement.spacedBy(12.dp), + .offset { IntOffset(x = 0, y = yOffset.roundToPx()) } ) { - //游戏内 - CheckChip( - selected = editKeyInGame, - label = { - Text(text = stringResource(R.string.settings_gamepad_mapping_in_game)) - }, - onClick = { - editKeyInGame = true - } - ) + val list = remember(refreshed) { + viewModel.getAllConfigKeys() + } + val isCreateOnly = remember(list, currentMapping) { + list.isEmpty() && currentMapping == null + } - //菜单内 - CheckChip( - selected = editKeyInGame.not(), - label = { - Text(text = stringResource(R.string.settings_gamepad_mapping_in_menu)) - }, + if (list.isNotEmpty()) { + ListSettingsCard( + modifier = Modifier.fillMaxWidth(), + position = CardPosition.Top, + unit = AllSettings.gamepadMappingConfig, + items = list, + getItemText = { it }, + getItemId = { it }, + title = stringResource(R.string.settings_gamepad_config_title), + summary = stringResource(R.string.settings_gamepad_config_summary), + enabled = AllSettings.gamepadControl.state, + onValueChange = { + viewModel.reloadAllMappings() + refreshed = refreshed.not() + } + ) + } + + if (currentMapping != null) { + SettingsCard( + modifier = Modifier.fillMaxWidth(), + position = CardPosition.Middle, + title = stringResource(R.string.settings_gamepad_config_delete), + innerPadding = PaddingValues(horizontal = 16.dp, vertical = 24.dp), + onClick = { + createConfigOperation = CreateNewConfigOperation.Delete + } + ) + } + + SettingsCard( + modifier = Modifier.fillMaxWidth(), + position = if (isCreateOnly) CardPosition.Single else CardPosition.Bottom, + title = stringResource(R.string.settings_gamepad_config_create), + innerPadding = PaddingValues(horizontal = 16.dp, vertical = 24.dp), onClick = { - editKeyInGame = false + createConfigOperation = CreateNewConfigOperation.Create } ) } } - animatedItems( - lazyListScope = scope, - items = GamepadMap.entries, - key = { it.identifier } - ) { _, item, yOffset -> - SettingsCard( - modifier = Modifier - .fillMaxWidth() - .offset { IntOffset(x = 0, y = yOffset.roundToPx()) }, - position = CardPosition.Single, - onClick = { - operation = BindKeyOperation.OnBind(item) - } - ) { + if (canShowBind) { + animatedItem(scope) { yOffset -> Row( modifier = Modifier - .padding(all = 16.dp) - .fillMaxWidth(), - verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(16.dp) + .fillMaxWidth() + .padding(horizontal = 8.dp) + .offset { IntOffset(x = 0, y = yOffset.roundToPx()) }, + horizontalArrangement = Arrangement.spacedBy(12.dp), ) { - Image( - modifier = Modifier - .padding(all = 6.dp) - .size(32.dp), - painter = painterResource(item.getIconRes()), - contentDescription = null, - contentScale = ContentScale.Fit + //游戏内 + CheckChip( + selected = editKeyInGame, + label = { + Text(text = stringResource(R.string.settings_gamepad_mapping_in_game)) + }, + onClick = { + editKeyInGame = true + } ) - Row( - modifier = Modifier.weight(1f), - horizontalArrangement = Arrangement.spacedBy(8.dp), - verticalAlignment = Alignment.CenterVertically - ) { - val codes = remember(item, editKeyInGame, refreshed) { - viewModel.findByMap(item, inGame = editKeyInGame)?.toList() ?: emptyList() + //菜单内 + CheckChip( + selected = editKeyInGame.not(), + label = { + Text(text = stringResource(R.string.settings_gamepad_mapping_in_menu)) + }, + onClick = { + editKeyInGame = false } + ) + } + } - Text( - text = if (codes.isNotEmpty()) { - stringResource(R.string.settings_gamepad_mapping_bound) - } else { - stringResource(R.string.settings_gamepad_mapping_unbound) - }, - style = MaterialTheme.typography.titleSmall + animatedItems( + lazyListScope = scope, + items = GamepadMap.entries, + key = { it.identifier } + ) { _, item, yOffset -> + SettingsCard( + modifier = Modifier + .fillMaxWidth() + .offset { IntOffset(x = 0, y = yOffset.roundToPx()) }, + position = CardPosition.Single, + onClick = { + bindKeyOperation = BindKeyOperation.OnBind(item) + } + ) { + Row( + modifier = Modifier + .padding(all = 16.dp) + .fillMaxWidth(), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.spacedBy(16.dp) + ) { + Image( + modifier = Modifier + .padding(all = 6.dp) + .size(32.dp), + painter = painterResource(item.getIconRes()), + contentDescription = null, + contentScale = ContentScale.Fit ) Row( - modifier = Modifier - .weight(1f) - .basicMarquee(Int.MAX_VALUE), - horizontalArrangement = Arrangement.spacedBy(8.dp) + modifier = Modifier.weight(1f), + horizontalArrangement = Arrangement.spacedBy(8.dp), + verticalAlignment = Alignment.CenterVertically ) { - codes.forEach { code -> - LittleTextLabel( - text = getNameByGamepadEvent(code) - ) + val codes = remember(item, editKeyInGame, refreshed) { + viewModel.currentMapping?.findByMap(item, inGame = editKeyInGame)?.toList() ?: emptyList() } - } - } - Row( - verticalAlignment = Alignment.CenterVertically - ) { - IconButton( - onClick = { - viewModel.resetMapping(item, editKeyInGame) - refreshed = refreshed.not() + Text( + text = if (codes.isNotEmpty()) { + stringResource(R.string.settings_gamepad_mapping_bound) + } else { + stringResource(R.string.settings_gamepad_mapping_unbound) + }, + style = MaterialTheme.typography.titleSmall + ) + + Row( + modifier = Modifier + .weight(1f) + .basicMarquee(Int.MAX_VALUE), + horizontalArrangement = Arrangement.spacedBy(8.dp) + ) { + codes.forEach { code -> + LittleTextLabel( + text = getNameByGamepadEvent(code) + ) + } } + } + + Row( + verticalAlignment = Alignment.CenterVertically ) { + IconButton( + onClick = { + viewModel.currentMapping?.resetMapping(item, editKeyInGame) + refreshed = refreshed.not() + } + ) { + Icon( + imageVector = Icons.Default.RestartAlt, + contentDescription = stringResource(R.string.generic_reset) + ) + } + Icon( - imageVector = Icons.Default.RestartAlt, - contentDescription = stringResource(R.string.generic_reset) + modifier = Modifier.size(28.dp), + imageVector = Icons.AutoMirrored.Rounded.ArrowRight, + contentDescription = null ) } - - Icon( - modifier = Modifier.size(28.dp), - imageVector = Icons.AutoMirrored.Rounded.ArrowRight, - contentDescription = null - ) } } } @@ -352,7 +464,7 @@ private fun BindKeyOperation( val gamepad = operation.map val selectedKeys = remember(gamepad, editKeyInGame) { - val mapList = viewModel.findByMap(gamepad, inGame = editKeyInGame)?.toList() ?: emptyList() + val mapList = viewModel.currentMapping?.findByMap(gamepad, inGame = editKeyInGame)?.toList() ?: emptyList() mapList.toMutableList() } @@ -360,12 +472,12 @@ private fun BindKeyOperation( selectedKeys = selectedKeys, onKeyAdd = { key -> selectedKeys.add(key) - viewModel.saveMapping(gamepad, selectedKeys.toSet(), editKeyInGame) + viewModel.currentMapping?.saveMapping(gamepad, selectedKeys.toSet(), editKeyInGame) onRefresh() }, onKeyRemove = { key -> selectedKeys.remove(key) - viewModel.saveMapping(gamepad, selectedKeys.toSet(), editKeyInGame) + viewModel.currentMapping?.saveMapping(gamepad, selectedKeys.toSet(), editKeyInGame) onRefresh() }, onDismissRequest = { @@ -374,4 +486,71 @@ private fun BindKeyOperation( ) } } +} + +@Composable +private fun CreateNewConfigOperation( + operation: CreateNewConfigOperation, + onChange: (CreateNewConfigOperation) -> Unit, + checkContains: (name: String) -> Boolean, + onCreateConfig: (name: String) -> Unit, + onDeleteCurrent: () -> Unit +) { + when (operation) { + is CreateNewConfigOperation.None -> {} + is CreateNewConfigOperation.Create -> { + var name by remember { mutableStateOf("") } + val isContains = remember(name) { + if (name.isEmptyOrBlank()) { + checkContains(name) + } else { + false + } + } + val isNameEmpty = remember(name) { + name.isEmptyOrBlank() + } + + SimpleEditDialog( + title = stringResource(R.string.settings_gamepad_config_create), + value = name, + onValueChange = { name = it.take(GAMEPAD_CONFIG_NAME_LENGTH) }, + label = { + val text = stringResource(R.string.settings_gamepad_config_create_name) + Text( + text = "$text (${name.length}/$GAMEPAD_CONFIG_NAME_LENGTH)" + ) + }, + isError = isContains || isNameEmpty, + supportingText = { + if (isContains) { + Text(stringResource(R.string.settings_gamepad_config_create_contains)) + } else if (isNameEmpty) { + Text(stringResource(R.string.generic_cannot_empty)) + } + }, + singleLine = true, + onConfirm = { + onCreateConfig(name) + onChange(CreateNewConfigOperation.None) + }, + onDismissRequest = { + onChange(CreateNewConfigOperation.None) + } + ) + } + is CreateNewConfigOperation.Delete -> { + SimpleAlertDialog( + title = stringResource(R.string.settings_gamepad_config_delete), + text = stringResource(R.string.settings_gamepad_config_delete_message), + onDismiss = { + onChange(CreateNewConfigOperation.None) + }, + onConfirm = { + onDeleteCurrent() + onChange(CreateNewConfigOperation.None) + } + ) + } + } } \ No newline at end of file diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/layouts/List.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/layouts/List.kt index c944efa0e..411de253a 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/layouts/List.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/layouts/List.kt @@ -83,7 +83,7 @@ fun ListSettingsCard( ) { require(items.isNotEmpty()) { "Items list cannot be empty" } - var selectedItem by remember { + var selectedItem by remember(currentId) { mutableStateOf( items.firstOrNull { getItemId(it) == currentId } ?: items.firstOrNull { getItemId(it) == defaultId } diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/GameScreen.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/GameScreen.kt index ee7eb648b..2b7bc0230 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/GameScreen.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/GameScreen.kt @@ -707,6 +707,7 @@ fun GameScreen( state = viewModel.gameMenuState, controlMenuTabIndex = viewModel.controlMenuTabIndex, onControlMenuTabChange = { viewModel.controlMenuTabIndex = it }, + gamepadViewModel = gamepadViewModel, closeScreen = { viewModel.gameMenuState = MenuState.HIDE }, onForceClose = { viewModel.forceCloseState = ForceCloseOperation.Show }, onSwitchLog = { onLogStateChange(logState.next()) }, diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/elements/GameMenuSubscreen.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/elements/GameMenuSubscreen.kt index 17db43536..b356ac125 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/elements/GameMenuSubscreen.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/game/elements/GameMenuSubscreen.kt @@ -64,6 +64,7 @@ import com.movtery.zalithlauncher.ui.components.MenuSwitchButton import com.movtery.zalithlauncher.ui.components.MenuTextButton import com.movtery.zalithlauncher.ui.control.HotbarRule import com.movtery.zalithlauncher.ui.control.gyroscope.isGyroscopeAvailable +import com.movtery.zalithlauncher.viewmodel.GamepadViewModel private sealed interface IconTab { data class ImageVectorTab(val icon: ImageVector, val iconSize: Dp = 18.dp): IconTab @@ -88,6 +89,7 @@ fun GameMenuSubscreen( state: MenuState, controlMenuTabIndex: Int, onControlMenuTabChange: (Int) -> Unit, + gamepadViewModel: GamepadViewModel, closeScreen: () -> Unit, onForceClose: () -> Unit, onSwitchLog: () -> Unit, @@ -168,7 +170,10 @@ fun GameMenuSubscreen( ) } 1 -> ControlMouse(modifier = Modifier.fillMaxSize()) - 2 -> ControlGamepad(modifier = Modifier.fillMaxSize()) + 2 -> ControlGamepad( + modifier = Modifier.fillMaxSize(), + gamepadViewModel = gamepadViewModel + ) 3 -> ControlGesture(modifier = Modifier.fillMaxSize()) 4 -> ControlGyroscope(modifier = Modifier.fillMaxSize()) } @@ -534,7 +539,8 @@ private fun ControlMouse( @Composable private fun ControlGamepad( - modifier: Modifier = Modifier + gamepadViewModel: GamepadViewModel, + modifier: Modifier = Modifier, ) { LazyColumn( modifier = modifier, @@ -592,6 +598,35 @@ private fun ControlGamepad( suffix = "%" ) } + + //手柄映射配置切换 + item { + val list = remember(gamepadViewModel) { + gamepadViewModel.getAllConfigKeys() + } + + if (list.isNotEmpty()) { + MenuListLayout( + modifier = Modifier.fillMaxWidth(), + title = stringResource(R.string.settings_gamepad_config_title), + items = list, + currentItem = AllSettings.gamepadMappingConfig.state, + onItemChange = { name -> + AllSettings.gamepadMappingConfig.save(name) + gamepadViewModel.reloadAllMappings() + }, + getItemText = { it }, + enabled = AllSettings.gamepadControl.state, + ) + } else { + MenuTextButton( + modifier = Modifier.fillMaxWidth(), + text = stringResource(R.string.settings_gamepad_config_no_items), + onClick = {}, + enabled = false + ) + } + } } } diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadRemapperViewModel.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadRemapperViewModel.kt index 8c9cee271..83da497bf 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadRemapperViewModel.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadRemapperViewModel.kt @@ -34,7 +34,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock -class GamepadRemapperViewModel(): ViewModel() { +class GamepadRemapperViewModel: ViewModel() { private val _events = MutableSharedFlow(extraBufferCapacity = 1) val events = _events.asSharedFlow() diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt index 8c205b277..2c0d80a4e 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt @@ -25,12 +25,15 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.geometry.Offset import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import com.movtery.zalithlauncher.setting.AllSettings import com.movtery.zalithlauncher.ui.control.gamepad.DpadDirection import com.movtery.zalithlauncher.ui.control.gamepad.GamepadMap import com.movtery.zalithlauncher.ui.control.gamepad.GamepadMapping +import com.movtery.zalithlauncher.ui.control.gamepad.GamepadMappingList import com.movtery.zalithlauncher.ui.control.gamepad.GamepadRemap import com.movtery.zalithlauncher.ui.control.gamepad.Joystick import com.movtery.zalithlauncher.ui.control.gamepad.JoystickType +import com.movtery.zalithlauncher.ui.control.gamepad.keyMappingListMMKV import com.movtery.zalithlauncher.ui.control.gamepad.keyMappingMMKV import com.movtery.zalithlauncher.ui.control.joystick.JoystickDirection import kotlinx.coroutines.flow.MutableSharedFlow @@ -38,6 +41,7 @@ import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.launch private const val BUTTON_PRESS_THRESHOLD = 0.85f +const val GAMEPAD_CONFIG_NAME_LENGTH = 16 class GamepadViewModel : ViewModel() { private val _keyEvents = MutableSharedFlow() @@ -54,11 +58,12 @@ class GamepadViewModel : ViewModel() { private val listeners = mutableListOf<(Event) -> Unit>() - /** - * 手柄与键盘按键映射绑定 - */ - private val allKeyMappings = mutableMapOf() - private val allDpadMappings = mutableMapOf() + private val listMMKV = keyMappingListMMKV() + private val oldMMKV = keyMappingMMKV() + + private val mappingLists = mutableListOf() + var currentMapping: GamepadMappingList? = null + private set /** 左摇杆状态 */ private val leftJoystick = Joystick(JoystickType.Left) @@ -114,98 +119,121 @@ class GamepadViewModel : ViewModel() { } fun reloadAllMappings() { - allKeyMappings.clear() - allDpadMappings.clear() + mappingLists.clear() + + var movedOldData = false + val movedName = "default" + + if (oldMMKV.count() > 0) { + val defaultMappings = mutableListOf() + GamepadMap.entries.forEach { entry -> + val mapping = oldMMKV.decodeParcelable(entry.identifier, GamepadMapping::class.java) + ?: GamepadMapping( + key = entry.gamepad, + dpadDirection = entry.dpadDirection, + targetsInGame = entry.defaultKeysInGame, + targetsInMenu = entry.defaultKeysInMenu + ) + defaultMappings.add(mapping) + } + val list = GamepadMappingList( + name = movedName, + list = defaultMappings + ) + oldMMKV.clear() + listMMKV.encode(movedName, list) + + mappingLists.add(list) + movedOldData = true + AllSettings.gamepadMappingConfig.save(movedName) + } - val mmkv = keyMappingMMKV() - GamepadMap.entries.forEach { entry -> - val mapping = mmkv.decodeParcelable(entry.identifier, GamepadMapping::class.java) - ?: GamepadMapping( - key = entry.gamepad, - dpadDirection = entry.dpadDirection, - targetsInGame = entry.defaultKeysInGame, - targetsInMenu = entry.defaultKeysInMenu - ) - addInMappingsMap(mapping) + listMMKV.allKeys()?.forEach { key -> + if (movedOldData && movedName == key) return@forEach + listMMKV.decodeParcelable(key, GamepadMappingList::class.java)?.let { + mappingLists.add(it) + } + } + + refreshLists() + } + + private fun refreshLists() { + mappingLists.forEach { list -> + list.load() } + currentMapping = loadCurrentConfig() } - private fun addInMappingsMap(mapping: GamepadMapping) { - val target = TargetKeys(mapping.targetsInGame, mapping.targetsInMenu) - mapping.dpadDirection?.let { allDpadMappings[it] = target } ?: run { - allKeyMappings[mapping.key] = target + private fun loadCurrentConfig(): GamepadMappingList? { + val config = AllSettings.gamepadMappingConfig.getValue() + return mappingLists.find { + it.name == config + } ?: mappingLists.firstOrNull()?.also { config -> + AllSettings.gamepadMappingConfig.save(config.name) } } /** - * 重置手柄与键盘按键映射绑定 + * 获取所有的手柄映射配置名称 */ - fun resetMapping(gamepadMap: GamepadMap, inGame: Boolean) = - applyMapping(gamepadMap, inGame, useDefault = true) + fun getAllConfigKeys(): List { + return mappingLists.map { it.name } + } /** - * 为指定手柄映射设置目标键盘映射 + * 该名称是否已被保存的配置使用 */ - fun saveMapping(gamepadMap: GamepadMap, targets: Set, inGame: Boolean) = - applyMapping(gamepadMap, inGame, customTargets = targets) + fun containsConfig(name: String): Boolean = listMMKV.containsKey(name) /** - * 保存或重置手柄与键盘按键映射绑定 - * @param gamepadMap 手柄映射对象 - * @param inGame 是否为游戏内映射(true 为游戏内,false 为菜单内) - * @param customTargets 自定义目标键 - * @param useDefault 是否使用默认按键 + * 创建新的手柄映射配置 */ - private fun applyMapping( - gamepadMap: GamepadMap, - inGame: Boolean, - customTargets: Set? = null, - useDefault: Boolean = false + fun createNewConfig( + name: String, + onContainsConfig: () -> Unit, + onFinished: () -> Unit = {} ) { - val dpad = gamepadMap.dpadDirection - val existing = if (dpad != null) allDpadMappings[dpad] else allKeyMappings[gamepadMap.gamepad] - - val (targetsInGame, targetsInMenu) = if (inGame) { - val newTargets = customTargets ?: if (useDefault) gamepadMap.defaultKeysInGame else emptySet() - newTargets to (existing?.inMenu ?: emptySet()) - } else { - (existing?.inGame ?: emptySet()) to (customTargets ?: if (useDefault) gamepadMap.defaultKeysInMenu else emptySet()) + val name0 = name.take(GAMEPAD_CONFIG_NAME_LENGTH) + if (containsConfig(name0)) onContainsConfig() + + val defaultMappings = mutableListOf() + GamepadMap.entries.forEach { entry -> + defaultMappings.add( + GamepadMapping( + key = entry.gamepad, + dpadDirection = entry.dpadDirection, + targetsInGame = entry.defaultKeysInGame, + targetsInMenu = entry.defaultKeysInMenu + ) + ) } + val list = GamepadMappingList( + name = name0, + list = defaultMappings + ) - GamepadMapping( - key = gamepadMap.gamepad, - dpadDirection = dpad, - targetsInGame = targetsInGame, - targetsInMenu = targetsInMenu - ).also { it.save(gamepadMap.identifier) } - } - private fun GamepadMapping.save(identifier: String) { - addInMappingsMap(this) - keyMappingMMKV().encode(identifier, this) - } + mappingLists.add(list) + listMMKV.encode(name0, list) + refreshLists() - /** - * 根据手柄按键键值获取对应的键盘映射代码 - * @return 若未找到,则返回null - */ - fun findByCode(key: Int, inGame: Boolean) = - allKeyMappings[key]?.getKeys(inGame) + onFinished() + } /** - * 根据手柄方向键获取对应的键盘映射代码 - * @return 若未找到,则返回null + * 删除一个手柄映射配置 */ - fun findByDpad(dir: DpadDirection, inGame: Boolean) = - allDpadMappings[dir]?.getKeys(inGame) + fun deleteConfig( + name: String, + onFinished: () -> Unit = {} + ) { + mappingLists.removeIf { it.name == name } + listMMKV.remove(name) + refreshLists() - /** - * 根据手柄映射获取对应的键盘映射代码 - * @return 若未找到,则返回null - */ - fun findByMap(map: GamepadMap, inGame: Boolean) = - (map.dpadDirection?.let { allDpadMappings[it] } ?: allKeyMappings[map.gamepad]) - ?.getKeys(inGame) + onFinished() + } fun updateButton(code: Int, pressed: Boolean) { onActive() @@ -284,16 +312,6 @@ class GamepadViewModel : ViewModel() { listeners.remove(listener) } - /** - * 便于记录目标键盘映射的数据类 - */ - private data class TargetKeys( - val inGame: Set, - val inMenu: Set - ) { - fun getKeys(isInGame: Boolean) = if (isInGame) inGame else inMenu - } - sealed interface Event { /** * 手柄按钮按下/松开事件 diff --git a/ZalithLauncher/src/main/res/values-zh-rCN/strings.xml b/ZalithLauncher/src/main/res/values-zh-rCN/strings.xml index 8939c863e..1c27ffa13 100644 --- a/ZalithLauncher/src/main/res/values-zh-rCN/strings.xml +++ b/ZalithLauncher/src/main/res/values-zh-rCN/strings.xml @@ -947,6 +947,14 @@ 已完成绑定 稍候,启动器正在保存并应用。 已成功保存手柄映射,您可以关闭此对话框了! + 手柄映射配置 + 选择要使用的手柄映射配置 + 删除当前配置 + 您确定要删除这个配置吗? + 创建手柄映射配置 + 配置名称 + 已有同名称的配置 + 未创建配置,无法切换 颜色主题 更改启动器的整体颜色主题 深色模式 diff --git a/ZalithLauncher/src/main/res/values-zh-rTW/strings.xml b/ZalithLauncher/src/main/res/values-zh-rTW/strings.xml index 793d78c4e..218ea2a24 100644 --- a/ZalithLauncher/src/main/res/values-zh-rTW/strings.xml +++ b/ZalithLauncher/src/main/res/values-zh-rTW/strings.xml @@ -870,6 +870,14 @@ 綁定完成 請稍候,啟動器正在儲存並套用設定。 已成功儲存手把映射,您可以關閉此對話框了! + 手把映射設定 + 選擇要使用的手把映射設定 + 刪除目前設定 + 您確定要刪除此設定嗎? + 建立手把映射設定 + 設定名稱 + 已存在相同名稱的設定 + 尚未建立任何設定,無法切換 顏色主題 變更啟動器的整體顏色主題 深色模式 diff --git a/ZalithLauncher/src/main/res/values/strings.xml b/ZalithLauncher/src/main/res/values/strings.xml index f8091a4db..3d9003c16 100644 --- a/ZalithLauncher/src/main/res/values/strings.xml +++ b/ZalithLauncher/src/main/res/values/strings.xml @@ -949,6 +949,14 @@ Binding Completed Please wait, the launcher is saving and applying the settings. Gamepad mapping saved successfully. You can now close this dialog! + Gamepad Mapping Configuration + Select the gamepad mapping configuration to use + Delete Current Configuration + Are you sure you want to delete this configuration? + Create Gamepad Mapping Configuration + Configuration Name + A configuration with the same name already exists + No configurations created, unable to switch Color Theme Customize launcher colors Dark Mode From 5ca447146ffbab77b567f8f25574ba48422eab5d Mon Sep 17 00:00:00 2001 From: movte Date: Sun, 22 Feb 2026 21:58:43 +0800 Subject: [PATCH 2/4] =?UTF-8?q?chore(=E6=89=8B=E6=9F=84=E6=98=A0=E5=B0=84)?= =?UTF-8?q?:=20=E7=BA=BF=E7=A8=8B=E5=AE=89=E5=85=A8=20&=20=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E6=93=8D=E4=BD=9C=E4=BD=93=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../movtery/zalithlauncher/viewmodel/GamepadViewModel.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt index 2c0d80a4e..4d1941843 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt @@ -36,6 +36,7 @@ import com.movtery.zalithlauncher.ui.control.gamepad.JoystickType import com.movtery.zalithlauncher.ui.control.gamepad.keyMappingListMMKV import com.movtery.zalithlauncher.ui.control.gamepad.keyMappingMMKV import com.movtery.zalithlauncher.ui.control.joystick.JoystickDirection +import io.ktor.util.collections.ConcurrentSet import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.launch @@ -61,7 +62,7 @@ class GamepadViewModel : ViewModel() { private val listMMKV = keyMappingListMMKV() private val oldMMKV = keyMappingMMKV() - private val mappingLists = mutableListOf() + private val mappingLists = ConcurrentSet() var currentMapping: GamepadMappingList? = null private set @@ -140,7 +141,7 @@ class GamepadViewModel : ViewModel() { name = movedName, list = defaultMappings ) - oldMMKV.clear() + oldMMKV.clearAll() listMMKV.encode(movedName, list) mappingLists.add(list) @@ -213,9 +214,10 @@ class GamepadViewModel : ViewModel() { list = defaultMappings ) - mappingLists.add(list) listMMKV.encode(name0, list) + + AllSettings.gamepadMappingConfig.save(name0) refreshLists() onFinished() From f9bc858e77e2def6622a96a871b635955e51eb1d Mon Sep 17 00:00:00 2001 From: movte Date: Sun, 22 Feb 2026 22:00:44 +0800 Subject: [PATCH 3/4] =?UTF-8?q?fix(=E6=89=8B=E6=9F=84=E6=98=A0=E5=B0=84):?= =?UTF-8?q?=20=E6=97=A0=E6=B3=95=E6=AD=A3=E5=B8=B8=E6=A3=80=E6=9F=A5?= =?UTF-8?q?=E6=98=AF=E5=90=A6=E5=8C=85=E5=90=AB=E5=90=8C=E6=A0=B7=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/screens/content/settings/GamepadSettingsScreen.kt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt index 129672652..42d3f325e 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/ui/screens/content/settings/GamepadSettingsScreen.kt @@ -501,7 +501,7 @@ private fun CreateNewConfigOperation( is CreateNewConfigOperation.Create -> { var name by remember { mutableStateOf("") } val isContains = remember(name) { - if (name.isEmptyOrBlank()) { + if (!name.isEmptyOrBlank()) { checkContains(name) } else { false @@ -531,8 +531,10 @@ private fun CreateNewConfigOperation( }, singleLine = true, onConfirm = { - onCreateConfig(name) - onChange(CreateNewConfigOperation.None) + if (!isContains && !isNameEmpty) { + onCreateConfig(name) + onChange(CreateNewConfigOperation.None) + } }, onDismissRequest = { onChange(CreateNewConfigOperation.None) From 01f17d653ef3820b6d21d32f2ad2a809b142575e Mon Sep 17 00:00:00 2001 From: movte Date: Sun, 22 Feb 2026 22:14:56 +0800 Subject: [PATCH 4/4] =?UTF-8?q?chore(=E6=89=8B=E6=9F=84=E6=98=A0=E5=B0=84)?= =?UTF-8?q?:=20=E9=BB=98=E8=AE=A4=E5=88=9B=E5=BB=BA=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E6=98=A0=E5=B0=84=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../viewmodel/GamepadViewModel.kt | 51 ++++++++++++------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt index 4d1941843..f4144a18b 100644 --- a/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt +++ b/ZalithLauncher/src/main/java/com/movtery/zalithlauncher/viewmodel/GamepadViewModel.kt @@ -123,7 +123,7 @@ class GamepadViewModel : ViewModel() { mappingLists.clear() var movedOldData = false - val movedName = "default" + val defaultName = "default" if (oldMMKV.count() > 0) { val defaultMappings = mutableListOf() @@ -138,21 +138,29 @@ class GamepadViewModel : ViewModel() { defaultMappings.add(mapping) } val list = GamepadMappingList( - name = movedName, + name = defaultName, list = defaultMappings ) oldMMKV.clearAll() - listMMKV.encode(movedName, list) + listMMKV.encode(defaultName, list) mappingLists.add(list) movedOldData = true - AllSettings.gamepadMappingConfig.save(movedName) + AllSettings.gamepadMappingConfig.save(defaultName) } - listMMKV.allKeys()?.forEach { key -> - if (movedOldData && movedName == key) return@forEach - listMMKV.decodeParcelable(key, GamepadMappingList::class.java)?.let { - mappingLists.add(it) + if (!movedOldData && listMMKV.count() == 0L) { + //当前没有任何的配置 + val list = createDefaultMapping(defaultName) + AllSettings.gamepadMappingConfig.save(defaultName) + listMMKV.encode(defaultName, list) + mappingLists.add(list) + } else { + listMMKV.allKeys()?.forEach { key -> + if (movedOldData && defaultName == key) return@forEach + listMMKV.decodeParcelable(key, GamepadMappingList::class.java)?.let { + mappingLists.add(it) + } } } @@ -198,6 +206,21 @@ class GamepadViewModel : ViewModel() { val name0 = name.take(GAMEPAD_CONFIG_NAME_LENGTH) if (containsConfig(name0)) onContainsConfig() + val list = createDefaultMapping(name0) + + mappingLists.add(list) + listMMKV.encode(name0, list) + + AllSettings.gamepadMappingConfig.save(name0) + refreshLists() + + onFinished() + } + + /** + * 创建一个默认的映射配置 + */ + private fun createDefaultMapping(name: String): GamepadMappingList { val defaultMappings = mutableListOf() GamepadMap.entries.forEach { entry -> defaultMappings.add( @@ -209,18 +232,10 @@ class GamepadViewModel : ViewModel() { ) ) } - val list = GamepadMappingList( - name = name0, + return GamepadMappingList( + name = name, list = defaultMappings ) - - mappingLists.add(list) - listMMKV.encode(name0, list) - - AllSettings.gamepadMappingConfig.save(name0) - refreshLists() - - onFinished() } /**