Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 27 additions & 11 deletions libraries/keybinds/README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,42 @@
# Keybinds API

The keybinds API provides events for registering keybinds. You may register a callback to this event in your mod's initializer:
The Keybinds API provides events and utilities for registering and working with keybinds.

## Registering Custom Keybinds

Keybind registration should be done in a listener to the `REGISTER_KEYBINDS` event. The `KeybindRegistry` class provides utility methods for registering keybinds.

An example is shown below.

```java
package com.example;

import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer;
import net.ornithemc.osl.keybinds.api.KeyBindingEvents;

import org.lwjgl.input.Keyboard;
import net.ornithemc.osl.keybinds.api.KeybindEvents;

public class ExampleInitializer implements ClientModInitializer {

public static KeyBinding cookieKeybind;

@Override
public void initClient() {
KeyBindingEvents.REGISTER_KEYBINDS.register(registry -> {
cookieKeybind = registry.register("Cookie", Keyboard.KEY_NONE, "Example Mod");
});
KeybindEvents.REGISTER_KEYBINDS.register(ExampleKeybinds::init);
}
}
```

```java
package com.example;

import org.lwjgl.glfw.GLFW;

import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.keybinds.api.KeybindRegistry;

public final class ExampleKeybinds {

public static final KeyBinding COOKIE = KeybindRegistry.register("cookie", GLFW.GLFW_KEY_Z, "example");

public static void init() {
}
}
```
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

