Allow raw key handlers to cancel keybindings (required for #305)

So that when you press e.g. Ctrl+Z, it doesn't trigger the keybinding bound to
Z (currently full brightness).
This commit is contained in:
Jonas Herzig
2020-11-06 14:10:26 +01:00
parent ccb08d37a7
commit 28facc430e
8 changed files with 73 additions and 62 deletions

View File

@@ -4,6 +4,8 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.replaymod.core.mixin.KeyBindingAccessor;
import de.johni0702.minecraft.gui.utils.EventRegistrations;
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import com.replaymod.core.versions.MCVer;
import net.minecraft.client.options.KeyBinding;
import net.minecraft.util.crash.CrashReport;
@@ -21,13 +23,9 @@ import static com.replaymod.core.ReplayMod.MOD_ID;
//#endif
//#if MC>=11400
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import com.replaymod.core.events.PreRenderCallback;
import org.lwjgl.glfw.GLFW;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//$$ import net.minecraftforge.fml.common.gameevent.InputEvent;
//$$ import net.minecraftforge.fml.common.gameevent.TickEvent;
//$$ import org.lwjgl.input.Keyboard;
//$$ import static com.replaymod.core.versions.MCVer.FML_BUS;
@@ -42,6 +40,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
public class KeyBindingRegistry extends EventRegistrations {
private static final String CATEGORY = "replaymod.title";
@@ -51,7 +50,7 @@ public class KeyBindingRegistry extends EventRegistrations {
private final Map<String, Binding> bindings = new HashMap<>();
private Set<KeyBinding> onlyInReplay = new HashSet<>();
private Multimap<Integer, Runnable> rawHandlers = ArrayListMultimap.create();
private Multimap<Integer, Supplier<Boolean>> rawHandlers = ArrayListMultimap.create();
public Binding registerKeyBinding(String name, int keyCode, Runnable whenPressed, boolean onlyInRepay) {
Binding binding = registerKeyBinding(name, keyCode, onlyInRepay);
@@ -91,7 +90,7 @@ public class KeyBindingRegistry extends EventRegistrations {
return binding;
}
public void registerRaw(int keyCode, Runnable whenPressed) {
public void registerRaw(int keyCode, Supplier<Boolean> whenPressed) {
rawHandlers.put(keyCode, whenPressed);
}
@@ -104,17 +103,9 @@ public class KeyBindingRegistry extends EventRegistrations {
}
//#if MC>=11400
{ on(KeyBindingEventCallback.EVENT, this::handleKeyBindings); }
{ on(KeyEventCallback.EVENT, (keyCode, scanCode, action, modifiers) -> handleRaw(keyCode, action)); }
{ on(PreRenderCallback.EVENT, this::handleRepeatedKeyBindings); }
//#else
//$$ @SubscribeEvent
//$$ public void onKeyInput(InputEvent.KeyInputEvent event) {
//$$ handleKeyBindings();
//$$ handleRaw();
//$$ }
//$$
//$$ @SubscribeEvent
//$$ public void onTick(TickEvent.RenderTickEvent event) {
//$$ if (event.phase != TickEvent.Phase.START) return;
//$$ handleRepeatedKeyBindings();
@@ -129,6 +120,7 @@ public class KeyBindingRegistry extends EventRegistrations {
}
}
{ on(KeyBindingEventCallback.EVENT, this::handleKeyBindings); }
private void handleKeyBindings() {
for (Binding binding : bindings.values()) {
while (binding.keyBinding.wasPressed()) {
@@ -152,24 +144,23 @@ public class KeyBindingRegistry extends EventRegistrations {
}
}
//#if MC>=11400
private void handleRaw(int keyCode, int action) {
if (action != GLFW.GLFW_PRESS) return;
//#else
//$$ private void handleRaw() {
//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
//#endif
for (final Runnable runnable : rawHandlers.get(keyCode)) {
{ on(KeyEventCallback.EVENT, (keyCode, scanCode, action, modifiers) -> handleRaw(keyCode, action)); }
private boolean handleRaw(int keyCode, int action) {
if (action != KeyEventCallback.ACTION_PRESS) return false;
for (final Supplier<Boolean> handler : rawHandlers.get(keyCode)) {
try {
runnable.run();
if (handler.get()) {
return true;
}
} catch (Throwable cause) {
CrashReport crashReport = CrashReport.create(cause, "Handling Raw Key Binding");
CrashReportSection category = crashReport.addElement("Key Binding");
MCVer.addDetail(category, "Key Code", () -> "" + keyCode);
MCVer.addDetail(category, "Handler", runnable::toString);
MCVer.addDetail(category, "Handler", handler::toString);
throw new CrashException(crashReport);
}
}
return false;
}
public class Binding {

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
@@ -14,4 +13,3 @@ public interface KeyBindingEventCallback {
void onKeybindingEvent();
}
//#endif

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event;
@@ -7,11 +6,21 @@ public interface KeyEventCallback {
Event<KeyEventCallback> EVENT = Event.create((listeners) ->
(key, scanCode, action, modifiers) -> {
for (KeyEventCallback listener : listeners) {
listener.onKeyEvent(key, scanCode, action, modifiers);
if (listener.onKeyEvent(key, scanCode, action, modifiers)) {
return true;
}
}
return false;
}
);
void onKeyEvent(int key, int scanCode, int action, int modifiers);
//#if MC>=11400
int ACTION_RELEASE = org.lwjgl.glfw.GLFW.GLFW_RELEASE;
int ACTION_PRESS = org.lwjgl.glfw.GLFW.GLFW_PRESS;
//#else
//$$ int ACTION_RELEASE = 0;
//$$ int ACTION_PRESS = 1;
//#endif
boolean onKeyEvent(int key, int scanCode, int action, int modifiers);
}
//#endif

View File

@@ -1,20 +1,51 @@
//#if MC>=11400
package com.replaymod.core.mixin;
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
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;
//#if MC>=11400
import net.minecraft.client.Keyboard;
//#else
//$$ import net.minecraft.client.settings.KeyBinding;
//$$ import org.lwjgl.input.Keyboard;
//#endif
//#if MC>=11400
@Mixin(Keyboard.class)
public class MixinKeyboardListener {
@Inject(method = "onKey", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V", shift = At.Shift.AFTER))
private static final String ON_KEY_PRESSED = "Lnet/minecraft/client/options/KeyBinding;onKeyPressed(Lnet/minecraft/client/util/InputUtil$Key;)V";
@Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED), cancellable = true)
private void beforeKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) {
if (KeyEventCallback.EVENT.invoker().onKeyEvent(key, scanCode, action, modifiers)) {
ci.cancel();
}
}
@Inject(method = "onKey", at = @At(value = "INVOKE", target = ON_KEY_PRESSED, shift = At.Shift.AFTER))
private void afterKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) {
KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
KeyEventCallback.EVENT.invoker().onKeyEvent(key, scanCode, action, modifiers);
}
}
//#else
//$$ @Mixin(KeyBinding.class)
//$$ public class MixinKeyboardListener {
//$$ @Inject(method = "onTick", at = @At("HEAD"), cancellable = true)
//$$ private static void beforeKeyBindingTick(CallbackInfo ci) {
//$$ int keyCode = Keyboard.getEventKey() == 0 ? Keyboard.getEventCharacter() + 256 : Keyboard.getEventKey();
//$$ int action = Keyboard.getEventKeyState() ? KeyEventCallback.ACTION_PRESS : KeyEventCallback.ACTION_RELEASE;
//$$ if (KeyEventCallback.EVENT.invoker().onKeyEvent(keyCode, 0, action, 0)) {
//$$ ci.cancel();
//$$ }
//$$ }
//$$
//$$ @Inject(method = "onTick", at = @At("RETURN"))
//$$ private static void afterKeyBindingTick(CallbackInfo ci) {
//$$ KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent();
//$$ }
//$$ }
//#endif

View File

@@ -1,6 +1,8 @@
package com.replaymod.replay.gui.overlay;
import com.replaymod.core.ReplayMod;
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import com.replaymod.core.versions.MCVer.Keyboard;
import com.replaymod.replay.ReplayHandler;
import com.replaymod.replay.ReplayModReplay;
@@ -23,15 +25,6 @@ import de.johni0702.minecraft.gui.utils.lwjgl.WritablePoint;
import net.minecraft.client.options.GameOptions;
import net.minecraft.client.resource.language.I18n;
//#if MC>=11400
import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback;
import org.lwjgl.glfw.GLFW;
//#else
//$$ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
//$$ import net.minecraftforge.fml.common.gameevent.InputEvent;
//#endif
import static com.replaymod.core.ReplayMod.TEXTURE_SIZE;
public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
@@ -183,13 +176,8 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
//$$ public // All event handlers need to be public in 1.7.10
//#endif
class EventHandler extends EventRegistrations {
//#if MC>=11400
{ on(KeyBindingEventCallback.EVENT, this::onKeyBindingEvent); }
private void onKeyBindingEvent() {
//#else
//$$ @SubscribeEvent
//$$ public void onKeyBindingEvent(InputEvent.KeyInputEvent event) {
//#endif
GameOptions gameSettings = getMinecraft().options;
while (gameSettings.keyChat.wasPressed() || gameSettings.keyCommand.wasPressed()) {
if (!isMouseVisible()) {
@@ -198,16 +186,9 @@ public class GuiReplayOverlay extends AbstractGuiOverlay<GuiReplayOverlay> {
}
}
//#if MC>=11400
{ on(KeyEventCallback.EVENT, (int key, int scanCode, int action, int modifiers) -> onKeyInput(key, action)); }
{ on(KeyEventCallback.EVENT, (int key, int scanCode, int action, int modifiers) -> { onKeyInput(key, action); return false; }); }
private void onKeyInput(int key, int action) {
if (action != GLFW.GLFW_PRESS) return;
//#else
//$$ @SubscribeEvent
//$$ public void onKeyInput(InputEvent.KeyInputEvent event) {
//$$ if (!Keyboard.getEventKeyState()) return;
//$$ int key = Keyboard.getEventKey();
//#endif
if (action != KeyEventCallback.ACTION_PRESS) return;
// Allow F1 to be used to hide the replay gui (e.g. for recording with OBS)
if (isMouseVisible() && key == Keyboard.KEY_F1) {
hidden = !hidden;

View File

@@ -97,9 +97,8 @@ public class ReplayModSimplePathing extends EventRegistrations implements Module
settingsRegistry.set(Setting.AUTO_SYNC, active);
settingsRegistry.save();
});
core.getKeyBindingRegistry().registerRaw(Keyboard.KEY_DELETE, () -> {
if (guiPathing != null) guiPathing.deleteButtonPressed();
});
core.getKeyBindingRegistry().registerRaw(Keyboard.KEY_DELETE, () ->
guiPathing != null && guiPathing.deleteButtonPressed());
keyPositionKeyframe = core.getKeyBindingRegistry().registerKeyBinding("replaymod.input.positionkeyframe", Keyboard.KEY_I, () -> {
if (guiPathing != null) guiPathing.toggleKeyframe(SPPath.POSITION, false);
}, true);

View File

@@ -468,10 +468,12 @@ public class GuiPathing {
});
}
public void deleteButtonPressed() {
public boolean deleteButtonPressed() {
if (mod.getSelectedPath() != null) {
toggleKeyframe(mod.getSelectedPath(), false);
return true;
}
return false;
}
private void startLoadingEntityTracker() {