Architectury API

Architectury API

234M Downloads

MixinKeyboardHandler never invoke event KEY_RELEASED_PRE or KEY_RELEASED_POST now

Myitian opened this issue ยท 1 comments

commented

Method wrapKeyPressed and wrapKeyReleased in MixinKeyboardHandler behave differently than onKey and onKeyAfter before.

It causes some keyboard events will be invoked twice. For example, pressing backspace once in the REI search bar will delete 2 characters.
(shedaniel/RoughlyEnoughItems#1759)

Current Behaviour

  • Both of wrapKeyPressed and wrapKeyReleased invoke KEY_PRESSED_PRE and KEY_PRESSED_POST;
  • None of them invoke KEY_RELEASED_PRE or KEY_RELEASED_POST;

Former Behaviour

  • Method onKey invokes KEY_PRESSED_PRE and KEY_RELEASED_PRE;
  • Method onKeyAfter invokes KEY_PRESSED_POST and KEY_RELEASED_POST;

Related Codes

@WrapOperation(method = "keyPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;keyPressed(III)Z"))
private boolean wrapKeyPressed(Screen screen, int keyCode, int scanCode, int modifiers, Operation<Boolean> original) {
var result = ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(minecraft, screen, keyCode, scanCode, modifiers);
if (result.isPresent())
return true;
if (original.call(screen, keyCode, scanCode, modifiers))
return true;
result = ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(minecraft, screen, keyCode, scanCode, modifiers);
return result.isPresent();
}
@WrapOperation(method = "keyPress", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;keyReleased(III)Z"))
private boolean wrapKeyReleased(Screen screen, int keyCode, int scanCode, int modifiers, Operation<Boolean> original) {
var result = ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(minecraft, screen, keyCode, scanCode, modifiers);
if (result.isPresent())
return true;
if (original.call(screen, keyCode, scanCode, modifiers))
return true;
result = ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(minecraft, screen, keyCode, scanCode, modifiers);
return result.isPresent();
}

@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0), cancellable = true)
public void onKey(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info) {
if (!info.isCancelled()) {
if (int_3 != 1 && int_3 != 2) {
if (int_3 == 0) {
var result = ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(minecraft, minecraft.screen, int_1, int_2, int_4);
if (result.isPresent())
info.cancel();
}
} else {
var result = ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(minecraft, minecraft.screen, int_1, int_2, int_4);
if (result.isPresent())
info.cancel();
}
}
}
@Inject(method = "keyPress", at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/gui/screens/Screen;wrapScreenError(Ljava/lang/Runnable;Ljava/lang/String;Ljava/lang/String;)V",
ordinal = 0, shift = At.Shift.AFTER),
cancellable = true)
public void onKeyAfter(long long_1, int int_1, int int_2, int int_3, int int_4, CallbackInfo info, @Local Screen screen, @Local boolean[] bls) {
if (!info.isCancelled() && !bls[0]) {
EventResult result;
if (int_3 != 1 && int_3 != 2) {
result = ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(minecraft, screen, int_1, int_2, int_4);
} else {
result = ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(minecraft, screen, int_1, int_2, int_4);
}
if (result.isPresent())
info.cancel();
}
}

commented

I've just run into a similar problem too.

ClientScreenInputEvent.KEY_RELEASED_PRE.register((minecraft, screen, keyCode, scanCode, modifiers) -> {
    System.out.println("key released");
});

This never prints anything on Fabric, but works as expected on Neo