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

View File

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

View File

@@ -1,4 +1,3 @@
//#if MC>=11400
package com.replaymod.core.events; package com.replaymod.core.events;
import de.johni0702.minecraft.gui.utils.Event; import de.johni0702.minecraft.gui.utils.Event;
@@ -7,11 +6,21 @@ public interface KeyEventCallback {
Event<KeyEventCallback> EVENT = Event.create((listeners) -> Event<KeyEventCallback> EVENT = Event.create((listeners) ->
(key, scanCode, action, modifiers) -> { (key, scanCode, action, modifiers) -> {
for (KeyEventCallback listener : listeners) { 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; package com.replaymod.core.mixin;
import com.replaymod.core.events.KeyBindingEventCallback; import com.replaymod.core.events.KeyBindingEventCallback;
import com.replaymod.core.events.KeyEventCallback; import com.replaymod.core.events.KeyEventCallback;
import net.minecraft.client.Keyboard;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; 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) @Mixin(Keyboard.class)
public class MixinKeyboardListener { 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) { private void afterKeyBindingTick(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) {
KeyBindingEventCallback.EVENT.invoker().onKeybindingEvent(); 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 //#endif

View File

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

View File

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

View File

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

View File

@@ -12,12 +12,12 @@
"Mixin_RegisterDynamicResourcePacks", "Mixin_RegisterDynamicResourcePacks",
//#endif //#endif
//#if MC>=11400 //#if MC>=11400
"MixinKeyboardListener",
"MixinMouse", "MixinMouse",
//#endif //#endif
//#if MC<10800 //#if MC<10800
//$$ "ResourcePackRepositoryAccessor", //$$ "ResourcePackRepositoryAccessor",
//#endif //#endif
"MixinKeyboardListener",
"MixinMinecraft", "MixinMinecraft",
"GuiMainMenuAccessor", "GuiMainMenuAccessor",
"GuiScreenAccessor", "GuiScreenAccessor",