Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
16 changes: 10 additions & 6 deletions 16 src/main/java/com/lambda/mixin/input/KeyboardMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import com.lambda.event.EventFlow;
import com.lambda.event.events.KeyboardEvent;
import com.lambda.module.modules.player.InventoryMove;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import net.minecraft.client.Keyboard;
import net.minecraft.client.option.KeyBinding;
import net.minecraft.client.util.InputUtil;
Expand All @@ -30,9 +32,10 @@

@Mixin(Keyboard.class)
public class KeyboardMixin {
@Inject(method = "onKey", at = @At("HEAD"))
private void onKey(long window, int key, int scancode, int action, int modifiers, CallbackInfo ci) {
@WrapMethod(method = "onKey")
private void onKey(long window, int key, int scancode, int action, int modifiers, Operation<Void> original) {
EventFlow.post(new KeyboardEvent.Press(key, scancode, action, modifiers));
original.call(window, key, scancode, action, modifiers);
}

@Inject(method = "onKey", at = @At("RETURN"))
Expand All @@ -42,12 +45,13 @@ private void onKeyTail(long window, int key, int scancode, int action, int modif
KeyBinding.setKeyPressed(fromCode, action != 0);
}

@Inject(method = "onChar", at = @At("HEAD"))
private void onChar(long window, int codePoint, int modifiers, CallbackInfo ci) {
@WrapMethod(method = "onChar")
private void onChar(long window, int codePoint, int modifiers, Operation<Void> original) {
char[] chars = Character.toChars(codePoint);

for (char c : chars) {
for (char c : chars)
EventFlow.post(new KeyboardEvent.Char(c));
}

original.call(window, codePoint, modifiers);
}
}
33 changes: 14 additions & 19 deletions 33 src/main/java/com/lambda/mixin/input/MouseMixin.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,49 +21,44 @@
import com.lambda.event.events.MouseEvent;
import com.lambda.module.modules.render.Zoom;
import com.lambda.util.math.Vec2d;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import net.minecraft.client.Mouse;
import net.minecraft.client.option.GameOptions;
import net.minecraft.client.option.SimpleOption;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

@Mixin(Mouse.class)
public class MouseMixin {
@Shadow private double x;

@Shadow private double y;

@Inject(method = "onMouseButton(JIII)V", at = @At("HEAD"), cancellable = true)
private void onMouseButton(long window, int button, int action, int mods, CallbackInfo ci) {
Vec2d position = new Vec2d(x, y);

if (EventFlow.post(new MouseEvent.Click(button, action, mods, position)).isCanceled()) {
ci.cancel();
}
@WrapMethod(method = "onMouseButton(JIII)V")
private void onMouseButton(long window, int button, int action, int mods, Operation<Void> original) {
if (!EventFlow.post(new MouseEvent.Click(button, action, mods)).isCanceled())
original.call(window, button, action, mods);
}

@Inject(method = "onMouseScroll(JDD)V", at = @At("HEAD"), cancellable = true)
private void onMouseScroll(long window, double horizontal, double vertical, CallbackInfo ci) {
@WrapMethod(method = "onMouseScroll(JDD)V")
private void onMouseScroll(long window, double horizontal, double vertical, Operation<Void> original) {
Vec2d delta = new Vec2d(horizontal, vertical);

if (EventFlow.post(new MouseEvent.Scroll(delta)).isCanceled()) {
ci.cancel();
}
if (!EventFlow.post(new MouseEvent.Scroll(delta)).isCanceled())
original.call(window, horizontal, vertical);
}

@Inject(method = "onCursorPos(JDD)V", at = @At("HEAD"), cancellable = true)
private void onCursorPos(long window, double x, double y, CallbackInfo ci) {
@WrapMethod(method = "onCursorPos(JDD)V")
private void onCursorPos(long window, double x, double y, Operation<Void> original) {
if (x + y == this.x + this.y) return;

Vec2d position = new Vec2d(x, y);

if (EventFlow.post(new MouseEvent.Move(position)).isCanceled()) {
ci.cancel();
}
if (!EventFlow.post(new MouseEvent.Move(position)).isCanceled())
original.call(window, x, y);
}

@Redirect(method = "updateMouse", at = @At(value = "FIELD", target = "Lnet/minecraft/client/option/GameOptions;smoothCameraEnabled:Z"))
Expand Down
3 changes: 2 additions & 1 deletion 3 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
143 changes: 109 additions & 34 deletions 143 src/main/kotlin/com/lambda/config/settings/complex/KeybindSetting.kt
Original file line number Diff line number Diff line change
Expand Up @@ -18,42 +18,55 @@
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
import imgui.flag.ImGuiCol
import imgui.flag.ImGuiHoveredFlags
import imgui.flag.ImGuiMouseButton
import net.minecraft.command.CommandRegistryAccess
import org.lwjgl.glfw.GLFW
import org.lwjgl.glfw.GLFW.GLFW_KEY_LEFT_SHIFT
import org.lwjgl.glfw.GLFW.GLFW_KEY_RIGHT_SUPER
import org.lwjgl.glfw.GLFW.GLFW_MOD_ALT
import org.lwjgl.glfw.GLFW.GLFW_MOD_CAPS_LOCK
import org.lwjgl.glfw.GLFW.GLFW_MOD_CONTROL
import org.lwjgl.glfw.GLFW.GLFW_MOD_NUM_LOCK
import org.lwjgl.glfw.GLFW.GLFW_MOD_SHIFT
import org.lwjgl.glfw.GLFW.GLFW_MOD_SUPER

class KeybindSetting(
override var name: String,
defaultValue: KeyCode,
defaultValue: Bind,
description: String,
visibility: () -> Boolean,
) : AbstractSetting<KeyCode>(
) : AbstractSetting<Bind>(
name,
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 preview =
if (listening) "$name: Press any key…"
else bind.name

if (listening) {
withStyleColor(ImGuiCol.Button, 0.20f, 0.50f, 1.00f, 1.00f) {
Expand All @@ -68,16 +81,8 @@ class KeybindSetting(
}

lambdaTooltip {
if (!listening) {
description.ifBlank { "Click to set. Right-click to unbind. Esc cancels. Backspace/Delete unbinds." }
} else {
"Listening… Press a key to bind. Esc to cancel. Backspace/Delete to unbind."
}
}

onItemClick(ImGuiMouseButton.Right) {
value = KeyCode.UNBOUND
listening = false
if (!listening) description.ifBlank { "Click to set. Esc cancels. Backspace/Delete unbinds." }
else "Listening… Press a key to bind. Esc to cancel. Backspace/Delete to unbind."
}

if (listening && !isAnyItemHovered && isMouseClicked(ImGuiMouseButton.Left)) {
Expand All @@ -86,38 +91,108 @@ 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
if (listening) {
InputUtils.newMouseEvent()
?.let {
value = Bind(0, it.modifiers, it.button)
listening = false
return
}
else -> {
value = key
listening = false

InputUtils.newKeyboardEvent()
?.let {
val isModKey = it.keyCode in GLFW_KEY_LEFT_SHIFT..GLFW_KEY_RIGHT_SUPER

// If a mod key is pressed first ignore it unless it was released without any other keys
if ((it.isPressed && !isModKey) || (it.isReleased && isModKey)) {
when (it.translated) {
KeyCode.ESCAPE -> {}
KeyCode.BACKSPACE, KeyCode.DELETE -> value = Bind.EMPTY
else -> value = Bind(it.keyCode, it.modifiers, -1)
}

listening = false
}

return
}
}
}
}

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()).code, 0)
} catch(_: IllegalArgumentException) {
return@executeWithResult failure("${name().value()} doesn't match with a bind")
}
}

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

data class Bind(
val key: Int,
val modifiers: Int,
val mouse: Int = -1,
) {
val truemods = buildList {
if (modifiers and GLFW_MOD_SHIFT != 0) add(KeyCode.LEFT_SHIFT)
if (modifiers and GLFW_MOD_CONTROL != 0) add(KeyCode.LEFT_CONTROL)
if (modifiers and GLFW_MOD_ALT != 0) add(KeyCode.LEFT_ALT)
if (modifiers and GLFW_MOD_SUPER != 0) add(KeyCode.LEFT_SUPER)
if (modifiers and GLFW_MOD_CAPS_LOCK != 0) add(KeyCode.CAPS_LOCK)
if (modifiers and GLFW_MOD_NUM_LOCK != 0) add(KeyCode.NUM_LOCK)
}

val name: String
get() {
if (mouse < 0 && modifiers <= 0 && key <= 0) return "Unbound"

val list = mutableListOf<Any>()

if (mouse >= 0) list.add(Mouse.entries[mouse])
if (modifiers > 0) list.add(truemods.joinToString(separator = "+") { it.name })
if (key > 0) list.add(KeyCode.fromKeyCode(key))

return list.joinToString(separator = "+") { it.toString() }
}

override fun toString() =
"Key Code: $key, Modifiers: ${truemods.joinToString(separator = "+") { it.name }}, Mouse Button: ${Mouse.entries.getOrNull(mouse) ?: "None"}"

companion object {
val EMPTY = Bind(0, 0)

fun mouseBind(code: Int) = Bind(0, 0, code)
}
}
16 changes: 3 additions & 13 deletions 16 src/main/kotlin/com/lambda/event/events/KeyboardEvent.kt
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,9 @@

package com.lambda.event.events

import com.lambda.config.settings.complex.Bind
import com.lambda.event.Event
import com.lambda.util.KeyCode
import org.lwjgl.glfw.GLFW.GLFW_MOD_ALT
import org.lwjgl.glfw.GLFW.GLFW_MOD_CAPS_LOCK
import org.lwjgl.glfw.GLFW.GLFW_MOD_CONTROL
import org.lwjgl.glfw.GLFW.GLFW_MOD_NUM_LOCK
import org.lwjgl.glfw.GLFW.GLFW_MOD_SHIFT
import org.lwjgl.glfw.GLFW.GLFW_MOD_SUPER
import org.lwjgl.glfw.GLFW.GLFW_PRESS
import org.lwjgl.glfw.GLFW.GLFW_RELEASE

Expand All @@ -51,15 +46,10 @@ sealed class KeyboardEvent {
val translated: KeyCode
get() = KeyCode.virtualMapUS(keyCode, scanCode)

val isPressed = action == GLFW_PRESS
val isPressed = action >= GLFW_PRESS
val isReleased = action == GLFW_RELEASE

val hasShift = modifiers and GLFW_MOD_SHIFT != 0
val hasControl = modifiers and GLFW_MOD_CONTROL != 0
val hasAlt = modifiers and GLFW_MOD_ALT != 0
val hasSuper = modifiers and GLFW_MOD_SUPER != 0
val hasCapsLock = modifiers and GLFW_MOD_CAPS_LOCK != 0
val hasNumLock = modifiers and GLFW_MOD_NUM_LOCK != 0
fun satisfies(bind: Bind) = bind.key == keyCode && bind.modifiers and modifiers == bind.modifiers
}

/**
Expand Down
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.