Skip to content
3 changes: 2 additions & 1 deletion src/main/kotlin/com/lambda/config/Configurable.kt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.lambda.config.settings.collections.MapSetting
import com.lambda.config.settings.collections.SetSetting
import com.lambda.config.settings.comparable.BooleanSetting
import com.lambda.config.settings.comparable.EnumSetting
import com.lambda.config.settings.complex.Bind
import com.lambda.config.settings.complex.BlockPosSetting
import com.lambda.config.settings.complex.BlockSetting
import com.lambda.config.settings.complex.ColorSetting
Expand Down Expand Up @@ -381,7 +382,7 @@ abstract class Configurable(
*/
fun setting(
name: String,
defaultValue: KeyCode,
defaultValue: Bind,
description: String = "",
visibility: () -> Boolean = { true },
) = KeybindSetting(name, defaultValue, description, visibility).register()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@
package com.lambda.config.settings.complex

import com.google.gson.reflect.TypeToken
import com.lambda.brigadier.CommandResult.Companion.failure
import com.lambda.brigadier.CommandResult.Companion.success
import com.lambda.brigadier.argument.boolean
import com.lambda.brigadier.argument.value
import com.lambda.brigadier.argument.word
import com.lambda.brigadier.execute
import com.lambda.brigadier.executeWithResult
import com.lambda.brigadier.optional
import com.lambda.brigadier.required
import com.lambda.config.AbstractSetting
import com.lambda.config.settings.complex.Bind.Companion.mouseBind
import com.lambda.gui.dsl.ImGuiBuilder
import com.lambda.util.InputUtils
import com.lambda.util.KeyCode
import com.lambda.util.KeyboardUtils
import com.lambda.util.Mouse
import com.lambda.util.StringUtils.capitalize
import com.lambda.util.extension.CommandBuilder
import imgui.ImGui.isMouseClicked
Expand All @@ -37,22 +43,23 @@ import org.lwjgl.glfw.GLFW

class KeybindSetting(
override val name: String,
defaultValue: KeyCode,
defaultValue: Bind,
description: String,
visibility: () -> Boolean,
) : AbstractSetting<KeyCode>(
) : AbstractSetting<Bind>(
defaultValue,
TypeToken.get(KeyCode::class.java).type,
TypeToken.get(Bind::class.java).type,
description,
visibility
) {
private var listening = false

override fun ImGuiBuilder.buildLayout() {
val key = value
val scancode = if (key == KeyCode.UNBOUND) -69 else GLFW.glfwGetKeyScancode(key.code)
val translated = if (key == KeyCode.UNBOUND) key else KeyCode.virtualMapUS(key.code, scancode)
val preview = if (listening) "$name: Press any key…" else "$name: $translated"
val bind = value
val scancode = if (bind.code == KeyCode.UNBOUND.code) -69 else GLFW.glfwGetKeyScancode(bind.code)
val translated = if (bind.keyCode == KeyCode.UNBOUND) bind.keyCode else KeyCode.virtualMapUS(bind.code, scancode)
val preview = if (listening) "$name: Press any key…"
else if (bind.isMouseButton) "Mouse ${bind.code}" else "$name: $translated"

if (listening) {
withStyleColor(ImGuiCol.Button, 0.20f, 0.50f, 1.00f, 1.00f) {
Expand All @@ -75,7 +82,7 @@ class KeybindSetting(
}

onItemClick(ImGuiMouseButton.Right) {
value = KeyCode.UNBOUND
value = Bind.EMPTY
listening = false
}

Expand All @@ -85,38 +92,78 @@ class KeybindSetting(

sameLine()
smallButton("Unbind") {
value = KeyCode.UNBOUND
value = Bind.EMPTY
listening = false
}
onItemHover(ImGuiHoveredFlags.Stationary) {
lambdaTooltip("Clear binding")
}

val poll = KeyboardUtils.lastEvent
if (listening && poll.isPressed) {
when (val key = poll.translated) {
KeyCode.ESCAPE -> listening = false
KeyCode.BACKSPACE, KeyCode.DELETE -> {
value = KeyCode.UNBOUND
listening = false
}
else -> {
value = key
listening = false
val keyboardPoll = InputUtils.lastKeyboardEvent
val mousePoll = InputUtils.lastMouseEvent
if (listening) {
if (keyboardPoll.isPressed) {
when (val key = keyboardPoll.translated) {
KeyCode.ESCAPE -> {}
KeyCode.BACKSPACE, KeyCode.DELETE -> value = Bind.EMPTY
else -> value = Bind(key)
}
listening = false
} else if (mousePoll.action == Mouse.Action.Click.ordinal) {
value = mouseBind(mousePoll.button)
listening = false
}
}
}

override fun CommandBuilder.buildCommand(registry: CommandRegistryAccess) {
required(word(name)) { parameter ->
required(word(name)) { name ->
suggests { _, builder ->
KeyCode.entries.forEach { builder.suggest(it.name.capitalize()) }
(1..10).forEach { builder.suggest(it) }
builder.buildFuture()
}
execute {
trySetValue(KeyCode.valueOf(parameter().value()))
optional(boolean("mouse button")) { isMouseButton ->
executeWithResult {
val isMouse = if (isMouseButton != null) isMouseButton().value() else false
var bind = Bind.EMPTY
if (isMouse) {
val num = try {
name().value().toInt()
} catch(_: NumberFormatException) {
return@executeWithResult failure("${name().value()} doesn't match with a mouse button")
}
bind = mouseBind(num)
} else {
bind = try {
Bind(KeyCode.valueOf(name().value()))
} catch(_: IllegalArgumentException) {
return@executeWithResult failure("${name().value()} doesn't match with a bind")
}
}

trySetValue(bind)
return@executeWithResult success()
}
}
}
}
}

data class Bind(
val keyCode: KeyCode = KeyCode.UNBOUND,
val code: Int = keyCode.code,
val isMouseButton: Boolean = false
) {
val name: String
get() = if (isMouseButton) "Mouse $code" else keyCode.name

override fun toString() =
"Key Code: $keyCode, Code: $code, Mouse Button: $isMouseButton"

companion object {
val EMPTY = Bind()

fun mouseBind(code: Int) = Bind(code = code, isMouseButton = true)
}
}
4 changes: 2 additions & 2 deletions src/main/kotlin/com/lambda/module/HudModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@

package com.lambda.module

import com.lambda.config.settings.complex.Bind
import com.lambda.gui.Layout
import com.lambda.module.tag.ModuleTag
import com.lambda.util.KeyCode
import java.awt.Color

abstract class HudModule(
Expand All @@ -29,7 +29,7 @@ abstract class HudModule(
val customWindow: Boolean = false,
alwaysListening: Boolean = false,
enabledByDefault: Boolean = false,
defaultKeybind: KeyCode = KeyCode.UNBOUND,
defaultKeybind: Bind = Bind.EMPTY,
) : Module(name, description, tag, alwaysListening, enabledByDefault, defaultKeybind), Layout {
val backgroundColor by setting("Background Color", Color(0, 0, 0, 0))
val outline by setting("Show Outline", false)
Expand Down
28 changes: 20 additions & 8 deletions src/main/kotlin/com/lambda/module/Module.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,19 @@

package com.lambda.module

import com.lambda.Lambda.mc
import com.lambda.command.LambdaCommand
import com.lambda.config.AbstractSetting
import com.lambda.config.Configurable
import com.lambda.config.Configuration
import com.lambda.config.configurations.ModuleConfig
import com.lambda.config.settings.complex.Bind
import com.lambda.context.SafeContext
import com.lambda.event.Muteable
import com.lambda.event.events.ClientEvent
import com.lambda.event.events.ConnectionEvent
import com.lambda.event.events.KeyboardEvent
import com.lambda.event.events.MouseEvent
import com.lambda.event.listener.Listener
import com.lambda.event.listener.SafeListener
import com.lambda.event.listener.SafeListener.Companion.listen
Expand All @@ -35,6 +38,7 @@ import com.lambda.module.tag.ModuleTag
import com.lambda.sound.LambdaSound
import com.lambda.sound.SoundManager.play
import com.lambda.util.KeyCode
import com.lambda.util.Mouse
import com.lambda.util.Nameable

/**
Expand Down Expand Up @@ -111,7 +115,7 @@ abstract class Module(
val tag: ModuleTag,
private val alwaysListening: Boolean = false,
enabledByDefault: Boolean = false,
defaultKeybind: KeyCode = KeyCode.UNBOUND,
defaultKeybind: Bind = Bind.EMPTY,
autoDisable: Boolean = false
) : Nameable, Muteable, Configurable(ModuleConfig) {
private val isEnabledSetting = setting("Enabled", enabledByDefault) { false }
Expand All @@ -122,20 +126,20 @@ abstract class Module(
var isEnabled by isEnabledSetting
val isDisabled get() = !isEnabled

val keybind by keybindSetting
var keybind by keybindSetting

override val isMuted: Boolean
get() = !isEnabled && !alwaysListening

init {
listen<KeyboardEvent.Press>(alwaysListen = true) { event ->
if (mc.options.commandKey.isPressed) return@listen
if (!event.isPressed) return@listen
if (keybind == KeyCode.UNBOUND) return@listen
if (event.translated != keybind) return@listen
if (mc.currentScreen != null) return@listen
if (event.isPressed)
onButtonPress(event.keyCode)
}

toggle()
listen<MouseEvent.Click>(alwaysListen = true) { event ->
if (event.action == Mouse.Action.Click.ordinal)
onButtonPress(event.button)
}

onEnable { LambdaSound.MODULE_ON.play() }
Expand All @@ -149,6 +153,14 @@ abstract class Module(
listen<ConnectionEvent.Disconnect> { if (autoDisable) disable() }
}

private fun onButtonPress(code: Int, mouseButton: Boolean = false) {
if (mc.options.commandKey.isPressed) return
if (mc.currentScreen != null) return
if (keybind.code == KeyCode.UNBOUND.code) return
if (code != keybind.code) return
toggle()
}

fun enable() {
isEnabled = true
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/kotlin/com/lambda/module/hud/ModuleList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ object ModuleList : HudModule(

enabled.forEach {
text(it.name); sameLine()
val color = if (it.keybind == KeyCode.UNBOUND) Color.RED else Color.GREEN
val color = if (it.keybind.code == KeyCode.UNBOUND.code) Color.RED else Color.GREEN

withStyleColor(ImGuiCol.Text, color) { text(" [${it.keybind.name}]") }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import com.lambda.interaction.request.rotating.RotationMode
import com.lambda.interaction.request.rotating.visibilty.lookAt
import com.lambda.module.Module
import com.lambda.module.tag.ModuleTag
import com.lambda.util.KeyboardUtils.isKeyPressed
import com.lambda.util.InputUtils.isKeyPressed
import com.lambda.util.math.MathUtils.toFloatSign
import net.minecraft.client.gui.screen.ChatScreen
import net.minecraft.client.gui.screen.Screen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import com.lambda.module.tag.ModuleTag
import com.lambda.util.BlockUtils.blockPos
import com.lambda.util.BlockUtils.blockState
import com.lambda.util.KeyCode
import com.lambda.util.KeyboardUtils.isKeyPressed
import com.lambda.util.InputUtils.isKeyPressed
import com.lambda.util.NamedEnum
import com.lambda.util.math.distSq
import com.lambda.util.world.raycast.InteractionMask
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ package com.lambda.util
import com.lambda.context.SafeContext
import com.lambda.core.Loadable
import com.lambda.event.events.KeyboardEvent
import com.lambda.event.events.MouseEvent
import com.lambda.event.listener.UnsafeListener.Companion.listenUnsafe
import com.lambda.util.math.Vec2d
import net.minecraft.client.util.InputUtil

object KeyboardUtils : Loadable {
var lastEvent: KeyboardEvent.Press = KeyboardEvent.Press(0, 0, -1, 0)
object InputUtils : Loadable {
var lastKeyboardEvent: KeyboardEvent.Press = KeyboardEvent.Press(0, 0, -1, 0); private set
var lastMouseEvent: MouseEvent.Click = MouseEvent.Click(Mouse.Button.Left, Mouse.Action.Click, 0, Vec2d(0, 0)); private set

/**
* Returns whether any of the key-codes (not scan-codes) are being pressed
Expand All @@ -34,6 +37,7 @@ object KeyboardUtils : Loadable {

init {
// hacking imgui jni lib rn because it's missing a lot of native functions including i/o stuff
listenUnsafe<KeyboardEvent.Press> { lastEvent = it }
listenUnsafe<KeyboardEvent.Press> { lastKeyboardEvent = it }
listenUnsafe<MouseEvent.Click> { lastMouseEvent = it }
}
}