/**
* Events related to Minecraft's keybinds.
*
* @deprecated use {@linkplain KeybindEvents} instead
*/
@Deprecated
public class KeyBindingEvents {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.ornithemc.osl.keybinds.api;

import net.ornithemc.osl.core.api.events.Event;

/**
* Events related to Minecraft's keybinds.
*/
public final class KeybindEvents {

/**
* This event is invoked upon game start-up, before game options are loaded.
*
* <p>
* Custom keybind registration should be done in a listener of this event.
* Helper methods for registering keybinds can be found in the {@linkplain
* KeybindRegistry} class.
*
* <p>
* Listeners to this event should be registered in your mod's entrypoint,
* and can be done as follows:
*
* <pre>
* {@code
* KeybindEvents.REGISTER_KEYBINDS.register(() -> {
* KeybindRegistry.register("cookie", Keyboard.KEY_Z, "example");
* });
* }
* </pre>
*
* @see KeybindRegistry
*/
public static final Event<Runnable> REGISTER_KEYBINDS = Event.runnable();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.ornithemc.osl.keybinds.api;

import java.util.Set;

import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.keybinds.impl.KeybindRegistryImpl;

/**
* Public access to the Keybinds registry.
*/
public final class KeybindRegistry {

/**
* @return the set of all keybind categories.
*/
public static Set<String> getCategories() {
return KeybindRegistryImpl.getCategories();
}

/**
* @param name the name or translation key of the keybind.
* @param defaultKeyCode the default key code of the keybind.
* @param category the name or translation key of the category to which the keybind belongs.
* @return the registered keybind.
*/
public static KeyBinding register(String name, int defaultKeyCode, String category) {
return KeybindRegistryImpl.register(name, defaultKeyCode, category);
}

/**
* @param keybind the keybind to register.
* @return the registered keybind.
*/
public static KeyBinding register(KeyBinding keybind) {
return KeybindRegistryImpl.register(keybind);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package net.ornithemc.osl.keybinds.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.ArrayUtils;

import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.keybinds.api.KeyBindingEvents;
import net.ornithemc.osl.keybinds.api.KeyBindingRegistry;
import net.ornithemc.osl.keybinds.api.KeybindEvents;
import net.ornithemc.osl.keybinds.impl.mixin.client.KeyBindingAccessor;

public final class KeybindRegistryImpl {

private static GameOptions options;
private static Set<String> categories;

private static List<KeyBinding> pendingKeybinds;

public static Set<String> getCategories() {
return categories;
}

public static KeyBinding register(String name, int defaultKeyCode, String category) {
return register(new KeyBinding(name, defaultKeyCode, category));
}

public static KeyBinding register(KeyBinding keybind) {
addCategory(keybind.getCategory());
addKeybind(keybind);

return keybind;
}

private static void addCategory(String category) {
categories.add(category);
}

private static void addKeybind(KeyBinding keybind) {
if (pendingKeybinds != null) {
pendingKeybinds.add(keybind);
} else {
// this code path is only reached if register methods are called after
// the event has been run - manually append the keybind anyway
options.keyBindings = ArrayUtils.addAll(options.keyBindings, keybind);
}
}

public static void init(GameOptions gameOptions) {
options = gameOptions;
categories = KeyBindingAccessor.accessCategories();

pendingKeybinds = new ArrayList<>();

KeyBindingEvents.REGISTER_KEYBINDS.invoker().accept(new KeyBindingRegistry() {

@Override
public KeyBinding register(String name, int defaultKeyCode, String category) {
return KeybindRegistryImpl.register(name, defaultKeyCode, category);
}

@Override
public KeyBinding register(KeyBinding keybind) {
return KeybindRegistryImpl.register(keybind);
}
});
KeybindEvents.REGISTER_KEYBINDS.invoker().run();

options.keyBindings = ArrayUtils.addAll(options.keyBindings, pendingKeybinds.toArray(new KeyBinding[0]));
pendingKeybinds = null;
}
}
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
package net.ornithemc.osl.keybinds.impl.mixin.client;

import java.util.LinkedHashSet;
import java.util.Set;

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.callback.CallbackInfo;

import net.minecraft.client.options.GameOptions;
import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.keybinds.api.KeyBindingEvents;
import net.ornithemc.osl.keybinds.api.KeyBindingRegistry;
import net.ornithemc.osl.keybinds.impl.KeybindRegistryImpl;

@Mixin(GameOptions.class)
public class GameOptionsMixin implements KeyBindingRegistry {

@Shadow private KeyBinding[] keyBindings;
private Set<KeyBinding> modKeyBindings;
public class GameOptionsMixin {

@Inject(
method = "<init>(Lnet/minecraft/client/Minecraft;Ljava/io/File;)V",
Expand All @@ -29,30 +20,6 @@ public class GameOptionsMixin implements KeyBindingRegistry {
)
)
private void osl$keybinds$registerKeybinds(CallbackInfo ci) {
modKeyBindings = new LinkedHashSet<>();

KeyBindingEvents.REGISTER_KEYBINDS.invoker().accept(this);

KeyBinding[] mcKeybinds = keyBindings;
keyBindings = new KeyBinding[mcKeybinds.length + modKeyBindings.size()];

int i = 0;
for (KeyBinding keybind : mcKeybinds) {
keyBindings[i++] = keybind;
}
for (KeyBinding keybind : modKeyBindings) {
keyBindings[i++] = keybind;
}
}

@Override
public KeyBinding register(String name, int defaultKeyCode, String category) {
return register(new KeyBinding(name, defaultKeyCode, category));
}

@Override
public KeyBinding register(KeyBinding keybind) {
modKeyBindings.add(keybind);
return keybind;
KeybindRegistryImpl.init((GameOptions) (Object) this);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package net.ornithemc.osl.keybinds.impl.mixin.client;

import java.util.Set;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;

import net.minecraft.client.options.KeyBinding;

@Mixin(KeyBinding.class)
public interface KeyBindingAccessor {

@Accessor("CATEGORIES")
static Set<String> accessCategories() {
throw new UnsupportedOperationException();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"mixins": [
],
"client": [
"client.GameOptionsMixin"
"client.GameOptionsMixin",
"client.KeyBindingAccessor"
],
"server": [
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@

/**
* Events related to Minecraft's keybinds.
*
* @deprecated use {@linkplain KeybindEvents} instead
*/
@Deprecated
public class KeyBindingEvents {

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package net.ornithemc.osl.keybinds.api;

import net.ornithemc.osl.core.api.events.Event;

/**
* Events related to Minecraft's keybinds.
*/
public final class KeybindEvents {

/**
* This event is invoked upon game start-up, before game options are loaded.
*
* <p>
* Custom keybind registration should be done in a listener of this event.
* Helper methods for registering keybinds can be found in the {@linkplain
* KeybindRegistry} class.
*
* <p>
* Listeners to this event should be registered in your mod's entrypoint,
* and can be done as follows:
*
* <pre>
* {@code
* KeybindEvents.REGISTER_KEYBINDS.register(() -> {
* KeybindRegistry.register("cookie", Keyboard.KEY_Z, "example");
* });
* }
* </pre>
*
* @see KeybindRegistry
*/
public static final Event<Runnable> REGISTER_KEYBINDS = Event.runnable();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package net.ornithemc.osl.keybinds.api;

import java.util.Set;

import net.minecraft.client.options.KeyBinding;

import net.ornithemc.osl.keybinds.impl.KeybindRegistryImpl;

/**
* Public access to the Keybinds registry.
*/
public final class KeybindRegistry {

/**
* @return the set of all keybind categories.
*/
public static Set<String> getCategories() {
return KeybindRegistryImpl.getCategories();
}

/**
* @param name the name or translation key of the keybind.
* @param defaultKeyCode the default key code of the keybind.
* @param category the name or translation key of the category to which the keybind belongs.
* @return the registered keybind.
*/
public static KeyBinding register(String name, int defaultKeyCode, String category) {
return KeybindRegistryImpl.register(name, defaultKeyCode, category);
}

/**
* @param keybind the keybind to register.
* @return the registered keybind.
*/
public static KeyBinding register(KeyBinding keybind) {
return KeybindRegistryImpl.register(keybind);
}
}
Loading
Loading