Make ESC/Back bindable (Main menu and world screen only) (#11379)

* Some Keyboard code linting

* Make ESC/BACK bindable in two places
This commit is contained in:
SomeTroglodyte
2024-04-04 22:40:15 +02:00
committed by GitHub
parent 48212e8c15
commit aab6e2643e
7 changed files with 34 additions and 23 deletions

View File

@ -384,8 +384,8 @@ object GdxKeyCodeFixes {
fun toString(keyCode: Int): String = when(keyCode) { fun toString(keyCode: Int): String = when(keyCode) {
UNKNOWN -> "" UNKNOWN -> ""
DEL -> "Del" DEL -> "Del" // Gdx would name this "Forward Delete"
BACKSPACE -> "Backspace" BACKSPACE -> "Backspace" // Gdx would name this "Delete"
else -> Input.Keys.toString(keyCode) else -> Input.Keys.toString(keyCode)
?: "" ?: ""
} }

View File

@ -1,6 +1,7 @@
package com.unciv.ui.components.input package com.unciv.ui.components.input
import com.badlogic.gdx.Input import com.badlogic.gdx.Input
import com.badlogic.gdx.scenes.scene2d.InputListener
import com.badlogic.gdx.utils.Json import com.badlogic.gdx.utils.Json
import com.badlogic.gdx.utils.JsonValue import com.badlogic.gdx.utils.JsonValue
import com.unciv.ui.components.extensions.GdxKeyCodeFixes 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) * Example: KeyCharAndCode('R'), KeyCharAndCode(Input.Keys.F1)
* @see KeyboardBinding
* @see KeyShortcutListener
*/ */
data class KeyCharAndCode(val char: Char, val code: Int) { data class KeyCharAndCode(val char: Char, val code: Int) {
/** helper 'cloning constructor' to allow feeding both fields from a factory function */ /** 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 { companion object {
// Convenience shortcuts for frequently used constants // 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) val BACK = KeyCharAndCode(Input.Keys.BACK)
/** Automatically assigned for [BACK] */ /** Automatically assigned for [BACK] - please use that instead */
val ESC = KeyCharAndCode(Input.Keys.ESCAPE) val ESC = KeyCharAndCode(Input.Keys.ESCAPE)
/** Assigns [NUMPAD_ENTER] automatically as well */ /** Assigns [NUMPAD_ENTER] automatically as well */
val RETURN = KeyCharAndCode(Input.Keys.ENTER) 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) 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 { fun parse(text: String): KeyCharAndCode = when {
text.length == 1 && text[0].isDefined() -> KeyCharAndCode(text[0]) text.length == 1 && text[0].isDefined() -> KeyCharAndCode(text[0])
text.length == 3 && text[0] == '"' && text[2] == '"' -> KeyCharAndCode(text[1]) text.length == 3 && text[0] == '"' && text[2] == '"' -> KeyCharAndCode(text[1])

View File

@ -25,6 +25,7 @@ enum class KeyboardBinding(
None(Category.None, KeyCharAndCode.UNKNOWN), None(Category.None, KeyCharAndCode.UNKNOWN),
// MainMenu // MainMenu
QuitMainMenu(Category.MainMenu, "Quit", KeyCharAndCode.BACK),
Resume(Category.MainMenu), Resume(Category.MainMenu),
Quickstart(Category.MainMenu), Quickstart(Category.MainMenu),
StartNewGame(Category.MainMenu, "Start new game", KeyCharAndCode('N')), // Not to be confused with NewGame (from World menu, Ctrl-N) 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 MainMenuOptions(Category.MainMenu, "Options", KeyCharAndCode('O')), // Separate binding from World where it's Ctrl-O default
// Worldscreen // Worldscreen
DeselectOrQuit(Category.WorldScreen, "Deselect then Quit", KeyCharAndCode.BACK),
Menu(Category.WorldScreen, KeyCharAndCode.TAB), Menu(Category.WorldScreen, KeyCharAndCode.TAB),
NextTurn(Category.WorldScreen), NextTurn(Category.WorldScreen),
NextTurnAlternate(Category.WorldScreen, KeyCharAndCode.SPACE), NextTurnAlternate(Category.WorldScreen, KeyCharAndCode.SPACE),

View File

@ -95,7 +95,7 @@ class KeyCapturingButton(
} }
private fun updateLabel() { private fun updateLabel() {
label.setText(if (current == KeyCharAndCode.UNKNOWN) "" else current.toString()) label.setText(if (current == KeyCharAndCode.BACK) "ESC/Back" else current.toString())
updateStyle() updateStyle()
} }
private fun updateStyle() { private fun updateStyle() {
@ -130,12 +130,16 @@ class KeyCapturingButton(
} }
override fun keyDown(event: InputEvent?, keycode: Int): Boolean { 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 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 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) { override fun clicked(event: InputEvent?, x: Float, y: Float) {
if (tapCount < 2 || event?.target !is Image) return if (tapCount < 2 || event?.target !is Image) return
myButton.resetKey() myButton.resetKey()

View File

@ -36,7 +36,7 @@ class DevConsolePopup(val screen: WorldScreen) : Popup(screen) {
open(true) open(true)
keyShortcuts.add(KeyCharAndCode.ESC) { close() } keyShortcuts.add(KeyCharAndCode.BACK) { close() }
keyShortcuts.add(KeyCharAndCode.TAB) { keyShortcuts.add(KeyCharAndCode.TAB) {
val textToAdd = getAutocomplete() val textToAdd = getAutocomplete()

View File

@ -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.center
import com.unciv.ui.components.extensions.surroundWithCircle import com.unciv.ui.components.extensions.surroundWithCircle
import com.unciv.ui.components.extensions.toLabel 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.KeyShortcutDispatcherVeto
import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.ui.components.input.keyShortcuts import com.unciv.ui.components.input.keyShortcuts
@ -189,7 +188,7 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize {
stage.addActor(scrollPane) stage.addActor(scrollPane)
table.center(scrollPane) table.center(scrollPane)
globalShortcuts.add(KeyCharAndCode.BACK) { globalShortcuts.add(KeyboardBinding.QuitMainMenu) {
if (hasOpenPopups()) { if (hasOpenPopups()) {
closeAllPopups() closeAllPopups()
return@add return@add
@ -358,5 +357,3 @@ class MainMenuScreen: BaseScreen(), RecreateOnResize {
// We contain a map... // We contain a map...
override fun getShortcutDispatcherVetoer() = KeyShortcutDispatcherVeto.createTileGroupMapDispatcherVetoer() override fun getShortcutDispatcherVetoer() = KeyShortcutDispatcherVeto.createTileGroupMapDispatcherVetoer()
} }

View File

@ -26,7 +26,6 @@ import com.unciv.models.ruleset.unique.UniqueType
import com.unciv.ui.components.extensions.centerX import com.unciv.ui.components.extensions.centerX
import com.unciv.ui.components.extensions.darken import com.unciv.ui.components.extensions.darken
import com.unciv.ui.components.extensions.toLabel 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.KeyShortcutDispatcherVeto
import com.unciv.ui.components.input.KeyboardBinding import com.unciv.ui.components.input.KeyboardBinding
import com.unciv.ui.components.input.KeyboardPanningListener import com.unciv.ui.components.input.KeyboardPanningListener
@ -182,15 +181,6 @@ class WorldScreen(
tutorialController.allTutorialsShowedCallback = { shouldUpdate = true } 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 addKeyboardListener() // for map panning by W,S,A,D
addKeyboardPresses() // shortcut keys like F1 addKeyboardPresses() // shortcut keys like F1
@ -242,6 +232,8 @@ class WorldScreen(
} }
private fun addKeyboardPresses() { private fun addKeyboardPresses() {
globalShortcuts.add(KeyboardBinding.DeselectOrQuit) { backButtonAndESCHandler() }
// Space and N are assigned in NextTurnButton constructor // Space and N are assigned in NextTurnButton constructor
// Functions that have a big button are assigned there (WorldScreenTopBar, TechPolicyDiplomacyButtons..) // Functions that have a big button are assigned there (WorldScreenTopBar, TechPolicyDiplomacyButtons..)
globalShortcuts.add(KeyboardBinding.Civilopedia) { game.pushScreen(CivilopediaScreen(gameInfo.ruleset)) } 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.ToggleYieldDisplay) { minimapWrapper.yieldImageButton.toggle() }
globalShortcuts.add(KeyboardBinding.ToggleWorkedTilesDisplay) { minimapWrapper.populationImageButton.toggle() } globalShortcuts.add(KeyboardBinding.ToggleWorkedTilesDisplay) { minimapWrapper.populationImageButton.toggle() }
globalShortcuts.add(KeyboardBinding.ToggleMovementDisplay) { minimapWrapper.movementsImageButton.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 // Handle disabling and re-enabling WASD listener while Options are open