From aab6e2643e8d587387767a41bd495418184bbd5f Mon Sep 17 00:00:00 2001 From: SomeTroglodyte <63000004+SomeTroglodyte@users.noreply.github.com> Date: Thu, 4 Apr 2024 22:40:15 +0200 Subject: [PATCH] Make ESC/Back bindable (Main menu and world screen only) (#11379) * Some Keyboard code linting * Make ESC/BACK bindable in two places --- .../components/extensions/Scene2dExtensions.kt | 4 ++-- .../ui/components/input/KeyCharAndCode.kt | 16 +++++++++++++--- .../ui/components/input/KeyboardBinding.kt | 2 ++ .../components/widgets/KeyCapturingButton.kt | 10 +++++++--- .../ui/screens/devconsole/DevConsolePopup.kt | 2 +- .../screens/mainmenuscreen/MainMenuScreen.kt | 5 +---- .../ui/screens/worldscreen/WorldScreen.kt | 18 ++++++++---------- 7 files changed, 34 insertions(+), 23 deletions(-) diff --git a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt index d11fef0f23..65ccfae7d0 100644 --- a/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt +++ b/core/src/com/unciv/ui/components/extensions/Scene2dExtensions.kt @@ -384,8 +384,8 @@ object GdxKeyCodeFixes { fun toString(keyCode: Int): String = when(keyCode) { UNKNOWN -> "" - DEL -> "Del" - BACKSPACE -> "Backspace" + DEL -> "Del" // Gdx would name this "Forward Delete" + BACKSPACE -> "Backspace" // Gdx would name this "Delete" else -> Input.Keys.toString(keyCode) ?: "" } diff --git a/core/src/com/unciv/ui/components/input/KeyCharAndCode.kt b/core/src/com/unciv/ui/components/input/KeyCharAndCode.kt index 40ea67e6dd..70dcc41ab5 100644 --- a/core/src/com/unciv/ui/components/input/KeyCharAndCode.kt +++ b/core/src/com/unciv/ui/components/input/KeyCharAndCode.kt @@ -1,6 +1,7 @@ package com.unciv.ui.components.input import com.badlogic.gdx.Input +import com.badlogic.gdx.scenes.scene2d.InputListener import com.badlogic.gdx.utils.Json import com.badlogic.gdx.utils.JsonValue import com.unciv.ui.components.extensions.GdxKeyCodeFixes @@ -19,9 +20,11 @@ import com.unciv.ui.components.extensions.GdxKeyCodeFixes */ /** - * Represents a key for use in an InputListener keyTyped() handler + * Represents a key for use in an [InputListener.keyDown] handler * * Example: KeyCharAndCode('R'), KeyCharAndCode(Input.Keys.F1) + * @see KeyboardBinding + * @see KeyShortcutListener */ data class KeyCharAndCode(val char: Char, val code: Int) { /** helper 'cloning constructor' to allow feeding both fields from a factory function */ @@ -44,9 +47,9 @@ data class KeyCharAndCode(val char: Char, val code: Int) { companion object { // Convenience shortcuts for frequently used constants - /** Android back, assigns ESC automatically as well */ + /** Android back, assigns [ESC] automatically as well */ val BACK = KeyCharAndCode(Input.Keys.BACK) - /** Automatically assigned for [BACK] */ + /** Automatically assigned for [BACK] - please use that instead */ val ESC = KeyCharAndCode(Input.Keys.ESCAPE) /** Assigns [NUMPAD_ENTER] automatically as well */ val RETURN = KeyCharAndCode(Input.Keys.ENTER) @@ -80,6 +83,13 @@ data class KeyCharAndCode(val char: Char, val code: Int) { return if (code == -1) KeyCharAndCode(char,0) else KeyCharAndCode(Char.MIN_VALUE, code) } + /** Parse a human-readable representation into a KeyCharAndCode, inverse of [KeyCharAndCode.toString], case-sensitive. + * + * Understands + * - Single characters or quoted single characters (double-quotes) + * - Names as produced by the non-conforming String.toString(Int) function in [com.badlogic.gdx.Input.Keys], with fixes for DEL and BACKSPACE. + * Not parseable input, including the empty string, results in [KeyCharAndCode.UNKNOWN]. + */ fun parse(text: String): KeyCharAndCode = when { text.length == 1 && text[0].isDefined() -> KeyCharAndCode(text[0]) text.length == 3 && text[0] == '"' && text[2] == '"' -> KeyCharAndCode(text[1]) diff --git a/core/src/com/unciv/ui/components/input/KeyboardBinding.kt b/core/src/com/unciv/ui/components/input/KeyboardBinding.kt index 7e39f4a7fc..e5f4bba1d7 100644 --- a/core/src/com/unciv/ui/components/input/KeyboardBinding.kt +++ b/core/src/com/unciv/ui/components/input/KeyboardBinding.kt @@ -25,6 +25,7 @@ enum class KeyboardBinding( None(Category.None, KeyCharAndCode.UNKNOWN), // MainMenu + QuitMainMenu(Category.MainMenu, "Quit", KeyCharAndCode.BACK), Resume(Category.MainMenu), Quickstart(Category.MainMenu), StartNewGame(Category.MainMenu, "Start new game", KeyCharAndCode('N')), // Not to be confused with NewGame (from World menu, Ctrl-N) @@ -36,6 +37,7 @@ enum class KeyboardBinding( MainMenuOptions(Category.MainMenu, "Options", KeyCharAndCode('O')), // Separate binding from World where it's Ctrl-O default // Worldscreen + DeselectOrQuit(Category.WorldScreen, "Deselect then Quit", KeyCharAndCode.BACK), Menu(Category.WorldScreen, KeyCharAndCode.TAB), NextTurn(Category.WorldScreen), NextTurnAlternate(Category.WorldScreen, KeyCharAndCode.SPACE), diff --git a/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt b/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt index 0f87f320e5..9285bb1476 100644 --- a/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt +++ b/core/src/com/unciv/ui/components/widgets/KeyCapturingButton.kt @@ -95,7 +95,7 @@ class KeyCapturingButton( } private fun updateLabel() { - label.setText(if (current == KeyCharAndCode.UNKNOWN) "" else current.toString()) + label.setText(if (current == KeyCharAndCode.BACK) "ESC/Back" else current.toString()) updateStyle() } private fun updateStyle() { @@ -130,12 +130,16 @@ class KeyCapturingButton( } override fun keyDown(event: InputEvent?, keycode: Int): Boolean { - if (keycode == Input.Keys.ESCAPE || keycode == Input.Keys.UNKNOWN) return false + if (keycode == Input.Keys.UNKNOWN) return false if (keycode == Input.Keys.CONTROL_LEFT || keycode == Input.Keys.CONTROL_RIGHT) return false - myButton.handleKey(keycode, Gdx.input.isControlKeyPressed()) + + myButton.handleKey(mapEscToBack(keycode), Gdx.input.isControlKeyPressed()) + event?.cancel() return true } + private fun mapEscToBack(keycode: Int): Int = if (keycode == Input.Keys.ESCAPE) Input.Keys.BACK else keycode + override fun clicked(event: InputEvent?, x: Float, y: Float) { if (tapCount < 2 || event?.target !is Image) return myButton.resetKey() diff --git a/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt b/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt index 5b55fde82c..e317c98b01 100644 --- a/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt +++ b/core/src/com/unciv/ui/screens/devconsole/DevConsolePopup.kt @@ -36,7 +36,7 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) { open(true) - keyShortcuts.add(KeyCharAndCode.ESC) { close() } + keyShortcuts.add(KeyCharAndCode.BACK) { close() } keyShortcuts.add(KeyCharAndCode.TAB) { val textToAdd = getAutocomplete() diff --git a/core/src/com/unciv/ui/screens/mainmenuscreen/MainMenuScreen.kt b/core/src/com/unciv/ui/screens/mainmenuscreen/MainMenuScreen.kt index 8bd4ecc868..376a23d3d4 100644 --- a/core/src/com/unciv/ui/screens/mainmenuscreen/MainMenuScreen.kt +++ b/core/src/com/unciv/ui/screens/mainmenuscreen/MainMenuScreen.kt @@ -27,7 +27,6 @@ import com.unciv.ui.components.UncivTooltip.Companion.addTooltip import com.unciv.ui.components.extensions.center import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.toLabel -import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyShortcutDispatcherVeto import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.keyShortcuts @@ -189,7 +188,7 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize { stage.addActor(scrollPane) table.center(scrollPane) - globalShortcuts.add(KeyCharAndCode.BACK) { + globalShortcuts.add(KeyboardBinding.QuitMainMenu) { if (hasOpenPopups()) { closeAllPopups() return@add @@ -358,5 +357,3 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize { // We contain a map... override fun getShortcutDispatcherVetoer() = KeyShortcutDispatcherVeto.createTileGroupMapDispatcherVetoer() } - - diff --git a/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt b/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt index 830aa538be..33c86700f7 100644 --- a/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt +++ b/core/src/com/unciv/ui/screens/worldscreen/WorldScreen.kt @@ -26,7 +26,6 @@ import com.unciv.models.ruleset.unique.UniqueType import com.unciv.ui.components.extensions.centerX import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.toLabel -import com.unciv.ui.components.input.KeyCharAndCode import com.unciv.ui.components.input.KeyShortcutDispatcherVeto import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.KeyboardPanningListener @@ -182,15 +181,6 @@ class WorldScreen( tutorialController.allTutorialsShowedCallback = { shouldUpdate = true } - globalShortcuts.add(KeyCharAndCode.BACK) { backButtonAndESCHandler() } - - - globalShortcuts.add(KeyboardBinding.DeveloperConsole) { - // No cheating unless you're by yourself - if (gameInfo.civilizations.count { it.isHuman() } > 1) return@add - val consolePopup = DevConsolePopup(this) - } - addKeyboardListener() // for map panning by W,S,A,D addKeyboardPresses() // shortcut keys like F1 @@ -242,6 +232,8 @@ class WorldScreen( } private fun addKeyboardPresses() { + globalShortcuts.add(KeyboardBinding.DeselectOrQuit) { backButtonAndESCHandler() } + // Space and N are assigned in NextTurnButton constructor // Functions that have a big button are assigned there (WorldScreenTopBar, TechPolicyDiplomacyButtons..) globalShortcuts.add(KeyboardBinding.Civilopedia) { game.pushScreen(CivilopediaScreen(gameInfo.ruleset)) } @@ -276,6 +268,12 @@ class WorldScreen( globalShortcuts.add(KeyboardBinding.ToggleYieldDisplay) { minimapWrapper.yieldImageButton.toggle() } globalShortcuts.add(KeyboardBinding.ToggleWorkedTilesDisplay) { minimapWrapper.populationImageButton.toggle() } globalShortcuts.add(KeyboardBinding.ToggleMovementDisplay) { minimapWrapper.movementsImageButton.toggle() } + + globalShortcuts.add(KeyboardBinding.DeveloperConsole) { + // No cheating unless you're by yourself + if (gameInfo.civilizations.count { it.isHuman() } > 1) return@add + val consolePopup = DevConsolePopup(this) + } } // Handle disabling and re-enabling WASD listener while Options are open