aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/compat/yacl/java/KeybindingController.kt5
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MaintainKeyboardStatePatch.java16
-rw-r--r--src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java7
-rw-r--r--src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java10
-rw-r--r--src/main/kotlin/events/HandledScreenKeyPressedEvent.kt43
-rw-r--r--src/main/kotlin/events/WorldKeyboardEvent.kt19
-rw-r--r--src/main/kotlin/features/fixes/Fixes.kt1
-rw-r--r--src/main/kotlin/features/inventory/SlotLocking.kt3
-rw-r--r--src/main/kotlin/features/macros/ComboProcessor.kt3
-rw-r--r--src/main/kotlin/gui/config/KeyBindingStateManager.kt64
-rw-r--r--src/main/kotlin/gui/config/ManagedConfig.kt24
-rw-r--r--src/main/kotlin/keybindings/FirmamentKeyboardState.kt23
-rw-r--r--src/main/kotlin/keybindings/GenericInputButton.kt289
-rw-r--r--src/main/kotlin/keybindings/IKeyBinding.kt50
-rw-r--r--src/main/kotlin/keybindings/SavedKeyBinding.kt125
-rw-r--r--src/main/kotlin/util/async/input.kt6
16 files changed, 443 insertions, 245 deletions
diff --git a/src/compat/yacl/java/KeybindingController.kt b/src/compat/yacl/java/KeybindingController.kt
index 204d521..e9bd500 100644
--- a/src/compat/yacl/java/KeybindingController.kt
+++ b/src/compat/yacl/java/KeybindingController.kt
@@ -10,6 +10,7 @@ import net.minecraft.text.Text
import moe.nea.firmament.gui.config.KeyBindingHandler
import moe.nea.firmament.gui.config.KeyBindingStateManager
import moe.nea.firmament.gui.config.ManagedOption
+import moe.nea.firmament.keybindings.GenericInputButton
import moe.nea.firmament.keybindings.SavedKeyBinding
class KeybindingController(
@@ -57,11 +58,11 @@ class KeybindingWidget(
}
override fun keyPressed(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
- return sm.keyboardEvent(keyCode, true)
+ return sm.keyboardEvent(GenericInputButton.ofKeyAndScan(keyCode, scanCode), true)
}
override fun keyReleased(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
- return sm.keyboardEvent(keyCode, false)
+ return sm.keyboardEvent(GenericInputButton.ofKeyAndScan(keyCode, scanCode), false)
}
override fun unfocus() {
diff --git a/src/main/java/moe/nea/firmament/mixins/MaintainKeyboardStatePatch.java b/src/main/java/moe/nea/firmament/mixins/MaintainKeyboardStatePatch.java
new file mode 100644
index 0000000..d433f39
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/MaintainKeyboardStatePatch.java
@@ -0,0 +1,16 @@
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.keybindings.FirmamentKeyboardState;
+import net.minecraft.client.Keyboard;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
+
+@Mixin(Keyboard.class)
+public class MaintainKeyboardStatePatch {
+ @Inject(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/option/InactivityFpsLimiter;onInput()V"))
+ private void onKeyInput(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) {
+ FirmamentKeyboardState.INSTANCE.maintainState(key, scancode, action, modifiers);
+ }
+}
diff --git a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
index 530fe47..38db0ba 100644
--- a/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/MixinHandledScreen.java
@@ -9,6 +9,8 @@ import moe.nea.firmament.events.HandledScreenForegroundEvent;
import moe.nea.firmament.events.HandledScreenKeyPressedEvent;
import moe.nea.firmament.events.IsSlotProtectedEvent;
import moe.nea.firmament.events.SlotRenderEvents;
+import moe.nea.firmament.keybindings.GenericInputAction;
+import moe.nea.firmament.keybindings.InputModifiers;
import net.minecraft.client.gui.DrawContext;
import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.entity.player.PlayerInventory;
@@ -50,7 +52,10 @@ public abstract class MixinHandledScreen<T extends ScreenHandler> {
@Inject(method = "keyPressed", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/ingame/HandledScreen;handleHotbarKeyPressed(II)Z", shift = At.Shift.BEFORE), cancellable = true)
public void onKeyPressed(int keyCode, int scanCode, int modifiers, CallbackInfoReturnable<Boolean> cir) {
- if (HandledScreenKeyPressedEvent.Companion.publish(new HandledScreenKeyPressedEvent((HandledScreen<?>) (Object) this, keyCode, scanCode, modifiers)).getCancelled()) {
+ if (HandledScreenKeyPressedEvent.Companion.publish(new HandledScreenKeyPressedEvent(
+ (HandledScreen<?>) (Object) this,
+ GenericInputAction.key(keyCode, scanCode),
+ InputModifiers.of(modifiers))).getCancelled()) {
cir.setReturnValue(true);
}
}
diff --git a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
index 4d51239..9027865 100644
--- a/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
+++ b/src/main/java/moe/nea/firmament/mixins/customgui/PatchHandledScreen.java
@@ -4,8 +4,9 @@ package moe.nea.firmament.mixins.customgui;
import com.llamalad7.mixinextras.injector.v2.WrapWithCondition;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
-import com.llamalad7.mixinextras.sugar.Local;
import moe.nea.firmament.events.HandledScreenKeyReleasedEvent;
+import moe.nea.firmament.keybindings.GenericInputAction;
+import moe.nea.firmament.keybindings.InputModifiers;
import moe.nea.firmament.util.customgui.CoordRememberingSlot;
import moe.nea.firmament.util.customgui.CustomGui;
import moe.nea.firmament.util.customgui.HasCustomGui;
@@ -75,7 +76,10 @@ public class PatchHandledScreen<T extends ScreenHandler> extends Screen implemen
}
public boolean keyReleased_firmament(int keyCode, int scanCode, int modifiers) {
- if (HandledScreenKeyReleasedEvent.Companion.publish(new HandledScreenKeyReleasedEvent((HandledScreen<?>) (Object) this, keyCode, scanCode, modifiers)).getCancelled())
+ if (HandledScreenKeyReleasedEvent.Companion.publish(new HandledScreenKeyReleasedEvent(
+ (HandledScreen<?>) (Object) this,
+ GenericInputAction.key(keyCode, scanCode),
+ InputModifiers.of(modifiers))).getCancelled())
return true;
return override != null && override.keyReleased(keyCode, scanCode, modifiers);
}
@@ -174,7 +178,7 @@ public class PatchHandledScreen<T extends ScreenHandler> extends Screen implemen
method = "mouseClicked",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screen/Screen;mouseClicked(DDI)Z"))
public boolean overrideMouseClicks(HandledScreen instance, double mouseX, double mouseY, int button,
- Operation<Boolean> original) {
+ Operation<Boolean> original) {
if (override != null) {
if (override.mouseClick(mouseX, mouseY, button))
return true;
diff --git a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
index 183ec71..de5dccf 100644
--- a/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
+++ b/src/main/kotlin/events/HandledScreenKeyPressedEvent.kt
@@ -1,38 +1,37 @@
package moe.nea.firmament.events
import net.minecraft.client.gui.screen.ingame.HandledScreen
-import net.minecraft.client.option.KeyBinding
-import moe.nea.firmament.keybindings.IKeyBinding
+import moe.nea.firmament.keybindings.GenericInputAction
+import moe.nea.firmament.keybindings.InputModifiers
+import moe.nea.firmament.keybindings.SavedKeyBinding
-sealed interface HandledScreenKeyEvent {
+sealed interface HandledScreenInputEvent {
val screen: HandledScreen<*>
- val keyCode: Int
- val scanCode: Int
- val modifiers: Int
-
- fun matches(keyBinding: KeyBinding): Boolean {
- return matches(IKeyBinding.minecraft(keyBinding))
- }
-
- fun matches(keyBinding: IKeyBinding): Boolean {
- return keyBinding.matches(keyCode, scanCode, modifiers)
- }
+ val input: GenericInputAction
+ val modifiers: InputModifiers
}
data class HandledScreenKeyPressedEvent(
override val screen: HandledScreen<*>,
- override val keyCode: Int,
- override val scanCode: Int,
- override val modifiers: Int
-) : FirmamentEvent.Cancellable(), HandledScreenKeyEvent {
+ override val input: GenericInputAction,
+ override val modifiers: InputModifiers,
+ // TODO: val isRepeat: Boolean,
+) : FirmamentEvent.Cancellable(), HandledScreenInputEvent {
+ fun matches(keyBinding: SavedKeyBinding, atLeast: Boolean = false): Boolean {
+ return keyBinding.matches(input, modifiers, atLeast)
+ }
+
companion object : FirmamentEventBus<HandledScreenKeyPressedEvent>()
}
data class HandledScreenKeyReleasedEvent(
override val screen: HandledScreen<*>,
- override val keyCode: Int,
- override val scanCode: Int,
- override val modifiers: Int
-) : FirmamentEvent.Cancellable(), HandledScreenKeyEvent {
+ override val input: GenericInputAction,
+ override val modifiers: InputModifiers,
+) : FirmamentEvent.Cancellable(), HandledScreenInputEvent {
+ fun matches(keyBinding: SavedKeyBinding, atLeast: Boolean = false): Boolean {
+ return keyBinding.matches(input, modifiers, atLeast)
+ }
+
companion object : FirmamentEventBus<HandledScreenKeyReleasedEvent>()
}
diff --git a/src/main/kotlin/events/WorldKeyboardEvent.kt b/src/main/kotlin/events/WorldKeyboardEvent.kt
index 1d6a758..eed892d 100644
--- a/src/main/kotlin/events/WorldKeyboardEvent.kt
+++ b/src/main/kotlin/events/WorldKeyboardEvent.kt
@@ -1,17 +1,16 @@
package moe.nea.firmament.events
-import net.minecraft.client.option.KeyBinding
-import moe.nea.firmament.keybindings.IKeyBinding
+import moe.nea.firmament.keybindings.GenericInputAction
+import moe.nea.firmament.keybindings.InputModifiers
+import moe.nea.firmament.keybindings.SavedKeyBinding
data class WorldKeyboardEvent(val keyCode: Int, val scanCode: Int, val modifiers: Int) : FirmamentEvent.Cancellable() {
- companion object : FirmamentEventBus<WorldKeyboardEvent>()
-
- fun matches(keyBinding: KeyBinding): Boolean {
- return matches(IKeyBinding.minecraft(keyBinding))
+ fun matches(keyBinding: SavedKeyBinding, atLeast: Boolean = false): Boolean {
+ return keyBinding.matches(intoAction(), InputModifiers(modifiers), atLeast)
}
- fun matches(keyBinding: IKeyBinding, atLeast: Boolean = false): Boolean {
- return if (atLeast) keyBinding.matchesAtLeast(keyCode, scanCode, modifiers) else
- keyBinding.matches(keyCode, scanCode, modifiers)
- }
+ fun intoAction() = GenericInputAction.key(keyCode, scanCode)
+
+
+ companion object : FirmamentEventBus<WorldKeyboardEvent>()
}
diff --git a/src/main/kotlin/features/fixes/Fixes.kt b/src/main/kotlin/features/fixes/Fixes.kt
index b002dbd..0cb5a32 100644
--- a/src/main/kotlin/features/fixes/Fixes.kt
+++ b/src/main/kotlin/features/fixes/Fixes.kt
@@ -1,6 +1,5 @@
package moe.nea.firmament.features.fixes
-import moe.nea.jarvis.api.Point
import org.joml.Vector2i
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable
import net.minecraft.client.MinecraftClient
diff --git a/src/main/kotlin/features/inventory/SlotLocking.kt b/src/main/kotlin/features/inventory/SlotLocking.kt
index 5aed40a..b4cd535 100644
--- a/src/main/kotlin/features/inventory/SlotLocking.kt
+++ b/src/main/kotlin/features/inventory/SlotLocking.kt
@@ -35,6 +35,7 @@ import moe.nea.firmament.events.ScreenChangeEvent
import moe.nea.firmament.events.SlotRenderEvents
import moe.nea.firmament.features.FirmamentFeature
import moe.nea.firmament.gui.config.ManagedConfig
+import moe.nea.firmament.keybindings.InputModifiers
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.mixins.accessor.AccessorHandledScreen
import moe.nea.firmament.util.CommonSoundEffects
@@ -142,7 +143,7 @@ object SlotLocking : FirmamentFeature {
object TConfig : ManagedConfig(identifier, Category.INVENTORY) {
val lockSlot by keyBinding("lock") { GLFW.GLFW_KEY_L }
val lockUUID by keyBindingWithOutDefaultModifiers("lock-uuid") {
- SavedKeyBinding(GLFW.GLFW_KEY_L, shift = true)
+ SavedKeyBinding.keyWithMods(GLFW.GLFW_KEY_L, InputModifiers.of(shift = true))
}
val slotBind by keyBinding("bind") { GLFW.GLFW_KEY_L }
val slotBindRequireShift by toggle("require-quick-move") { true }
diff --git a/src/main/kotlin/features/macros/ComboProcessor.kt b/src/main/kotlin/features/macros/ComboProcessor.kt
index 1f77ff6..03e9238 100644
--- a/src/main/kotlin/features/macros/ComboProcessor.kt
+++ b/src/main/kotlin/features/macros/ComboProcessor.kt
@@ -25,9 +25,6 @@ object ComboProcessor {
val breadCrumbs = mutableListOf<SavedKeyBinding>()
init {
- val f = SavedKeyBinding(InputUtil.GLFW_KEY_F)
- val one = SavedKeyBinding(InputUtil.GLFW_KEY_1)
- val two = SavedKeyBinding(InputUtil.GLFW_KEY_2)
setActions(
MacroData.DConfig.data.comboActions
)
diff --git a/src/main/kotlin/gui/config/KeyBindingStateManager.kt b/src/main/kotlin/gui/config/KeyBindingStateManager.kt
index 49a4465..500f0fa 100644
--- a/src/main/kotlin/gui/config/KeyBindingStateManager.kt
+++ b/src/main/kotlin/gui/config/KeyBindingStateManager.kt
@@ -11,6 +11,8 @@ import org.lwjgl.glfw.GLFW
import net.minecraft.text.Text
import net.minecraft.util.Formatting
import moe.nea.firmament.gui.FirmButtonComponent
+import moe.nea.firmament.keybindings.GenericInputButton
+import moe.nea.firmament.keybindings.InputModifiers
import moe.nea.firmament.keybindings.SavedKeyBinding
class KeyBindingStateManager(
@@ -20,8 +22,7 @@ class KeyBindingStateManager(
val requestFocus: () -> Unit,
) {
var editing = false
- var lastPressed = 0
- var lastPressedNonModifier = 0
+ var lastPressed: GenericInputButton? = null
var label: Text = Text.literal("")
fun onClick() {
@@ -35,60 +36,52 @@ class KeyBindingStateManager(
updateLabel()
}
- fun keyboardEvent(keyCode: Int, pressed: Boolean): Boolean {
- return if (pressed) onKeyPressed(keyCode, SavedKeyBinding.getModInt())
- else onKeyReleased(keyCode, SavedKeyBinding.getModInt())
+ fun keyboardEvent(keyCode: GenericInputButton, pressed: Boolean): Boolean {
+ return if (pressed) onKeyPressed(keyCode, InputModifiers.getCurrentModifiers())
+ else onKeyReleased(keyCode, InputModifiers.getCurrentModifiers())
}
- fun onKeyPressed(ch: Int, modifiers: Int): Boolean {
+ fun onKeyPressed(
+ ch: GenericInputButton,
+ modifiers: InputModifiers
+ ): Boolean { // TODO !!!!!: genericify this method to allow for other inputs
if (!editing) {
return false
}
- if (ch == GLFW.GLFW_KEY_ESCAPE) {
- lastPressedNonModifier = 0
+ if (ch == GenericInputButton.escape()) {
editing = false
- lastPressed = 0
- setValue(SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN))
+ lastPressed = null
+ setValue(SavedKeyBinding.unbound())
updateLabel()
blur()
return true
}
- if (ch == GLFW.GLFW_KEY_LEFT_SHIFT || ch == GLFW.GLFW_KEY_RIGHT_SHIFT
- || ch == GLFW.GLFW_KEY_LEFT_ALT || ch == GLFW.GLFW_KEY_RIGHT_ALT
- || ch == GLFW.GLFW_KEY_LEFT_CONTROL || ch == GLFW.GLFW_KEY_RIGHT_CONTROL
- ) {
+ if (ch.isModifier()) {
lastPressed = ch
} else {
- setValue(
- SavedKeyBinding(
- ch, modifiers
- )
- )
+ setValue(SavedKeyBinding(ch, modifiers))
editing = false
blur()
- lastPressed = 0
- lastPressedNonModifier = 0
+ lastPressed = null
}
updateLabel()
return true
}
fun onLostFocus() {
- lastPressedNonModifier = 0
editing = false
- lastPressed = 0
+ lastPressed = null
updateLabel()
}
- fun onKeyReleased(ch: Int, modifiers: Int): Boolean {
+ fun onKeyReleased(ch: GenericInputButton, modifiers: InputModifiers): Boolean {
if (!editing)
return false
- if (lastPressedNonModifier == ch || (lastPressedNonModifier == 0 && ch == lastPressed)) {
+ if (ch == lastPressed) { // TODO: check modifiers dont duplicate (CTRL+CTRL)
setValue(SavedKeyBinding(ch, modifiers))
editing = false
blur()
- lastPressed = 0
- lastPressedNonModifier = 0
+ lastPressed = null
}
updateLabel()
return true
@@ -97,16 +90,11 @@ class KeyBindingStateManager(
fun updateLabel() {
var stroke = value().format()
if (editing) {
- stroke = Text.literal("")
- val (shift, ctrl, alt) = SavedKeyBinding.getMods(SavedKeyBinding.getModInt())
- if (shift) {
- stroke.append("SHIFT + ")
- }
- if (alt) {
- stroke.append("ALT + ")
- }
- if (ctrl) {
- stroke.append("CTRL + ")
+ stroke = Text.empty()
+ val modifiers = InputModifiers.getCurrentModifiers()
+ if (!modifiers.isEmpty()) {
+ stroke.append(modifiers.format())
+ stroke.append(" + ")
}
stroke.append("???")
stroke.styled { it.withColor(Formatting.YELLOW) }
@@ -128,7 +116,7 @@ class KeyBindingStateManager(
}) {
override fun keyboardEvent(event: KeyboardEvent, context: GuiImmediateContext): Boolean {
if (event is KeyboardEvent.KeyPressed) {
- return this@KeyBindingStateManager.keyboardEvent(event.keycode, event.pressed)
+ return this@KeyBindingStateManager.keyboardEvent(GenericInputButton.ofKeyAndScan(event.keycode, event.scancode), event.pressed)
}
return super.keyboardEvent(event, context)
}
diff --git a/src/main/kotlin/gui/config/ManagedConfig.kt b/src/main/kotlin/gui/config/ManagedConfig.kt
index 2f4144c..90e58d0 100644
--- a/src/main/kotlin/gui/config/ManagedConfig.kt
+++ b/src/main/kotlin/gui/config/ManagedConfig.kt
@@ -26,6 +26,8 @@ import net.minecraft.text.Text
import net.minecraft.util.StringIdentifiable
import moe.nea.firmament.Firmament
import moe.nea.firmament.gui.FirmButtonComponent
+import moe.nea.firmament.keybindings.GenericInputButton
+import moe.nea.firmament.keybindings.InputModifiers
import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.ScreenUtil.setScreenLater
import moe.nea.firmament.util.collections.InstanceList
@@ -185,7 +187,9 @@ abstract class ManagedConfig(
protected fun keyBinding(
propertyName: String,
default: () -> Int,
- ): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(default()) }
+ ): ManagedOption<SavedKeyBinding> = keyBindingWithOutDefaultModifiers(propertyName) {
+ SavedKeyBinding.keyWithoutMods(default())
+ }
protected fun keyBindingWithOutDefaultModifiers(
propertyName: String,
@@ -197,7 +201,7 @@ abstract class ManagedConfig(
protected fun keyBindingWithDefaultUnbound(
propertyName: String,
): ManagedOption<SavedKeyBinding> {
- return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN) }
+ return keyBindingWithOutDefaultModifiers(propertyName) { SavedKeyBinding.unbound() }
}
protected fun integer(
@@ -231,15 +235,15 @@ abstract class ManagedConfig(
latestGuiAppender = guiapp
guiapp.appendFullRow(
RowComponent(
- FirmButtonComponent(TextComponent("←")) {
- if (parent != null) {
- save()
- setScreenLater(parent)
- } else {
- AllConfigsGui.showAllGuis()
+ FirmButtonComponent(TextComponent("←")) {
+ if (parent != null) {
+ save()
+ setScreenLater(parent)
+ } else {
+ AllConfigsGui.showAllGuis()
+ }
}
- }
- ))
+ ))
sortedOptions.forEach { it.appendToGui(guiapp) }
guiapp.reloadables.forEach { it() }
val component = CenterComponent(
diff --git a/src/main/kotlin/keybindings/FirmamentKeyboardState.kt b/src/main/kotlin/keybindings/FirmamentKeyboardState.kt
new file mode 100644
index 0000000..65288bc
--- /dev/null
+++ b/src/main/kotlin/keybindings/FirmamentKeyboardState.kt
@@ -0,0 +1,23 @@
+package moe.nea.firmament.keybindings
+
+import java.util.BitSet
+import org.lwjgl.glfw.GLFW
+
+object FirmamentKeyboardState {
+
+ private val pressedScancodes = BitSet()
+
+ @Synchronized
+ fun isScancodeDown(scancode: Int): Boolean {
+ // TODO: maintain a record of keycodes that were pressed for this scanCode to check if they are still held
+ return pressedScancodes.get(scancode)
+ }
+
+ @Synchronized
+ fun maintainState(key: Int, scancode: Int, action: Int, modifiers: Int) {
+ when (action) {
+ GLFW.GLFW_PRESS -> pressedScancodes.set(scancode)
+ GLFW.GLFW_RELEASE -> pressedScancodes.clear(scancode)
+ }
+ }
+}
diff --git a/src/main/kotlin/keybindings/GenericInputButton.kt b/src/main/kotlin/keybindings/GenericInputButton.kt
new file mode 100644
index 0000000..2d81bd8
--- /dev/null
+++ b/src/main/kotlin/keybindings/GenericInputButton.kt
@@ -0,0 +1,289 @@
+package moe.nea.firmament.keybindings
+
+import com.mojang.serialization.Codec
+import org.lwjgl.glfw.GLFW
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.encoding.Decoder
+import kotlinx.serialization.encoding.Encoder
+import kotlinx.serialization.json.JsonElement
+import kotlinx.serialization.json.JsonNull
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.int
+import kotlinx.serialization.json.put
+import net.minecraft.client.MinecraftClient
+import net.minecraft.client.util.InputUtil
+import net.minecraft.text.Text
+import moe.nea.firmament.util.MC
+import moe.nea.firmament.util.mc.InitLevel
+
+@Serializable(with = GenericInputButton.Serializer::class)
+sealed interface GenericInputButton {
+
+ object Serializer : KSerializer<GenericInputButton> {
+ override val descriptor: SerialDescriptor
+ get() = SerialDescriptor("Firmament:GenericInputButton", JsonElement.serializer().descriptor)
+
+ override fun serialize(
+ encoder: Encoder,
+ value: GenericInputButton
+ ) {
+ JsonElement.serializer().serialize(
+ encoder,
+ when (value) {
+ is KeyCodeButton -> buildJsonObject { put("keyCode", value.keyCode) }
+ is MouseButton -> buildJsonObject { put("mouse", value.mouseButton) }
+ is ScanCodeButton -> buildJsonObject { put("scanCode", value.scanCode) }
+ Unbound -> JsonNull
+ })
+ }
+
+ override fun deserialize(decoder: Decoder): GenericInputButton {
+ val element = JsonElement.serializer().deserialize(decoder)
+ if (element is JsonNull)
+ return Unbound
+ require(element is JsonObject)
+ (element["keyCode"] as? JsonPrimitive)?.let {
+ return KeyCodeButton(it.int)
+ }
+ (element["mouse"] as? JsonPrimitive)?.let {
+ return MouseButton(it.int)
+ }
+ (element["scanCode"] as? JsonPrimitive)?.let {
+ return ScanCodeButton(it.int)
+ }
+ error("Could not parse GenericInputButton: $element")
+ }
+ }
+
+ companion object {
+
+ fun escape() = ofKeyCode(GLFW.GLFW_KEY_ESCAPE)
+ fun ofKeyCode(keyCode: Int): GenericInputButton = KeyCodeButton(keyCode)
+ fun ofScanCode(scanCode: Int): GenericInputButton = ScanCodeButton(scanCode)
+ fun ofScanCodeFromKeyCode(keyCode: Int): GenericInputButton = ScanCodeButton(GLFW.glfwGetKeyScancode(keyCode))
+ fun unbound(): GenericInputButton = Unbound
+ fun ofKeyAndScan(keyCode: Int, scanCode: Int): GenericInputButton {
+ if (keyCode == GLFW.GLFW_KEY_UNKNOWN)
+ return ofScanCode(scanCode)
+ return ofKeyCode(keyCode) // TODO: should i always upgrade to a scanCode?
+ }
+ }
+
+ data object Unbound : GenericInputButton {
+ override fun toInputKey(): InputUtil.Key {
+ return InputUtil.UNKNOWN_KEY
+ }
+
+ override fun isBound(): Boolean {
+ return false
+ }
+
+ override fun isPressed(): Boolean {
+ return false
+ }
+ }
+
+ data class MouseButton(
+ val mouseButton: Int
+ ) : GenericInputButton {
+ override fun toInputKey(): InputUtil.Key {
+ return InputUtil.Type.MOUSE.createFromCode(mouseButton)
+ }
+
+ override fun isPressed(): Boolean {
+ return GLFW.glfwGetMouseButton(MC.window.handle, mouseButton) == GLFW.GLFW_PRESS
+ }
+ }
+
+ data class KeyCodeButton(
+ val keyCode: Int
+ ) : GenericInputButton {
+ override fun toInputKey(): InputUtil.Key {
+ return InputUtil.Type.KEYSYM.createFromCode(keyCode)
+ }
+
+ override fun isPressed(): Boolean {
+ return InputUtil.isKeyPressed(MC.window.handle, keyCode)
+ }
+
+ override fun isCtrl(): Boolean {
+ return keyCode in InputModifiers.controlKeys
+ }
+
+ override fun isAlt(): Boolean {
+ return keyCode in InputModifiers.altKeys
+ }
+
+ override fun isShift(): Boolean {
+ return keyCode in InputModifiers.shiftKeys
+ }
+
+ override fun isSuper(): Boolean {
+ return keyCode in InputModifiers.superKeys
+ }
+ }
+
+ data class ScanCodeButton(
+ val scanCode: Int
+ ) : GenericInputButton {
+ override fun toInputKey(): InputUtil.Key {
+ return InputUtil.Type.SCANCODE.createFromCode(scanCode)
+ }
+
+ override fun isPressed(): Boolean {
+ return FirmamentKeyboardState.isScancodeDown(scanCode)
+ }
+ }
+
+ fun isBound() = true
+
+ fun isModifier() = isCtrl() || isAlt() || isSuper() || isShift()
+ fun isCtrl() = false
+ fun isAlt() = false
+ fun isSuper() = false
+ fun isShift() = false
+
+ fun toInputKey(): InputUtil.Key
+ fun format(): Text =
+ if (InitLevel.isAtLeast(InitLevel.RENDER_INIT)) {
+ toInputKey().localizedText
+ } else {
+ Text.of(toString())
+ }
+
+ fun matches(inputAction: GenericInputAction) = inputAction.matches(this)
+ fun isPressed(): Boolean
+}
+
+sealed interface GenericInputAction {
+ fun matches(inputButton: GenericInputButton): Boolean
+
+ data class MouseInput(
+ val mouseButton: Int
+ ) : GenericInputAction {
+ override fun matches(inputButton: GenericInputButton): Boolean {
+ return inputButton is GenericInputButton.MouseButton && inputButton.mouseButton == mouseButton
+ }
+ }
+
+ data class KeyboardInput(
+ val keyCode: Int,
+ val scanCode: Int,
+ ) : GenericInputAction {
+ override fun matches(inputButton: GenericInputButton): Boolean {
+ return when (inputButton) {
+ is GenericInputButton.KeyCodeButton -> inputButton.keyCode == keyCode
+ is GenericInputButton.ScanCodeButton -> inputButton.scanCode == scanCode
+ else -> false
+ }
+ }
+ }
+
+ companion object {
+ @JvmStatic
+ fun mouse(mouseButton: Int): GenericInputAction = MouseInput(mouseButton)
+
+ @JvmStatic
+ fun key(keyCode: Int, scanCode: Int): GenericInputAction = KeyboardInput(keyCode, scanCode)
+ }
+}
+
+@Serializable
+data class InputModifiers(
+ val modifiers: Int
+) {
+ companion object {
+ fun getCurrentModifiers(): InputModifiers {
+ val h = MC.window.handle
+ val ctrl = if (MinecraftClient.IS_SYSTEM_MAC) {
+ InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER)
+ } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL)
+ val shift = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SHIFT) || InputUtil.isKeyPressed(
+ h,
+ GLFW.GLFW_KEY_RIGHT_SHIFT
+ )
+ val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT)
+ val `super` = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER)
+ || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER)
+ return of(
+ ctrl = ctrl,
+ shift = shift,
+ alt = alt,
+ `super` = `super`,
+ )
+ }
+
+
+ val superKeys = listOf(GLFW.GLFW_KEY_LEFT_SUPER, GLFW.GLFW_KEY_RIGHT_SUPER)
+ val controlKeys = if (MinecraftClient.IS_SYSTEM_MAC) {
+ listOf(GLFW.GLFW_KEY_LEFT_SUPER, GLFW.GLFW_KEY_RIGHT_SUPER)
+ } else {
+ listOf(GLFW.GLFW_KEY_LEFT_CONTROL, GLFW.GLFW_KEY_RIGHT_CONTROL)
+ }
+ val shiftKeys = listOf(GLFW.GLFW_KEY_LEFT_SHIFT, GLFW.GLFW_KEY_RIGHT_SHIFT)
+ val altKeys = listOf(GLFW.GLFW_KEY_LEFT_ALT, GLFW.GLFW_KEY_RIGHT_ALT)
+
+ fun of(
+ vararg useNamedArgs: Boolean,
+ ctrl: Boolean = false,
+ shift: Boolean = false,
+ alt: Boolean = false,
+ `super`: Boolean = false
+ ): InputModifiers {
+ require(useNamedArgs.isEmpty())
+ return InputModifiers(
+ (if (ctrl) GLFW.GLFW_MOD_CONTROL else 0)
+ or (if (shift) GLFW.GLFW_MOD_SHIFT else 0)
+ or (if (alt) GLFW.GLFW_MOD_ALT else 0)
+ or (if (`super`) GLFW.GLFW_MOD_SUPER else 0)
+ )
+ }
+
+ @JvmStatic
+ fun of(modifiers: Int) = InputModifiers(modifiers)
+
+ fun none(): InputModifiers {
+ return InputModifiers(0)
+ }
+ }
+
+ fun isAtLeast(other: InputModifiers): Boolean {
+ return this.modifiers and other.modifiers == this.modifiers
+ }
+
+ fun isEmpty() = modifiers == 0
+
+ fun getFlag(flag: Int) = modifiers and flag != 0
+ val ctrl get() = getFlag(GLFW.GLFW_MOD_CONTROL) // TODO: consult someone on control vs command again
+ val shift get() = getFlag(GLFW.GLFW_MOD_SHIFT)
+ val alt get() = getFlag(GLFW.GLFW_MOD_ALT)
+ val `super` get() = getFlag(GLFW.GLFW_MOD_SUPER)
+
+ override fun toString(): String {
+ return listOfNotNull(
+ if (ctrl) "CTRL" else null,
+ if (shift) "SHIFT" else null,
+ if (alt) "ALT" else null,
+ if (`super`) "SUPER" else null,
+ ).joinToString(" + ")
+ }
+
+ fun matches(other: InputModifiers, atLeast: Boolean): Boolean {
+ if (atLeast)
+ return isAtLeast(other)
+ return this == other
+ }
+
+ fun format(): Text { // TODO: translation for mods
+ return Text.of(toString())
+ }
+
+}
diff --git a/src/main/kotlin/keybindings/IKeyBinding.kt b/src/main/kotlin/keybindings/IKeyBinding.kt
deleted file mode 100644
index 9d9b106..0000000
--- a/src/main/kotlin/keybindings/IKeyBinding.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-package moe.nea.firmament.keybindings
-
-import net.minecraft.client.option.KeyBinding
-
-interface IKeyBinding {
- fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean
- fun matchesAtLeast(keyCode: Int, scanCode: Int, modifiers: Int): Boolean
-
- fun withModifiers(wantedModifiers: Int): IKeyBinding {
- val old = this
- return object : IKeyBinding {
- override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
- return old.matchesAtLeast(keyCode, scanCode, modifiers) && (modifiers and wantedModifiers) == wantedModifiers
- }
-
- override fun matchesAtLeast(
- keyCode: Int,
- scanCode: Int,
- modifiers: Int
- ): Boolean {
- return old.matchesAtLeast(keyCode, scanCode, modifiers) && (modifiers.inv() and wantedModifiers) == 0
- }
- }
- }
-
- companion object {
- fun minecraft(keyBinding: KeyBinding) = object : IKeyBinding {
- override fun matches(keyCode: Int, scanCode: Int, modifiers: Int) =
- keyBinding.matchesKey(keyCode, scanCode)
-
- override fun matchesAtLeast(
- keyCode: Int,
- scanCode: Int,
- modifiers: Int
- ): Boolean =
- keyBinding.matchesKey(keyCode, scanCode)
- }
-
- fun ofKeyCode(wantedKeyCode: Int) = object : IKeyBinding {
- override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean = keyCode == wantedKeyCode && modifiers == 0
- override fun matchesAtLeast(
- keyCode: Int,
- scanCode: Int,
- modifiers: Int
- ): Boolean = keyCode == wantedKeyCode
- }
- }
-}
diff --git a/src/main/kotlin/keybindings/SavedKeyBinding.kt b/src/main/kotlin/keybindings/SavedKeyBinding.kt
index 01baa8f..bc99e03 100644
--- a/src/main/kotlin/keybindings/SavedKeyBinding.kt
+++ b/src/main/kotlin/keybindings/SavedKeyBinding.kt
@@ -1,102 +1,28 @@
package moe.nea.firmament.keybindings
-import org.lwjgl.glfw.GLFW
import kotlinx.serialization.Serializable
-import net.minecraft.client.MinecraftClient
-import net.minecraft.client.util.InputUtil
import net.minecraft.text.Text
-import moe.nea.firmament.util.MC
-import moe.nea.firmament.util.mc.InitLevel
-// TODO: add support for mouse keybindings
@Serializable
data class SavedKeyBinding(
- val keyCode: Int,
- val shift: Boolean = false,
- val ctrl: Boolean = false,
- val alt: Boolean = false,
-) : IKeyBinding {
- val isBound: Boolean get() = keyCode != GLFW.GLFW_KEY_UNKNOWN
-
- constructor(keyCode: Int, mods: Triple<Boolean, Boolean, Boolean>) : this(
- keyCode,
- mods.first && keyCode != GLFW.GLFW_KEY_LEFT_SHIFT && keyCode != GLFW.GLFW_KEY_RIGHT_SHIFT,
- mods.second && keyCode != GLFW.GLFW_KEY_LEFT_CONTROL && keyCode != GLFW.GLFW_KEY_RIGHT_CONTROL,
- mods.third && keyCode != GLFW.GLFW_KEY_LEFT_ALT && keyCode != GLFW.GLFW_KEY_RIGHT_ALT,
- )
-
- constructor(keyCode: Int, mods: Int) : this(keyCode, getMods(mods))
-
+ val button: GenericInputButton,
+ val modifiers: InputModifiers,
+) {
companion object {
- fun getMods(modifiers: Int): Triple<Boolean, Boolean, Boolean> {
- return Triple(
- modifiers and GLFW.GLFW_MOD_SHIFT != 0,
- modifiers and GLFW.GLFW_MOD_CONTROL != 0,
- modifiers and GLFW.GLFW_MOD_ALT != 0,
- )
- }
-
- fun getModInt(): Int {
- val h = MC.window.handle
- val ctrl = if (MinecraftClient.IS_SYSTEM_MAC) {
- InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_SUPER)
- || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_SUPER)
- } else InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_CONTROL)
- || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_CONTROL)
- val shift = isShiftDown()
- val alt = InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_LEFT_ALT)
- || InputUtil.isKeyPressed(h, GLFW.GLFW_KEY_RIGHT_ALT)
- var mods = 0
- if (ctrl) mods = mods or GLFW.GLFW_MOD_CONTROL
- if (shift) mods = mods or GLFW.GLFW_MOD_SHIFT
- if (alt) mods = mods or GLFW.GLFW_MOD_ALT
- return mods
- }
+ fun isShiftDown() = InputModifiers.getCurrentModifiers().shift
- private val h get() = MC.window.handle
- fun isShiftDown() = shiftKeys.any { InputUtil.isKeyPressed(h, it) }
-
- fun unbound(): SavedKeyBinding =
- SavedKeyBinding(GLFW.GLFW_KEY_UNKNOWN)
-
- val controlKeys = if (MinecraftClient.IS_SYSTEM_MAC) {
- listOf(GLFW.GLFW_KEY_LEFT_SUPER, GLFW.GLFW_KEY_RIGHT_SUPER)
- } else {
- listOf(GLFW.GLFW_KEY_LEFT_CONTROL, GLFW.GLFW_KEY_RIGHT_CONTROL)
- }
- val shiftKeys = listOf(GLFW.GLFW_KEY_LEFT_SHIFT, GLFW.GLFW_KEY_RIGHT_SHIFT)
-
- val altKeys = listOf(GLFW.GLFW_KEY_LEFT_ALT, GLFW.GLFW_KEY_RIGHT_ALT)
+ fun unbound(): SavedKeyBinding = withoutMods(GenericInputButton.unbound())
+ fun withoutMods(input: GenericInputButton) = SavedKeyBinding(input, InputModifiers.none())
+ fun keyWithoutMods(keyCode: Int): SavedKeyBinding = withoutMods(GenericInputButton.ofKeyCode(keyCode))
+ fun keyWithMods(keyCode: Int, mods: InputModifiers) =
+ SavedKeyBinding(GenericInputButton.ofKeyCode(keyCode), mods)
}
fun isPressed(atLeast: Boolean = false): Boolean {
- if (!isBound) return false
- val h = MC.window.handle
- if (!InputUtil.isKeyPressed(h, keyCode)) return false
-
- // These are modifiers, so if the searched keyCode is a modifier key, then that key does not count as the modifier
- val ctrl = keyCode !in controlKeys && controlKeys.any { InputUtil.isKeyPressed(h, it) }
- val shift = keyCode !in shiftKeys && isShiftDown()
- val alt = keyCode !in altKeys && altKeys.any { InputUtil.isKeyPressed(h, it) }
- if (atLeast)
- return (ctrl >= this.ctrl) &&
- (alt >= this.alt) &&
- (shift >= this.shift)
-
- return (ctrl == this.ctrl) &&
- (alt == this.alt) &&
- (shift == this.shift)
- }
-
- override fun matchesAtLeast(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
- if (this.keyCode == GLFW.GLFW_KEY_UNKNOWN) return false
- val (shift, ctrl, alt) = getMods(modifiers)
- return keyCode == this.keyCode && this.shift <= shift && this.ctrl <= ctrl && this.alt <= alt
- }
-
- override fun matches(keyCode: Int, scanCode: Int, modifiers: Int): Boolean {
- if (this.keyCode == GLFW.GLFW_KEY_UNKNOWN) return false
- return keyCode == this.keyCode && getMods(modifiers) == Triple(shift, ctrl, alt)
+ if (!button.isPressed())
+ return false
+ val mods = InputModifiers.getCurrentModifiers()
+ return mods.matches(this.modifiers, atLeast)
}
override fun toString(): String {
@@ -104,22 +30,19 @@ data class SavedKeyBinding(
}
fun format(): Text {
- val stroke = Text.literal("")
- if (ctrl) {
- stroke.append("CTRL + ")
- }
- if (alt) {
- stroke.append("ALT + ")
- }
- if (shift) {
- stroke.append("SHIFT + ") // TODO: translations?
- }
- if (InitLevel.isAtLeast(InitLevel.RENDER_INIT)) {
- stroke.append(InputUtil.Type.KEYSYM.createFromCode(keyCode).localizedText)
- } else {
- stroke.append(keyCode.toString())
+ val stroke = Text.empty()
+ if (!modifiers.isEmpty()) {
+ stroke.append(modifiers.format())
+ stroke.append(" + ")
}
+ stroke.append(button.format())
return stroke
}
+ val isBound: Boolean get() = button.isBound()
+ fun matches(action: GenericInputAction, inputModifiers: InputModifiers, atLeast: Boolean = false): Boolean {
+ return action.matches(button) && this.modifiers.matches(inputModifiers, atLeast)
+ }
+
}
+
diff --git a/src/main/kotlin/util/async/input.kt b/src/main/kotlin/util/async/input.kt
index 2c546ba..35265f5 100644
--- a/src/main/kotlin/util/async/input.kt
+++ b/src/main/kotlin/util/async/input.kt
@@ -12,13 +12,13 @@ import kotlin.coroutines.resume
import net.minecraft.client.gui.screen.Screen
import moe.nea.firmament.events.HandledScreenKeyPressedEvent
import moe.nea.firmament.gui.FirmButtonComponent
-import moe.nea.firmament.keybindings.IKeyBinding
+import moe.nea.firmament.keybindings.SavedKeyBinding
import moe.nea.firmament.util.MC
import moe.nea.firmament.util.MoulConfigUtils
import moe.nea.firmament.util.ScreenUtil
private object InputHandler {
- data class KeyInputContinuation(val keybind: IKeyBinding, val onContinue: () -> Unit)
+ data class KeyInputContinuation(val keybind: SavedKeyBinding, val onContinue: () -> Unit)
private val activeContinuations = mutableListOf<KeyInputContinuation>()
@@ -46,7 +46,7 @@ private object InputHandler {
}
}
-suspend fun waitForInput(keybind: IKeyBinding): Unit = suspendCancellableCoroutine { cont ->
+suspend fun waitForInput(keybind: SavedKeyBinding): Unit = suspendCancellableCoroutine { cont ->
val unregister =
InputHandler.registerContinuation(InputHandler.KeyInputContinuation(keybind) { cont.resume(Unit) })
cont.invokeOnCancellation {